diff options
Diffstat (limited to 'src/lparser.c')
-rw-r--r-- | src/lparser.c | 570 |
1 files changed, 314 insertions, 256 deletions
diff --git a/src/lparser.c b/src/lparser.c index 9b37d9df..c18b75cc 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,11 +1,12 @@ /* -** $Id: lparser.c,v 1.3 1998/07/06 22:07:51 roberto Exp $ +** $Id: lparser.c,v 1.37 1999/06/17 17:04:03 roberto Exp $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ #include <stdio.h> +#include <string.h> #include "lauxlib.h" #include "ldo.h" @@ -21,35 +22,48 @@ #include "lzio.h" -/* for limit numbers in error messages */ -#define MES_LIM(x) "(limit=" x ")" - /* size of a "normal" jump instruction: OpCode + 1 byte */ #define JMPSIZE 2 /* maximum number of local variables */ -#define MAXLOCALS 32 -#define SMAXLOCALS "32" +#ifndef MAXLOCALS +#define MAXLOCALS 200 /* arbitrary limit (<256) */ +#endif /* maximum number of upvalues */ -#define MAXUPVALUES 16 -#define SMAXUPVALUES "16" +#ifndef MAXUPVALUES +#define MAXUPVALUES 32 /* arbitrary limit (<256) */ +#endif + + +/* maximum number of variables in the left side of an assignment */ +#ifndef MAXVARSLH +#define MAXVARSLH 100 /* arbitrary limit (<255) */ +#endif + + +/* maximum number of parameters in a function */ +#ifndef MAXPARAMS +#define MAXPARAMS 100 /* arbitrary limit (<ZEROVARARG) */ +#endif /* ** Variable descriptor: -** must include a "exp" option because LL(1) cannot distinguish +** must include an "exp" option because LL(1) cannot distinguish ** between variables, upvalues and function calls on first sight. -** VGLOBAL: info is constant index of global name -** VLOCAL: info is stack index -** VDOT: info is constant index of index name -** VEXP: info is pc index of "nparam" of function call (or 0 if exp is closed) */ -typedef enum {VGLOBAL, VLOCAL, VDOT, VINDEXED, VEXP} varkind; - -typedef struct { +typedef enum { + VGLOBAL, /* info is constant index of global name */ + VLOCAL, /* info is stack index */ + VDOT, /* info is constant index of index name */ + VINDEXED, /* no info (table and index are on the stack) */ + VEXP /* info is pc index of "nparam" of a call (or 0 if exp is closed) */ +} varkind; + +typedef struct vardesc { varkind k; int info; } vardesc; @@ -61,7 +75,7 @@ typedef struct { ** and, if last expression is open (a function call), ** where is its pc index of "nparam" */ -typedef struct { +typedef struct listdesc { int n; int pc; /* 0 if last expression is closed */ } listdesc; @@ -73,7 +87,7 @@ typedef struct { ** it is a list constructor (k = 0) or a record constructor (k = 1) ** or empty (k = ';' or '}') */ -typedef struct { +typedef struct constdesc { int n; int k; } constdesc; @@ -88,16 +102,16 @@ typedef struct FuncState { int maxstacksize; /* maximum number of values on activation register */ int nlocalvar; /* number of active local variables */ int nupvalues; /* number of upvalues */ - int nvars; /* number of entries in f->locvars */ - int maxcode; /* size of f->code */ - int maxvars; /* size of f->locvars (-1 if no debug information) */ - int maxconsts; /* size of f->consts */ + int nvars; /* number of entries in f->locvars (-1 if no debug information) */ int lastsetline; /* line where last SETLINE was issued */ vardesc upvalues[MAXUPVALUES]; /* upvalues */ TaggedString *localvar[MAXLOCALS]; /* store local variable names */ } FuncState; +/* +** prototypes for non-terminal functions +*/ static int assignment (LexState *ls, vardesc *v, int nvars); static int cond (LexState *ls); static int funcname (LexState *ls, vardesc *v); @@ -117,22 +131,28 @@ static void exp1 (LexState *ls); static void exp2 (LexState *ls, vardesc *v); static void explist (LexState *ls, listdesc *e); static void explist1 (LexState *ls, listdesc *e); -static void ifpart (LexState *ls); +static void ifpart (LexState *ls, int line); static void parlist (LexState *ls); static void part (LexState *ls, constdesc *cd); static void recfield (LexState *ls); static void ret (LexState *ls); -static void simpleexp (LexState *ls, vardesc *v); static void statlist (LexState *ls); static void var_or_func (LexState *ls, vardesc *v); static void var_or_func_tail (LexState *ls, vardesc *v); +static void checklimit (LexState *ls, int val, int limit, char *msg) { + if (val > limit) { + char buff[100]; + sprintf(buff, "too many %s (limit=%d)", msg, limit); + luaX_error(ls, buff); + } +} + + static void check_pc (FuncState *fs, int n) { - if (fs->pc+n > fs->maxcode) - fs->maxcode = luaM_growvector(&fs->f->code, fs->maxcode, - Byte, codeEM, MAX_INT); + luaM_growvector(fs->f->code, fs->pc, n, Byte, codeEM, MAX_INT); } @@ -146,76 +166,79 @@ static void deltastack (LexState *ls, int delta) { FuncState *fs = ls->fs; fs->stacksize += delta; if (fs->stacksize > fs->maxstacksize) { - if (fs->stacksize > 255) + if (fs->stacksize > MAX_BYTE) luaX_error(ls, "function/expression too complex"); fs->maxstacksize = fs->stacksize; } } -static int code_oparg_at (LexState *ls, int pc, OpCode op, int builtin, - int arg, int delta) { +static void code_oparg_at (LexState *ls, int pc, OpCode op, + int arg, int delta) { Byte *code = ls->fs->f->code; deltastack(ls, delta); - if (arg < builtin) { - code[pc] = op+1+arg; - return 1; + if (arg <= MAX_BYTE) { + code[pc] = (Byte)op; + code[pc+1] = (Byte)arg; } - else if (arg <= 255) { - code[pc] = op; - code[pc+1] = arg; - return 2; - } - else if (arg <= MAX_WORD) { - code[pc] = op+1+builtin; - code[pc+1] = arg>>8; - code[pc+2] = arg&0xFF; - return 3; + else if (arg > MAX_ARG) + luaX_error(ls, "code too long"); + else { /* MAX_BYTE < arg < MAX_ARG */ + if (arg > MAX_WORD) { + code[pc] = (Byte)LONGARG; + code[pc+1] = (Byte)(arg>>16); + pc += 2; + } + code[pc] = (Byte)(op-1); /* opcode for word argument */ + code[pc+1] = (Byte)((arg&0xFFFF)>>8); + code[pc+2] = (Byte)(arg&0xFF); } - else luaX_error(ls, "code too long " MES_LIM("64K")); - return 0; /* to avoid warnings */ } -static int fix_opcode (LexState *ls, int pc, OpCode op, int builtin, int arg) { - FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; - if (arg < builtin) { /* close space */ - luaO_memdown(f->code+pc+1, f->code+pc+2, fs->pc-(pc+2)); - fs->pc--; - } - else if (arg > 255) { /* open space */ - check_pc(fs, 1); - luaO_memup(f->code+pc+1, f->code+pc, fs->pc-pc); - fs->pc++; +static int codesize (int arg) { + if (arg <= MAX_BYTE) return 2; /* opcode + 1 byte */ + else if (arg <= MAX_WORD) return 3; /* opcode + 1 word (2 bytes) */ + else return 5; /* LONGARG + 1 byte + opcode + 1 word (2 bytes) */ +} + + +static int fix_opcode (LexState *ls, int pc, OpCode op, int arg) { + int tomove = codesize(arg)-2; + if (tomove > 0) { /* need to open space? */ + FuncState *fs = ls->fs; + TProtoFunc *f = fs->f; + check_pc(fs, tomove); + luaO_memup(f->code+pc+tomove, f->code+pc, fs->pc-pc); + fs->pc += tomove; } - return code_oparg_at(ls, pc, op, builtin, arg, 0) - 2; + code_oparg_at(ls, pc, op, arg, 0); + return tomove; } -static void code_oparg (LexState *ls, OpCode op, int builtin, int arg, - int delta) { - check_pc(ls->fs, 3); /* maximum code size */ - ls->fs->pc += code_oparg_at(ls, ls->fs->pc, op, builtin, arg, delta); + +static void code_oparg (LexState *ls, OpCode op, int arg, int delta) { + int size = codesize(arg); + check_pc(ls->fs, size); + code_oparg_at(ls, ls->fs->pc, op, arg, delta); + ls->fs->pc += size; } static void code_opcode (LexState *ls, OpCode op, int delta) { deltastack(ls, delta); - code_byte(ls->fs, op); + code_byte(ls->fs, (Byte)op); } static void code_constant (LexState *ls, int c) { - code_oparg(ls, PUSHCONSTANT, 8, c, 1); + code_oparg(ls, PUSHCONSTANT, c, 1); } static int next_constant (FuncState *fs) { TProtoFunc *f = fs->f; - if (f->nconsts >= fs->maxconsts) { - fs->maxconsts = luaM_growvector(&f->consts, fs->maxconsts, TObject, - constantEM, MAX_WORD); - } + luaM_growvector(f->consts, f->nconsts, 1, TObject, constantEM, MAX_ARG); return f->nconsts++; } @@ -249,9 +272,9 @@ static int real_constant (FuncState *fs, real r) { if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r) return c; } - /* not found; create a luaM_new entry */ + /* not found; create a new entry */ c = next_constant(fs); - cnt = fs->f->consts; /* 'next_constant' may reallocate this vector */ + cnt = fs->f->consts; /* 'next_constant' may have reallocated this vector */ ttype(&cnt[c]) = LUA_T_NUMBER; nvalue(&cnt[c]) = r; return c; @@ -259,9 +282,11 @@ static int real_constant (FuncState *fs, real r) { static void code_number (LexState *ls, real f) { - int i; - if (f >= 0 && f <= (real)MAX_WORD && (real)(i=(int)f) == f) - code_oparg(ls, PUSHNUMBER, 3, i, 1); /* f has a short integer value */ + real af = (f<0) ? -f : f; + if (0 <= af && af <= (real)MAX_WORD && (int)af == af) { + /* abs(f) has a short integer value */ + code_oparg(ls, (f<0) ? PUSHNUMBERNEG : PUSHNUMBER, (int)af, 1); + } else code_constant(ls, real_constant(ls->fs, f)); } @@ -269,24 +294,23 @@ static void code_number (LexState *ls, real f) { static void flush_record (LexState *ls, int n) { if (n > 0) - code_oparg(ls, SETMAP, 1, n-1, -2*n); + code_oparg(ls, SETMAP, n-1, -2*n); } static void flush_list (LexState *ls, int m, int n) { - if (n == 0) return; - code_oparg(ls, SETLIST, 1, m, -n); - code_byte(ls->fs, n); + if (n > 0) { + code_oparg(ls, SETLIST, m, -n); + code_byte(ls->fs, (Byte)n); + } } static void luaI_registerlocalvar (FuncState *fs, TaggedString *varname, int line) { - if (fs->maxvars != -1) { /* debug information? */ + if (fs->nvars != -1) { /* debug information? */ TProtoFunc *f = fs->f; - if (fs->nvars >= fs->maxvars) - fs->maxvars = luaM_growvector(&f->locvars, fs->maxvars, - LocVar, "", MAX_WORD); + luaM_growvector(f->locvars, fs->nvars, 1, LocVar, "", MAX_INT); f->locvars[fs->nvars].varname = varname; f->locvars[fs->nvars].line = line; fs->nvars++; @@ -301,10 +325,8 @@ static void luaI_unregisterlocalvar (FuncState *fs, int line) { static void store_localvar (LexState *ls, TaggedString *name, int n) { FuncState *fs = ls->fs; - if (fs->nlocalvar+n < MAXLOCALS) - fs->localvar[fs->nlocalvar+n] = name; - else - luaX_error(ls, "too many local variables " MES_LIM(SMAXLOCALS)); + checklimit(ls, fs->nlocalvar+n+1, MAXLOCALS, "local variables"); + fs->localvar[fs->nlocalvar+n] = name; luaI_registerlocalvar(fs, name, ls->linenumber); } @@ -315,6 +337,16 @@ static void add_localvar (LexState *ls, TaggedString *name) { } +static void correctvarlines (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + if (fs->nvars != -1) { /* debug information? */ + for (; nvars; nvars--) { /* correct line information */ + fs->f->locvars[fs->nvars-nvars].line = fs->lastsetline; + } + } +} + + static int aux_localname (FuncState *fs, TaggedString *n) { int i; for (i=fs->nlocalvar-1; i >= 0; i--) @@ -326,13 +358,13 @@ static int aux_localname (FuncState *fs, TaggedString *n) { static void singlevar (LexState *ls, TaggedString *n, vardesc *var, int prev) { FuncState *fs = prev ? ls->fs->prev : ls->fs; int i = aux_localname(fs, n); - if (i >= 0) { /* local value */ + if (i >= 0) { /* local value? */ var->k = VLOCAL; var->info = i; } - else { /* check shadowing */ + else { FuncState *level = fs; - while ((level = level->prev) != NULL) + while ((level = level->prev) != NULL) /* check shadowing */ if (aux_localname(level, n) >= 0) luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); var->k = VGLOBAL; @@ -351,29 +383,26 @@ static int indexupvalue (LexState *ls, TaggedString *n) { return i; } /* new one */ - if (++(fs->nupvalues) > MAXUPVALUES) - luaX_error(ls, "too many upvalues in a single function " - MES_LIM(SMAXUPVALUES)); + ++(fs->nupvalues); + checklimit(ls, fs->nupvalues, MAXUPVALUES, "upvalues"); fs->upvalues[i] = v; /* i = fs->nupvalues - 1 */ return i; } static void pushupvalue (LexState *ls, TaggedString *n) { - int i; if (ls->fs->prev == NULL) luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); if (aux_localname(ls->fs, n) >= 0) luaX_syntaxerror(ls, "cannot access an upvalue in current scope", n->str); - i = indexupvalue(ls, n); - code_oparg(ls, PUSHUPVALUE, 2, i, 1); + code_oparg(ls, PUSHUPVALUE, indexupvalue(ls, n), 1); } static void check_debugline (LexState *ls) { - if (lua_debug && ls->linenumber != ls->fs->lastsetline) { - code_oparg(ls, SETLINE, 0, ls->linenumber, 0); + if (L->debug && ls->linenumber != ls->fs->lastsetline) { + code_oparg(ls, SETLINE, ls->linenumber, 0); ls->fs->lastsetline = ls->linenumber; } } @@ -381,22 +410,22 @@ static void check_debugline (LexState *ls) { static void adjuststack (LexState *ls, int n) { if (n > 0) - code_oparg(ls, POP, 2, n-1, -n); + code_oparg(ls, POP, n, -n); else if (n < 0) - code_oparg(ls, PUSHNIL, 1, (-n)-1, -n); + code_oparg(ls, PUSHNIL, (-n)-1, -n); } static void close_exp (LexState *ls, int pc, int nresults) { - if (pc > 0) { /* expression is an open function call */ + if (pc > 0) { /* expression is an open function call? */ Byte *code = ls->fs->f->code; - int nparams = code[pc]; /* save nparams */ - pc += fix_opcode(ls, pc-2, CALLFUNC, 2, nresults); - code[pc] = nparams; /* restore nparams */ - if (nresults != MULT_RET) - deltastack(ls, nresults); /* "push" results */ - deltastack(ls, -(nparams+1)); /* "pop" params and function */ + code[pc-1] = (Byte)nresults; /* set nresults */ + /* push results, pop params (at code[pc]) and function */ + deltastack(ls, nresults-(code[pc]+1)); } +#ifdef DEBUG + code_oparg(ls, CHECKSTACK, ls->fs->stacksize, 0); +#endif } @@ -408,7 +437,7 @@ static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) { } else { /* must correct function call */ diff--; /* do not count function call itself */ - if (diff < 0) { /* more variables than values */ + if (diff <= 0) { /* more variables than values? */ /* function call must provide extra values */ close_exp(ls, d->pc, -diff); } @@ -423,29 +452,39 @@ static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) { static void code_args (LexState *ls, int nparams, int dots) { FuncState *fs = ls->fs; fs->nlocalvar += nparams; /* "self" may already be there */ + checklimit(ls, fs->nlocalvar, MAXPARAMS, "parameters"); nparams = fs->nlocalvar; if (!dots) { - fs->f->code[1] = nparams; /* fill-in arg information */ + fs->f->code[1] = (Byte)nparams; /* fill-in arg information */ deltastack(ls, nparams); } else { - fs->f->code[1] = nparams+ZEROVARARG; + fs->f->code[1] = (Byte)(nparams+ZEROVARARG); deltastack(ls, nparams+1); add_localvar(ls, luaS_new("arg")); } } +static void unloaddot (LexState *ls, vardesc *v) { + /* dotted variables <a.x> must be stored like regular indexed vars <a["x"]> */ + if (v->k == VDOT) { + code_constant(ls, v->info); + v->k = VINDEXED; + } +} + + static void lua_pushvar (LexState *ls, vardesc *var) { switch (var->k) { case VLOCAL: - code_oparg(ls, PUSHLOCAL, 8, var->info, 1); + code_oparg(ls, PUSHLOCAL, var->info, 1); break; case VGLOBAL: - code_oparg(ls, GETGLOBAL, 8, var->info, 1); + code_oparg(ls, GETGLOBAL, var->info, 1); break; case VDOT: - code_oparg(ls, GETDOTTED, 8, var->info, 0); + code_oparg(ls, GETDOTTED, var->info, 0); break; case VINDEXED: code_opcode(ls, GETTABLE, -1); @@ -462,13 +501,13 @@ static void lua_pushvar (LexState *ls, vardesc *var) { static void storevar (LexState *ls, vardesc *var) { switch (var->k) { case VLOCAL: - code_oparg(ls, SETLOCAL, 8, var->info, -1); + code_oparg(ls, SETLOCAL, var->info, -1); break; case VGLOBAL: - code_oparg(ls, SETGLOBAL, 8, var->info, -1); + code_oparg(ls, SETGLOBAL, var->info, -1); break; case VINDEXED: - code_opcode(ls, SETTABLE0, -3); + code_opcode(ls, SETTABLEPOP, -3); break; default: LUA_INTERNALERROR("invalid var kind to store"); @@ -478,21 +517,20 @@ static void storevar (LexState *ls, vardesc *var) { static int fix_jump (LexState *ls, int pc, OpCode op, int n) { /* jump is relative to position following jump instruction */ - return fix_opcode(ls, pc, op, 0, n-(pc+JMPSIZE)); + return fix_opcode(ls, pc, op, n-(pc+JMPSIZE)); } static void fix_upjmp (LexState *ls, OpCode op, int pos) { int delta = ls->fs->pc+JMPSIZE - pos; /* jump is relative */ - if (delta > 255) delta++; - code_oparg(ls, op, 0, delta, 0); + code_oparg(ls, op, delta+(codesize(delta)-2), 0); } static void codeIf (LexState *ls, int thenAdd, int elseAdd) { FuncState *fs = ls->fs; int elseinit = elseAdd+JMPSIZE; - if (fs->pc == elseinit) { /* no else part */ + if (fs->pc == elseinit) { /* no else part? */ fs->pc -= JMPSIZE; elseinit = fs->pc; } @@ -513,13 +551,14 @@ static void func_onstack (LexState *ls, FuncState *func) { else { for (i=0; i<func->nupvalues; i++) lua_pushvar(ls, &func->upvalues[i]); - code_oparg(ls, CLOSURE, 0, c, -func->nupvalues+1); - code_byte(fs, func->nupvalues); + deltastack(ls, 1); /* CLOSURE puts one extra element (before poping) */ + code_oparg(ls, CLOSURE, c, -func->nupvalues); + code_byte(fs, (Byte)func->nupvalues); } } -static void init_state (LexState *ls, FuncState *fs, TaggedString *filename) { +static void init_state (LexState *ls, FuncState *fs, TaggedString *source) { TProtoFunc *f = luaF_newproto(); fs->prev = ls->fs; /* linked list of funcstates */ ls->fs = fs; @@ -529,17 +568,15 @@ static void init_state (LexState *ls, FuncState *fs, TaggedString *filename) { fs->nupvalues = 0; fs->lastsetline = 0; fs->f = f; - f->fileName = filename; + f->source = source; fs->pc = 0; - fs->maxcode = 0; f->code = NULL; - fs->maxconsts = 0; - if (lua_debug) - fs->nvars = fs->maxvars = 0; - else - fs->maxvars = -1; /* flag no debug information */ - code_byte(fs, 0); /* to be filled with stacksize */ + fs->nvars = (L->debug) ? 0 : -1; /* flag no debug information? */ + code_byte(fs, 0); /* to be filled with maxstacksize */ code_byte(fs, 0); /* to be filled with arg information */ + /* push function (to avoid GC) */ + tfvalue(L->stack.top) = f; ttype(L->stack.top) = LUA_T_PROTO; + incr_top; } @@ -547,14 +584,15 @@ static void close_func (LexState *ls) { FuncState *fs = ls->fs; TProtoFunc *f = fs->f; code_opcode(ls, ENDCODE, 0); - f->code[0] = fs->maxstacksize; - f->code = luaM_reallocvector(f->code, fs->pc, Byte); - f->consts = luaM_reallocvector(f->consts, f->nconsts, TObject); - if (fs->maxvars != -1) { /* debug information? */ + f->code[0] = (Byte)fs->maxstacksize; + luaM_reallocvector(f->code, fs->pc, Byte); + luaM_reallocvector(f->consts, f->nconsts, TObject); + if (fs->nvars != -1) { /* debug information? */ luaI_registerlocalvar(fs, NULL, -1); /* flag end of vector */ - f->locvars = luaM_reallocvector(f->locvars, fs->nvars, LocVar); + luaM_reallocvector(f->locvars, fs->nvars, LocVar); } ls->fs = fs->prev; + L->stack.top--; /* pop function */ } @@ -562,13 +600,11 @@ static void close_func (LexState *ls) { static int expfollow [] = {ELSE, ELSEIF, THEN, IF, WHILE, REPEAT, DO, NAME, LOCAL, FUNCTION, END, UNTIL, RETURN, ')', ']', '}', ';', EOS, ',', 0}; + static int is_in (int tok, int *toks) { - int *t = toks; - while (*t) { - if (*t == tok) - return t-toks; - t++; - } + int *t; + for (t=toks; *t; t++) + if (*t == tok) return t-toks; return -1; } @@ -580,19 +616,25 @@ static void next (LexState *ls) { static void error_expected (LexState *ls, int token) { char buff[100], t[TOKEN_LEN]; - luaX_token2str(ls, token, t); + luaX_token2str(token, t); sprintf(buff, "`%s' expected", t); luaX_error(ls, buff); } + +static void error_unexpected (LexState *ls) { + luaX_error(ls, "unexpected token"); +} + + static void error_unmatched (LexState *ls, int what, int who, int where) { if (where == ls->linenumber) error_expected(ls, what); else { char buff[100]; char t_what[TOKEN_LEN], t_who[TOKEN_LEN]; - luaX_token2str(ls, what, t_what); - luaX_token2str(ls, who, t_who); + luaX_token2str(what, t_what); + luaX_token2str(who, t_who); sprintf(buff, "`%s' expected (to close `%s' at line %d)", t_what, t_who, where); luaX_error(ls, buff); @@ -612,13 +654,18 @@ static void check_match (LexState *ls, int what, int who, int where) { next(ls); } -static TaggedString *checkname (LexState *ls) { - TaggedString *ts; +static int checkname (LexState *ls) { + int sc; if (ls->token != NAME) luaX_error(ls, "`NAME' expected"); - ts = ls->seminfo.ts; + sc = string_constant(ls->fs, ls->seminfo.ts); next(ls); - return ts; + return sc; +} + + +static TaggedString *str_checkname (LexState *ls) { + return tsvalue(&ls->fs->f->consts[checkname(ls)]); } @@ -669,12 +716,9 @@ static int stat (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ FuncState *fs = ls->fs; switch (ls->token) { - case IF: { /* stat -> IF ifpart END */ - next(ls); - ifpart(ls); - check_match(ls, END, IF, line); + case IF: /* stat -> IF ifpart END */ + ifpart(ls, line); return 1; - } case WHILE: { /* stat -> WHILE cond DO block END */ TProtoFunc *f = fs->f; @@ -732,7 +776,8 @@ static int stat (LexState *ls) { next(ls); nvars = localnamelist(ls); decinit(ls, &d); - ls->fs->nlocalvar += nvars; + fs->nlocalvar += nvars; + correctvarlines(ls, nvars); /* vars will be alive only after decinit */ adjust_mult_assign(ls, nvars, &d); return 1; } @@ -746,8 +791,8 @@ static int stat (LexState *ls) { luaX_error(ls, "syntax error"); close_exp(ls, v.info, 0); } - else { - int left = assignment(ls, &v, 1); /* stat -> ['%'] NAME assignment */ + else { /* stat -> ['%'] NAME assignment */ + int left = assignment(ls, &v, 1); adjuststack(ls, left); /* remove eventual 'garbage' left on stack */ } return 1; @@ -758,7 +803,7 @@ static int stat (LexState *ls) { return 0; default: - luaX_error(ls, "<statement> expected"); + error_unexpected(ls); return 0; /* to avoid warnings */ } } @@ -788,18 +833,18 @@ static void block (LexState *ls) { chunk(ls); adjuststack(ls, fs->nlocalvar - nlocalvar); for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) - luaI_unregisterlocalvar(fs, ls->linenumber); + luaI_unregisterlocalvar(fs, fs->lastsetline); } static int funcname (LexState *ls, vardesc *v) { /* funcname -> NAME [':' NAME | '.' NAME] */ int needself = 0; - singlevar(ls, checkname(ls), v, 0); + singlevar(ls, str_checkname(ls), v, 0); if (ls->token == ':' || ls->token == '.') { needself = (ls->token == ':'); next(ls); lua_pushvar(ls, v); - code_string(ls, checkname(ls)); + code_constant(ls, checkname(ls)); v->k = VINDEXED; } return needself; @@ -808,7 +853,7 @@ static int funcname (LexState *ls, vardesc *v) { static void body (LexState *ls, int needself, int line) { /* body -> '(' parlist ')' chunk END */ FuncState newfs; - init_state(ls, &newfs, ls->fs->f->fileName); + init_state(ls, &newfs, ls->fs->f->source); newfs.f->lineDefined = line; check(ls, '('); if (needself) @@ -821,36 +866,40 @@ static void body (LexState *ls, int needself, int line) { func_onstack(ls, &newfs); } -static void ifpart (LexState *ls) { + +static void ifpart (LexState *ls, int line) { /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ - int c = cond(ls); + int c; int e; + next(ls); /* skip IF or ELSEIF */ + c = cond(ls); check(ls, THEN); block(ls); e = SaveWord(ls); - switch (ls->token) { - case ELSE: - next(ls); + if (ls->token == ELSEIF) + ifpart(ls, line); + else { + if (optional(ls, ELSE)) block(ls); - break; - - case ELSEIF: - next(ls); - ifpart(ls); - break; + check_match(ls, END, IF, line); } codeIf(ls, c, e); } + static void ret (LexState *ls) { /* ret -> [RETURN explist sc] */ - if (ls->token == RETURN) { + if (optional(ls, RETURN)) { listdesc e; check_debugline(ls); - next(ls); - explist(ls, &e); - close_exp(ls, e.pc, MULT_RET); - code_oparg(ls, RETCODE, 0, ls->fs->nlocalvar, 0); + explist(ls, &e); + if (e.pc > 0) { /* expression is an open function call? */ + Byte *code = ls->fs->f->code; + code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */ + code[e.pc-1] = (Byte)ls->fs->nlocalvar; + } + else + code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0); ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ optional(ls, ';'); } @@ -863,6 +912,9 @@ static void ret (LexState *ls) { ** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1. */ +#define INDNOT 0 +#define INDMINUS 1 + /* code of first binary operator */ #define FIRSTBIN 2 @@ -879,9 +931,9 @@ static int priority [POW+1] = {5, 5, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 4, 6}; static OpCode opcodes [POW+1] = {NOTOP, MINUSOP, EQOP, NEQOP, GTOP, LTOP, LEOP, GEOP, CONCOP, ADDOP, SUBOP, MULTOP, DIVOP, POWOP}; -#define MAXOPS 20 +#define MAXOPS 20 /* op's stack size (arbitrary limit) */ -typedef struct { +typedef struct stack_op { int ops[MAXOPS]; int top; } stack_op; @@ -892,39 +944,33 @@ static void exp1 (LexState *ls) { exp0(ls, &v); lua_pushvar(ls, &v); if (is_in(ls->token, expfollow) < 0) - luaX_error(ls, "ill formed expression"); + luaX_error(ls, "ill-formed expression"); } static void exp0 (LexState *ls, vardesc *v) { + /* exp0 -> exp2 {(AND | OR) exp2} */ exp2(ls, v); while (ls->token == AND || ls->token == OR) { - int is_and = (ls->token == AND); + int op = (ls->token == AND) ? ONFJMP : ONTJMP; int pc; lua_pushvar(ls, v); next(ls); pc = SaveWordPop(ls); exp2(ls, v); lua_pushvar(ls, v); - fix_jump(ls, pc, (is_and?ONFJMP:ONTJMP), ls->fs->pc); + fix_jump(ls, pc, op, ls->fs->pc); } } static void push (LexState *ls, stack_op *s, int op) { - if (s->top == MAXOPS) + if (s->top >= MAXOPS) luaX_error(ls, "expression too complex"); s->ops[s->top++] = op; } -static void prefix (LexState *ls, stack_op *s) { - while (ls->token == NOT || ls->token == '-') { - push(ls, s, ls->token==NOT?0:1); - next(ls); - } -} - static void pop_to (LexState *ls, stack_op *s, int prio) { int op; while (s->top > 0 && priority[(op=s->ops[s->top-1])] >= prio) { @@ -933,92 +979,104 @@ static void pop_to (LexState *ls, stack_op *s, int prio) { } } -static void exp2 (LexState *ls, vardesc *v) { - stack_op s; - int op; - s.top = 0; - prefix(ls, &s); - simpleexp(ls, v); - while ((op = is_in(ls->token, binop)) >= 0) { - op += FIRSTBIN; - lua_pushvar(ls, v); - /* '^' is right associative, so must 'simulate' a higher priority */ - pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]); - push(ls, &s, op); - next(ls); - prefix(ls, &s); - simpleexp(ls, v); - lua_pushvar(ls, v); - } - if (s.top > 0) { - lua_pushvar(ls, v); - pop_to(ls, &s, 0); - } -} - - -static void simpleexp (LexState *ls, vardesc *v) { +static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { check_debugline(ls); switch (ls->token) { - case '(': /* simpleexp -> '(' exp0 ')' */ - next(ls); - exp0(ls, v); - check(ls, ')'); - break; - - case NUMBER: /* simpleexp -> NUMBER */ - code_number(ls, ls->seminfo.r); + case NUMBER: { /* simpleexp -> NUMBER */ + real r = ls->seminfo.r; next(ls); - v->k = VEXP; v->info = 0; + /* dirty trick: check whether it is a -NUMBER not followed by '^' */ + /* (because the priority of '^' is closer than '-'...) */ + if (s->top > 0 && s->ops[s->top-1] == INDMINUS && ls->token != '^') { + s->top--; /* remove '-' from stack */ + r = -r; + } + code_number(ls, r); break; + } case STRING: /* simpleexp -> STRING */ - code_string(ls, ls->seminfo.ts); + code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */ next(ls); - v->k = VEXP; v->info = 0; break; case NIL: /* simpleexp -> NIL */ adjuststack(ls, -1); next(ls); - v->k = VEXP; v->info = 0; break; case '{': /* simpleexp -> constructor */ constructor(ls); - v->k = VEXP; v->info = 0; break; - case FUNCTION: { /* simpleexp -> FUNCTION body */ - int line = ls->linenumber; + case FUNCTION: /* simpleexp -> FUNCTION body */ next(ls); - body(ls, 0, line); - v->k = VEXP; v->info = 0; + body(ls, 0, ls->linenumber); break; - } + + case '(': /* simpleexp -> '(' exp0 ')' */ + next(ls); + exp0(ls, v); + check(ls, ')'); + return; case NAME: case '%': var_or_func(ls, v); - break; + return; default: luaX_error(ls, "<expression> expected"); - break; + return; + } + v->k = VEXP; v->info = 0; +} + + +static void prefixexp (LexState *ls, vardesc *v, stack_op *s) { + /* prefixexp -> {NOT | '-'} simpleexp */ + while (ls->token == NOT || ls->token == '-') { + push(ls, s, (ls->token==NOT)?INDNOT:INDMINUS); + next(ls); + } + simpleexp(ls, v, s); +} + + +static void exp2 (LexState *ls, vardesc *v) { + stack_op s; + int op; + s.top = 0; + prefixexp(ls, v, &s); + while ((op = is_in(ls->token, binop)) >= 0) { + op += FIRSTBIN; + lua_pushvar(ls, v); + /* '^' is right associative, so must 'simulate' a higher priority */ + pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]); + push(ls, &s, op); + next(ls); + prefixexp(ls, v, &s); + lua_pushvar(ls, v); + } + if (s.top > 0) { + lua_pushvar(ls, v); + pop_to(ls, &s, 0); } } + static void var_or_func (LexState *ls, vardesc *v) { /* var_or_func -> ['%'] NAME var_or_func_tail */ if (optional(ls, '%')) { /* upvalue? */ - pushupvalue(ls, checkname(ls)); + pushupvalue(ls, str_checkname(ls)); v->k = VEXP; v->info = 0; /* closed expression */ } else /* variable name */ - singlevar(ls, checkname(ls), v, 0); + singlevar(ls, str_checkname(ls), v, 0); var_or_func_tail(ls, v); } + static void var_or_func_tail (LexState *ls, vardesc *v) { for (;;) { switch (ls->token) { @@ -1026,7 +1084,7 @@ static void var_or_func_tail (LexState *ls, vardesc *v) { next(ls); lua_pushvar(ls, v); /* 'v' must be on stack */ v->k = VDOT; - v->info = string_constant(ls->fs, checkname(ls)); + v->info = checkname(ls); break; case '[': /* var_or_func_tail -> '[' exp1 ']' */ @@ -1040,7 +1098,7 @@ static void var_or_func_tail (LexState *ls, vardesc *v) { case ':': /* var_or_func_tail -> ':' NAME funcparams */ next(ls); lua_pushvar(ls, v); /* 'v' must be on stack */ - code_oparg(ls, PUSHSELF, 8, string_constant(ls->fs, checkname(ls)), 1); + code_oparg(ls, PUSHSELF, checkname(ls), 1); v->k = VEXP; v->info = funcparams(ls, 1); break; @@ -1058,13 +1116,14 @@ static void var_or_func_tail (LexState *ls, vardesc *v) { static int funcparams (LexState *ls, int slf) { FuncState *fs = ls->fs; - int nparams = 1; /* default value */ + int nparams = 1; /* in cases STRING and constructor */ switch (ls->token) { case '(': { /* funcparams -> '(' explist ')' */ + int line = ls->linenumber; listdesc e; next(ls); explist(ls, &e); - check(ls, ')'); + check_match(ls, ')', '(', line); close_exp(ls, e.pc, 1); nparams = e.n; break; @@ -1075,7 +1134,7 @@ static int funcparams (LexState *ls, int slf) { break; case STRING: /* funcparams -> STRING */ - code_string(ls, ls->seminfo.ts); + code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */ next(ls); break; @@ -1083,9 +1142,9 @@ static int funcparams (LexState *ls, int slf) { luaX_error(ls, "function arguments expected"); break; } - code_byte(fs, 0); /* save space for opcode */ - code_byte(fs, 0); /* and nresult */ - code_byte(fs, nparams+slf); + code_byte(fs, CALL); + code_byte(fs, 0); /* save space for nresult */ + code_byte(fs, (Byte)(nparams+slf)); return fs->pc-1; } @@ -1131,7 +1190,7 @@ static void parlist (LexState *ls) { case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ init: - store_localvar(ls, checkname(ls), nparams++); + store_localvar(ls, str_checkname(ls), nparams++); if (ls->token == ',') { next(ls); switch (ls->token) { @@ -1158,10 +1217,10 @@ static void parlist (LexState *ls) { static int localnamelist (LexState *ls) { /* localnamelist -> NAME {',' NAME} */ int i = 1; - store_localvar(ls, checkname(ls), 0); + store_localvar(ls, str_checkname(ls), 0); while (ls->token == ',') { next(ls); - store_localvar(ls, checkname(ls), i++); + store_localvar(ls, str_checkname(ls), i++); } return i; } @@ -1178,13 +1237,11 @@ static void decinit (LexState *ls, listdesc *d) { } } + static int assignment (LexState *ls, vardesc *v, int nvars) { int left = 0; - /* dotted variables <a.x> must be stored like regular indexed vars <a["x"]> */ - if (v->k == VDOT) { - code_constant(ls, v->info); - v->k = VINDEXED; - } + checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); + unloaddot(ls, v); if (ls->token == ',') { /* assignment -> ',' NAME assignment */ vardesc nv; next(ls); @@ -1204,12 +1261,13 @@ static int assignment (LexState *ls, vardesc *v, int nvars) { storevar(ls, v); } else { /* indexed var with values in between*/ - code_oparg(ls, SETTABLE, 0, left+(nvars-1), -1); - left += 2; /* table/index are not popped, because they aren't on top */ + code_oparg(ls, SETTABLE, left+(nvars-1), -1); + left += 2; /* table&index are not popped, because they aren't on top */ } return left; } + static void constructor (LexState *ls) { /* constructor -> '{' part [';' part] '}' */ int line = ls->linenumber; @@ -1229,7 +1287,7 @@ static void constructor (LexState *ls) { nelems += other_cd.n; } check_match(ls, '}', '{', line); - fix_opcode(ls, pc, CREATEARRAY, 2, nelems); + fix_opcode(ls, pc, CREATEARRAY, nelems); } static void part (LexState *ls, constdesc *cd) { @@ -1251,7 +1309,7 @@ static void part (LexState *ls, constdesc *cd) { code_string(ls, ls->fs->localvar[v.info]); break; default: - luaX_error(ls, "`=' unexpected"); + error_unexpected(ls); } next(ls); exp1(ls); @@ -1316,7 +1374,7 @@ static void recfield (LexState *ls) { /* recfield -> (NAME | '['exp1']') = exp1 */ switch (ls->token) { case NAME: - code_string(ls, checkname(ls)); + code_constant(ls, checkname(ls)); break; case '[': |