|
|
@ -1,5 +1,5 @@ |
|
|
|
/*
|
|
|
|
** $Id: lparser.c,v 2.97 2011/02/04 17:34:43 roberto Exp roberto $ |
|
|
|
** $Id: lparser.c,v 2.98 2011/02/07 12:28:27 roberto Exp roberto $ |
|
|
|
** Lua Parser |
|
|
|
** See Copyright Notice in lua.h |
|
|
|
*/ |
|
|
@ -42,8 +42,8 @@ |
|
|
|
typedef struct BlockCnt { |
|
|
|
struct BlockCnt *previous; /* chain */ |
|
|
|
int breaklist; /* list of jumps out of this loop */ |
|
|
|
int firstlabel; /* index (in Labellist) of first label in this block */ |
|
|
|
int firstgoto; /* index (in Gotolist) of first pending goto in this block */ |
|
|
|
int firstlabel; /* index of first label in this block */ |
|
|
|
int firstgoto; /* index of first pending goto in this block */ |
|
|
|
lu_byte nactvar; /* # active locals outside the block */ |
|
|
|
lu_byte upval; /* true if some variable in the block is an upvalue */ |
|
|
|
lu_byte isbreakable; /* true if `block' is a loop */ |
|
|
@ -169,13 +169,13 @@ static int registerlocalvar (LexState *ls, TString *varname) { |
|
|
|
|
|
|
|
static void new_localvar (LexState *ls, TString *name) { |
|
|
|
FuncState *fs = ls->fs; |
|
|
|
Varlist *vl = ls->varl; |
|
|
|
Dyndata *dyd = ls->dyd; |
|
|
|
int reg = registerlocalvar(ls, name); |
|
|
|
checklimit(fs, vl->nactvar + 1 - fs->firstlocal, |
|
|
|
checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, |
|
|
|
MAXVARS, "local variables"); |
|
|
|
luaM_growvector(ls->L, vl->actvar, vl->nactvar + 1, |
|
|
|
vl->actvarsize, Vardesc, MAX_INT, "local variables"); |
|
|
|
vl->actvar[vl->nactvar++].idx = cast(unsigned short, reg); |
|
|
|
luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, |
|
|
|
dyd->actvar.size, Vardesc, MAX_INT, "local variables"); |
|
|
|
dyd->actvar.arr[dyd->actvar.n++].idx = cast(unsigned short, reg); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -188,7 +188,7 @@ static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { |
|
|
|
|
|
|
|
|
|
|
|
static LocVar *getlocvar (FuncState *fs, int i) { |
|
|
|
int idx = fs->ls->varl->actvar[fs->firstlocal + i].idx; |
|
|
|
int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; |
|
|
|
lua_assert(idx < fs->nlocvars); |
|
|
|
return &fs->f->locvars[idx]; |
|
|
|
} |
|
|
@ -204,7 +204,7 @@ static void adjustlocalvars (LexState *ls, int nvars) { |
|
|
|
|
|
|
|
|
|
|
|
static void removevars (FuncState *fs, int tolevel) { |
|
|
|
fs->ls->varl->nactvar -= (fs->nactvar - tolevel); |
|
|
|
fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); |
|
|
|
while (fs->nactvar > tolevel) |
|
|
|
getlocvar(fs, --fs->nactvar)->endpc = fs->pc; |
|
|
|
} |
|
|
@ -332,19 +332,20 @@ static void enterlevel (LexState *ls) { |
|
|
|
static void closegoto (LexState *ls, int g, Labeldesc *label) { |
|
|
|
int i; |
|
|
|
FuncState *fs = ls->fs; |
|
|
|
Gotodesc *gt = &ls->gtl->gt[g]; |
|
|
|
Dyndata *dyd = ls->dyd; |
|
|
|
Labeldesc *gt = &dyd->gt.arr[g]; |
|
|
|
lua_assert(gt->name == label->name); |
|
|
|
if (gt->currlevel < label->nactvar) { |
|
|
|
if (gt->nactvar < label->nactvar) { |
|
|
|
const char *msg = luaO_pushfstring(ls->L, |
|
|
|
"<goto> at line %d attemps to jump into the scope of local " LUA_QS, |
|
|
|
gt->line, getstr(getlocvar(fs, gt->currlevel)->varname));; |
|
|
|
gt->line, getstr(getlocvar(fs, gt->nactvar)->varname));; |
|
|
|
luaX_syntaxerror(ls, msg); |
|
|
|
} |
|
|
|
luaK_patchlist(fs, gt->pc, label->pc); |
|
|
|
/* remove goto from pending list */ |
|
|
|
for (i = g; i < ls->gtl->ngt - 1; i++) |
|
|
|
ls->gtl->gt[i] = ls->gtl->gt[i + 1]; |
|
|
|
ls->gtl->ngt--; |
|
|
|
for (i = g; i < dyd->gt.n - 1; i++) |
|
|
|
dyd->gt.arr[i] = dyd->gt.arr[i + 1]; |
|
|
|
dyd->gt.n--; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -354,15 +355,15 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) { |
|
|
|
static int findlabel (LexState *ls, int g) { |
|
|
|
int i; |
|
|
|
BlockCnt *bl = ls->fs->bl; |
|
|
|
Labellist *labell = ls->labell; |
|
|
|
Gotodesc *gt = &ls->gtl->gt[g]; |
|
|
|
Dyndata *dyd = ls->dyd; |
|
|
|
Labeldesc *gt = &dyd->gt.arr[g]; |
|
|
|
/* check labels in current block for a match */ |
|
|
|
for (i = bl->firstlabel; i < labell->nlabel; i++) { |
|
|
|
Labeldesc *lb = &labell->label[i]; |
|
|
|
for (i = bl->firstlabel; i < dyd->label.n; i++) { |
|
|
|
Labeldesc *lb = &dyd->label.arr[i]; |
|
|
|
if (lb->name == gt->name) { |
|
|
|
lua_assert(labell->label[i].pc <= gt->pc); |
|
|
|
if (gt->currlevel > lb->nactvar && |
|
|
|
(bl->upval || ls->labell->nlabel > bl->firstlabel)) |
|
|
|
lua_assert(lb->pc <= gt->pc); |
|
|
|
if (gt->nactvar > lb->nactvar && |
|
|
|
(bl->upval || dyd->label.n > bl->firstlabel)) |
|
|
|
luaK_patchclose(ls->fs, gt->pc, lb->nactvar); |
|
|
|
closegoto(ls, g, lb); /* close it */ |
|
|
|
return 1; |
|
|
@ -378,9 +379,9 @@ static int findlabel (LexState *ls, int g) { |
|
|
|
*/ |
|
|
|
static void findgotos (LexState *ls, Labeldesc *lb) { |
|
|
|
int i; |
|
|
|
Gotolist *gtl = ls->gtl; |
|
|
|
for (i = ls->fs->bl->firstgoto; i < gtl->ngt; i++) { |
|
|
|
if (gtl->gt[i].name == lb->name) |
|
|
|
Dyndata *dyd = ls->dyd; |
|
|
|
for (i = ls->fs->bl->firstgoto; i < dyd->gt.n; i++) { |
|
|
|
if (dyd->gt.arr[i].name == lb->name) |
|
|
|
closegoto(ls, i, lb); |
|
|
|
} |
|
|
|
} |
|
|
@ -394,17 +395,17 @@ static void findgotos (LexState *ls, Labeldesc *lb) { |
|
|
|
*/ |
|
|
|
static void movegotosout (FuncState *fs, BlockCnt *bl) { |
|
|
|
int i = bl->firstgoto; |
|
|
|
LexState *ls = fs->ls; |
|
|
|
Dyndata *dyd = fs->ls->dyd; |
|
|
|
/* correct pending gotos to current block and try to close it
|
|
|
|
with visible labels */ |
|
|
|
while (i < ls->gtl->ngt) { |
|
|
|
Gotodesc *gt = &ls->gtl->gt[i]; |
|
|
|
if (gt->currlevel > bl->nactvar) { |
|
|
|
while (i < dyd->gt.n) { |
|
|
|
Labeldesc *gt = &dyd->gt.arr[i]; |
|
|
|
if (gt->nactvar > bl->nactvar) { |
|
|
|
if (bl->upval) |
|
|
|
luaK_patchclose(fs, gt->pc, bl->nactvar); |
|
|
|
gt->currlevel = bl->nactvar; |
|
|
|
gt->nactvar = bl->nactvar; |
|
|
|
} |
|
|
|
if (!findlabel(ls, i)) |
|
|
|
if (!findlabel(fs->ls, i)) |
|
|
|
i++; /* move to next one */ |
|
|
|
} |
|
|
|
} |
|
|
@ -414,8 +415,8 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { |
|
|
|
bl->breaklist = NO_JUMP; |
|
|
|
bl->isbreakable = isbreakable; |
|
|
|
bl->nactvar = fs->nactvar; |
|
|
|
bl->firstlabel = fs->ls->labell->nlabel; |
|
|
|
bl->firstgoto = fs->ls->gtl->ngt; |
|
|
|
bl->firstlabel = fs->ls->dyd->label.n; |
|
|
|
bl->firstgoto = fs->ls->dyd->gt.n; |
|
|
|
bl->upval = 0; |
|
|
|
bl->previous = fs->bl; |
|
|
|
fs->bl = bl; |
|
|
@ -427,7 +428,7 @@ static void leaveblock (FuncState *fs) { |
|
|
|
BlockCnt *bl = fs->bl; |
|
|
|
fs->bl = bl->previous; |
|
|
|
removevars(fs, bl->nactvar); |
|
|
|
fs->ls->labell->nlabel = bl->firstlabel; /* remove local labels */ |
|
|
|
fs->ls->dyd->label.n = bl->firstlabel; /* remove local labels */ |
|
|
|
movegotosout(fs, bl); |
|
|
|
if (bl->upval) { |
|
|
|
/* create a 'jump to here' to close upvalues */ |
|
|
@ -479,7 +480,7 @@ static void open_func (LexState *ls, FuncState *fs) { |
|
|
|
fs->nups = 0; |
|
|
|
fs->nlocvars = 0; |
|
|
|
fs->nactvar = 0; |
|
|
|
fs->firstlocal = ls->varl->nactvar; |
|
|
|
fs->firstlocal = ls->dyd->actvar.n; |
|
|
|
fs->bl = NULL; |
|
|
|
f = luaF_newproto(L); |
|
|
|
fs->f = f; |
|
|
@ -540,8 +541,8 @@ static void mainblock (LexState *ls, FuncState *fs) { |
|
|
|
BlockCnt bl; |
|
|
|
enterblock(fs, &bl, 0); |
|
|
|
statlist(ls); /* read main block */ |
|
|
|
if (bl.firstgoto < ls->gtl->ngt) { /* check pending gotos */ |
|
|
|
Gotodesc *gt = &ls->gtl->gt[bl.firstgoto]; |
|
|
|
if (bl.firstgoto < ls->dyd->gt.n) { /* check pending gotos */ |
|
|
|
Labeldesc *gt = &ls->dyd->gt.arr[bl.firstgoto]; |
|
|
|
const char *msg = luaO_pushfstring(ls->L, |
|
|
|
"label " LUA_QS " (<goto> at line %d) undefined", |
|
|
|
getstr(gt->name), gt->line); |
|
|
@ -552,17 +553,16 @@ static void mainblock (LexState *ls, FuncState *fs) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, |
|
|
|
Gotolist *gtl, Labellist *labell, const char *name) { |
|
|
|
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, |
|
|
|
Dyndata *dyd, const char *name) { |
|
|
|
LexState lexstate; |
|
|
|
FuncState funcstate; |
|
|
|
TString *tname = luaS_new(L, name); |
|
|
|
setsvalue2s(L, L->top, tname); /* push name to protect it */ |
|
|
|
incr_top(L); |
|
|
|
lexstate.buff = buff; |
|
|
|
lexstate.varl = varl; |
|
|
|
lexstate.gtl = gtl; |
|
|
|
lexstate.labell = labell; |
|
|
|
lexstate.dyd = dyd; |
|
|
|
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; |
|
|
|
luaX_setinput(L, &lexstate, z, tname); |
|
|
|
open_mainfunc(&lexstate, &funcstate); |
|
|
|
luaX_next(&lexstate); /* read first token */ |
|
|
@ -1172,22 +1172,27 @@ static void breakstat (LexState *ls) { |
|
|
|
luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); |
|
|
|
if (upval || |
|
|
|
(fs->nactvar > bl->nactvar && |
|
|
|
ls->labell->nlabel > bl->firstlabel)) |
|
|
|
ls->dyd->label.n > bl->firstlabel)) |
|
|
|
luaK_patchclose(fs, bl->breaklist, bl->nactvar); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int newlabelentry (LexState *ls, Labellist *l, TString *name, |
|
|
|
int line, int pc) { |
|
|
|
int n = l->n; |
|
|
|
luaM_growvector(ls->L, l->arr, l->n, l->size, Labeldesc, MAX_INT, "labels"); |
|
|
|
l->arr[n].name = name; |
|
|
|
l->arr[n].line = line; |
|
|
|
l->arr[n].nactvar = ls->fs->nactvar; |
|
|
|
l->arr[n].pc = pc; |
|
|
|
l->n++; |
|
|
|
return n; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void gotostat (LexState *ls, TString *label, int line) { |
|
|
|
Gotolist *gtl = ls->gtl; |
|
|
|
int g = gtl->ngt; /* index of new goto being created */ |
|
|
|
/* create new entry for this goto */ |
|
|
|
luaM_growvector(ls->L, gtl->gt, gtl->ngt, gtl->gtsize, |
|
|
|
Gotodesc, MAX_INT, "labels"); |
|
|
|
gtl->gt[g].name = label; |
|
|
|
gtl->gt[g].line = line; |
|
|
|
gtl->gt[g].currlevel = ls->fs->nactvar; |
|
|
|
gtl->gt[g].pc = luaK_jump(ls->fs); /* create jump instruction */ |
|
|
|
gtl->ngt++; |
|
|
|
int g = newlabelentry(ls, &ls->dyd->gt, label, line, luaK_jump(ls->fs)); |
|
|
|
findlabel(ls, g); |
|
|
|
} |
|
|
|
|
|
|
@ -1195,21 +1200,17 @@ static void gotostat (LexState *ls, TString *label, int line) { |
|
|
|
static void labelstat (LexState *ls, TString *label) { |
|
|
|
/* label -> '@' NAME ':' */ |
|
|
|
FuncState *fs = ls->fs; |
|
|
|
Labellist *labell = ls->labell; |
|
|
|
int l = labell->nlabel; /* index of new label being created */ |
|
|
|
int l; /* index of new label being created */ |
|
|
|
Labeldesc *lb; |
|
|
|
checknext(ls, ':'); |
|
|
|
/* create new entry for this label */ |
|
|
|
luaM_growvector(ls->L, labell->label, labell->nlabel, labell->labelsize, |
|
|
|
Labeldesc, MAX_INT, "labels"); |
|
|
|
labell->label[l].name = label; |
|
|
|
labell->label[l].pc = fs->pc; |
|
|
|
l = newlabelentry(ls, &ls->dyd->label, label, 0, fs->pc); |
|
|
|
lb = &ls->dyd->label.arr[l]; |
|
|
|
/* if label is last statement in the block,
|
|
|
|
assume that local variables are already out of scope */ |
|
|
|
labell->label[l].nactvar = (ls->t.token == TK_END) |
|
|
|
? fs->bl->nactvar |
|
|
|
: fs->nactvar; |
|
|
|
labell->nlabel++; |
|
|
|
findgotos(ls, &labell->label[l]); |
|
|
|
if (ls->t.token == TK_END) |
|
|
|
lb->nactvar = fs->bl->nactvar; |
|
|
|
findgotos(ls, lb); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|