Browse Source

NEW LL(1) PARSER

Roberto Ierusalimschy 27 years ago
parent
commit
7e59a8901d
6 changed files with 1442 additions and 1025 deletions
  1. 74 64
      llex.c
  2. 26 5
      llex.h
  3. 1332 0
      lparser.c
  4. 1 3
      lstate.h
  5. 0 940
      lua.stx
  6. 9 13
      makefile

+ 74 - 64
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;
         }
     }

+ 26 - 5
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

+ 1332 - 0
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);
+}
+

+ 1 - 3
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;

+ 0 - 940
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; }
-	  ;
-
-%%
-

+ 9 - 13
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