summaryrefslogtreecommitdiff
path: root/src/lparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lparser.c')
-rw-r--r--src/lparser.c254
1 files changed, 146 insertions, 108 deletions
diff --git a/src/lparser.c b/src/lparser.c
index 99bd3020..a8dafb6f 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 1.208a 2003/04/03 13:35:34 roberto Exp $
+** $Id: lparser.c,v 2.2 2004/03/12 19:53:56 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -13,6 +13,7 @@
#include "lcode.h"
#include "ldebug.h"
+#include "ldo.h"
#include "lfunc.h"
#include "llex.h"
#include "lmem.h"
@@ -27,9 +28,10 @@
#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]])
+#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) luaY_errorlimit(fs,l,m)
-#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \
- luaX_syntaxerror(ls, "too many syntax levels");
+#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \
+ luaX_lexerror(ls, "chunk has too many syntax levels", 0)
#define leavelevel(ls) ((ls)->nestlevel--)
@@ -39,9 +41,9 @@
typedef struct BlockCnt {
struct BlockCnt *previous; /* chain */
int breaklist; /* list of jumps out of this loop */
- int nactvar; /* # active local variables outside the breakable structure */
- int upval; /* true if some variable in the block is an upvalue */
- int isbreakable; /* true if `block' is a loop */
+ lu_byte nactvar; /* # active locals outside the breakable structure */
+ lu_byte upval; /* true if some variable in the block is an upvalue */
+ lu_byte isbreakable; /* true if `block' is a loop */
} BlockCnt;
@@ -71,12 +73,29 @@ static void lookahead (LexState *ls) {
}
+static void anchor_token (LexState *ls) {
+ if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
+ TString *ts = ls->t.seminfo.ts;
+ luaX_newstring(ls, getstr(ts), ts->tsv.len);
+ }
+}
+
+
static void error_expected (LexState *ls, int token) {
luaX_syntaxerror(ls,
luaO_pushfstring(ls->L, "`%s' expected", luaX_token2str(ls, token)));
}
+static void luaY_errorlimit (FuncState *fs, int limit, const char *what) {
+ const char *msg = (fs->f->lineDefined == 0) ?
+ luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
+ luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
+ fs->f->lineDefined, limit, what);
+ luaX_lexerror(fs->ls, msg, 0);
+}
+
+
static int testnext (LexState *ls, int c) {
if (ls->t.token == c) {
next(ls);
@@ -138,17 +157,25 @@ static void checkname(LexState *ls, expdesc *e) {
static int luaI_registerlocalvar (LexState *ls, TString *varname) {
FuncState *fs = ls->fs;
Proto *f = fs->f;
+ int oldsize = f->sizelocvars;
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
- LocVar, MAX_INT, "");
+ LocVar, USHRT_MAX, "too many local variables");
+ while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
f->locvars[fs->nlocvars].varname = varname;
+ luaC_objbarrier(ls->L, f, varname);
return fs->nlocvars++;
}
+#define new_localvarliteral(ls,v,n) \
+ new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n)
+
+
static void new_localvar (LexState *ls, TString *name, int n) {
FuncState *fs = ls->fs;
- luaX_checklimit(ls, fs->nactvar+n+1, MAXVARS, "local variables");
- fs->actvar[fs->nactvar+n] = luaI_registerlocalvar(ls, name);
+ luaY_checklimit(fs, fs->nactvar+n+1, MAXVARS, "local variables");
+ fs->actvar[fs->nactvar+n] = cast(unsigned short,
+ luaI_registerlocalvar(ls, name));
}
@@ -168,32 +195,26 @@ static void removevars (LexState *ls, int tolevel) {
}
-static void new_localvarstr (LexState *ls, const char *name, int n) {
- new_localvar(ls, luaS_new(ls->L, name), n);
-}
-
-
-static void create_local (LexState *ls, const char *name) {
- new_localvarstr(ls, name, 0);
- adjustlocalvars(ls, 1);
-}
-
-
static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
int i;
Proto *f = fs->f;
+ int oldsize = f->sizeupvalues;
for (i=0; i<f->nups; i++) {
if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->info) {
- lua_assert(fs->f->upvalues[i] == name);
+ lua_assert(f->upvalues[i] == name);
return i;
}
}
/* new one */
- luaX_checklimit(fs->ls, f->nups + 1, MAXUPVALUES, "upvalues");
- luaM_growvector(fs->L, fs->f->upvalues, f->nups, fs->f->sizeupvalues,
+ luaY_checklimit(fs, f->nups + 1, MAXUPVALUES, "upvalues");
+ luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues,
TString *, MAX_INT, "");
- fs->f->upvalues[f->nups] = name;
- fs->upvalues[f->nups] = *v;
+ while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL;
+ f->upvalues[f->nups] = name;
+ luaC_objbarrier(fs->L, f, name);
+ lua_assert(v->k == VLOCAL || v->k == VUPVAL);
+ fs->upvalues[f->nups].k = cast(lu_byte, v->k);
+ fs->upvalues[f->nups].info = cast(lu_byte, v->info);
return f->nups++;
}
@@ -267,18 +288,6 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
}
-static void code_params (LexState *ls, int nparams, int dots) {
- FuncState *fs = ls->fs;
- adjustlocalvars(ls, nparams);
- luaX_checklimit(ls, fs->nactvar, MAXPARAMS, "parameters");
- fs->f->numparams = cast(lu_byte, fs->nactvar);
- fs->f->is_vararg = cast(lu_byte, dots);
- if (dots)
- create_local(ls, "arg");
- luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */
-}
-
-
static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) {
bl->breaklist = NO_JUMP;
bl->isbreakable = isbreakable;
@@ -305,10 +314,13 @@ static void leaveblock (FuncState *fs) {
static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
FuncState *fs = ls->fs;
Proto *f = fs->f;
+ int oldsize = f->sizep;
int i;
luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
MAXARG_Bx, "constant table overflow");
+ while (oldsize < f->sizep) f->p[oldsize++] = NULL;
f->p[fs->np++] = func->f;
+ luaC_objbarrier(ls->L, f, func->f);
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
for (i=0; i<func->f->nups; i++) {
OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
@@ -318,24 +330,30 @@ static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
static void open_func (LexState *ls, FuncState *fs) {
- Proto *f = luaF_newproto(ls->L);
+ lua_State *L = ls->L;
+ Proto *f = luaF_newproto(L);
fs->f = f;
fs->prev = ls->fs; /* linked list of funcstates */
fs->ls = ls;
- fs->L = ls->L;
+ fs->L = L;
ls->fs = fs;
fs->pc = 0;
fs->lasttarget = 0;
fs->jpc = NO_JUMP;
fs->freereg = 0;
fs->nk = 0;
- fs->h = luaH_new(ls->L, 0, 0);
fs->np = 0;
fs->nlocvars = 0;
fs->nactvar = 0;
fs->bl = NULL;
f->source = ls->source;
f->maxstacksize = 2; /* registers 0/1 are always valid */
+ fs->h = luaH_new(L, 0, 0);
+ /* anchor table of constants and prototype (to avoid being collected) */
+ sethvalue2s(L, L->top, fs->h);
+ incr_top(L);
+ setptvalue2s(L, L->top, f);
+ incr_top(L);
}
@@ -349,7 +367,7 @@ static void close_func (LexState *ls) {
f->sizecode = fs->pc;
luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
f->sizelineinfo = fs->pc;
- luaM_reallocvector(L, f->k, f->sizek, fs->nk, TObject);
+ luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
f->sizek = fs->nk;
luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
f->sizep = fs->np;
@@ -360,15 +378,18 @@ static void close_func (LexState *ls) {
lua_assert(luaG_checkcode(f));
lua_assert(fs->bl == NULL);
ls->fs = fs->prev;
+ L->top -= 2; /* remove table and prototype from the stack */
+ /* last token read was anchored in defunct function; must reanchor it */
+ if (fs) anchor_token(ls);
}
-Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) {
+Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
struct LexState lexstate;
struct FuncState funcstate;
lexstate.buff = buff;
lexstate.nestlevel = 0;
- luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z)));
+ luaX_setinput(L, &lexstate, z, luaS_new(L, name));
open_func(&lexstate, &funcstate);
next(&lexstate); /* read first token */
chunk(&lexstate);
@@ -377,6 +398,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) {
lua_assert(funcstate.prev == NULL);
lua_assert(funcstate.f->nups == 0);
lua_assert(lexstate.nestlevel == 0);
+ lua_assert(lexstate.fs == NULL);
return funcstate.f;
}
@@ -429,7 +451,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) {
int reg = ls->fs->freereg;
expdesc key, val;
if (ls->t.token == TK_NAME) {
- luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor");
+ luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
cc->nh++;
checkname(ls, &key);
}
@@ -473,7 +495,7 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
static void listfield (LexState *ls, struct ConsControl *cc) {
expr(ls, &cc->v);
- luaX_checklimit(ls, cc->na, MAXARG_Bx, "items in a constructor");
+ luaY_checklimit(ls->fs, cc->na, MAXARG_Bx, "items in a constructor");
cc->na++;
cc->tostore++;
}
@@ -527,18 +549,35 @@ static void constructor (LexState *ls, expdesc *t) {
static void parlist (LexState *ls) {
/* parlist -> [ param { `,' param } ] */
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f;
int nparams = 0;
- int dots = 0;
+ f->is_vararg = 0;
if (ls->t.token != ')') { /* is `parlist' not empty? */
do {
switch (ls->t.token) {
- case TK_DOTS: dots = 1; next(ls); break;
- case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break;
+ case TK_NAME: { /* param -> NAME [ `=' `...' ] */
+ new_localvar(ls, str_checkname(ls), nparams++);
+ if (testnext(ls, '=')) {
+ check(ls, TK_DOTS);
+ f->is_vararg = 1;
+ }
+ break;
+ }
+ case TK_DOTS: { /* param -> `...' */
+ next(ls);
+ /* use `arg' as default name */
+ new_localvarliteral(ls, "arg", nparams++);
+ f->is_vararg = 1;
+ break;
+ }
default: luaX_syntaxerror(ls, "<name> or `...' expected");
}
- } while (!dots && testnext(ls, ','));
+ } while (!f->is_vararg && testnext(ls, ','));
}
- code_params(ls, nparams, dots);
+ adjustlocalvars(ls, nparams);
+ f->numparams = fs->nactvar - f->is_vararg;
+ luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */
}
@@ -548,8 +587,10 @@ static void body (LexState *ls, expdesc *e, int needself, int line) {
open_func(ls, &new_fs);
new_fs.f->lineDefined = line;
check(ls, '(');
- if (needself)
- create_local(ls, "self");
+ if (needself) {
+ new_localvarliteral(ls, "self", 0);
+ adjustlocalvars(ls, 1);
+ }
parlist(ls);
check(ls, ')');
chunk(ls);
@@ -645,18 +686,6 @@ static void prefixexp (LexState *ls, expdesc *v) {
singlevar(ls, v, 1);
return;
}
-#ifdef LUA_COMPATUPSYNTAX
- case '%': { /* for compatibility only */
- TString *varname;
- int line = ls->linenumber;
- next(ls); /* skip `%' */
- varname = singlevar(ls, v, 1);
- if (v->k != VUPVAL)
- luaX_errorline(ls, "global upvalues are obsolete",
- getstr(varname), line);
- return;
- }
-#endif
default: {
luaX_syntaxerror(ls, "unexpected symbol");
return;
@@ -796,7 +825,7 @@ static const struct {
** subexpr -> (simplexep | unop subexpr) { binop subexpr }
** where `binop' is any binary operator with a priority higher than `limit'
*/
-static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
+static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
BinOpr op;
UnOpr uop;
enterlevel(ls);
@@ -809,13 +838,13 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
else simpleexp(ls, v);
/* expand while operators have priorities higher than `limit' */
op = getbinopr(ls->t.token);
- while (op != OPR_NOBINOPR && cast(int, priority[op].left) > limit) {
+ while (op != OPR_NOBINOPR && priority[op].left > limit) {
expdesc v2;
BinOpr nextop;
next(ls);
luaK_infix(ls->fs, op, v);
/* read sub-expression with higher priority */
- nextop = subexpr(ls, &v2, cast(int, priority[op].right));
+ nextop = subexpr(ls, &v2, priority[op].right);
luaK_posfix(ls->fs, op, v, &v2);
op = nextop;
}
@@ -825,7 +854,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
static void expr (LexState *ls, expdesc *v) {
- subexpr(ls, v, -1);
+ subexpr(ls, v, 0);
}
/* }==================================================================== */
@@ -931,12 +960,14 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
}
-static void cond (LexState *ls, expdesc *v) {
+static int cond (LexState *ls) {
/* cond -> exp */
- expr(ls, v); /* read condition */
- if (v->k == VNIL) v->k = VFALSE; /* `falses' are all equal here */
- luaK_goiftrue(ls->fs, v);
- luaK_patchtohere(ls->fs, v->t);
+ expdesc v;
+ expr(ls, &v); /* read condition */
+ if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */
+ luaK_goiftrue(ls->fs, &v);
+ luaK_patchtohere(ls->fs, v.t);
+ return v.f;
}
@@ -1004,14 +1035,14 @@ static void repeatstat (LexState *ls, int line) {
/* repeatstat -> REPEAT block UNTIL cond */
FuncState *fs = ls->fs;
int repeat_init = luaK_getlabel(fs);
- expdesc v;
+ int flist;
BlockCnt bl;
enterblock(fs, &bl, 1);
next(ls);
block(ls);
check_match(ls, TK_UNTIL, TK_REPEAT, line);
- cond(ls, &v);
- luaK_patchlist(fs, v.f, repeat_init);
+ flist = cond(ls);
+ luaK_patchlist(fs, flist, repeat_init);
leaveblock(fs);
}
@@ -1027,30 +1058,34 @@ static int exp1 (LexState *ls) {
static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
+ /* forbody -> DO block */
BlockCnt bl;
FuncState *fs = ls->fs;
int prep, endfor;
- adjustlocalvars(ls, nvars); /* scope for all variables */
+ adjustlocalvars(ls, 3); /* control variables */
check(ls, TK_DO);
- enterblock(fs, &bl, 1); /* loop block */
- prep = luaK_getlabel(fs);
+ prep = luaK_codeAsBx(fs, (isnum ? OP_FORPREP : OP_TFORPREP), base, NO_JUMP);
+ enterblock(fs, &bl, 0); /* scope for declared variables */
+ adjustlocalvars(ls, nvars);
+ luaK_reserveregs(fs, nvars);
block(ls);
- luaK_patchtohere(fs, prep-1);
+ leaveblock(fs); /* end of scope for declared variables */
+ luaK_patchtohere(fs, prep);
endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) :
- luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3);
+ luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */
- luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep);
- leaveblock(fs);
+ luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1);
}
static void fornum (LexState *ls, TString *varname, int line) {
- /* fornum -> NAME = exp1,exp1[,exp1] DO body */
+ /* fornum -> NAME = exp1,exp1[,exp1] forbody */
FuncState *fs = ls->fs;
int base = fs->freereg;
- new_localvar(ls, varname, 0);
- new_localvarstr(ls, "(for limit)", 1);
- new_localvarstr(ls, "(for step)", 2);
+ new_localvarliteral(ls, "(for index)", 0);
+ new_localvarliteral(ls, "(for limit)", 1);
+ new_localvarliteral(ls, "(for step)", 2);
+ new_localvar(ls, varname, 3);
check(ls, '=');
exp1(ls); /* initial value */
check(ls, ',');
@@ -1061,39 +1096,39 @@ static void fornum (LexState *ls, TString *varname, int line) {
luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
luaK_reserveregs(fs, 1);
}
- luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1);
- luaK_jump(fs);
- forbody(ls, base, line, 3, 1);
+ forbody(ls, base, line, 1, 1);
}
static void forlist (LexState *ls, TString *indexname) {
- /* forlist -> NAME {,NAME} IN explist1 DO body */
+ /* forlist -> NAME {,NAME} IN explist1 forbody */
FuncState *fs = ls->fs;
expdesc e;
int nvars = 0;
int line;
int base = fs->freereg;
- new_localvarstr(ls, "(for generator)", nvars++);
- new_localvarstr(ls, "(for state)", nvars++);
+ /* create control variables */
+ new_localvarliteral(ls, "(for generator)", nvars++);
+ new_localvarliteral(ls, "(for state)", nvars++);
+ new_localvarliteral(ls, "(for control)", nvars++);
+ /* create declared variables */
new_localvar(ls, indexname, nvars++);
while (testnext(ls, ','))
new_localvar(ls, str_checkname(ls), nvars++);
check(ls, TK_IN);
line = ls->linenumber;
- adjust_assign(ls, nvars, explist1(ls, &e), &e);
+ adjust_assign(ls, 3, explist1(ls, &e), &e);
luaK_checkstack(fs, 3); /* extra space to call generator */
- luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP);
- forbody(ls, base, line, nvars, 0);
+ forbody(ls, base, line, nvars - 3, 0);
}
static void forstat (LexState *ls, int line) {
- /* forstat -> fornum | forlist */
+ /* forstat -> FOR (fornum | forlist) END */
FuncState *fs = ls->fs;
TString *varname;
BlockCnt bl;
- enterblock(fs, &bl, 0); /* block to control variable scope */
+ enterblock(fs, &bl, 1); /* scope for loop and control variables */
next(ls); /* skip `for' */
varname = str_checkname(ls); /* first variable name */
switch (ls->t.token) {
@@ -1102,38 +1137,40 @@ static void forstat (LexState *ls, int line) {
default: luaX_syntaxerror(ls, "`=' or `in' expected");
}
check_match(ls, TK_END, TK_FOR, line);
- leaveblock(fs);
+ leaveblock(fs); /* loop scope (`break' jumps to this point) */
}
-static void test_then_block (LexState *ls, expdesc *v) {
+static int test_then_block (LexState *ls) {
/* test_then_block -> [IF | ELSEIF] cond THEN block */
+ int flist;
next(ls); /* skip IF or ELSEIF */
- cond(ls, v);
+ flist = cond(ls);
check(ls, TK_THEN);
block(ls); /* `then' part */
+ return flist;
}
static void ifstat (LexState *ls, int line) {
/* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
FuncState *fs = ls->fs;
- expdesc v;
+ int flist;
int escapelist = NO_JUMP;
- test_then_block(ls, &v); /* IF cond THEN block */
+ flist = test_then_block(ls); /* IF cond THEN block */
while (ls->t.token == TK_ELSEIF) {
luaK_concat(fs, &escapelist, luaK_jump(fs));
- luaK_patchtohere(fs, v.f);
- test_then_block(ls, &v); /* ELSEIF cond THEN block */
+ luaK_patchtohere(fs, flist);
+ flist = test_then_block(ls); /* ELSEIF cond THEN block */
}
if (ls->t.token == TK_ELSE) {
luaK_concat(fs, &escapelist, luaK_jump(fs));
- luaK_patchtohere(fs, v.f);
+ luaK_patchtohere(fs, flist);
next(ls); /* skip ELSE (after patch, for correct line info) */
block(ls); /* `else' part */
}
else
- luaK_concat(fs, &escapelist, v.f);
+ luaK_concat(fs, &escapelist, flist);
luaK_patchtohere(fs, escapelist);
check_match(ls, TK_END, TK_IF, line);
}
@@ -1324,7 +1361,8 @@ static void chunk (LexState *ls) {
while (!islast && !block_follow(ls->t.token)) {
islast = statement(ls);
testnext(ls, ';');
- lua_assert(ls->fs->freereg >= ls->fs->nactvar);
+ lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
+ ls->fs->freereg >= ls->fs->nactvar);
ls->fs->freereg = ls->fs->nactvar; /* free registers */
}
leavelevel(ls);