first implementation of FOR

This commit is contained in:
Roberto Ierusalimschy 2000-04-12 15:57:19 -03:00
parent 0c3fe2c44b
commit f9cf402fbd
7 changed files with 87 additions and 15 deletions

View File

@ -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 ** Code generator for Lua
** See Copyright Notice in lua.h ** 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 */ SETARG_S(*jmp, NO_JUMP); /* point to itself to represent end of list */
else { /* jump is relative to position following jump instruction */ else { /* jump is relative to position following jump instruction */
int offset = dest-(pc+1); int offset = dest-(pc+1);
LUA_ASSERT(L, offset != NO_JUMP, "cannot link to itself");
if (abs(offset) > MAXARG_S) if (abs(offset) > MAXARG_S)
luaK_error(fs->ls, "control structure too long"); luaK_error(fs->ls, "control structure too long");
SETARG_S(*jmp, offset); SETARG_S(*jmp, offset);
@ -434,7 +433,6 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
mode = iP; mode = iP;
switch (o) { switch (o) {
case OP_JMP: delta = 0; mode = iS; break;
case OP_CLOSURE: delta = -arg2+1; mode = iAB; break; case OP_CLOSURE: delta = -arg2+1; mode = iAB; break;
case OP_SETLINE: mode = iU; break; case OP_SETLINE: mode = iU; break;
case OP_CALL: mode = iAB; 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_SETTABLE: delta = -arg2; mode = iAB; break;
case OP_SETLIST: delta = -(arg2+1); mode = iAB; break; case OP_SETLIST: delta = -(arg2+1); mode = iAB; break;
case OP_SETMAP: delta = -2*(arg1+1); mode = iU; 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: case OP_END: case OP_PUSHNILJMP: case OP_NOT:
mode = iO; break; mode = iO; break;

4
llex.c
View File

@ -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 ** Lexical Analyzer
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -32,7 +32,7 @@
/* ORDER RESERVED */ /* ORDER RESERVED */
static const char *const token2string [] = { 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", "function", "if", "local", "nil", "not", "or", "repeat", "return", "then",
"until", "while", "", "..", "...", "==", ">=", "<=", "~=", "", "", "<eof>"}; "until", "while", "", "..", "...", "==", ">=", "<=", "~=", "", "", "<eof>"};

4
llex.h
View File

@ -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 ** Lexical Analyzer
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -24,7 +24,7 @@
enum RESERVED { enum RESERVED {
/* terminal symbols denoted by reserved words */ /* terminal symbols denoted by reserved words */
TK_AND = FIRST_RESERVED, TK_BREAK, 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, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_UNTIL, TK_WHILE,
/* other terminal symbols */ /* other terminal symbols */
TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,

View File

@ -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 ** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -148,6 +148,9 @@ OP_JMP,/* J - - PC+=s */
OP_PUSHNILJMP,/* - - nil PC++; */ 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_CLOSURE,/* A B v_b-v_1 closure(KPROTO[a], v_1-v_b) */
OP_SETLINE/* U - - LINE=u */ OP_SETLINE/* U - - LINE=u */

View File

@ -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 ** LL(1) Parser and code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -884,7 +884,7 @@ static void whilestat (LexState *ls, int line) {
block(ls); block(ls);
luaK_patchlist(fs, luaK_jump(fs), while_init); luaK_patchlist(fs, luaK_jump(fs), while_init);
luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); 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); 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 */ setline_and_next(ls); /* skip IF or ELSEIF */
expr(ls, v); /* cond */ expr(ls, v); /* cond */
luaK_goiftrue(ls->fs, v, 0); luaK_goiftrue(ls->fs, v, 0);
@ -921,11 +954,11 @@ static void ifstat (LexState *ls, int line) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
expdesc v; expdesc v;
int escapelist = NO_JUMP; 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) { while (ls->token == TK_ELSEIF) {
luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_concat(fs, &escapelist, luaK_jump(fs));
luaK_patchlist(fs, v.u.l.f, luaK_getlabel(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) { if (ls->token == TK_ELSE) {
luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_concat(fs, &escapelist, luaK_jump(fs));
@ -1062,6 +1095,10 @@ static int stat (LexState *ls) {
check_END(ls, TK_DO, line); check_END(ls, TK_DO, line);
return 1; return 1;
case TK_FOR: /* stat -> forstat */
forstat(ls, line);
return 1;
case TK_REPEAT: /* stat -> repeatstat */ case TK_REPEAT: /* stat -> repeatstat */
repeatstat(ls, line); repeatstat(ls, line);
return 1; return 1;

View File

@ -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 ** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h ** 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_PUSHNILJMP: O("PUSHNILJMP"); break;
case OP_JMPT: S("JMPT"); break; case OP_JMPT: S("JMPT"); break;
case OP_JMPF: S("JMPF"); 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_CLOSURE: AB("CLOSURE"); break;
case OP_SETLINE: U("SETLINE"); break; case OP_SETLINE: U("SETLINE"); break;
} }

30
lvm.c
View File

@ -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 ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -630,6 +630,34 @@ StkId luaV_execute (lua_State *L, const Closure *cl, register StkId base) {
pc++; pc++;
break; 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: case OP_CLOSURE:
L->top = top; L->top = top;
luaV_Lclosure(L, tf->kproto[GETARG_A(i)], GETARG_B(i)); luaV_Lclosure(L, tf->kproto[GETARG_A(i)], GETARG_B(i));