// forstat -> FOR (fornum | forlist) END private void ForStat( int line ) { var fs = CurFunc; var block = new BlockCnt(); EnterBlock( fs, block, true ); Lexer.Next(); // skip `for' string varname = CheckName(); switch( Lexer.Token.TokenType ) { case (int)'=': ForNum( varname, line ); break; case (int)',': case (int)TK.IN: ForList( varname ); break; default: Lexer.SyntaxError("'=' or 'in' expected"); break; } CheckMatch( (int)TK.END, (int)TK.FOR, line ); LeaveBlock( fs ); }
// test_then_block -> [IF | ELSEIF] cond THEN block private int TestThenBlock( int escapeList ) { var fs = CurFunc; var block = new BlockCnt(); int jf; // instruction to skip `then' code (if condition is false) // skip IF or ELSEIF Lexer.Next(); // read condition var v = new ExpDesc(); Expr( v ); CheckNext( (int)TK.THEN ); if( Lexer.Token.TokenType == (int)TK.GOTO || Lexer.Token.TokenType == (int)TK.BREAK ) { // will jump to label if condition is true Coder.GoIfFalse( CurFunc, v ); // must enter block before `goto' EnterBlock( fs, block, false ); // handle goto/break GotoStat( v.ExitTrue ); // skip other no-op statements SkipNoOpStat(); // `goto' is the entire block? if( BlockFollow( false ) ) { LeaveBlock( fs ); return escapeList; } else { jf = Coder.Jump( fs ); } } // regular case (not goto/break) else { // skip over block if condition is false Coder.GoIfTrue( CurFunc, v ); EnterBlock( fs, block, false ); jf = v.ExitFalse; } // `then' part StatList(); LeaveBlock( fs ); // followed by `else' or `elseif' if( Lexer.Token.TokenType == (int)TK.ELSE || Lexer.Token.TokenType == (int)TK.ELSEIF ) { // must jump over it escapeList = Coder.Concat( fs, escapeList, Coder.Jump(fs) ); } Coder.PatchToHere( fs, jf ); return escapeList; }
// repeatstat -> REPEAT block UNTIL cond private void RepeatStat( int line ) { var fs = CurFunc; int repeatInit = Coder.GetLabel( fs ); var blockLoop = new BlockCnt(); var blockScope = new BlockCnt(); EnterBlock( fs, blockLoop, true ); EnterBlock( fs, blockScope, false ); Lexer.Next(); StatList(); CheckMatch( (int)TK.UNTIL, (int)TK.REPEAT, line ); int condExit = Cond(); if( blockScope.HasUpValue ) { Coder.PatchClose( fs, condExit, blockScope.NumActVar ); } LeaveBlock( fs ); Coder.PatchList( fs, condExit, repeatInit ); // close the loop LeaveBlock( fs ); }
// forbody -> DO block private void ForBody( int t, int line, int nvars, bool isnum ) { var fs = CurFunc; var block = new BlockCnt(); AdjustLocalVars( 3 ); // control variables CheckNext( (int)TK.DO ); int prep = isnum ? Coder.CodeAsBx( fs, OpCode.OP_FORPREP, t, Coder.NO_JUMP ) : Coder.Jump( fs ); EnterBlock( fs, block, false ); AdjustLocalVars( nvars ); Coder.ReserveRegs( fs, nvars ); Block(); LeaveBlock( fs ); Coder.PatchToHere( fs, prep ); int endfor; if( isnum ) // numeric for? { endfor = Coder.CodeAsBx( fs, OpCode.OP_FORLOOP, t, Coder.NO_JUMP ); } else // generic for { Coder.CodeABC( fs, OpCode.OP_TFORCALL, t, 0, nvars ); Coder.FixLine( fs, line ); endfor = Coder.CodeAsBx( fs, OpCode.OP_TFORLOOP, t+2, Coder.NO_JUMP ); } Coder.PatchList( fs, endfor, prep+1 ); Coder.FixLine( fs, line ); }
private void EnterBlock( FuncState fs, BlockCnt block, bool isLoop ) { block.IsLoop = isLoop; block.NumActVar = fs.NumActVar; block.FirstLabel = ActiveLabels.Count; block.FirstGoto = PendingGotos.Count; block.HasUpValue = false; block.Previous = fs.Block; fs.Block = block; Utl.Assert( fs.FreeReg == fs.NumActVar ); }
// whilestat -> WHILE cond DO block END private void WhileStat( int line ) { var fs = CurFunc; var block = new BlockCnt(); Lexer.Next(); // skip WHILE int whileInit = Coder.GetLabel( fs ); int condExit = Cond(); EnterBlock( fs, block, true ); CheckNext( (int)TK.DO ); Block(); Coder.JumpTo( fs, whileInit ); CheckMatch( (int)TK.END, (int)TK.WHILE, line ); LeaveBlock( fs ); Coder.PatchToHere( fs, condExit ); }
// "export" pending gotos to outer level, to check them against // outer labels; if the block being exited has upvalues, and // the goto exits the scope of any variable (which can be the // upvalue), close those variables being exited. private void MoveGotosOut( FuncState fs, BlockCnt block ) { int i = block.FirstGoto; // correct pending gotos to current block and try to close it // with visible labels while( i < PendingGotos.Count ) { var gt = PendingGotos[i]; if( gt.NumActVar > block.NumActVar ) { if( block.HasUpValue ) Coder.PatchClose( fs, gt.Pc, block.NumActVar ); gt.NumActVar = block.NumActVar; } if( !FindLabel(i) ) ++i; // move to next one } }
private void MainFunc( FuncState fs ) { ExpDesc v = new ExpDesc(); var block = new BlockCnt(); OpenFunc( fs, block ); fs.Proto.IsVarArg = true; // main func is always vararg InitExp( v, ExpKind.VLOCAL, 0 ); NewUpvalue( fs, LuaDef.LUA_ENV, v ); Lexer.Next(); // read first token StatList(); // check TK_EOS CloseFunc(); }
private void OpenFunc( FuncState fs, BlockCnt block ) { fs.Lexer = Lexer; fs.Prev = CurFunc; CurFunc = fs; fs.Pc = 0; fs.LastTarget = 0; fs.Jpc = Coder.NO_JUMP; fs.FreeReg = 0; fs.NumActVar = 0; fs.FirstLocal = ActVars.Count; // registers 0/1 are always valid fs.Proto.MaxStackSize = 2; fs.Proto.Source = Lexer.Source; EnterBlock( fs, block, false ); }
private void Body( ExpDesc e, bool isMethod, int line ) { var newFs = new FuncState(); var block = new BlockCnt(); newFs.Proto = AddPrototype(); newFs.Proto.LineDefined = line; OpenFunc( newFs, block ); CheckNext( (int)'(' ); if( isMethod ) { // create `self' parameter var v = NewLocalVar("self"); ActVars.Add(v); AdjustLocalVars(1); } ParList(); CheckNext( (int)')' ); StatList(); newFs.Proto.LastLineDefined = Lexer.LineNumber; CheckMatch( (int)TK.END, (int)TK.FUNCTION, line ); CodeClosure(e); CloseFunc(); }
// block -> statlist private void Block() { var fs = CurFunc; var block = new BlockCnt(); EnterBlock( fs, block, false ); StatList(); LeaveBlock( fs ); }