commit 7e59a8901d063dbea4eb0693c9c2d85bda1fc5f6
parent abc6eac404da8181ad945ac6950f61a65ba7dfa5
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed, 27 May 1998 10:08:13 -0300
NEW LL(1) PARSER
Diffstat:
M | llex.c | | | 138 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
M | llex.h | | | 31 | ++++++++++++++++++++++++++----- |
A | lparser.c | | | 1332 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | lstate.h | | | 4 | +--- |
D | lua.stx | | | 940 | ------------------------------------------------------------------------------- |
M | makefile | | | 22 | +++++++++------------- |
6 files changed, 1442 insertions(+), 1025 deletions(-)
diff --git 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,23 +26,53 @@ 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 = "<eof>";
+ 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);
}
@@ -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
@@ -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
@@ -0,0 +1,1332 @@
+/*
+** $Id: $
+** LL(1) Parser and code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdio.h>
+
+#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; i<fs->nupvalues; 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; i<func->nupvalues; 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, "<eof> 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, "<statement> 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], op<FIRSTBIN?0:-1);
+ s->top--;
+ }
+}
+
+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, "<expression> 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 <a.x> must be stored like regular indexed vars <a["x"]> */
+ 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
@@ -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
@@ -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 <stdlib.h>
-#include <string.h>
-
-#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 0<n<MINGLOBAL, represents local variable indexed by (n-1);
-** if MINGLOBAL<=n, represents global variable at position (n-MINGLOBAL);
-** if n<0, indexed variable with index (-n)-1 (table on top of stack);
-** if n==0, an indexed variable (table and index on top of stack)
-** Must be long to store negative Word values.
-*/
-typedef long vardesc;
-
-#define isglobal(v) (MINGLOBAL<=(v))
-#define globalindex(v) ((v)-MINGLOBAL)
-#define islocal(v) (0<(v) && (v)<MINGLOBAL)
-#define localindex(v) ((v)-1)
-#define isdot(v) (v<0)
-#define dotindex(v) ((-(v))-1)
-
-/* state needed to generate code for a given function */
-typedef struct FuncState {
- TProtoFunc *f; /* current function header */
- int pc; /* next position to code */
- TaggedString *localvar[MAXLOCALS]; /* store local variable names */
- 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 */
- 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 = "<eof>";
- 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 <a.x> must be stored like regular indexed vars <a["x"]>
-*/
-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; i<L->currState->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; i<nupvalues; i++)
- lua_pushvar((L->currState+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 <vReal> NUMBER
-%token <pTStr> NAME STRING
-
-%type <vInt> SaveWord, cond, GetPC, SaveWordPop, SaveWordPush
-%type <vLong> exprlist, exprlist1 /* if > 0, points to function return
- counter (which has list length); if <= 0, -list lenght */
-%type <vLong> functioncall, expr, sexp /* if != 0, points to function return
- counter */
-%type <vInt> varlist1, funcParams, funcvalue
-%type <vInt> fieldlist, localnamelist, decinit
-%type <vInt> ffieldlist1, lfieldlist1, ffieldlist, lfieldlist, part
-%type <vLong> 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 : {$<vInt>$ = L->currState->nlocalvar;} chunk
- {
- adjuststack(L->currState->nlocalvar - $<vInt>1);
- for (; L->currState->nlocalvar > $<vInt>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 ',' { $<vLong>$ = adjust_functioncall($1, 1); } expr
- {
- if ($4 == 0) $$ = -($<vLong>3 + 1); /* -length */
- else {
- L->currState->f->code[$4] = $<vLong>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
@@ -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