From bd8b9c94b38ddaa3cd7324cbca98571633e03f91 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 8 Mar 2002 16:10:32 -0300 Subject: generic for (with any number of control variables) --- lcode.c | 27 ++++++++++++++------ lcode.h | 4 ++- ldebug.c | 21 +++++++++++++--- lopcodes.c | 5 ++-- lopcodes.h | 10 +++++--- lparser.c | 84 ++++++++++++++++++++++++++++++++------------------------------ lvm.c | 15 +++++------ 7 files changed, 98 insertions(+), 68 deletions(-) diff --git a/lcode.c b/lcode.c index ffd77f2e..3cc0ea5c 100644 --- a/lcode.c +++ b/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 1.89 2002/02/05 22:39:12 roberto Exp roberto $ +** $Id: lcode.c,v 1.90 2002/03/05 12:42:47 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -158,6 +158,11 @@ void luaK_patchlist (FuncState *fs, int list, int target) { } +void luaK_patchtohere (FuncState *fs, int list) { + luaK_patchlist(fs, list, luaK_getlabel(fs)); +} + + void luaK_concat (FuncState *fs, int *l1, int l2) { if (*l1 == NO_JUMP) *l1 = l2; @@ -171,16 +176,22 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { } -void luaK_reserveregs (FuncState *fs, int n) { - fs->freereg += n; - if (fs->freereg > fs->f->maxstacksize) { - if (fs->freereg >= MAXSTACK) +void luaK_checkstack (FuncState *fs, int n) { + int newstack = fs->freereg + n; + if (newstack > fs->f->maxstacksize) { + if (newstack >= MAXSTACK) luaK_error(fs->ls, "function or expression too complex"); - fs->f->maxstacksize = cast(lu_byte, fs->freereg); + fs->f->maxstacksize = cast(lu_byte, newstack); } } +void luaK_reserveregs (FuncState *fs, int n) { + luaK_checkstack(fs, n); + fs->freereg += n; +} + + static void freereg (FuncState *fs, int reg) { if (reg >= fs->nactloc && reg < MAXSTACK) { fs->freereg--; @@ -533,7 +544,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { } } luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ - luaK_patchlist(fs, e->t, luaK_getlabel(fs)); + luaK_patchtohere(fs, e->t); e->t = NO_JUMP; } @@ -560,7 +571,7 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) { } } luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ - luaK_patchlist(fs, e->f, luaK_getlabel(fs)); + luaK_patchtohere(fs, e->f); e->f = NO_JUMP; } diff --git a/lcode.h b/lcode.h index 0a6d7bf5..ef6b1f61 100644 --- a/lcode.h +++ b/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $ +** $Id: lcode.h,v 1.27 2002/02/05 22:39:12 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -42,6 +42,7 @@ void luaK_error (LexState *ls, const char *msg); int luaK_codeABc (FuncState *fs, OpCode o, int A, unsigned int Bc); int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); void luaK_nil (FuncState *fs, int from, int n); +void luaK_checkstack (FuncState *fs, int n); void luaK_reserveregs (FuncState *fs, int n); int luaK_stringK (FuncState *fs, TString *s); int luaK_numberK (FuncState *fs, lua_Number r); @@ -57,6 +58,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults); int luaK_jump (FuncState *fs); void luaK_patchlist (FuncState *fs, int list, int target); +void luaK_patchtohere (FuncState *fs, int list); void luaK_concat (FuncState *fs, int *l1, int l2); int luaK_getlabel (FuncState *fs); void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); diff --git a/ldebug.c b/ldebug.c index 48090ae7..6f9bf9e9 100644 --- a/ldebug.c +++ b/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 1.97 2002/01/09 22:02:47 roberto Exp $ +** $Id: ldebug.c,v 1.100 2002/02/05 22:39:12 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -375,9 +375,10 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { check(c < MAXSTACK && b < c); break; } - case OP_JMP: case OP_FORLOOP: - case OP_TFORLOOP: { + checkreg(pt, a+2); + /* go through */ + case OP_JMP: { int dest = pc+1+b; check(0 <= dest && dest < pt->sizecode); /* not full check and jump is forward and do not skip `lastpc'? */ @@ -385,6 +386,12 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { pc += b; /* do the jump */ break; } + case OP_TFORLOOP: { + checkreg(pt, a+c); + checkreg(pt, a+2); /* at least 2 for table generators */ + check(pc+2 < pt->sizecode); /* check skip */ + break; + } case OP_CALL: { if (b != 0) { checkreg(pt, a+b-1); @@ -408,8 +415,14 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_CLOSURE: { + int nup; check(b < pt->sizep); - check(pc + pt->p[b]->nupvalues < pt->sizecode); + nup = pt->p[b]->nupvalues; + check(pc + nup < pt->sizecode); + for (; nup>0; nup--) { + OpCode op1 = GET_OPCODE(pt->code[pc+nup]); + check(op1 == OP_GETUPVAL || op1 == OP_MOVE); + } break; } default: break; diff --git a/lopcodes.c b/lopcodes.c index 7c452783..b48d1f71 100644 --- a/lopcodes.c +++ b/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.8 2001/12/11 22:48:44 roberto Exp $ +** $Id: lopcodes.c,v 1.11 2002/02/05 22:39:12 roberto Exp roberto $ ** extracted automatically from lopcodes.h by mkprint.lua ** DO NOT EDIT ** See Copyright Notice in lua.h @@ -60,6 +60,7 @@ const char *const luaP_opnames[] = { ((b)<= R/K(C)) then pc++ */ OP_TESTT,/* A B if (R(B)) then R(A) := R(B) else pc++ */ OP_TESTF,/* A B if not (R(B)) then R(A) := R(B) else pc++ */ -OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))*/ +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see (3)) */ -OP_FORLOOP,/* A sBc */ -OP_TFORLOOP,/* A sBc */ +OP_FORLOOP,/* A sBc R(A)+=R(A+2); if R(A) fs; adjustlocalvars(ls, nparams); luaX_checklimit(ls, fs->nactloc, MAXPARAMS, "parameters"); - fs->f->numparams = cast(short, fs->nactloc); /* `self' could be there already */ - fs->f->is_vararg = dots; + fs->f->numparams = cast(lu_byte, fs->nactloc); + fs->f->is_vararg = cast(lu_byte, dots); if (dots) { new_localvarstr(ls, "arg", 0); adjustlocalvars(ls, 1); @@ -271,7 +271,7 @@ static void enterbreak (FuncState *fs, Breaklabel *bl) { static void leavebreak (FuncState *fs, Breaklabel *bl) { fs->bl = bl->previous; - luaK_patchlist(fs, bl->breaklist, luaK_getlabel(fs)); + luaK_patchtohere(fs, bl->breaklist); lua_assert(bl->nactloc == fs->nactloc); } @@ -471,8 +471,11 @@ static void recfield (LexState *ls, struct ConsControl *cc) { FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc key, val; - if (ls->t.token == TK_NAME) + if (ls->t.token == TK_NAME) { + luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor"); + cc->nh++; checkname(ls, &key); + } else /* ls->t.token == '[' */ luaY_index(ls, &key); check(ls, '='); @@ -481,8 +484,6 @@ static void recfield (LexState *ls, struct ConsControl *cc) { luaK_exp2anyreg(fs, &val); luaK_codeABC(fs, OP_SETTABLE, val.info, cc->t->info, luaK_exp2RK(fs, &key)); fs->freereg = reg; /* free registers */ - luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor"); - cc->nh++; } @@ -893,7 +894,7 @@ static void whilestat (LexState *ls, int line) { check(ls, TK_DO); block(ls); luaK_patchlist(fs, luaK_jump(fs), while_init); - luaK_patchlist(fs, v.f, luaK_getlabel(fs)); + luaK_patchtohere(fs, v.f); check_match(ls, TK_END, TK_WHILE, line); leavebreak(fs, &bl); } @@ -922,24 +923,11 @@ static void exp1 (LexState *ls) { } -static void forbody (LexState *ls, OpCode loopfor) { - /* forbody -> DO block END */ - FuncState *fs = ls->fs; - int basereg = fs->freereg - 3; - int prep = luaK_jump(fs); - int blockinit = luaK_getlabel(fs); - check(ls, TK_DO); - adjustlocalvars(ls, 3); /* scope for control variables */ - block(ls); - luaK_patchlist(fs, prep, luaK_getlabel(fs)); - luaK_patchlist(fs, luaK_codeAsBc(fs, loopfor, basereg, NO_JUMP), blockinit); - removelocalvars(ls, 3, 1); -} - - static void fornum (LexState *ls, TString *varname) { - /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + /* fornum -> NAME = exp1,exp1[,exp1] DO body */ FuncState *fs = ls->fs; + int prep; + int base = fs->freereg; new_localvar(ls, varname, 0); new_localvarstr(ls, "(limit)", 1); new_localvarstr(ls, "(step)", 2); @@ -954,26 +942,42 @@ static void fornum (LexState *ls, TString *varname) { luaK_reserveregs(fs, 1); } luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); - forbody(ls, OP_FORLOOP); + luaK_jump(fs); + prep = luaK_getlabel(fs); + check(ls, TK_DO); + adjustlocalvars(ls, 3); /* scope for control variables */ + block(ls); + luaK_patchtohere(fs, prep-1); + luaK_patchlist(fs, luaK_codeAsBc(fs, OP_FORLOOP, base, NO_JUMP), prep); + removelocalvars(ls, 3, 1); } static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME,NAME IN exp1 forbody */ + /* forlist -> NAME {,NAME} IN exp1 DO body */ FuncState *fs = ls->fs; + int nvars = 0; + int prep; + int base = fs->freereg; new_localvarstr(ls, "(table)", 0); - new_localvar(ls, indexname, 1); - if (optional(ls, ',')) { - new_localvar(ls, str_checkname(ls), 2); - next(ls); /* skip var name */ + new_localvar(ls, indexname, ++nvars); + while (optional(ls, ',')) { + new_localvar(ls, str_checkname(ls), ++nvars); + next(ls); } - else - new_localvarstr(ls, "(val)", 2); check(ls, TK_IN); exp1(ls); /* table */ - luaK_reserveregs(fs, 2); /* registers for index and val */ - luaK_codeABC(fs, OP_LOADNIL, fs->freereg - 2, fs->freereg - 1, 0); - forbody(ls, OP_TFORLOOP); + luaK_checkstack(fs, 2); /* at least two slots, to traverse tables */ + luaK_reserveregs(fs, nvars); /* registers for vars */ + luaK_codeABC(fs, OP_LOADNIL, base+1, base+nvars, 0); + adjustlocalvars(ls, nvars+1); /* scope for control variables */ + luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); + prep = luaK_jump(fs); + check(ls, TK_DO); + block(ls); + luaK_patchlist(fs, luaK_jump(fs), prep-1); + luaK_patchtohere(fs, prep); + removelocalvars(ls, nvars+1, 1); } @@ -1013,18 +1017,18 @@ static void ifstat (LexState *ls, int line) { test_then_block(ls, &v); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchlist(fs, v.f, luaK_getlabel(fs)); + luaK_patchtohere(fs, v.f); test_then_block(ls, &v); /* ELSEIF cond THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchlist(fs, v.f, luaK_getlabel(fs)); + luaK_patchtohere(fs, v.f); next(ls); /* skip ELSE */ block(ls); /* `else' part */ } else luaK_concat(fs, &escapelist, v.f); - luaK_patchlist(fs, escapelist, luaK_getlabel(fs)); + luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); } @@ -1182,7 +1186,7 @@ static int statement (LexState *ls) { static void parlist (LexState *ls) { /* parlist -> [ param { `,' param } ] */ int nparams = 0; - short dots = 0; + int dots = 0; if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { diff --git a/lvm.c b/lvm.c index 6a282196..7058af88 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.217 2002/03/04 15:40:04 roberto Exp roberto $ +** $Id: lvm.c,v 1.218 2002/03/04 21:33:09 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -560,24 +560,21 @@ StkId luaV_execute (lua_State *L) { break; } case OP_TFORLOOP: { - int j = GETARG_sBc(i); - int loop = 0; - pc += j; /* jump back before tests (for error messages) */ if (ttype(ra) == LUA_TTABLE) { Table *t = hvalue(ra); - loop = luaH_next(L, t, ra+1); + if (luaH_next(L, t, ra+1)) + pc++; /* skip jump (keep looping) */ } else if (ttype(ra) == LUA_TFUNCTION) { setobj(ra+1, ra); L->top = ra+2; /* no arguments */ - luaD_call(L, ra+1, 2); + luaD_call(L, ra+1, GETARG_C(i)); L->top = L->ci->top; - loop = (ttype(ra+1) != LUA_TNIL); + if (ttype(ra+1) != LUA_TNIL) + pc++; /* skip jump (keep looping) */ } else luaD_error(L, "`for' generator must be a table or function"); - if (!loop) - pc -= j; /* undo jump */ break; } case OP_SETLIST: -- cgit v1.2.3-55-g6feb