From 7e59a8901d063dbea4eb0693c9c2d85bda1fc5f6 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 27 May 1998 10:08:34 -0300 Subject: [PATCH] NEW LL(1) PARSER --- llex.c | 138 +++--- llex.h | 31 +- lparser.c | 1332 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lstate.h | 4 +- lua.stx | 940 ------------------------------------- makefile | 22 +- 6 files changed, 1442 insertions(+), 1025 deletions(-) create mode 100644 lparser.c delete mode 100644 lua.stx diff --git a/llex.c b/llex.c index d1301463..7a19eb7e 100644 --- a/llex.c +++ b/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 1.17 1998/03/09 17:22:49 roberto Exp roberto $ +** $Id: llex.c,v 1.18 1998/03/20 14:18:18 roberto Exp roberto $ ** Lexical Analizer ** See Copyright Notice in lua.h */ @@ -15,7 +15,6 @@ #include "lparser.h" #include "lstate.h" #include "lstring.h" -#include "lstx.h" #include "luadebug.h" #include "lzio.h" @@ -27,26 +26,56 @@ int lua_debug=0; #define next(LS) (LS->current = zgetc(LS->lex_z)) -static struct { - char *name; - int token; -} reserved [] = { - {"and", AND}, {"do", DO}, {"else", ELSE}, {"elseif", ELSEIF}, - {"end", END}, {"function", FUNCTION}, {"if", IF}, {"local", LOCAL}, - {"nil", NIL}, {"not", NOT}, {"or", OR}, {"repeat", REPEAT}, - {"return", RETURN}, {"then", THEN}, {"until", UNTIL}, {"while", WHILE} -}; +#define save(c) luaL_addchar(c) +#define save_and_next(LS) (save(LS->current), next(LS)) + + +char *reserved [] = {"and", "do", "else", "elseif", "end", "function", + "if", "local", "nil", "not", "or", "repeat", "return", "then", + "until", "while"}; + void luaX_init (void) { int i; for (i=0; i<(sizeof(reserved)/sizeof(reserved[0])); i++) { - TaggedString *ts = luaS_new(reserved[i].name); - ts->head.marked = reserved[i].token; /* reserved word (always > 255) */ + TaggedString *ts = luaS_new(reserved[i]); + ts->head.marked = FIRST_RESERVED+i; /* reserved word (always > 255) */ } } +void luaX_syntaxerror (LexState *ls, char *s, char *token) { + if (token[0] == 0) + token = ""; + luaL_verror("%.100s;\n last token read: `%.50s' at line %d in file %.50s", + s, token, ls->linenumber, zname(ls->lex_z)); +} + + +void luaX_error (LexState *ls, char *s) { + save(0); + luaX_syntaxerror(ls, s, luaL_buffer()); +} + + +void luaX_token2str (LexState *ls, int token, char *s) { + if (token < 255) { + s[0] = token; + s[1] = 0; + } + else + strcpy(s, reserved[token-FIRST_RESERVED]); +} + + +static void luaX_invalidchar (LexState *ls, int c) { + char buff[10]; + sprintf(buff, "0x%X", c); + luaX_syntaxerror(ls, "invalid control char", buff); +} + + static void firstline (LexState *LS) { int c = zgetc(LS->lex_z); @@ -56,16 +85,15 @@ static void firstline (LexState *LS) } -void luaX_setinput (ZIO *z) +void luaX_setinput (LexState *LS, ZIO *z) { - LexState *LS = L->lexstate; LS->current = '\n'; - LS->linelasttoken = 0; LS->linenumber = 0; LS->iflevel = 0; LS->ifstate[0].skip = 0; LS->ifstate[0].elsepart = 1; /* to avoid a free $else */ LS->lex_z = z; + LS->fs = NULL; firstline(LS); luaL_resetbuffer(); } @@ -87,7 +115,7 @@ static void skipspace (LexState *LS) } -static int checkcond (char *buff) +static int checkcond (LexState *LS, char *buff) { static char *opts[] = {"nil", "1", NULL}; int i = luaO_findstring(buff, opts); @@ -95,7 +123,7 @@ static int checkcond (char *buff) else if (isalpha((unsigned char)buff[0]) || buff[0] == '_') return luaS_globaldefined(buff); else { - luaY_syntaxerror("invalid $if condition", buff); + luaX_syntaxerror(LS, "invalid $if condition", buff); return 0; /* to avoid warnings */ } } @@ -108,7 +136,7 @@ static void readname (LexState *LS, char *buff) while (isalnum(LS->current) || LS->current == '_') { if (i >= PRAGMASIZE) { buff[PRAGMASIZE] = 0; - luaY_syntaxerror("pragma too long", buff); + luaX_syntaxerror(LS, "pragma too long", buff); } buff[i++] = LS->current; next(LS); @@ -126,7 +154,7 @@ static void ifskip (LexState *LS) if (LS->current == '\n') inclinenumber(LS); else if (LS->current == EOZ) - luaY_error("input ends inside a $if"); + luaX_error(LS, "input ends inside a $if"); else next(LS); } } @@ -159,35 +187,35 @@ static void inclinenumber (LexState *LS) break; case 3: /* end */ if (LS->iflevel-- == 0) - luaY_syntaxerror("unmatched $end", "$end"); + luaX_syntaxerror(LS, "unmatched $end", "$end"); break; case 4: /* ifnot */ ifnot = 1; /* go through */ case 5: /* if */ if (LS->iflevel == MAX_IFS-1) - luaY_syntaxerror("too many nested $ifs", "$if"); + luaX_syntaxerror(LS, "too many nested $ifs", "$if"); readname(LS, buff); LS->iflevel++; LS->ifstate[LS->iflevel].elsepart = 0; - LS->ifstate[LS->iflevel].condition = checkcond(buff) ? !ifnot : ifnot; + LS->ifstate[LS->iflevel].condition = checkcond(LS, buff) ? !ifnot : ifnot; LS->ifstate[LS->iflevel].skip = skip || !LS->ifstate[LS->iflevel].condition; break; case 6: /* else */ if (LS->ifstate[LS->iflevel].elsepart) - luaY_syntaxerror("unmatched $else", "$else"); + luaX_syntaxerror(LS, "unmatched $else", "$else"); LS->ifstate[LS->iflevel].elsepart = 1; LS->ifstate[LS->iflevel].skip = LS->ifstate[LS->iflevel-1].skip || LS->ifstate[LS->iflevel].condition; break; default: - luaY_syntaxerror("unknown pragma", buff); + luaX_syntaxerror(LS, "unknown pragma", buff); } skipspace(LS); if (LS->current == '\n') /* pragma must end with a '\n' ... */ inclinenumber(LS); else if (LS->current != EOZ) /* or eof */ - luaY_syntaxerror("invalid pragma format", buff); + luaX_syntaxerror(LS, "invalid pragma format", buff); ifskip(LS); } } @@ -201,25 +229,16 @@ static void inclinenumber (LexState *LS) -#define save(c) luaL_addchar(c) -#define save_and_next(LS) (save(LS->current), next(LS)) -char *luaX_lasttoken (void) -{ - save(0); - return luaL_buffer(); -} - - -static int read_long_string (LexState *LS, YYSTYPE *l) +static int read_long_string (LexState *LS) { int cont = 0; while (1) { switch (LS->current) { case EOZ: - luaY_error("unfinished long string"); - return 0; /* to avoid warnings */ + luaX_error(LS, "unfinished long string"); + return EOS; /* to avoid warnings */ case '[': save_and_next(LS); if (LS->current == '[') { @@ -244,25 +263,15 @@ static int read_long_string (LexState *LS, YYSTYPE *l) } } endloop: save_and_next(LS); /* pass the second ']' */ - l->pTStr = luaS_newlstr(L->Mbuffbase+2, + LS->seminfo.ts = luaS_newlstr(L->Mbuffbase+2, L->Mbuffnext-(L->Mbuffbase-L->Mbuffer)-4); return STRING; } -/* to avoid warnings; this declaration cannot be public since YYSTYPE -** cannot be visible in llex.h (otherwise there is an error, since -** the parser body redefines it!) -*/ -int luaY_lex (YYSTYPE *l); -int luaY_lex (YYSTYPE *l) -{ - LexState *LS = L->lexstate; +int luaX_lex (LexState *LS) { double a; luaL_resetbuffer(); - if (lua_debug) - luaY_codedebugline(LS->linelasttoken); - LS->linelasttoken = LS->linenumber; while (1) { switch (LS->current) { @@ -272,7 +281,6 @@ int luaY_lex (YYSTYPE *l) case '\n': inclinenumber(LS); - LS->linelasttoken = LS->linenumber; continue; case '-': @@ -287,7 +295,7 @@ int luaY_lex (YYSTYPE *l) if (LS->current != '[') return '['; else { save_and_next(LS); /* pass the second '[' */ - return read_long_string(LS, l); + return read_long_string(LS); } case '=': @@ -318,8 +326,8 @@ int luaY_lex (YYSTYPE *l) switch (LS->current) { case EOZ: case '\n': - luaY_error("unfinished string"); - return 0; /* to avoid warnings */ + luaX_error(LS, "unfinished string"); + return EOS; /* to avoid warnings */ case '\\': next(LS); /* do not save the '\' */ switch (LS->current) { @@ -345,13 +353,13 @@ int luaY_lex (YYSTYPE *l) next(LS); } while (++i<3 && isdigit(LS->current)); if (c >= 256) - luaY_error("escape sequence too large"); + luaX_error(LS, "escape sequence too large"); save(c); } else { save('\\'); save(LS->current); - luaY_error("invalid escape sequence"); + luaX_error(LS, "invalid escape sequence"); } break; } @@ -362,7 +370,7 @@ int luaY_lex (YYSTYPE *l) } } save_and_next(LS); /* skip delimiter */ - l->pTStr = luaS_newlstr(L->Mbuffbase+1, + LS->seminfo.ts = luaS_newlstr(L->Mbuffbase+1, L->Mbuffnext-(L->Mbuffbase-L->Mbuffer)-2); return STRING; } @@ -395,7 +403,7 @@ int luaY_lex (YYSTYPE *l) save_and_next(LS); if (LS->current == '.') { save('.'); - luaY_error( + luaX_error(LS, "ambiguous syntax (decimal point x string concatenation)"); } } @@ -415,7 +423,7 @@ int luaY_lex (YYSTYPE *l) neg = (LS->current=='-'); if (LS->current == '+' || LS->current == '-') save_and_next(LS); if (!isdigit(LS->current)) - luaY_error("invalid numeral format"); + luaX_error(LS, "invalid numeral format"); do { e = 10.0*e + (LS->current-'0'); save_and_next(LS); @@ -426,18 +434,20 @@ int luaY_lex (YYSTYPE *l) ea *= ea; } } - l->vReal = a; + LS->seminfo.r = a; return NUMBER; } case EOZ: if (LS->iflevel > 0) - luaY_error("input ends inside a $if"); - return 0; + luaX_error(LS, "input ends inside a $if"); + return EOS; default: if (LS->current != '_' && !isalpha(LS->current)) { int c = LS->current; + if (iscntrl(c)) + luaX_invalidchar(LS, c); save_and_next(LS); return c; } @@ -448,9 +458,9 @@ int luaY_lex (YYSTYPE *l) } while (isalnum(LS->current) || LS->current == '_'); save(0); ts = luaS_new(L->Mbuffbase); - if (ts->head.marked > 255) + if (ts->head.marked >= 'A') return ts->head.marked; /* reserved word */ - l->pTStr = ts; + LS->seminfo.ts = ts; return NAME; } } diff --git a/llex.h b/llex.h index dcce5149..3947bf5d 100644 --- a/llex.h +++ b/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.6 1997/12/17 20:48:58 roberto Exp roberto $ +** $Id: llex.h,v 1.7 1998/01/09 14:57:43 roberto Exp $ ** Lexical Analizer ** See Copyright Notice in lua.h */ @@ -11,6 +11,20 @@ #include "lzio.h" +#define FIRST_RESERVED 260 + +/* maximum length of a reserved word (+1 for terminal 0) */ +#define TOKEN_LEN 15 + +enum RESERVED { + /* terminal symbols denoted by reserved words */ + AND = FIRST_RESERVED, + DO, ELSE, ELSEIF, END, FUNCTION, IF, LOCAL, NIL, NOT, OR, + REPEAT, RETURN, THEN, UNTIL, WHILE, + /* other terminal symbols */ + NAME, CONC, DOTS, EQ, GE, LE, NE, NUMBER, STRING, EOS}; + + #define MAX_IFS 5 /* "ifstate" keeps the state of each nested $if the lexical is dealing with. */ @@ -24,18 +38,25 @@ struct ifState { typedef struct LexState { int current; /* look ahead character */ + int token; /* look ahead token */ + struct FuncState *fs; /* 'FuncState' is private for the parser */ + union { + real r; + TaggedString *ts; + } seminfo; /* semantics information */ struct zio *lex_z; /* input stream */ int linenumber; /* input line counter */ - int linelasttoken; /* line where last token was read */ - int lastline; /* last line wherein a SETLINE was generated */ int iflevel; /* level of nested $if's (for lexical analysis) */ struct ifState ifstate[MAX_IFS]; } LexState; void luaX_init (void); -void luaX_setinput (ZIO *z); -char *luaX_lasttoken (void); +void luaX_setinput (LexState *LS, ZIO *z); +int luaX_lex (LexState *LS); +void luaX_syntaxerror (LexState *ls, char *s, char *token); +void luaX_error (LexState *ls, char *s); +void luaX_token2str (LexState *ls, int token, char *s); #endif diff --git a/lparser.c b/lparser.c new file mode 100644 index 00000000..0eefb204 --- /dev/null +++ b/lparser.c @@ -0,0 +1,1332 @@ +/* +** $Id: $ +** LL(1) Parser and code generator for Lua +** See Copyright Notice in lua.h +*/ + + +#include + +#include "lauxlib.h" +#include "ldo.h" +#include "lfunc.h" +#include "llex.h" +#include "lmem.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "lua.h" +#include "luadebug.h" +#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" + + +/* maximum number of upvalues */ +#define MAXUPVALUES 16 +#define SMAXUPVALUES "16" + + +/* +** Variable descriptor: +** must include a "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 { + varkind k; + int info; +} vardesc; + + +/* +** Expression List descriptor: +** tells number of expressions in the list, +** and, if last expression is open (a function call), +** where is its pc index of "nparam" +*/ +typedef struct { + int n; + int pc; /* 0 if last expression is closed */ +} listdesc; + + +/* +** Constructors descriptor: +** "n" indicates number of elements, and "k" signals whether +** it is a list constructor (k = 0) or a record constructor (k = 1) +** or empty (k = ';' or '}') +*/ +typedef struct { + int n; + int k; +} constdesc; + + +/* state needed to generate code for a given function */ +typedef struct FuncState { + TProtoFunc *f; /* current function header */ + struct FuncState *prev; /* enclosuring function */ + int pc; /* next position to code */ + int stacksize; /* number of values on activation register */ + 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 lastsetline; /* line where last SETLINE was issued */ + vardesc upvalues[MAXUPVALUES]; /* upvalues */ + TaggedString *localvar[MAXLOCALS]; /* store local variable names */ +} FuncState; + + +static int assignment (LexState *ls, vardesc *v, int nvars); +static int cond (LexState *ls); +static int funcname (LexState *ls, vardesc *v); +static int funcparams (LexState *ls, int slf); +static int listfields (LexState *ls); +static int localnamelist (LexState *ls); +static int optional (LexState *ls, int c); +static int recfields (LexState *ls); +static int stat (LexState *ls); +static void block (LexState *ls); +static void body (LexState *ls, int needself, int line); +static void chunk (LexState *ls); +static void constructor (LexState *ls); +static void decinit (LexState *ls, listdesc *d); +static void exp (LexState *ls, vardesc *v); +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 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 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); +} + + +static void code_byte (FuncState *fs, Byte c) { + check_pc(fs, 1); + fs->f->code[fs->pc++] = c; +} + + +static void deltastack (LexState *ls, int delta) { + FuncState *fs = ls->fs; + fs->stacksize += delta; + if (fs->stacksize > fs->maxstacksize) { + if (fs->stacksize > 255) + 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) { + Byte *code = ls->fs->f->code; + deltastack(ls, delta); + if (arg < builtin) { + code[pc] = op+1+arg; + return 1; + } + 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 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++; + } + return code_oparg_at(ls, pc, op, builtin, arg, 0) - 2; +} + +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_opcode (LexState *ls, OpCode op, int delta) { + deltastack(ls, delta); + code_byte(ls->fs, op); +} + + +static void code_constant (LexState *ls, int c) { + code_oparg(ls, PUSHCONSTANT, 8, 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); + } + return f->nconsts++; +} + + +static int string_constant (FuncState *fs, TaggedString *s) { + TProtoFunc *f = fs->f; + int c = s->constindex; + if (!(c < f->nconsts && + ttype(&f->consts[c]) == LUA_T_STRING && tsvalue(&f->consts[c]) == s)) { + c = next_constant(fs); + ttype(&f->consts[c]) = LUA_T_STRING; + tsvalue(&f->consts[c]) = s; + s->constindex = c; /* hint for next time */ + } + return c; +} + + +static void code_string (LexState *ls, TaggedString *s) { + code_constant(ls, string_constant(ls->fs, s)); +} + + +#define LIM 20 +static int real_constant (FuncState *fs, real r) { + /* check whether 'r' has appeared within the last LIM entries */ + TObject *cnt = fs->f->consts; + int c = fs->f->nconsts; + int lim = c < LIM ? 0 : c-LIM; + while (--c >= lim) { + if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r) + return c; + } + /* not found; create a luaM_new entry */ + c = next_constant(fs); + cnt = fs->f->consts; /* 'next_constant' may reallocate this vector */ + ttype(&cnt[c]) = LUA_T_NUMBER; + nvalue(&cnt[c]) = r; + return c; +} + + +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 */ + else + code_constant(ls, real_constant(ls->fs, f)); +} + + +static void flush_record (LexState *ls, int n) { + if (n > 0) + code_oparg(ls, SETMAP, 1, 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); +} + + +static void luaI_registerlocalvar (FuncState *fs, TaggedString *varname, + int line) { + if (fs->maxvars != -1) { /* debug information? */ + TProtoFunc *f = fs->f; + if (fs->nvars >= fs->maxvars) + fs->maxvars = luaM_growvector(&f->locvars, fs->maxvars, + LocVar, "", MAX_WORD); + f->locvars[fs->nvars].varname = varname; + f->locvars[fs->nvars].line = line; + fs->nvars++; + } +} + + +static void luaI_unregisterlocalvar (FuncState *fs, int line) { + luaI_registerlocalvar(fs, NULL, 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)); + luaI_registerlocalvar(fs, name, ls->linenumber); +} + + +static void add_localvar (LexState *ls, TaggedString *name) { + store_localvar(ls, name, 0); + ls->fs->nlocalvar++; +} + + +static int aux_localname (FuncState *fs, TaggedString *n) { + int i; + for (i=fs->nlocalvar-1; i >= 0; i--) + if (n == fs->localvar[i]) return i; /* local var index */ + return -1; /* not found */ +} + + +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 */ + var->k = VLOCAL; + var->info = i; + } + else { /* check shadowing */ + FuncState *level = fs; + while ((level = level->prev) != NULL) + if (aux_localname(level, n) >= 0) + luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); + var->k = VGLOBAL; + var->info = string_constant(fs, n); + } +} + + +static int indexupvalue (LexState *ls, TaggedString *n) { + FuncState *fs = ls->fs; + vardesc v; + int i; + singlevar(ls, n, &v, 1); + for (i=0; inupvalues; i++) { + if (fs->upvalues[i].k == v.k && fs->upvalues[i].info == v.info) + return i; + } + /* new one */ + if (++(fs->nupvalues) > MAXUPVALUES) + luaX_error(ls, "too many upvalues in a single function " + MES_LIM(SMAXUPVALUES)); + 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); +} + + + +static void check_debugline (LexState *ls) { + if (lua_debug && ls->linenumber != ls->fs->lastsetline) { + code_oparg(ls, SETLINE, 0, ls->linenumber, 0); + ls->fs->lastsetline = ls->linenumber; + } +} + + +static void adjuststack (LexState *ls, int n) { + if (n > 0) + code_oparg(ls, POP, 2, n-1, -n); + else if (n < 0) + code_oparg(ls, PUSHNIL, 1, (-n)-1, -n); +} + + +static void close_exp (LexState *ls, int pc, int nresults) { + 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 */ + } +} + + +static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) { + int diff = d->n - nvars; + if (d->pc == 0) { /* list is closed */ + /* push or pop eventual difference between list lengths */ + adjuststack(ls, diff); + } + else { /* must correct function call */ + diff--; /* do not count function call itself */ + if (diff < 0) { /* more variables than values */ + /* function call must provide extra values */ + close_exp(ls, d->pc, -diff); + } + else { /* more values than variables */ + close_exp(ls, d->pc, 0); /* call should provide no value */ + adjuststack(ls, diff); /* pop eventual extra values */ + } + } +} + + +static void code_args (LexState *ls, int nparams, int dots) { + FuncState *fs = ls->fs; + fs->nlocalvar += nparams; /* "self" may already be there */ + nparams = fs->nlocalvar; + if (!dots) { + fs->f->code[1] = nparams; /* fill-in arg information */ + deltastack(ls, nparams); + } + else { + fs->f->code[1] = nparams+ZEROVARARG; + deltastack(ls, nparams+1); + add_localvar(ls, luaS_new("arg")); + } +} + + +static void lua_pushvar (LexState *ls, vardesc *var) { + switch (var->k) { + case VLOCAL: + code_oparg(ls, PUSHLOCAL, 8, var->info, 1); + break; + case VGLOBAL: + code_oparg(ls, GETGLOBAL, 8, var->info, 1); + break; + case VDOT: + code_oparg(ls, GETDOTTED, 8, var->info, 0); + break; + case VINDEXED: + code_opcode(ls, GETTABLE, -1); + break; + case VEXP: + close_exp(ls, var->info, 1); /* function must return 1 value */ + break; + } + var->k = VEXP; + var->info = 0; /* now this is a closed expression */ +} + + +static void storevar (LexState *ls, vardesc *var) { + switch (var->k) { + case VLOCAL: + code_oparg(ls, SETLOCAL, 8, var->info, -1); + break; + case VGLOBAL: + code_oparg(ls, SETGLOBAL, 8, var->info, -1); + break; + case VINDEXED: + code_opcode(ls, SETTABLE0, -3); + break; + default: + LUA_INTERNALERROR("invalid var kind to store"); + } +} + + +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)); +} + + +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); +} + + +static void codeIf (LexState *ls, int thenAdd, int elseAdd) { + FuncState *fs = ls->fs; + int elseinit = elseAdd+JMPSIZE; + if (fs->pc == elseinit) { /* no else part */ + fs->pc -= JMPSIZE; + elseinit = fs->pc; + } + else + elseinit += fix_jump(ls, elseAdd, JMP, fs->pc); + fix_jump(ls, thenAdd, IFFJMP, elseinit); +} + + +static void func_onstack (LexState *ls, FuncState *func) { + FuncState *fs = ls->fs; + int i; + int c = next_constant(fs); + ttype(&fs->f->consts[c]) = LUA_T_PROTO; + fs->f->consts[c].value.tf = func->f; + if (func->nupvalues == 0) + code_constant(ls, c); + else { + for (i=0; inupvalues; i++) + lua_pushvar(ls, &func->upvalues[i]); + code_oparg(ls, CLOSURE, 0, c, -func->nupvalues+1); + code_byte(fs, func->nupvalues); + } +} + + +static void init_state (LexState *ls, FuncState *fs, TaggedString *filename) { + TProtoFunc *f = luaF_newproto(); + fs->prev = ls->fs; /* linked list of funcstates */ + ls->fs = fs; + fs->stacksize = 0; + fs->maxstacksize = 0; + fs->nlocalvar = 0; + fs->nupvalues = 0; + fs->lastsetline = 0; + fs->f = f; + f->fileName = filename; + 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 */ + code_byte(fs, 0); /* to be filled with arg information */ +} + + +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? */ + luaI_registerlocalvar(fs, NULL, -1); /* flag end of vector */ + f->locvars = luaM_reallocvector(f->locvars, fs->nvars, LocVar); + } + ls->fs = fs->prev; +} + + + +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++; + } + return -1; +} + + +static void next (LexState *ls) { + ls->token = luaX_lex(ls); +} + + +static void error_expected (LexState *ls, int token) { + char buff[100], t[TOKEN_LEN]; + luaX_token2str(ls, token, t); + sprintf(buff, "`%s' expected", t); + luaX_error(ls, buff); +} + +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); + sprintf(buff, "`%s' expected (to close `%s' at line %d)", + t_what, t_who, where); + luaX_error(ls, buff); + } +} + +static void check (LexState *ls, int c) { + if (ls->token != c) + error_expected(ls, c); + next(ls); +} + +static void check_match (LexState *ls, int what, int who, int where) { + if (ls->token != what) + error_unmatched(ls, what, who, where); + check_debugline(ls); /* to 'mark' the 'what' */ + next(ls); +} + +static TaggedString *checkname (LexState *ls) { + TaggedString *ts; + if (ls->token != NAME) + luaX_error(ls, "`NAME' expected"); + ts = ls->seminfo.ts; + next(ls); + return ts; +} + + +static int optional (LexState *ls, int c) { + if (ls->token == c) { + next(ls); + return 1; + } + else return 0; +} + + +TProtoFunc *luaY_parser (ZIO *z) { + struct LexState lexstate; + struct FuncState funcstate; + luaX_setinput(&lexstate, z); + init_state(&lexstate, &funcstate, luaS_new(zname(z))); + next(&lexstate); /* read first token */ + chunk(&lexstate); + if (lexstate.token != EOS) + luaX_error(&lexstate, " expected"); + close_func(&lexstate); + return funcstate.f; +} + + + +/*============================================================*/ +/* GRAMAR RULES */ +/*============================================================*/ + +static void chunk (LexState *ls) { + /* chunk -> statlist ret */ + statlist(ls); + ret(ls); +} + +static void statlist (LexState *ls) { + /* statlist -> { stat [;] } */ + while (stat(ls)) { + LUA_ASSERT(ls->fs->stacksize == ls->fs->nlocalvar, + "stack size != # local vars"); + optional(ls, ';'); + } +} + +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); + return 1; + } + + case WHILE: { /* stat -> WHILE cond DO block END */ + TProtoFunc *f = fs->f; + int while_init = fs->pc; + int cond_end, cond_size; + next(ls); + cond_end = cond(ls); + check(ls, DO); + block(ls); + check_match(ls, END, WHILE, line); + cond_size = cond_end-while_init; + check_pc(fs, cond_size); + memcpy(f->code+fs->pc, f->code+while_init, cond_size); + luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init); + while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size); + fix_upjmp(ls, IFTUPJMP, while_init); + return 1; + } + + case DO: { /* stat -> DO block END */ + next(ls); + block(ls); + check_match(ls, END, DO, line); + return 1; + } + + case REPEAT: { /* stat -> REPEAT block UNTIL exp1 */ + int repeat_init = fs->pc; + next(ls); + block(ls); + check_match(ls, UNTIL, REPEAT, line); + exp1(ls); + fix_upjmp(ls, IFFUPJMP, repeat_init); + deltastack(ls, -1); /* pops condition */ + return 1; + } + + case FUNCTION: { /* stat -> FUNCTION funcname body */ + int needself; + vardesc v; + if (ls->fs->prev) /* inside other function? */ + return 0; + check_debugline(ls); + next(ls); + needself = funcname(ls, &v); + body(ls, needself, line); + storevar(ls, &v); + return 1; + } + + case LOCAL: { /* stat -> LOCAL localnamelist decinit */ + listdesc d; + int nvars; + check_debugline(ls); + next(ls); + nvars = localnamelist(ls); + decinit(ls, &d); + ls->fs->nlocalvar += nvars; + adjust_mult_assign(ls, nvars, &d); + return 1; + } + + case NAME: case '%': { /* stat -> func | ['%'] NAME assignment */ + vardesc v; + check_debugline(ls); + var_or_func(ls, &v); + if (v.k == VEXP) { /* stat -> func */ + if (v.info == 0) /* is just an upper value? */ + luaX_error(ls, "syntax error"); + close_exp(ls, v.info, 0); + } + else { + int left = assignment(ls, &v, 1); /* stat -> ['%'] NAME assignment */ + adjuststack(ls, left); /* remove eventual 'garbage' left on stack */ + } + return 1; + } + + case RETURN: case ';': case ELSE: case ELSEIF: + case END: case UNTIL: case EOS: /* 'stat' follow */ + return 0; + + default: + luaX_error(ls, " expected"); + return 0; /* to avoid warnings */ + } +} + +static int SaveWord (LexState *ls) { + int res = ls->fs->pc; + check_pc(ls->fs, JMPSIZE); + ls->fs->pc += JMPSIZE; /* open space */ + return res; +} + +static int SaveWordPop (LexState *ls) { + deltastack(ls, -1); /* pop condition */ + return SaveWord(ls); +} + +static int cond (LexState *ls) { + /* cond -> exp1 */ + exp1(ls); + return SaveWordPop(ls); +} + +static void block (LexState *ls) { + /* block -> chunk */ + FuncState *fs = ls->fs; + int nlocalvar = fs->nlocalvar; + chunk(ls); + adjuststack(ls, fs->nlocalvar - nlocalvar); + for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) + luaI_unregisterlocalvar(fs, ls->linenumber); +} + +static int funcname (LexState *ls, vardesc *v) { + /* funcname -> NAME [':' NAME | '.' NAME] */ + int needself = 0; + singlevar(ls, checkname(ls), v, 0); + if (ls->token == ':' || ls->token == '.') { + needself = (ls->token == ':'); + next(ls); + lua_pushvar(ls, v); + code_string(ls, checkname(ls)); + v->k = VINDEXED; + } + return needself; +} + +static void body (LexState *ls, int needself, int line) { + /* body -> '(' parlist ')' chunk END */ + FuncState newfs; + init_state(ls, &newfs, ls->fs->f->fileName); + newfs.f->lineDefined = line; + check(ls, '('); + if (needself) + add_localvar(ls, luaS_new("self")); + parlist(ls); + check(ls, ')'); + chunk(ls); + check_match(ls, END, FUNCTION, line); + close_func(ls); + func_onstack(ls, &newfs); +} + +static void ifpart (LexState *ls) { + /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ + int c = cond(ls); + int e; + check(ls, THEN); + block(ls); + e = SaveWord(ls); + switch (ls->token) { + case ELSE: + next(ls); + block(ls); + break; + + case ELSEIF: + next(ls); + ifpart(ls); + break; + } + codeIf(ls, c, e); +} + +static void ret (LexState *ls) { + /* ret -> [RETURN explist sc] */ + if (ls->token == 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); + ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ + optional(ls, ';'); + } +} + + +/* +** For parsing expressions, we use a classic stack with priorities. +** Each binary operator is represented by its index in "binop" + FIRSTBIN +** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1. +*/ + +/* code of first binary operator */ +#define FIRSTBIN 2 + +/* code for power operator (last operator) +** '^' needs special treatment because it is right associative +*/ +#define POW 13 + +static int binop [] = {EQ, NE, '>', '<', LE, GE, CONC, + '+', '-', '*', '/', '^', 0}; + +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 + +typedef struct { + int ops[MAXOPS]; + int top; +} stack_op; + + +static void exp1 (LexState *ls) { + vardesc v; + exp(ls, &v); + lua_pushvar(ls, &v); + if (is_in(ls->token, expfollow) < 0) + luaX_error(ls, "ill formed expression"); +} + + +static void exp (LexState *ls, vardesc *v) { + exp2(ls, v); + while (ls->token == AND || ls->token == OR) { + int is_and = (ls->token == AND); + 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); + } +} + + +static void push (LexState *ls, stack_op *s, int op) { + 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) { + code_opcode(ls, opcodes[op], optop--; + } +} + +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) { + check_debugline(ls); + switch (ls->token) { + case '(': /* simpleexp -> '(' exp ')' */ + next(ls); + exp(ls, v); + check(ls, ')'); + break; + + case NUMBER: /* simpleexp -> NUMBER */ + code_number(ls, ls->seminfo.r); + next(ls); + v->k = VEXP; v->info = 0; + break; + + case STRING: /* simpleexp -> STRING */ + code_string(ls, ls->seminfo.ts); + 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; + next(ls); + body(ls, 0, line); + v->k = VEXP; v->info = 0; + break; + } + + case NAME: case '%': + var_or_func(ls, v); + break; + + default: + luaX_error(ls, " expected"); + break; + } +} + +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)); + v->k = VEXP; + v->info = 0; /* closed expression */ + } + else /* variable name */ + singlevar(ls, checkname(ls), v, 0); + var_or_func_tail(ls, v); +} + +static void var_or_func_tail (LexState *ls, vardesc *v) { + for (;;) { + switch (ls->token) { + case '.': /* var_or_func_tail -> '.' NAME */ + next(ls); + lua_pushvar(ls, v); /* 'v' must be on stack */ + v->k = VDOT; + v->info = string_constant(ls->fs, checkname(ls)); + break; + + case '[': /* var_or_func_tail -> '[' exp1 ']' */ + next(ls); + lua_pushvar(ls, v); /* 'v' must be on stack */ + exp1(ls); + check(ls, ']'); + v->k = VINDEXED; + break; + + 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); + v->k = VEXP; + v->info = funcparams(ls, 1); + break; + + case '(': case STRING: case '{': /* var_or_func_tail -> funcparams */ + lua_pushvar(ls, v); /* 'v' must be on stack */ + v->k = VEXP; + v->info = funcparams(ls, 0); + break; + + default: return; /* should be follow... */ + } + } +} + +static int funcparams (LexState *ls, int slf) { + FuncState *fs = ls->fs; + int nparams = 1; /* default value */ + switch (ls->token) { + case '(': { /* funcparams -> '(' explist ')' */ + listdesc e; + next(ls); + explist(ls, &e); + check(ls, ')'); + close_exp(ls, e.pc, 1); + nparams = e.n; + break; + } + + case '{': /* funcparams -> constructor */ + constructor(ls); + break; + + case STRING: /* funcparams -> STRING */ + next(ls); + break; + + default: + 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); + return fs->pc-1; +} + +static void explist (LexState *ls, listdesc *d) { + switch (ls->token) { + case ELSE: case ELSEIF: case END: case UNTIL: + case EOS: case ';': case ')': + d->pc = 0; + d->n = 0; + break; + + default: + explist1(ls, d); + } +} + +static void explist1 (LexState *ls, listdesc *d) { + vardesc v; + exp(ls, &v); + d->n = 1; + while (ls->token == ',') { + d->n++; + lua_pushvar(ls, &v); + next(ls); + exp(ls, &v); + } + if (v.k == VEXP) + d->pc = v.info; + else { + lua_pushvar(ls, &v); + d->pc = 0; + } +} + +static void parlist (LexState *ls) { + int nparams = 0; + int dots = 0; + switch (ls->token) { + case DOTS: /* parlist -> DOTS */ + next(ls); + dots = 1; + break; + + case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ + init: + store_localvar(ls, checkname(ls), nparams++); + if (ls->token == ',') { + next(ls); + switch (ls->token) { + case DOTS: /* tailparlist -> DOTS */ + next(ls); + dots = 1; + break; + + case NAME: /* tailparlist -> NAME [',' tailparlist] */ + goto init; + + default: luaX_error(ls, "NAME or `...' expected"); + } + } + break; + + case ')': break; /* parlist -> empty */ + + default: luaX_error(ls, "NAME or `...' expected"); + } + code_args(ls, nparams, dots); +} + +static int localnamelist (LexState *ls) { + /* localnamelist -> NAME {',' NAME} */ + int i = 1; + store_localvar(ls, checkname(ls), 0); + while (ls->token == ',') { + next(ls); + store_localvar(ls, checkname(ls), i++); + } + return i; +} + +static void decinit (LexState *ls, listdesc *d) { + /* decinit -> ['=' explist1] */ + if (ls->token == '=') { + next(ls); + explist1(ls, d); + } + else { + d->n = 0; + d->pc = 0; + } +} + +static int assignment (LexState *ls, vardesc *v, int nvars) { + int left = 0; + /* dotted variables must be stored like regular indexed vars */ + if (v->k == VDOT) { + code_constant(ls, v->info); + v->k = VINDEXED; + } + if (ls->token == ',') { /* assignment -> ',' NAME assignment */ + vardesc nv; + next(ls); + var_or_func(ls, &nv); + if (nv.k == VEXP) + luaX_error(ls, "syntax error"); + left = assignment(ls, &nv, nvars+1); + } + else { /* assignment -> '=' explist1 */ + listdesc d; + check(ls, '='); + explist1(ls, &d); + adjust_mult_assign(ls, nvars, &d); + } + if (v->k != VINDEXED || left+(nvars-1) == 0) { + /* global/local var or indexed var without values in between */ + 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 */ + } + return left; +} + +static void constructor (LexState *ls) { + /* constructor -> '{' part [';' part] '}' */ + int line = ls->linenumber; + int pc = SaveWord(ls); + int nelems; + constdesc cd; + deltastack(ls, 1); + check(ls, '{'); + part(ls, &cd); + nelems = cd.n; + if (ls->token == ';') { + constdesc other_cd; + next(ls); + part(ls, &other_cd); + if (cd.k == other_cd.k) /* repeated parts? */ + luaX_error(ls, "invalid constructor syntax"); + nelems += other_cd.n; + } + check_match(ls, '}', '{', line); + fix_opcode(ls, pc, CREATEARRAY, 2, nelems); +} + +static void part (LexState *ls, constdesc *cd) { + switch (ls->token) { + case ';': case '}': /* part -> empty */ + cd->n = 0; + cd->k = ls->token; + return; + + case NAME: { + vardesc v; + exp(ls, &v); + if (ls->token == '=') { + switch (v.k) { + case VGLOBAL: + code_constant(ls, v.info); + break; + case VLOCAL: + code_string(ls, ls->fs->localvar[v.info]); + break; + default: + luaX_error(ls, "`=' unexpected"); + } + next(ls); + exp1(ls); + cd->n = recfields(ls); + cd->k = 1; /* record */ + } + else { + lua_pushvar(ls, &v); + cd->n = listfields(ls); + cd->k = 0; /* list */ + } + break; + } + + case '[': /* part -> recfield recfields */ + recfield(ls); + cd->n = recfields(ls); + cd->k = 1; /* record */ + break; + + default: /* part -> exp1 listfields */ + exp1(ls); + cd->n = listfields(ls); + cd->k = 0; /* list */ + break; + } +} + +static int recfields (LexState *ls) { + /* recfields -> { ',' recfield } [','] */ + int n = 1; /* one has been read before */ + while (ls->token == ',') { + next(ls); + if (ls->token == ';' || ls->token == '}') + break; + recfield(ls); + n++; + if (n%RFIELDS_PER_FLUSH == 0) + flush_record(ls, RFIELDS_PER_FLUSH); + } + flush_record(ls, n%RFIELDS_PER_FLUSH); + return n; +} + +static int listfields (LexState *ls) { + /* listfields -> { ',' exp1 } [','] */ + int n = 1; /* one has been read before */ + while (ls->token == ',') { + next(ls); + if (ls->token == ';' || ls->token == '}') + break; + exp1(ls); + n++; + if (n%LFIELDS_PER_FLUSH == 0) + flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); + } + flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); + return n; +} + +static void recfield (LexState *ls) { + /* recfield -> (NAME | '['exp1']') = exp1 */ + switch (ls->token) { + case NAME: + code_string(ls, checkname(ls)); + break; + + case '[': + next(ls); + exp1(ls); + check(ls, ']'); + break; + + default: luaX_error(ls, "NAME or `[' expected"); + } + check(ls, '='); + exp1(ls); +} + diff --git a/lstate.h b/lstate.h index 06b4aced..21cbef59 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.6 1997/12/17 20:48:58 roberto Exp roberto $ +** $Id: lstate.h,v 1.7 1998/01/09 14:57:43 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -57,8 +57,6 @@ typedef struct LState { struct IM *IMtable; /* table for tag methods */ int IMtable_size; /* size of IMtable */ int last_tag; /* last used tag in IMtable */ - struct FuncState *mainState, *currState; /* point to local structs in yacc */ - struct LexState *lexstate; /* point to local struct in yacc */ struct ref *refArray; /* locked objects */ int refSize; /* size of refArray */ unsigned long GCthreshold; diff --git a/lua.stx b/lua.stx deleted file mode 100644 index 41aff108..00000000 --- a/lua.stx +++ /dev/null @@ -1,940 +0,0 @@ -%{ -/* -** $Id: lua.stx,v 1.36 1998/03/25 18:52:29 roberto Exp roberto $ -** Syntax analizer and code generator -** See Copyright Notice in lua.h -*/ - - -#include -#include - -#include "lauxlib.h" -#include "ldo.h" -#include "lfunc.h" -#include "llex.h" -#include "lmem.h" -#include "lopcodes.h" -#include "lparser.h" -#include "lstate.h" -#include "lstring.h" -#include "lua.h" -#include "luadebug.h" -#include "lzio.h" - - -int luaY_parse (void); - - -#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" - -#define MINGLOBAL (MAXLOCALS+1) - -/* maximum number of variables in a multiple assignment */ -#define MAXVAR 32 -#define SMAXVAR "32" - -/* maximum number of nested functions */ -#define MAXSTATES 6 -#define SMAXSTATES "6" - -/* maximum number of upvalues */ -#define MAXUPVALUES 16 -#define SMAXUPVALUES "16" - - - -/* -** Variable descriptor: -** if 0locvars */ - int maxcode; /* size of f->code */ - int maxvars; /* size of f->locvars (-1 if no debug information) */ - int maxconsts; /* size of f->consts */ - vardesc varbuffer[MAXVAR]; /* variables in an assignment list */ - vardesc upvalues[MAXUPVALUES]; /* upvalues */ -} FuncState; - - - -#define YYPURE 1 - - -void luaY_syntaxerror (char *s, char *token) -{ - if (token[0] == 0) - token = ""; - luaL_verror("%.100s;\n last token read: \"%.50s\" at line %d in file %.50s", - s, token, L->lexstate->linenumber, L->mainState->f->fileName->str); -} - - -void luaY_error (char *s) -{ - luaY_syntaxerror(s, luaX_lasttoken()); -} - - -static void check_pc (int n) -{ - FuncState *fs = L->currState; - if (fs->pc+n > fs->maxcode) - fs->maxcode = luaM_growvector(&fs->f->code, fs->maxcode, - Byte, codeEM, MAX_INT); -} - - -static void code_byte (Byte c) -{ - check_pc(1); - L->currState->f->code[L->currState->pc++] = c; -} - - -static void deltastack (int delta) -{ - FuncState *fs = L->currState; - fs->stacksize += delta; - if (fs->stacksize > fs->maxstacksize) { - if (fs->stacksize > 255) - luaY_error("function/expression too complex"); - fs->maxstacksize = fs->stacksize; - } -} - - -static int code_oparg_at (int pc, OpCode op, int builtin, int arg, int delta) -{ - Byte *code = L->currState->f->code; - deltastack(delta); - if (arg < builtin) { - code[pc] = op+1+arg; - return 1; - } - 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 luaY_error("code too long " MES_LIM("64K")); - return 0; /* to avoid warnings */ -} - - -static int fix_opcode (int pc, OpCode op, int builtin, int arg) -{ - FuncState *fs = L->currState; - if (arg < builtin) { /* close space */ - luaO_memdown(fs->f->code+pc+1, fs->f->code+pc+2, fs->pc-(pc+2)); - fs->pc--; - } - else if (arg > 255) { /* open space */ - check_pc(1); - luaO_memup(fs->f->code+pc+1, fs->f->code+pc, fs->pc-pc); - fs->pc++; - } - return code_oparg_at(pc, op, builtin, arg, 0) - 2; -} - - -static void code_oparg (OpCode op, int builtin, int arg, int delta) -{ - check_pc(3); /* maximum code size */ - L->currState->pc += code_oparg_at(L->currState->pc, op, builtin, arg, delta); -} - - -static void code_opcode (OpCode op, int delta) -{ - deltastack(delta); - code_byte(op); -} - - -static void code_pop (OpCode op) -{ - code_opcode(op, -1); -} - -/* binary operations get 2 arguments and leave one, so they pop one */ -#define code_binop(op) code_pop(op) - - -static void code_neutralop (OpCode op) -{ - code_opcode(op, 0); -} - -/* unary operations get 1 argument and leave one, so they are neutral */ -#define code_unop(op) code_neutralop(op) - - -static void code_constant (int c) -{ - code_oparg(PUSHCONSTANT, 8, c, 1); -} - - -static int next_constant (FuncState *cs) -{ - TProtoFunc *f = cs->f; - if (f->nconsts >= cs->maxconsts) { - cs->maxconsts = luaM_growvector(&f->consts, cs->maxconsts, TObject, - constantEM, MAX_WORD); - } - return f->nconsts++; -} - - -static int string_constant (TaggedString *s, FuncState *cs) -{ - TProtoFunc *f = cs->f; - int c = s->constindex; - if (!(c < f->nconsts && - ttype(&f->consts[c]) == LUA_T_STRING && tsvalue(&f->consts[c]) == s)) { - c = next_constant(cs); - ttype(&f->consts[c]) = LUA_T_STRING; - tsvalue(&f->consts[c]) = s; - s->constindex = c; /* hint for next time */ - } - return c; -} - - -static void code_string (TaggedString *s) -{ - code_constant(string_constant(s, L->currState)); -} - - -#define LIM 20 -static int real_constant (real r) -{ - /* check whether 'r' has appeared within the last LIM entries */ - TObject *cnt = L->currState->f->consts; - int c = L->currState->f->nconsts; - int lim = c < LIM ? 0 : c-LIM; - while (--c >= lim) { - if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r) - return c; - } - /* not found; create a luaM_new entry */ - c = next_constant(L->currState); - cnt = L->currState->f->consts; /* 'next_constant' may reallocate this vector */ - ttype(&cnt[c]) = LUA_T_NUMBER; - nvalue(&cnt[c]) = r; - return c; -} - - -static void code_number (real f) -{ - int i; - if (f >= 0 && f <= (real)MAX_WORD && (real)(i=(int)f) == f) - code_oparg(PUSHNUMBER, 3, i, 1); /* f has an (short) integer value */ - else - code_constant(real_constant(f)); -} - - -static void flush_record (int n) -{ - if (n > 0) - code_oparg(SETMAP, 1, n-1, -2*n); -} - -static void flush_list (int m, int n) -{ - if (n == 0) return; - code_oparg(SETLIST, 1, m, -n); - code_byte(n); -} - - -static void luaI_registerlocalvar (TaggedString *varname, int line) -{ - FuncState *fs = L->currState; - if (fs->maxvars != -1) { /* debug information? */ - if (fs->nvars >= fs->maxvars) - fs->maxvars = luaM_growvector(&fs->f->locvars, fs->maxvars, - LocVar, "", MAX_WORD); - fs->f->locvars[fs->nvars].varname = varname; - fs->f->locvars[fs->nvars].line = line; - fs->nvars++; - } -} - - -static void luaI_unregisterlocalvar (int line) -{ - luaI_registerlocalvar(NULL, line); -} - - -static void store_localvar (TaggedString *name, int n) -{ - if (L->currState->nlocalvar+n < MAXLOCALS) - L->currState->localvar[L->currState->nlocalvar+n] = name; - else - luaY_error("too many local variables " MES_LIM(SMAXLOCALS)); - luaI_registerlocalvar(name, L->lexstate->linenumber); -} - -static void add_localvar (TaggedString *name) -{ - store_localvar(name, 0); - L->currState->nlocalvar++; -} - - -/* -** dotted variables must be stored like regular indexed vars -*/ -static vardesc var2store (vardesc var) -{ - if (isdot(var)) { - code_constant(dotindex(var)); - var = 0; - } - return var; -} - - -static void add_varbuffer (vardesc var, int n) -{ - if (n >= MAXVAR) - luaY_error("variable buffer overflow " MES_LIM(SMAXVAR)); - L->currState->varbuffer[n] = var2store(var); -} - - -static int aux_localname (TaggedString *n, FuncState *st) -{ - int i; - for (i=st->nlocalvar-1; i >= 0; i--) - if (n == st->localvar[i]) return i; /* local var index */ - return -1; /* not found */ -} - - -static vardesc singlevar (TaggedString *n, FuncState *st) -{ - int i = aux_localname(n, st); - if (i == -1) { /* check shadowing */ - int l; - for (l=1; l<=(st-L->mainState); l++) - if (aux_localname(n, st-l) >= 0) - luaY_syntaxerror("cannot access a variable in outer scope", n->str); - return string_constant(n, st)+MINGLOBAL; /* global value */ - } - else return i+1; /* local value */ -} - - -static int indexupvalue (TaggedString *n) -{ - vardesc v = singlevar(n, L->currState-1); - int i; - for (i=0; icurrState->nupvalues; i++) { - if (L->currState->upvalues[i] == v) - return i; - } - /* new one */ - if (++(L->currState->nupvalues) > MAXUPVALUES) - luaY_error("too many upvalues in a single function " MES_LIM(SMAXUPVALUES)); - L->currState->upvalues[i] = v; /* i = L->currState->nupvalues - 1 */ - return i; -} - - -static void pushupvalue (TaggedString *n) -{ - int i; - if (L->currState == L->mainState) - luaY_error("cannot access upvalue in main"); - if (aux_localname(n, L->currState) >= 0) - luaY_syntaxerror("cannot access an upvalue in current scope", n->str); - i = indexupvalue(n); - code_oparg(PUSHUPVALUE, 2, i, 1); -} - - -void luaY_codedebugline (int line) -{ - if (lua_debug && line != L->lexstate->lastline) { - code_oparg(SETLINE, 0, line, 0); - L->lexstate->lastline = line; - } -} - - -static void adjuststack (int n) -{ - if (n > 0) - code_oparg(POP, 2, n-1, -n); - else if (n < 0) - code_oparg(PUSHNIL, 1, (-n)-1, -n); -} - - -static long adjust_functioncall (long exp, int nresults) -{ - if (exp <= 0) - return -exp; /* exp is -list length */ - else { - int temp = L->currState->f->code[exp]; - int nparams = L->currState->f->code[exp-1]; - exp += fix_opcode(exp-2, CALLFUNC, 2, nresults); - L->currState->f->code[exp] = nparams; - if (nresults != MULT_RET) - deltastack(nresults); - deltastack(-(nparams+1)); - return temp+nresults; - } -} - - -static void adjust_mult_assign (int vars, long exps) -{ - if (exps > 0) { /* must correct function call */ - int diff = L->currState->f->code[exps] - vars; - if (diff < 0) - adjust_functioncall(exps, -diff); - else { - adjust_functioncall(exps, 0); - adjuststack(diff); - } - } - else adjuststack((-exps)-vars); -} - - -static void code_args (int nparams, int dots) -{ - L->currState->nlocalvar += nparams; /* "self" may already be there */ - nparams = L->currState->nlocalvar; - if (!dots) { - L->currState->f->code[1] = nparams; /* fill-in arg information */ - deltastack(nparams); - } - else { - L->currState->f->code[1] = nparams+ZEROVARARG; - deltastack(nparams+1); - add_localvar(luaS_new("arg")); - } -} - - -static void lua_pushvar (vardesc var) -{ - if (isglobal(var)) - code_oparg(GETGLOBAL, 8, globalindex(var), 1); - else if (islocal(var)) - code_oparg(PUSHLOCAL, 8, localindex(var), 1); - else if (isdot(var)) - code_oparg(GETDOTTED, 8, dotindex(var), 0); - else - code_pop(GETTABLE); -} - - -static void storevar (vardesc var) -{ - if (var == 0) /* indexed var */ - code_opcode(SETTABLE0, -3); - else if (isglobal(var)) - code_oparg(SETGLOBAL, 8, globalindex(var), -1); - else /* local var */ - code_oparg(SETLOCAL, 8, localindex(var), -1); -} - - -/* returns how many elements are left as 'garbage' on the stack */ -static int lua_codestore (int i, int left) -{ - if (L->currState->varbuffer[i] != 0 || /* global or local var or */ - left+i == 0) { /* indexed var without values in between */ - storevar(L->currState->varbuffer[i]); - return left; - } - else { /* indexed var with values in between*/ - code_oparg(SETTABLE, 0, left+i, -1); - return left+2; /* table/index are not popped, since they are not on top */ - } -} - - -static int fix_jump (int pc, OpCode op, int n) -{ - /* jump is relative to position following jump instruction */ - return fix_opcode(pc, op, 0, n-(pc+JMPSIZE)); -} - - -static void fix_upjmp (OpCode op, int pos) -{ - int delta = L->currState->pc+JMPSIZE - pos; /* jump is relative */ - if (delta > 255) delta++; - code_oparg(op, 0, delta, 0); -} - - -static void codeIf (int thenAdd, int elseAdd) -{ - int elseinit = elseAdd+JMPSIZE; - if (L->currState->pc == elseinit) { /* no else part */ - L->currState->pc -= JMPSIZE; - elseinit = L->currState->pc; - } - else - elseinit += fix_jump(elseAdd, JMP, L->currState->pc); - fix_jump(thenAdd, IFFJMP, elseinit); -} - - -static void code_shortcircuit (int pc, OpCode op) -{ - fix_jump(pc, op, L->currState->pc); -} - - -static void codereturn (void) -{ - code_oparg(RETCODE, 0, L->currState->nlocalvar, 0); - L->currState->stacksize = L->currState->nlocalvar; -} - - -static void func_onstack (TProtoFunc *f) -{ - int i; - int nupvalues = (L->currState+1)->nupvalues; - int c = next_constant(L->currState); - ttype(&L->currState->f->consts[c]) = LUA_T_PROTO; - L->currState->f->consts[c].value.tf = (L->currState+1)->f; - if (nupvalues == 0) - code_constant(c); - else { - for (i=0; icurrState+1)->upvalues[i]); - code_oparg(CLOSURE, 0, c, -nupvalues+1); - code_byte(nupvalues); - } -} - - -static void init_state (TaggedString *filename) -{ - TProtoFunc *f = luaF_newproto(); - FuncState *fs = L->currState; - fs->stacksize = 0; - fs->maxstacksize = 0; - fs->nlocalvar = 0; - fs->nupvalues = 0; - fs->f = f; - f->fileName = filename; - fs->pc = 0; - fs->maxcode = 0; - f->code = NULL; - fs->maxconsts = 0; - if (lua_debug) { - fs->nvars = 0; - fs->maxvars = 0; - } - else - fs->maxvars = -1; /* flag no debug information */ - code_byte(0); /* to be filled with stacksize */ - code_byte(0); /* to be filled with arg information */ - L->lexstate->lastline = 0; /* invalidate it */ -} - - -static void init_func (void) -{ - if (L->currState-L->mainState >= MAXSTATES-1) - luaY_error("too many nested functions " MES_LIM(SMAXSTATES)); - L->currState++; - init_state(L->mainState->f->fileName); - luaY_codedebugline(L->lexstate->linenumber); - L->currState->f->lineDefined = L->lexstate->linenumber; -} - -static TProtoFunc *close_func (void) -{ - TProtoFunc *f = L->currState->f; - code_neutralop(ENDCODE); - f->code[0] = L->currState->maxstacksize; - f->code = luaM_reallocvector(f->code, L->currState->pc, Byte); - f->consts = luaM_reallocvector(f->consts, f->nconsts, TObject); - if (L->currState->maxvars != -1) { /* debug information? */ - luaI_registerlocalvar(NULL, -1); /* flag end of vector */ - f->locvars = luaM_reallocvector(f->locvars, L->currState->nvars, LocVar); - } - L->currState--; - return f; -} - - -/* -** Parse Lua code. -*/ -TProtoFunc *luaY_parser (ZIO *z) -{ - struct LexState lexstate; - FuncState state[MAXSTATES]; - L->currState = L->mainState = &state[0]; - L->lexstate = &lexstate; - luaX_setinput(z); - init_state(luaS_new(zname(z))); - if (luaY_parse()) lua_error("parse error"); - return close_func(); -} - - -%} - - -%union -{ - int vInt; - real vReal; - char *pChar; - long vLong; - TaggedString *pTStr; - TProtoFunc *pFunc; -} - -%start chunk - -%token NIL -%token IF THEN ELSE ELSEIF WHILE DO REPEAT UNTIL END -%token RETURN -%token LOCAL -%token FUNCTION -%token DOTS -%token NUMBER -%token NAME STRING - -%type SaveWord, cond, GetPC, SaveWordPop, SaveWordPush -%type exprlist, exprlist1 /* if > 0, points to function return - counter (which has list length); if <= 0, -list lenght */ -%type functioncall, expr, sexp /* if != 0, points to function return - counter */ -%type varlist1, funcParams, funcvalue -%type fieldlist, localnamelist, decinit -%type ffieldlist1, lfieldlist1, ffieldlist, lfieldlist, part -%type var, varname, funcname /* vardesc */ - - -%left AND OR -%left EQ NE '>' '<' LE GE -%left CONC -%left '+' '-' -%left '*' '/' -%left UNARY NOT -%right '^' - - -%% /* beginning of rules section */ - - -chunk : statlist ret ; - -statlist : /* empty */ - | statlist stat sc - { LUA_ASSERT(L->currState->stacksize == L->currState->nlocalvar, - "stack size != # local vars"); } - ; - -sc : /* empty */ | ';' ; - -stat : IF cond THEN block SaveWord elsepart END { codeIf($2, $5); } - - | DO block END - - | WHILE GetPC cond DO block END - {{ - FuncState *fs = L->currState; - int expsize = $3-$2; - int newpos = $2+JMPSIZE; - check_pc(expsize); - memcpy(fs->f->code+fs->pc, fs->f->code+$2, expsize); - luaO_memdown(fs->f->code+$2, fs->f->code+$3, fs->pc-$2); - newpos += fix_jump($2, JMP, fs->pc-expsize); - fix_upjmp(IFTUPJMP, newpos); - }} - - | REPEAT GetPC block UNTIL expr1 - { - fix_upjmp(IFFUPJMP, $2); - deltastack(-1); /* pops condition */ - } - - | varlist1 '=' exprlist1 - {{ - int i; - int left = 0; - adjust_mult_assign($1, $3); - for (i=$1-1; i>=0; i--) - left = lua_codestore(i, left); - adjuststack(left); /* remove eventual 'garbage' left on stack */ - }} - - | functioncall { adjust_functioncall($1, 0); } - - | LOCAL localnamelist decinit - { - L->currState->nlocalvar += $2; - adjust_mult_assign($2, $3); - } - - | FUNCTION funcname body { storevar($2); } - ; - -block : {$$ = L->currState->nlocalvar;} chunk - { - adjuststack(L->currState->nlocalvar - $1); - for (; L->currState->nlocalvar > $1; L->currState->nlocalvar--) - luaI_unregisterlocalvar(L->lexstate->linenumber); - } - ; - -funcname : varname { $$ = $1; init_func(); } - | fvarname '.' fname - { - $$ = 0; /* flag indexed variable */ - init_func(); - } - | fvarname ':' fname - { - $$ = 0; /* flag indexed variable */ - init_func(); - add_localvar(luaS_new("self")); - } - ; - -fvarname : varname { lua_pushvar($1); } ; - -fname : NAME { code_string($1); } ; - -body : '(' parlist ')' chunk END { func_onstack(close_func()); } ; - -elsepart : /* empty */ - | ELSE block - | ELSEIF cond THEN block SaveWord elsepart { codeIf($2, $5); } - ; - -ret : /* empty */ - | RETURN exprlist sc - { - adjust_functioncall($2, MULT_RET); - codereturn(); - } - ; - -GetPC : /* empty */ { $$ = L->currState->pc; } ; - -SaveWord : /* empty */ - { $$ = L->currState->pc; - check_pc(JMPSIZE); - L->currState->pc += JMPSIZE; /* open space */ - } - ; - -SaveWordPop : SaveWord { $$ = $1; deltastack(-1); /* pop condition */ } ; - -SaveWordPush : SaveWord { $$ = $1; deltastack(1); /* push a value */ } ; - -cond : expr1 SaveWordPop { $$ = $2; } ; - -expr1 : expr { adjust_functioncall($1, 1); } ; - -expr : '(' expr ')' { $$ = $2; } - | expr1 EQ expr1 { code_binop(EQOP); $$ = 0; } - | expr1 '<' expr1 { code_binop(LTOP); $$ = 0; } - | expr1 '>' expr1 { code_binop(GTOP); $$ = 0; } - | expr1 NE expr1 { code_binop(NEQOP); $$ = 0; } - | expr1 LE expr1 { code_binop(LEOP); $$ = 0; } - | expr1 GE expr1 { code_binop(GEOP); $$ = 0; } - | expr1 '+' expr1 { code_binop(ADDOP); $$ = 0; } - | expr1 '-' expr1 { code_binop(SUBOP); $$ = 0; } - | expr1 '*' expr1 { code_binop(MULTOP); $$ = 0; } - | expr1 '/' expr1 { code_binop(DIVOP); $$ = 0; } - | expr1 '^' expr1 { code_binop(POWOP); $$ = 0; } - | expr1 CONC expr1 { code_binop(CONCOP); $$ = 0; } - | '-' expr1 %prec UNARY { code_unop(MINUSOP); $$ = 0;} - | NOT expr1 { code_unop(NOTOP); $$ = 0;} - | sexp { $$ = $1; /* simple expressions */ } - | table { $$ = 0; } - | NUMBER { code_number($1); $$ = 0; } - | STRING { code_string($1); $$ = 0; } - | NIL { adjuststack(-1); $$ = 0; } - | FUNCTION { init_func(); } body { $$ = 0; } - | expr1 AND SaveWordPop expr1 { code_shortcircuit($3, ONFJMP); $$ = 0; } - | expr1 OR SaveWordPop expr1 { code_shortcircuit($3, ONTJMP); $$ = 0; } - ; - -sexp1 : sexp { adjust_functioncall($1, 1); } ; - -sexp : var { lua_pushvar($1); $$ = 0; } - | '%' NAME { pushupvalue($2); $$ = 0; } - | functioncall { $$ = $1; } - ; - -var : varname { $$ = $1; } - | sexp1 '[' expr1 ']' { $$ = 0; } /* indexed variable */ - | sexp1 '.' NAME { $$ = (-string_constant($3, L->currState))-1; } - ; - -varname : NAME { $$ = singlevar($1, L->currState); } ; - -table : '{' SaveWordPush fieldlist '}' { fix_opcode($2, CREATEARRAY, 2, $3); } ; - -functioncall : funcvalue funcParams - { - code_byte(0); /* save space for opcode */ - code_byte($1+$2); /* number of parameters */ - $$ = L->currState->pc; - code_byte(0); /* must be adjusted by other rules */ - } - ; - -funcvalue : sexp1 { $$ = 0; } - | sexp1 ':' NAME - { - code_oparg(PUSHSELF, 8, string_constant($3, L->currState), 1); - $$ = 1; - } - ; - -funcParams : '(' exprlist ')' { $$ = adjust_functioncall($2, 1); } - | table { $$ = 1; } - | STRING { code_string($1); $$ = 1; } - ; - -exprlist : /* empty */ { $$ = 0; } - | exprlist1 { $$ = $1; } - ; - -exprlist1 : expr { if ($1 != 0) $$ = $1; else $$ = -1; } - | exprlist1 ',' { $$ = adjust_functioncall($1, 1); } expr - { - if ($4 == 0) $$ = -($3 + 1); /* -length */ - else { - L->currState->f->code[$4] = $3; /* store list length */ - $$ = $4; - } - } - ; - -parlist : /* empty */ { code_args(0, 0); } - | DOTS { code_args(0, 1); } - | localnamelist { code_args($1, 0); } - | localnamelist ',' DOTS { code_args($1, 1); } - ; - -fieldlist : part { $$ = abs($1); } - | part ';' part - { - if ($1*$3 > 0) /* repeated parts? */ - luaY_error("invalid constructor syntax"); - $$ = abs($1)+abs($3); - } - ; - -part : /* empty */ { $$ = 0; } - | ffieldlist { $$ = $1; } - | lfieldlist { $$ = $1; } - ; - -lastcomma : /* empty */ | ',' ; - -ffieldlist : ffieldlist1 lastcomma - { - flush_record($1%RFIELDS_PER_FLUSH); - $$ = -$1; /* negative signals a "record" part */ - } - ; - -lfieldlist : lfieldlist1 lastcomma - { - flush_list($1/LFIELDS_PER_FLUSH, $1%LFIELDS_PER_FLUSH); - $$ = $1; - } - ; - -ffieldlist1 : ffield {$$=1;} - | ffieldlist1 ',' ffield - { - $$=$1+1; - if ($$%RFIELDS_PER_FLUSH == 0) - flush_record(RFIELDS_PER_FLUSH); - } - ; - -ffield : ffieldkey '=' expr1 ; - -ffieldkey : '[' expr1 ']' - | fname - ; - -lfieldlist1 : expr1 {$$=1;} - | lfieldlist1 ',' expr1 - { - $$=$1+1; - if ($$%LFIELDS_PER_FLUSH == 0) - flush_list($$/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); - } - ; - -varlist1 : var { $$ = 1; add_varbuffer($1, 0); } - | varlist1 ',' var { add_varbuffer($3, $1); $$ = $1+1; } - ; - -localnamelist : NAME {store_localvar($1, 0); $$ = 1;} - | localnamelist ',' NAME { store_localvar($3, $1); $$ = $1+1; } - ; - -decinit : /* empty */ { $$ = 0; } - | '=' exprlist1 { $$ = $2; } - ; - -%% - diff --git a/makefile b/makefile index f5b426b4..c9a76afd 100644 --- a/makefile +++ b/makefile @@ -1,5 +1,5 @@ # -## $Id: makefile,v 1.10 1998/01/05 17:12:54 roberto Exp roberto $ +## $Id: makefile,v 1.11 1998/05/18 22:26:03 roberto Exp roberto $ ## Makefile ## See Copyright Notice in lua.h # @@ -18,7 +18,7 @@ # define LUA_COMPAT2_5 if yous system does need to be compatible with # version 2.5 (or older) # -#define LUA_NUM_TYPE if you need numbers to be different from double +# define LUA_NUM_TYPE if you need numbers to be different from double CONFIG = -DPOPEN -D_POSIX_SOURCE #CONFIG = -DLUA_COMPAT2_5 -DOLD_ANSI -DDEBUG @@ -46,8 +46,8 @@ LUAOBJS = \ llex.o \ lmem.o \ lobject.o \ + lparser.o \ lstate.o \ - lstx.o \ lstring.o \ ltable.o \ ltm.o \ @@ -75,16 +75,11 @@ liblualib.a : $(LIBOBJS) liblua.so.1.0 : lua.o ld -o liblua.so.1.0 $(LUAOBJS) -lstx.c lstx.h : lua.stx - bison -o lstx.c -p luaY_ -d lua.stx -# yacc -d lua.stx -# sed -e 's/yy/luaY_/g' -e 's/malloc\.h/stdlib\.h/g' y.tab.c > lstx.c -# sed -e 's/yy/luaY_/g' y.tab.h > lstx.h clear : rcsclean rm -f *.o - rm -f lstx.c lstx.h + rm -f co lua.h lualib.h luadebug.h @@ -94,6 +89,7 @@ clear : %.c : RCS/%.c,v co $@ + lapi.o: lapi.c lapi.h lua.h lobject.h lauxlib.h ldo.h lstate.h lfunc.h \ lgc.h lmem.h lstring.h ltable.h ltm.h luadebug.h lvm.h lauxlib.o: lauxlib.c lauxlib.h lua.h luadebug.h @@ -107,18 +103,18 @@ lgc.o: lgc.c ldo.h lobject.h lua.h lstate.h lfunc.h lgc.h lmem.h \ lstring.h ltable.h ltm.h liolib.o: liolib.c lauxlib.h lua.h luadebug.h lualib.h llex.o: llex.c lauxlib.h lua.h llex.h lobject.h lzio.h lmem.h \ - lparser.h lstate.h lstring.h lstx.h luadebug.h + lparser.h lstate.h lstring.h luadebug.h lmathlib.o: lmathlib.c lauxlib.h lua.h lualib.h lmem.o: lmem.c lmem.h lstate.h lobject.h lua.h lobject.o: lobject.c lobject.h lua.h +lparser.o: lparser.c lauxlib.h lua.h ldo.h lobject.h lstate.h lfunc.h \ + llex.h lzio.h lmem.h lopcodes.h lparser.h lstring.h luadebug.h lstate.o: lstate.c lbuiltin.h ldo.h lobject.h lua.h lstate.h lfunc.h \ lgc.h llex.h lzio.h lmem.h lstring.h ltable.h ltm.h lstring.o: lstring.c lmem.h lobject.h lua.h lstate.h lstring.h lstrlib.o: lstrlib.c lauxlib.h lua.h lualib.h -lstx.o: lstx.c lauxlib.h lua.h ldo.h lobject.h lstate.h lfunc.h llex.h \ - lzio.h lmem.h lopcodes.h lparser.h lstring.h luadebug.h ltable.o: ltable.c lauxlib.h lua.h lmem.h lobject.h lstate.h ltable.h -ltm.o: ltm.c lauxlib.h lua.h lmem.h lobject.h lstate.h ltm.h lapi.h +ltm.o: ltm.c lauxlib.h lua.h lmem.h lobject.h lstate.h ltm.h lua.o: lua.c lua.h luadebug.h lualib.h lundump.o: lundump.c lauxlib.h lua.h lfunc.h lobject.h lmem.h \ lstring.h lundump.h lzio.h