diff --git a/lcode.c b/lcode.c index c1bcc980..f75ac359 100644 --- a/lcode.c +++ b/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 1.22 2000/04/07 13:13:11 roberto Exp roberto $ +** $Id: lcode.c,v 1.23 2000/04/07 19:35:20 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -53,7 +53,6 @@ static void luaK_fixjump (FuncState *fs, int pc, int dest) { SETARG_S(*jmp, NO_JUMP); /* point to itself to represent end of list */ else { /* jump is relative to position following jump instruction */ int offset = dest-(pc+1); - LUA_ASSERT(L, offset != NO_JUMP, "cannot link to itself"); if (abs(offset) > MAXARG_S) luaK_error(fs->ls, "control structure too long"); SETARG_S(*jmp, offset); @@ -434,7 +433,6 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { mode = iP; switch (o) { - case OP_JMP: delta = 0; mode = iS; break; case OP_CLOSURE: delta = -arg2+1; mode = iAB; break; case OP_SETLINE: mode = iU; break; case OP_CALL: mode = iAB; break; @@ -443,6 +441,10 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { case OP_SETTABLE: delta = -arg2; mode = iAB; break; case OP_SETLIST: delta = -(arg2+1); mode = iAB; break; case OP_SETMAP: delta = -2*(arg1+1); mode = iU; break; + case OP_FORLOOP: delta = -3; arg1 = NO_JUMP; mode = iS; break; + + case OP_FORPREP: arg1 = NO_JUMP; /* go through */ + case OP_JMP: mode = iS; break; case OP_END: case OP_PUSHNILJMP: case OP_NOT: mode = iO; break; diff --git a/llex.c b/llex.c index 7c8ccd22..4efcb873 100644 --- a/llex.c +++ b/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 1.55 2000/04/05 17:51:58 roberto Exp roberto $ +** $Id: llex.c,v 1.56 2000/04/07 13:11:49 roberto Exp roberto $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -32,7 +32,7 @@ /* ORDER RESERVED */ static const char *const token2string [] = { - "and", "break", "do", "else", "elseif", "end", + "and", "break", "do", "else", "elseif", "end", "for", "function", "if", "local", "nil", "not", "or", "repeat", "return", "then", "until", "while", "", "..", "...", "==", ">=", "<=", "~=", "", "", ""}; diff --git a/llex.h b/llex.h index 0dac5b8a..fd1daf00 100644 --- a/llex.h +++ b/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.22 2000/04/05 17:51:58 roberto Exp roberto $ +** $Id: llex.h,v 1.23 2000/04/07 13:11:49 roberto Exp roberto $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ enum RESERVED { /* terminal symbols denoted by reserved words */ TK_AND = FIRST_RESERVED, TK_BREAK, - TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FUNCTION, TK_IF, TK_LOCAL, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FOR, TK_FUNCTION, TK_IF, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_UNTIL, TK_WHILE, /* other terminal symbols */ TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, diff --git a/lopcodes.h b/lopcodes.h index a40fcbde..91c74759 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.55 2000/04/07 13:12:50 roberto Exp roberto $ +** $Id: lopcodes.h,v 1.56 2000/04/07 19:35:31 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -148,6 +148,9 @@ OP_JMP,/* J - - PC+=s */ OP_PUSHNILJMP,/* - - nil PC++; */ +OP_FORPREP,/* J */ +OP_FORLOOP,/* J */ + OP_CLOSURE,/* A B v_b-v_1 closure(KPROTO[a], v_1-v_b) */ OP_SETLINE/* U - - LINE=u */ diff --git a/lparser.c b/lparser.c index 39127e2a..df4aeecf 100644 --- a/lparser.c +++ b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.80 2000/04/10 19:21:14 roberto Exp roberto $ +** $Id: lparser.c,v 1.81 2000/04/11 18:37:18 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -884,7 +884,7 @@ static void whilestat (LexState *ls, int line) { block(ls); luaK_patchlist(fs, luaK_jump(fs), while_init); luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); - check_END(ls, TK_WHILE, line); + check_END(ls, TK_WHILE, line); /* trace END when loop ends */ leavebreak(fs, &bl); } @@ -906,7 +906,40 @@ static void repeatstat (LexState *ls, int line) { } -static void test_and_bock (LexState *ls, expdesc *v) { +static void forstat (LexState *ls, int line) { + /* forstat -> FOR NAME '=' expr1 ',' expr1 [',' expr1] DO block END */ + FuncState *fs = ls->fs; + int prep; + int blockinit; + Breaklabel bl; + enterbreak(fs, &bl); + setline_and_next(ls); /* skip for */ + store_localvar(ls, str_checkname(ls), 0); /* control variable */ + check(ls, '='); + exp1(ls); /* initial value */ + check(ls, ','); + exp1(ls); /* limit */ + if (optional(ls, ',')) + exp1(ls); /* optional step */ + else + luaK_code1(fs, OP_PUSHINT, 1); /* default step */ + adjustlocalvars(ls, 1, 0); /* init scope for control variable */ + add_localvar(ls, " limit "); + add_localvar(ls, " step "); + prep = luaK_code0(fs, OP_FORPREP); + blockinit = luaK_getlabel(fs); + check(ls, TK_DO); + block(ls); + luaK_patchlist(fs, prep, luaK_getlabel(fs)); + luaK_patchlist(fs, luaK_code0(fs, OP_FORLOOP), blockinit); + check_END(ls, TK_WHILE, line); + leavebreak(fs, &bl); + removelocalvars(ls, 3, fs->lastsetline); +} + + +static void test_and_block (LexState *ls, expdesc *v) { + /* test_and_block -> [IF | ELSEIF] cond THEN block */ setline_and_next(ls); /* skip IF or ELSEIF */ expr(ls, v); /* cond */ luaK_goiftrue(ls->fs, v, 0); @@ -921,11 +954,11 @@ static void ifstat (LexState *ls, int line) { FuncState *fs = ls->fs; expdesc v; int escapelist = NO_JUMP; - test_and_bock(ls, &v); /* IF cond THEN block */ + test_and_block(ls, &v); /* IF cond THEN block */ while (ls->token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); - test_and_bock(ls, &v); /* ELSEIF cond THEN block */ + test_and_block(ls, &v); /* ELSEIF cond THEN block */ } if (ls->token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); @@ -1062,6 +1095,10 @@ static int stat (LexState *ls) { check_END(ls, TK_DO, line); return 1; + case TK_FOR: /* stat -> forstat */ + forstat(ls, line); + return 1; + case TK_REPEAT: /* stat -> repeatstat */ repeatstat(ls, line); return 1; diff --git a/ltests.c b/ltests.c index 596fee2b..75be74c3 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 1.11 2000/04/06 17:35:23 roberto Exp roberto $ +** $Id: ltests.c,v 1.12 2000/04/07 13:12:50 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -104,6 +104,8 @@ static int printop (lua_State *L, Instruction i) { case OP_PUSHNILJMP: O("PUSHNILJMP"); break; case OP_JMPT: S("JMPT"); break; case OP_JMPF: S("JMPF"); break; + case OP_FORPREP: S("OP_FORPREP"); break; + case OP_FORLOOP: S("OP_FORLOOP"); break; case OP_CLOSURE: AB("CLOSURE"); break; case OP_SETLINE: U("SETLINE"); break; } diff --git a/lvm.c b/lvm.c index fc8cb262..29819b1e 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.99 2000/04/04 20:48:44 roberto Exp roberto $ +** $Id: lvm.c,v 1.100 2000/04/07 13:13:11 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -630,6 +630,34 @@ StkId luaV_execute (lua_State *L, const Closure *cl, register StkId base) { pc++; break; + case OP_FORPREP: + if (tonumber(top-1)) + lua_error(L, "`for' step must be a number"); + if (tonumber(top-2)) + lua_error(L, "`for' limit must be a number"); + if (tonumber(top-3)) + lua_error(L, "`for' initial value must be a number"); + nvalue(top-3) -= nvalue(top-1); /* to be undone by first FORLOOP */ + pc += GETARG_S(i); + break; + + case OP_FORLOOP: { + Number step = nvalue(top-1); + Number limit = nvalue(top-2); + Number index; + LUA_ASSERT(L, ttype(top-1) == TAG_NUMBER, "invalid step"); + LUA_ASSERT(L, ttype(top-2) == TAG_NUMBER, "invalid limit"); + if (tonumber(top-3)) lua_error(L, "`for' index must be a number"); + index = nvalue(top-3)+step; + if ((step>0) ? index<=limit : index>=limit) { + nvalue(top-3) = index; + pc += GETARG_S(i); + } + else /* end of `for': remove control variables */ + top -= 3; + break; + } + case OP_CLOSURE: L->top = top; luaV_Lclosure(L, tf->kproto[GETARG_A(i)], GETARG_B(i));