From 8cd67ac676fd7ff6c085e1ad6675ba6af0cb1fc3 Mon Sep 17 00:00:00 2001
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Tue, 16 Sep 1997 16:33:21 -0300
Subject: Syntax analizer and code generator

---
 lparser.h |  20 ++
 lua.stx   | 771 ++++++++++++++++++++++++++++++++++----------------------------
 2 files changed, 444 insertions(+), 347 deletions(-)
 create mode 100644 lparser.h

diff --git a/lparser.h b/lparser.h
new file mode 100644
index 00000000..5df77abc
--- /dev/null
+++ b/lparser.h
@@ -0,0 +1,20 @@
+/*
+** $Id: $
+** Syntax analizer and code generator
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lparser_h
+#define lparser_h
+
+#include "lobject.h"
+#include "lzio.h"
+
+
+void luaY_codedebugline (int line);
+TProtoFunc *luaY_parser (ZIO *z, char *chunkname);
+void luaY_error (char *s);
+void luaY_syntaxerror (char *s, char *token);
+
+
+#endif
diff --git a/lua.stx b/lua.stx
index 7c1b748e..fcd8cb65 100644
--- a/lua.stx
+++ b/lua.stx
@@ -1,84 +1,121 @@
 %{
+/*
+** $Id: $
+** Syntax analizer and code generator
+** See Copyright Notice in lua.h
+*/
 
-char *rcs_luastx = "$Id: lua.stx,v 3.50 1997/07/31 20:46:59 roberto Exp roberto $";
 
 #include <stdlib.h>
 
-#include "luadebug.h"
-#include "luamem.h"
-#include "lex.h"
-#include "opcode.h"
-#include "hash.h"
-#include "inout.h"
-#include "tree.h"
-#include "table.h"
+#include "lauxlib.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lglobal.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstring.h"
 #include "lua.h"
-#include "func.h"
+#include "luadebug.h"
+#include "lzio.h"
 
-/* to avoid warnings generated by yacc */
-int yyparse (void);
-#define malloc luaI_malloc
-#define realloc luaI_realloc
-#define free luaI_free
 
-#ifndef LISTING
-#define LISTING 0
-#endif
+/* to avoid warnings generated by yacc */
+int luaY_parse (void);
+#define malloc luaM_malloc
+#define realloc luaM_realloc
+#define free luaM_free
 
-#ifndef CODE_BLOCK
-#define CODE_BLOCK 1000
-#endif
 
+/* maximum number of local variables */
 #define MAXLOCALS 32
 
+/* maximum number of variables in a multiple assignment */
+#define MAXVAR 32
+
+/* maximum number of nested functions */
+#define MAXSTATES  6
+
+/* maximum number of upvalues */
+#define MAXUPVALUES 8
+
+/*
+** Variable descriptor: if n>0, represents global variable indexed
+** by (n-1); if n<0, represents local variable index (-n)-1;
+** if n==0, represents an indexed variable (table and index on top of stack)
+** Must be long to store negative Word values.
+*/
+typedef long vardesc;
+
+
 /* state needed to generate code for a given function */
-struct State {
-  TFunc *f;  /* current function header */
-  int codesize;
+static struct State {
+  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 maxconsts;  /* size of consts vector */
-  int nvars;  /* total number of local variables (for debugging information) */
-  int maxvars;  /* = -1 if no debug information */
-} stateMain, stateFunc, *currState;
-
-
-#define MAXVAR 32
-static Long    varbuffer[MAXVAR];    /* variables in an assignment list;
-				it's long to store negative Word values */
-static int     nvarbuffer=0;	     /* number of variables at a list */
+  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 */
+} *mainState, *currState;
 
 
-int lua_debug = 0;
 
-/* Internal functions */
 
-static void yyerror (char *s)
+void luaY_syntaxerror (char *s, char *token)
 {
-  luaI_syntaxerror(s);
+  if (token[0] == 0)
+    token = "<eof>";
+  luaL_verror("%.100s;\n> last token read: \"%.50s\" at line %d in file %.50s",
+           s, token, luaX_linenumber, mainState->f->fileName->str);
 }
 
-static void check_space (int i)
+
+void luaY_error (char *s)
 {
-  if (currState->pc+i >= currState->codesize)
-    currState->codesize = growvector(&currState->f->code, currState->codesize,
-                                     Byte, codeEM, MAX_INT);
+  luaY_syntaxerror(s, luaX_lasttoken());
 }
 
 
 static void code_byte (Byte c)
 {
-  check_space(1);
+  if (currState->pc >= currState->maxcode)
+    currState->maxcode = luaM_growvector(&currState->f->code,
+                                currState->maxcode, Byte, codeEM, MAX_INT);
   currState->f->code[currState->pc++] = c;
 }
 
 
+static void deltastack (int delta)
+{
+  currState->stacksize += delta;
+  if (currState->stacksize > currState->maxstacksize) {
+    if (currState->stacksize > 255)
+      luaY_error("expression too complex");
+    currState->maxstacksize = currState->stacksize;
+  }
+}
+
+
+static void code_opcode (OpCode op, int delta)
+{
+  code_byte(op);
+  deltastack(delta);
+}
+
+
 static void code_word_at (int pc, int n)
 {
   Word w = n;
   if (w != n)
-    yyerror("block too big");
+    luaY_error("block too big");
   currState->f->code[pc] = n&0xFF;
   currState->f->code[pc+1] = n>>8;
 }
@@ -92,11 +129,11 @@ static void code_word (int n)
 static void code_constant (int c)
 {
   if (c <= 255) {
-    code_byte(PUSHCONSTANTB);
+    code_opcode(PUSHCONSTANTB, 1);
     code_byte(c);
   }
   else {
-    code_byte(PUSHCONSTANT);
+    code_opcode(PUSHCONSTANT, 1);
     code_word(c);
   }
 }
@@ -104,10 +141,10 @@ static void code_constant (int c)
 
 static int next_constant (void)
 {
-  TFunc *f = currState->f;
+  TProtoFunc *f = currState->f;
   if (f->nconsts >= currState->maxconsts) {
     currState->maxconsts =
-      growvector(&f->consts, currState->maxconsts, TObject,
+      luaM_growvector(&f->consts, currState->maxconsts, TObject,
                  constantEM, MAX_WORD);
   }
   return f->nconsts++;
@@ -116,7 +153,7 @@ static int next_constant (void)
 
 static int string_constant (TaggedString *s)
 {
-  TFunc *f = currState->f;
+  TProtoFunc *f = currState->f;
   int c = s->u.s.constindex;
   if (!(0 <= c && c < f->nconsts &&
       ttype(&f->consts[c]) == LUA_T_STRING && tsvalue(&f->consts[c]) == s)) {
@@ -125,7 +162,6 @@ static int string_constant (TaggedString *s)
     tsvalue(&f->consts[c]) = s;
     s->u.s.constindex = c;  /* hint for next time */
   }
-  luaI_releasestring(s);
   return c;
 }
 
@@ -136,7 +172,7 @@ static void code_string (TaggedString *s)
 }
 
 
-#define LIM 10
+#define LIM 13
 static int real_constant (real r)
 {
   /* check whether 'r' has appeared within the last LIM entries */
@@ -147,7 +183,7 @@ static int real_constant (real r)
     if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r)
       return c;
   }
-  /* not found; create a new entry */
+  /* not found; create a luaM_new entry */
   c = next_constant();
   cnt = currState->f->consts;  /* 'next_constant' may reallocate this vector */
   ttype(&cnt[c]) = LUA_T_NUMBER;
@@ -157,17 +193,17 @@ static int real_constant (real r)
 
 
 static void code_number (real f)
-{ 
+{
   Word i;
   if (f >= 0 && f <= (real)MAX_WORD && (real)(i=(Word)f) == f) {
     /* f has an (short) integer value */
-    if (i <= 2) code_byte(PUSH0 + i);
+    if (i <= 2) code_opcode(PUSH0 + i, 1);
     else if (i <= 255) {
-      code_byte(PUSHBYTE);
+      code_opcode(PUSHBYTE, 1);
       code_byte(i);
     }
     else {
-      code_byte(PUSHWORD);
+      code_opcode(PUSHWORD, 1);
       code_word(i);
     }
   }
@@ -179,7 +215,7 @@ static void code_number (real f)
 static void flush_record (int n)
 {
   if (n == 0) return;
-  code_byte(STOREMAP);
+  code_opcode(SETMAP, -2*n);
   code_byte(n);
 }
 
@@ -187,15 +223,13 @@ static void flush_list (int m, int n)
 {
   if (n == 0) return;
   if (m == 0)
-    code_byte(STORELIST0); 
-  else
-  if (m < 255)
-  {
-    code_byte(STORELIST);
+    code_opcode(SETLIST0, -n);
+  else if (m < 255) {
+    code_opcode(SETLIST, -n);
     code_byte(m);
   }
   else
-   yyerror ("list constructor too long");
+    luaY_error("list constructor too long");
   code_byte(n);
 }
 
@@ -204,7 +238,7 @@ static void luaI_registerlocalvar (TaggedString *varname, int line)
 {
   if (currState->maxvars != -1) {  /* debug information? */
     if (currState->nvars >= currState->maxvars)
-      currState->maxvars = growvector(&currState->f->locvars,
+      currState->maxvars = luaM_growvector(&currState->f->locvars,
                                       currState->maxvars, LocVar, "", MAX_WORD);
     currState->f->locvars[currState->nvars].varname = varname;
     currState->f->locvars[currState->nvars].line = line;
@@ -221,12 +255,11 @@ static void luaI_unregisterlocalvar (int line)
 
 static void store_localvar (TaggedString *name, int n)
 {
-  luaI_fixstring(name);  /* local var names cannot be GC */
   if (currState->nlocalvar+n < MAXLOCALS)
     currState->localvar[currState->nlocalvar+n] = name;
   else
-    yyerror ("too many local variables");
-  luaI_registerlocalvar(name, lua_linenumber);
+    luaY_error("too many local variables");
+  luaI_registerlocalvar(name, luaX_linenumber);
 }
 
 static void add_localvar (TaggedString *name)
@@ -235,165 +268,202 @@ static void add_localvar (TaggedString *name)
   currState->nlocalvar++;
 }
 
-static void add_varbuffer (Long var)
+static void add_varbuffer (vardesc var, int n)
 {
- if (nvarbuffer < MAXVAR)
-  varbuffer[nvarbuffer++] = var;
- else
-  yyerror ("variable buffer overflow");
+  if (n >= MAXVAR)
+    luaY_error("variable buffer overflow");
+  currState->varbuffer[n] = var;
 }
 
 
-/*
-** Search a local name and if find return its index. If do not find return -1
-*/
-static int lua_localname (TaggedString *n)
+static int aux_localname (TaggedString *n, struct State *st)
 {
- int i;
- for (i=currState->nlocalvar-1; i >= 0; i--)
-  if (n == currState->localvar[i]) return i;  /* local var */
- return -1;  /* global var */
+  int i;
+  for (i=st->nlocalvar-1; i >= 0; i--)
+    if (n == st->localvar[i]) return i;  /* local var index */
+  return -1;  /* not found */
 }
 
-/*
-** Push a variable given a number. If number is positive, push global variable
-** indexed by (number -1). If negative, push local indexed by ABS(number)-1.
-** Otherwise, if zero, push indexed variable (record).
-*/
-static void lua_pushvar (Long number)
-{ 
- if (number > 0)	/* global var */
- {
-  code_byte(PUSHGLOBAL);
-  code_word(number-1);
- }
- else if (number < 0)	/* local var */
- {
-  number = (-number) - 1;
-  if (number < 10) code_byte(PUSHLOCAL0 + number);
-  else
-  {
-   code_byte(PUSHLOCAL);
-   code_byte(number);
+
+static vardesc singlevar (TaggedString *n, struct State *st)
+{
+  int i = aux_localname(n, st);
+  if (i == -1) {  /* check shadowing */
+    int l;
+    for (l=1; l<=(st-mainState); l++)
+      if (aux_localname(n, st-l) >= 0)
+        luaY_syntaxerror("cannot access a variable in outer scope", n->str);
+    return luaG_findsymbol(n)+1;  /* positive value */
   }
- }
- else
- {
-  code_byte(PUSHINDEXED);
- }
+  else return -(i+1);  /* negative value */
 }
 
-static void lua_codeadjust (int n)
+
+static int indexupvalue (TaggedString *n)
 {
-  n += currState->nlocalvar;
-  if (n == 0)
-    code_byte(ADJUST0);
-  else {
-    code_byte(ADJUST);
-    code_byte(n);
+  vardesc v = singlevar(n, currState-1);
+  int i;
+  for (i=0; i<currState->f->nupvalues; i++) {
+    if (currState->upvalues[i] == v)
+      return i;
   }
+  /* new one */
+  if (++currState->f->nupvalues > MAXUPVALUES)
+    luaY_error("too many upvalues in a single function");
+  currState->upvalues[i] = v;  /* i = currState->f->nupvalues - 1 */
+  return i;
 }
 
 
+static void pushupvalue (TaggedString *n)
+{
+  int i;
+  if (currState == mainState)
+    luaY_error("cannot access upvalue in main");
+  if (aux_localname(n, currState) >= 0)
+    luaY_syntaxerror("cannot access an upvalue in current scope", n->str);
+  i = indexupvalue(n);
+  if (i == 0)
+    code_opcode(PUSHUPVALUE0, 1);
+  else {
+    code_opcode(PUSHUPVALUE, 1);
+    code_byte(i);
+  }
+}
+
 
-void luaI_codedebugline (int line)
+void luaY_codedebugline (int line)
 {
   static int lastline = 0;
-  if (lua_debug && line != lastline)
-  {
-    code_byte(SETLINE);
+  if (lua_debug && line != lastline) {
+    code_opcode(SETLINE, 0);
     code_word(line);
     lastline = line;
   }
 }
 
-static int adjust_functioncall (Long exp, int i)
+
+static void adjuststack (int n)
+{
+  if (n > 0) {
+    code_opcode(POPS, -n);
+    code_byte(n);
+  }
+  else if (n < 0) {
+    if (n == -1)
+      code_opcode(PUSHNIL, 1);
+    else {
+      code_opcode(PUSHNILS, -n);
+      code_byte(-n);
+    }
+  }
+}
+
+
+static long adjust_functioncall (long exp, int i)
 {
   if (exp <= 0)
     return -exp; /* exp is -list length */
   else {
     int temp = currState->f->code[exp];
     currState->f->code[exp] = i;
+    if (i != MULT_RET)
+      deltastack(i);
     return temp+i;
   }
 }
 
-static void adjust_mult_assign (int vars, Long exps, int temps)
+
+static void adjust_mult_assign (int vars, long exps)
 {
   if (exps > 0) { /* must correct function call */
-    int diff = vars - currState->f->code[exps];
-    if (diff >= 0)
-      adjust_functioncall(exps, diff);
+    int diff = currState->f->code[exps] - vars;
+    if (diff < 0)
+      adjust_functioncall(exps, -diff);
     else {
       adjust_functioncall(exps, 0);
-      lua_codeadjust(temps);
+      adjuststack(diff);
     }
   }
-  else if (vars != -exps)
-    lua_codeadjust(temps);
+  else adjuststack((-exps)-vars);
 }
 
-static int close_parlist (int dots)
+
+static void code_args (int dots)
 {
-  if (!dots)
-    lua_codeadjust(0);
+  if (!dots) {
+    code_opcode(ARGS, currState->nlocalvar);
+    code_byte(currState->nlocalvar);
+  }
   else {
-    code_byte(VARARGS);
+    code_opcode(VARARGS, currState->nlocalvar+1);
     code_byte(currState->nlocalvar);
-    add_localvar(luaI_createstring("arg"));
+    add_localvar(luaS_new("arg"));
   }
-  return lua_linenumber;
-}
-
-
-static void storesinglevar (Long v)
-{
- if (v > 0)		/* global var */
- {
-   code_byte(STOREGLOBAL);
-   code_word(v-1);
- }
- else if (v < 0)      /* local var */
- {
-   int number = (-v) - 1;
-   if (number < 10) code_byte(STORELOCAL0 + number);
-   else
-   {
-     code_byte(STORELOCAL);
-     code_byte(number);
-   }
- }
- else 
-   code_byte(STOREINDEXED0);
-}
-
-
-static void lua_codestore (int i)
-{
- if (varbuffer[i] != 0)  /* global or local var */
-  storesinglevar(varbuffer[i]);
- else				  /* indexed var */
- {
-  int j;
-  int upper=0;     	/* number of indexed variables upper */
-  int param;		/* number of itens until indexed expression */
-  for (j=i+1; j <nvarbuffer; j++)
-   if (varbuffer[j] == 0) upper++;
-  param = upper*2 + i;
-  if (param == 0)
-   code_byte(STOREINDEXED0);
-  else
-  {
-   code_byte(STOREINDEXED);
-   code_byte(param);
+}
+
+
+static void lua_pushvar (vardesc number)
+{
+  if (number > 0) {  /* global var */
+    code_opcode(PUSHGLOBAL, 1);
+    code_word(number-1);
+  }
+  else if (number < 0) {  /* local var */
+    number = (-number) - 1;
+    if (number < 10)
+      code_opcode(PUSHLOCAL0 + number, 1);
+    else {
+      code_opcode(PUSHLOCAL, 1);
+      code_byte(number);
+    }
+  }
+  else {
+    code_opcode(PUSHTABLE, -1);
   }
- }
 }
 
-static void codeIf (Long thenAdd, Long elseAdd)
+
+static void storevar (vardesc number)
+{
+  if (number == 0)  /* indexed var */
+    code_opcode(SETTABLE0, -3);
+  else if (number > 0) {  /* global var */
+    code_opcode(SETGLOBAL, -1);
+    code_word(number-1);
+  }
+  else {  /* number < 0 - local var */
+    number = (-number) - 1;
+    if (number < 10)
+      code_opcode(SETLOCAL0 + number, -1);
+    else {
+      code_opcode(SETLOCAL, -1);
+      code_byte(number);
+    }
+  }
+}
+
+
+/* returns how many elements are left as 'garbage' on the stack */
+static int lua_codestore (int i, int left)
 {
-  Long elseinit = elseAdd+sizeof(Word)+1;
-  if (currState->pc == elseinit) {  /* no else */
+  if (currState->varbuffer[i] != 0 ||  /* global or local var or */
+      left+i == 0) {  /* indexed var without values in between */
+    storevar(currState->varbuffer[i]);
+    return left;
+  }
+  else {  /* indexed var with values in between*/
+    code_opcode(SETTABLE, -1);
+    code_byte(left+i);  /* number of elements between table/index and value */
+    return left+2;  /* table/index are not poped, since they are not on top */
+  }
+}
+
+
+static void codeIf (int thenAdd, int elseAdd)
+{
+  int elseinit = elseAdd+sizeof(Word)+1;
+  if (currState->pc == elseinit) {  /* no else part */
     currState->pc -= sizeof(Word)+1;
     elseinit = currState->pc;
   }
@@ -413,13 +483,39 @@ static void code_shortcircuit (int pc, Byte jmp)
 }
 
 
-static void init_state (TFunc *f)
+static void codereturn (void)
 {
+  code_opcode(RETCODE, 0);
+  code_byte(currState->nlocalvar);
+  currState->stacksize = currState->nlocalvar;
+}
+
+
+static void func_onstack (TProtoFunc *f)
+{
+  int i;
+  int nupvalues = (currState+1)->f->nupvalues;
+  int c = next_constant();
+  ttype(&currState->f->consts[c]) = LUA_T_PROTO;
+  currState->f->consts[c].value.tf = (currState+1)->f;
+  for (i=0; i<nupvalues; i++)
+    lua_pushvar((currState+1)->upvalues[i]);
+  code_constant(c);
+  code_opcode(CLOSURE, -nupvalues);
+}
+
+
+static void init_state (TaggedString *filename)
+{
+  TProtoFunc *f = luaF_newproto();
+  currState->stacksize = 0;
+  currState->maxstacksize = 0;
   currState->nlocalvar = 0;
   currState->f = f;
+  f->fileName = filename;
   currState->pc = 0;
-  currState->codesize = CODE_BLOCK;
-  f->code = newvector(CODE_BLOCK, Byte);
+  currState->maxcode = 0;
+  f->code = NULL;
   currState->maxconsts = 0;
   if (lua_debug) {
     currState->nvars = 0;
@@ -427,74 +523,63 @@ static void init_state (TFunc *f)
   }
   else
     currState->maxvars = -1;  /* flag no debug information */
+  code_byte(0);  /* to be filled with stacksize */
 }
 
 
-static void init_func (Long v)
+static void init_func (void)
 {
-  TFunc *f = new(TFunc);
-  int c = next_constant();
-  ttype(&currState->f->consts[c]) = LUA_T_FUNCTION;
-  currState->f->consts[c].value.tf = f;
-  code_constant(c);
-  storesinglevar(v);
-  currState = &stateFunc;
-  luaI_initTFunc(f);
-  init_state(f);
-  luaI_codedebugline(lua_linenumber);
+  if (currState-mainState >= MAXSTATES-1)
+    luaY_error("too many nested functions");
+  currState++;
+  init_state(mainState->f->fileName);
+  luaY_codedebugline(luaX_linenumber);
+  currState->f->lineDefined = luaX_linenumber;
 }
 
 
-static void codereturn (void)
-{
-  if (currState->nlocalvar == 0)
-    code_byte(RETCODE0);
-  else
-  {
-    code_byte(RETCODE);
-    code_byte(currState->nlocalvar);
-  }
-}
-
 
-static void close_func (void)
+static TProtoFunc *close_func (void)
 {
-  codereturn();
-  code_byte(ENDCODE);
-  currState->f->code = shrinkvector(currState->f->code, currState->pc, Byte);
-  currState->f->consts = shrinkvector(currState->f->consts,
-                                      currState->f->nconsts, TObject);
+  TProtoFunc *f = currState->f;
+  code_opcode(ENDCODE, 0);
+  f->code[0] = currState->maxstacksize;
+  f->code = luaM_reallocvector(f->code, currState->pc, Byte);
+  f->consts = luaM_reallocvector(f->consts, f->nconsts, TObject);
   if (currState->maxvars != -1) {  /* debug information? */
     luaI_registerlocalvar(NULL, -1);  /* flag end of vector */
-    currState->f->locvars = shrinkvector(currState->f->locvars,
-                                    currState->nvars, LocVar);
+    f->locvars = luaM_reallocvector(f->locvars, currState->nvars, LocVar);
   }
+  currState--;
+  return f;
 }
 
 
 /*
 ** Parse LUA code.
 */
-void lua_parse (TFunc *tf)
+TProtoFunc *luaY_parser (ZIO *z, char *chunkname)
 {
-  currState = &stateMain;
-  init_state(tf);
-  if (yyparse ()) lua_error("parse error");
-  currState = &stateMain;
-  close_func();
+  struct State state[MAXSTATES];
+  currState = mainState = &state[0];
+  luaX_setinput(z);
+  init_state(luaS_new(chunkname));
+  if (luaY_parse ()) lua_error("parse error");
+  return close_func();
 }
 
 
 %}
 
 
-%union 
+%union
 {
- int   vInt;
- real vReal;
- char *pChar;
- Long  vLong;
- TaggedString *pTStr;
+  int vInt;
+  real vReal;
+  char *pChar;
+  long vLong;
+  TaggedString *pTStr;
+  TProtoFunc *pFunc;
 }
 
 %start chunk
@@ -509,7 +594,7 @@ void lua_parse (TFunc *tf)
 %token <vReal> NUMBER
 %token <pTStr>  NAME STRING
 
-%type <vLong> PrepJump
+%type <vInt> PrepJump, PrepJumpPop
 %type <vLong> exprlist, exprlist1  /* if > 0, points to function return
 	counter (which has list length); if <= 0, -list lenght */
 %type <vLong> functioncall, expr  /* if != 0, points to function return
@@ -518,8 +603,10 @@ void lua_parse (TFunc *tf)
 %type <vInt>  fieldlist, localdeclist, decinit
 %type <vInt>  ffieldlist, ffieldlist1, semicolonpart
 %type <vInt>  lfieldlist, lfieldlist1
-%type <vInt>  parlist, parlist1, par
-%type <vLong> var, singlevar
+%type <vInt>  parlist1, par
+%type <vLong> var, singlevar, funcname  /* vardesc */
+%type <pFunc> body
+
 
 %left AND OR
 %left EQ NE '>' '<' LE GE
@@ -532,89 +619,82 @@ void lua_parse (TFunc *tf)
 
 %% /* beginning of rules section */
 
-chunk	: chunklist ret ;
-
-chunklist : /* empty */
-	  | chunklist stat sc
-	  | chunklist function
-	  ;
 
-function     : FUNCTION funcname body 	 
-	       ;
-
-funcname	: var { init_func($1); }
-		| varexp ':' NAME
-	{
-	  code_string($3);
-	  init_func(0);  /* indexed variable */
-	  add_localvar(luaI_createstring("self"));
-	}
-		;
-
-body :  '(' parlist ')' block END
-	{
-	  close_func();
-	  currState->f->lineDefined = $2;
-	  currState = &stateMain;  /* change back to main code */
-	}
-		;
+chunk    : statlist ret
+         ;
 
 statlist : /* empty */
-	 | statlist stat sc
+	 | statlist stat sc { if (currState->stacksize != currState->nlocalvar)
+                             { luaY_error("contagem"); exit(1); }}
 	 ;
 
 sc	 : /* empty */ | ';' ;
 
-stat   : IF expr1 THEN PrepJump block PrepJump elsepart END
+stat   : IF expr1 THEN PrepJumpPop block PrepJump elsepart END
 	{ codeIf($4, $6); }
 
-       | WHILE {$<vLong>$=currState->pc;} expr1 DO PrepJump block PrepJump END
+       | WHILE {$<vInt>$=currState->pc;} expr1 DO PrepJumpPop block PrepJump END
        {
          currState->f->code[$5] = IFFJMP;
 	 code_word_at($5+1, currState->pc - ($5+sizeof(Word)+1));
          currState->f->code[$7] = UPJMP;
-	 code_word_at($7+1, currState->pc - ($<vLong>2));
+	 code_word_at($7+1, currState->pc - ($<vInt>2));
        }
-     
-       | REPEAT {$<vLong>$=currState->pc;} block UNTIL expr1 PrepJump
+
+       | REPEAT {$<vInt>$=currState->pc;} block UNTIL expr1 PrepJumpPop
        {
          currState->f->code[$6] = IFFUPJMP;
-	 code_word_at($6+1, currState->pc - ($<vLong>2));
+	 code_word_at($6+1, currState->pc - ($<vInt>2));
        }
 
        | varlist1 '=' exprlist1
-       {
-        {
-         int i;
-         adjust_mult_assign(nvarbuffer, $3, $1 * 2 + nvarbuffer);
-	 for (i=nvarbuffer-1; i>=0; i--)
-	  lua_codestore(i);
-	 if ($1 > 1 || ($1 == 1 && varbuffer[0] != 0))
-	  lua_codeadjust(0);
-	}
-       } 
-       | functioncall {;}
+       {{
+	  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
        | LOCAL localdeclist decinit
-	{ currState->nlocalvar += $2;
-	  adjust_mult_assign($2, $3, 0);
-	}
+       {
+         currState->nlocalvar += $2;
+         adjust_mult_assign($2, $3);
+       }
+       | FUNCTION funcname body
+       {
+	 func_onstack($3);
+	 storevar($2);
+       }
        ;
 
+block    : {$<vInt>$ = currState->nlocalvar;} chunk
+         {
+           adjuststack(currState->nlocalvar - $<vInt>1);
+	   for (; currState->nlocalvar > $<vInt>1; currState->nlocalvar--)
+	     luaI_unregisterlocalvar(luaX_linenumber);
+         }
+         ;
+
+funcname	: var { init_func(); $$ = $1; }
+		| varexp ':' NAME
+	{
+	  code_string($3);
+          $$ = 0;  /* indexed variable */
+	  init_func();
+	  add_localvar(luaS_new("self"));
+	}
+		;
+
+body :  '(' parlist ')' chunk END { $$ = close_func(); }
+		;
+
 elsepart : /* empty */
 	 | ELSE block
-         | ELSEIF expr1 THEN PrepJump block PrepJump elsepart
+         | ELSEIF expr1 THEN PrepJumpPop block PrepJump elsepart
 	{ codeIf($4, $6); }
          ;
-     
-block    : {$<vInt>$ = currState->nlocalvar;} statlist ret 
-         {
-	   if (currState->nlocalvar != $<vInt>1) {
-	     for (; currState->nlocalvar > $<vInt>1; currState->nlocalvar--)
-	       luaI_unregisterlocalvar(lua_linenumber);
-	     lua_codeadjust(0);
-	   }
-         }
-         ;
 
 ret	: /* empty */
         | RETURN exprlist sc
@@ -625,30 +705,33 @@ ret	: /* empty */
 	;
 
 PrepJump : /* empty */
-	 { 
-	  $$ = currState->pc;
-	  code_byte(0);		/* open space */
-	  code_word(0);
+	 {
+	   $$ = currState->pc;
+	   code_opcode(0, 0);  /* open space */
+	   code_word(0);
          }
 	 ;
-	   
+
+PrepJumpPop : PrepJump	{ $$ = $1; deltastack(-1);  /* pop condition */ }
+	 ;
+
 expr1	 : expr { adjust_functioncall($1, 1); }
 	 ;
 				
 expr :  '(' expr ')'  { $$ = $2; }
-     |  expr1 EQ  expr1	{ code_byte(EQOP);   $$ = 0; }
-     |	expr1 '<' expr1	{ code_byte(LTOP);   $$ = 0; }
-     |	expr1 '>' expr1	{ code_byte(GTOP);   $$ = 0; }
-     |	expr1 NE  expr1	{ code_byte(EQOP); code_byte(NOTOP); $$ = 0; }
-     |	expr1 LE  expr1	{ code_byte(LEOP);   $$ = 0; }
-     |	expr1 GE  expr1	{ code_byte(GEOP);   $$ = 0; }
-     |	expr1 '+' expr1 { code_byte(ADDOP);  $$ = 0; }
-     |	expr1 '-' expr1 { code_byte(SUBOP);  $$ = 0; }
-     |	expr1 '*' expr1 { code_byte(MULTOP); $$ = 0; }
-     |	expr1 '/' expr1 { code_byte(DIVOP);  $$ = 0; }
-     |	expr1 '^' expr1 { code_byte(POWOP);  $$ = 0; }
-     |	expr1 CONC expr1 { code_byte(CONCOP);  $$ = 0; }
-     |	'-' expr1 %prec UNARY	{ code_byte(MINUSOP); $$ = 0;}
+     |  expr1 EQ  expr1	{ code_opcode(EQOP, -1);   $$ = 0; }
+     |	expr1 '<' expr1	{ code_opcode(LTOP, -1);   $$ = 0; }
+     |	expr1 '>' expr1	{ code_opcode(GTOP, -1);   $$ = 0; }
+     |	expr1 NE  expr1	{ code_opcode(NEQOP, -1);  $$ = 0; }
+     |	expr1 LE  expr1	{ code_opcode(LEOP, -1);   $$ = 0; }
+     |	expr1 GE  expr1	{ code_opcode(GEOP, -1);   $$ = 0; }
+     |	expr1 '+' expr1 { code_opcode(ADDOP, -1);  $$ = 0; }
+     |	expr1 '-' expr1 { code_opcode(SUBOP, -1);  $$ = 0; }
+     |	expr1 '*' expr1 { code_opcode(MULTOP, -1); $$ = 0; }
+     |	expr1 '/' expr1 { code_opcode(DIVOP, -1);  $$ = 0; }
+     |	expr1 '^' expr1 { code_opcode(POWOP, -1);  $$ = 0; }
+     |	expr1 CONC expr1 { code_opcode(CONCOP, -1);  $$ = 0; }
+     |	'-' expr1 %prec UNARY	{ code_opcode(MINUSOP, 0); $$ = 0;}
      | table { $$ = 0; }
      |  varexp          { $$ = 0;}
      |  NUMBER          { code_number($1); $$ = 0; }
@@ -657,45 +740,46 @@ expr :  '(' expr ')'  { $$ = $2; }
        code_string($1);
        $$ = 0;
      }
-     |	NIL		{code_byte(PUSHNIL); $$ = 0; }
+     |	NIL		{code_opcode(PUSHNIL, 1); $$ = 0; }
      |  functioncall    { $$ = $1; }
-     |	NOT expr1	{ code_byte(NOTOP);  $$ = 0;}
-     |	expr1 AND PrepJump expr1
-     { 
+     |	NOT expr1	{ code_opcode(NOTOP, 0);  $$ = 0;}
+     |	expr1 AND PrepJumpPop expr1
+     {
        code_shortcircuit($3, ONFJMP);
        $$ = 0;
      }
-     |	expr1 OR PrepJump expr1	
-     { 
+     |	expr1 OR PrepJumpPop expr1	
+     {
        code_shortcircuit($3, ONTJMP);
        $$ = 0;
      }
+     | FUNCTION { init_func(); } body { func_onstack($3); $$ = 0; }
      ;
 
 table :
      {
-      code_byte(CREATEARRAY);
-      $<vLong>$ = currState->pc; code_word(0);
+      code_opcode(CREATEARRAY, 1);
+      $<vInt>$ = currState->pc; code_word(0);
      }
       '{' fieldlist '}'
      {
-      code_word_at($<vLong>1, $3);
+      code_word_at($<vInt>1, $3);
      }
          ;
 
 functioncall : funcvalue funcParams
 	{
-	  code_byte(CALLFUNC);
+	  code_opcode(CALLFUNC, -($1+$2+1));  /* ajdust counts results */
 	  code_byte($1+$2);
 	  $$ = currState->pc;
-	  code_byte(0);  /* may be modified by other rules */
+	  code_byte(0);  /* may be adjusted by other rules */
 	}
 	     ;
 
 funcvalue    : varexp { $$ = 0; }
-	     | varexp ':' NAME 
-	     { 
-               code_byte(PUSHSELF); 
+	     | varexp ':' NAME
+	     {
+               code_opcode(PUSHSELF, 1);
 	       code_word(string_constant($3));
                $$ = 1;
 	     }
@@ -711,26 +795,26 @@ exprlist  :	/* empty */		{ $$ = 0; }
 	  ;
 		
 exprlist1 :  expr	{ if ($1 != 0) $$ = $1; else $$ = -1; }
-	  |  exprlist1 ',' { $<vLong>$ = adjust_functioncall($1, 1); } expr 
+	  |  exprlist1 ',' { $<vLong>$ = adjust_functioncall($1, 1); } expr
 	{
 	  if ($4 == 0) $$ = -($<vLong>3 + 1);  /* -length */
 	  else
 	  {
-	    adjust_functioncall($4, $<vLong>3);
+            currState->f->code[$4] = $<vLong>3;  /* store list length */
 	    $$ = $4;
 	  }
 	}
 	  ;
 
-parlist  :	/* empty */ { $$ = close_parlist(0); }
-	  |	parlist1    { $$ = close_parlist($1); }
+parlist  :	/* empty */ { code_args(0); }
+	  |	parlist1    { code_args($1); }
 	  ;
 		
 parlist1 :	par		  { $$ = $1; }
 	  |	parlist1 ',' par
 	{
 	  if ($1)
-            lua_error("invalid parameter list");
+            luaY_error("invalid parameter list");
           $$ = $3;
 	}
 	  ;
@@ -740,34 +824,35 @@ par : NAME	{ add_localvar($1); $$ = 0; }
     ;
 		
 fieldlist  : lfieldlist
-  	     { flush_list($1/FIELDS_PER_FLUSH, $1%FIELDS_PER_FLUSH); }
+  	     { flush_list($1/LFIELDS_PER_FLUSH, $1%LFIELDS_PER_FLUSH); }
 	     semicolonpart
 	     { $$ = $1+$3; }
 	   | ffieldlist1 lastcomma
-	     { $$ = $1; flush_record($1%FIELDS_PER_FLUSH); }
+	     { $$ = $1; flush_record($1%RFIELDS_PER_FLUSH); }
 	   ;
 
 semicolonpart : /* empty */
 	        { $$ = 0; }
 	      | ';' ffieldlist
-	        { $$ = $2; flush_record($2%FIELDS_PER_FLUSH); }
+	        { $$ = $2; flush_record($2%RFIELDS_PER_FLUSH); }
 	      ;
 
-lastcomma  : /* empty */ 
+lastcomma  : /* empty */
 	   | ','
 	   ;
 
 ffieldlist  : /* empty */ { $$ = 0; }
             | ffieldlist1 lastcomma { $$ = $1; }
-            ;   
+            ;
 
 ffieldlist1 : ffield			{$$=1;}
 	   | ffieldlist1 ',' ffield	
 		{
 		  $$=$1+1;
-		  if ($$%FIELDS_PER_FLUSH == 0) flush_record(FIELDS_PER_FLUSH);
+		  if ($$%RFIELDS_PER_FLUSH == 0)
+	            flush_record(RFIELDS_PER_FLUSH);
 		}
-	   ; 
+	   ;
 
 ffield      : ffieldkey '=' expr1
            ;
@@ -784,26 +869,25 @@ lfieldlist1 : expr1  {$$=1;}
 	    | lfieldlist1 ',' expr1
 		{
 		  $$=$1+1;
-		  if ($$%FIELDS_PER_FLUSH == 0) 
-		    flush_list($$/FIELDS_PER_FLUSH - 1, FIELDS_PER_FLUSH);
+		  if ($$%LFIELDS_PER_FLUSH == 0)
+		    flush_list($$/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH);
 		}
             ;
 
 varlist1  :	var			
 	  {
-	   nvarbuffer = 0; 
-	   add_varbuffer($1);
-	   $$ = ($1 == 0) ? 1 : 0;
+	    $$ = 1;
+	    add_varbuffer($1, 0);
 	  }
 	  |	varlist1 ',' var	
-	  { 
-	   add_varbuffer($3);
-	   $$ = ($3 == 0) ? $1 + 1 : $1;
+	  {
+	    add_varbuffer($3, $1);
+	    $$ = $1+1;
 	  }
 	  ;
 		
 var	  :	singlevar { $$ = $1; }
-	  |	varexp '[' expr1 ']' 
+	  |	varexp '[' expr1 ']'
 	  {
 	   $$ = 0;		/* indexed variable */
 	  }
@@ -814,22 +898,15 @@ var	  :	singlevar { $$ = $1; }
 	  }
 	  ;
 		
-singlevar :	NAME
-	  {
-	   int local = lua_localname($1);
-	   if (local == -1)	/* global var */
-	    $$ = luaI_findsymbol($1)+1;  /* return positive value */
-           else
-	    $$ = -(local+1);		/* return negative value */
-           luaI_fixstring($1);  /* cannot GC variable names */
-	  }
+singlevar :	NAME { $$ = singlevar($1, currState); }
 	  ;
 
 varexp	: var { lua_pushvar($1); }
+	| '%' NAME { pushupvalue($2); }
 	;
-	  
+
 localdeclist  : NAME {store_localvar($1, 0); $$ = 1;}
-     	  | localdeclist ',' NAME 
+     	  | localdeclist ',' NAME
 	    {
 	     store_localvar($3, $1);
 	     $$ = $1+1;
@@ -839,5 +916,5 @@ localdeclist  : NAME {store_localvar($1, 0); $$ = 1;}
 decinit	  : /* empty */  { $$ = 0; }
 	  | '=' exprlist1 { $$ = $2; }
 	  ;
-	  
+
 %%
-- 
cgit v1.2.3-55-g6feb