C:\JS_KRESREAL\HBP_konverzia\lua\lparser.c C:\JS_LUA\lua-5.2.0\src\lparser.c
/* /*
** $Id: lparser.c,v 2.124 2011/12/02 13:23:56 roberto Exp $ ** $Id: lparser.c,v 2.124 2011/12/02 13:23:56 roberto Exp $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/  */ 
   
   
#include <string.h> #include <string.h>
   
#define lparser_c #define lparser_c
#define LUA_CORE #define LUA_CORE
   
#include "lua.h" #include "lua.h"
   
#include "lcode.h" #include "lcode.h"
#include "ldebug.h" #include "ldebug.h"
#include "ldo.h" #include "ldo.h"
#include "lfunc.h" #include "lfunc.h"
#include "llex.h" #include "llex.h"
#include "lmem.h" #include "lmem.h"
#include "lobject.h" #include "lobject.h"
#include "lopcodes.h" #include "lopcodes.h"
#include "lparser.h" #include "lparser.h"
#include "lstate.h" #include "lstate.h"
#include "lstring.h" #include "lstring.h"
#include "ltable.h" #include "ltable.h"
   
   
   
/* maximum number of local variables per function (must be smaller /* maximum number of local variables per function (must be smaller
  than 250, due to the bytecode format) */    than 250, due to the bytecode format) */ 
#define MAXVARS     200 #define MAXVARS     200
   
   
#define hasmultret(k)       ((k) == VCALL || (k) == VVARARG) #define hasmultret(k)       ((k) == VCALL || (k) == VVARARG)
   
   
   
/* /*
** nodes for block list (list of active blocks) ** nodes for block list (list of active blocks)
*/  */ 
typedef struct BlockCnt { typedef struct BlockCnt {
 struct BlockCnt *previous;  /* chain */   struct BlockCnt *previous;  /* chain */ 
 short firstlabel;  /* index of first label in this block */   short firstlabel;  /* index of first label in this block */ 
 short firstgoto;  /* index of first pending goto in this block */   short firstgoto;  /* index of first pending goto in this block */ 
 lu_byte nactvar;  /* # active locals outside the block */   lu_byte nactvar;  /* # active locals outside the block */ 
 lu_byte upval;  /* true if some variable in the block is an upvalue */   lu_byte upval;  /* true if some variable in the block is an upvalue */ 
 lu_byte isloop;  /* true if `block' is a loop */   lu_byte isloop;  /* true if `block' is a loop */ 
} BlockCnt; } BlockCnt;
   
   
   
/* /*
** prototypes for recursive non-terminal functions ** prototypes for recursive non-terminal functions
*/  */ 
static void statement (LexState *ls); static void statement (LexState *ls);
static void expr (LexState *ls, expdesc *v); static void expr (LexState *ls, expdesc *v);
   
   
static void anchor_token (LexState *ls) { static void anchor_token (LexState *ls) {
 /* last token from outer function must be EOS */   /* last token from outer function must be EOS */ 
 lua_assert(ls->fs != NULL || ls->t.token == TK_EOS);  lua_assert(ls->fs != NULL || ls->t.token == TK_EOS);
 if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {  if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
   TString *ts = ls->t.seminfo.ts;    TString *ts = ls->t.seminfo.ts;
   luaX_newstring(ls, getstr(ts), ts->tsv.len);    luaX_newstring(ls, getstr(ts), ts->tsv.len);
 }  }
} }
   
   
/* semantic error */  /* semantic error */ 
static l_noret semerror (LexState *ls, const char *msg) { static l_noret semerror (LexState *ls, const char *msg) {
 ls->t.token = 0;  /* remove 'near to' from final message */   ls->t.token = 0;  /* remove 'near to' from final message */ 
 luaX_syntaxerror(ls, msg);  luaX_syntaxerror(ls, msg);
} }
   
   
static l_noret error_expected (LexState *ls, int token) { static l_noret error_expected (LexState *ls, int token) {
 luaX_syntaxerror(ls,  luaX_syntaxerror(ls,
     luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token)));      luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token)));
} }
   
   
static l_noret errorlimit (FuncState *fs, int limit, const char *what) { static l_noret errorlimit (FuncState *fs, int limit, const char *what) {
 lua_State *L = fs->ls->L;  lua_State *L = fs->ls->L;
 const char *msg;  const char *msg;
 int line = fs->f->linedefined;  int line = fs->f->linedefined;
 const char *where = (line == 0)  const char *where = (line == 0)
                     ? "main function"                       ? "main function" 
                     : luaO_pushfstring(L, "function at line %d", line);                      : luaO_pushfstring(L, "function at line %d", line);
 msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s",  msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s",
                               what, limit, where);                             what, limit, where);
 luaX_syntaxerror(fs->ls, msg);  luaX_syntaxerror(fs->ls, msg);
} }
   
   
static void checklimit (FuncState *fs, int v, int l, const char *what) { static void checklimit (FuncState *fs, int v, int l, const char *what) {
 if (v > l) errorlimit(fs, l, what);  if (v > l) errorlimit(fs, l, what);
} }
   
   
static int testnext (LexState *ls, int c) { static int testnext (LexState *ls, int c) {
 if (ls->t.token == c) {  if (ls->t.token == c) {
   luaX_next(ls);    luaX_next(ls);
   return 1;    return 1;
 }  }
 else return 0;  else return 0;
} }
   
   
static void check (LexState *ls, int c) { static void check (LexState *ls, int c) {
 if (ls->t.token != c)  if (ls->t.token != c)
   error_expected(ls, c);    error_expected(ls, c);
} }
   
   
static void checknext (LexState *ls, int c) { static void checknext (LexState *ls, int c) {
 check(ls, c);  check(ls, c);
 luaX_next(ls);  luaX_next(ls);
} }
   
   
#define check_condition(ls,c,msg)   { if (!(c)) luaX_syntaxerror(ls, msg); } #define check_condition(ls,c,msg)   { if (!(c)) luaX_syntaxerror(ls, msg); }
   
   
   
static void check_match (LexState *ls, int what, int who, int where) { static void check_match (LexState *ls, int what, int who, int where) {
 if (!testnext(ls, what)) {  if (!testnext(ls, what)) {
   if (where == ls->linenumber)    if (where == ls->linenumber)
     error_expected(ls, what);      error_expected(ls, what);
   else {    else {
     luaX_syntaxerror(ls, luaO_pushfstring(ls->L,      luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
            "%s expected (to close %s at line %d)",             "%s expected (to close %s at line %d)",
             luaX_token2str(ls, what), luaX_token2str(ls, who), where));              luaX_token2str(ls, what), luaX_token2str(ls, who), where));
   }    }
 }  }
} }
   
   
static TString *str_checkname (LexState *ls) { static TString *str_checkname (LexState *ls) {
 TString *ts;  TString *ts;
 check(ls, TK_NAME);  check(ls, TK_NAME);
 ts = ls->t.seminfo.ts;  ts = ls->t.seminfo.ts;
 luaX_next(ls);  luaX_next(ls);
 return ts;  return ts;
} }
   
   
static void init_exp (expdesc *e, expkind k, int i) { static void init_exp (expdesc *e, expkind k, int i) {
 e->f = e->t = NO_JUMP;  e->f = e->t = NO_JUMP;
 e->k = k;  e->k = k;
 e->u.info = i;  e->u.info = i;
} }
   
   
static void codestring (LexState *ls, expdesc *e, TString *s) { static void codestring (LexState *ls, expdesc *e, TString *s) {
 init_exp(e, VK, luaK_stringK(ls->fs, s));  init_exp(e, VK, luaK_stringK(ls->fs, s));
} }
   
   
static void checkname (LexState *ls, expdesc *e) { static void checkname (LexState *ls, expdesc *e) {
 codestring(ls, e, str_checkname(ls));  codestring(ls, e, str_checkname(ls));
} }
   
   
static int registerlocalvar (LexState *ls, TString *varname) { static int registerlocalvar (LexState *ls, TString *varname) {
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 Proto *f = fs->f;  Proto *f = fs->f;
 int oldsize = f->sizelocvars;  int oldsize = f->sizelocvars;
 luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
                 LocVar, SHRT_MAX, "local variables");                  LocVar, SHRT_MAX, "local variables");
 while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;  while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
 f->locvars[fs->nlocvars].varname = varname;  f->locvars[fs->nlocvars].varname = varname;
 luaC_objbarrier(ls->L, f, varname);  luaC_objbarrier(ls->L, f, varname);
 return fs->nlocvars++;  return fs->nlocvars++;
} }
   
   
static void new_localvar (LexState *ls, TString *name) { static void new_localvar (LexState *ls, TString *name) {
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 Dyndata *dyd = ls->dyd;  Dyndata *dyd = ls->dyd;
 int reg = registerlocalvar(ls, name);  int reg = registerlocalvar(ls, name);
 checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,  checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
                 MAXVARS, "local variables");                  MAXVARS, "local variables");
 luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,  luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
                 dyd->actvar.size, Vardesc, MAX_INT, "local variables");                  dyd->actvar.size, Vardesc, MAX_INT, "local variables");
 dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg);  dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg);
} }
   
   
static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
 new_localvar(ls, luaX_newstring(ls, name, sz));  new_localvar(ls, luaX_newstring(ls, name, sz));
} }
   
#define new_localvarliteral(ls,v) \ #define new_localvarliteral(ls,v) \
   new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1)    new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1)
   
   
static LocVar *getlocvar (FuncState *fs, int i) { static LocVar *getlocvar (FuncState *fs, int i) {
 int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;  int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;
 lua_assert(idx < fs->nlocvars);  lua_assert(idx < fs->nlocvars);
 return &fs->f->locvars[idx];  return &fs->f->locvars[idx];
} }
   
   
static void adjustlocalvars (LexState *ls, int nvars) { static void adjustlocalvars (LexState *ls, int nvars) {
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 fs->nactvar = cast_byte(fs->nactvar + nvars);  fs->nactvar = cast_byte(fs->nactvar + nvars);
 for (; nvars; nvars--) {  for (; nvars; nvars--) {
   getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;    getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;
 }  }
} }
   
   
static void removevars (FuncState *fs, int tolevel) { static void removevars (FuncState *fs, int tolevel) {
 fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);  fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
 while (fs->nactvar > tolevel)  while (fs->nactvar > tolevel)
   getlocvar(fs, --fs->nactvar)->endpc = fs->pc;    getlocvar(fs, --fs->nactvar)->endpc = fs->pc;
} }
   
   
static int searchupvalue (FuncState *fs, TString *name) { static int searchupvalue (FuncState *fs, TString *name) {
 int i;  int i;
 Upvaldesc *up = fs->f->upvalues;  Upvaldesc *up = fs->f->upvalues;
 for (i = 0; i < fs->nups; i++) {  for (i = 0; i < fs->nups; i++) {
   if (eqstr(up[i].name, name)) return i;    if (eqstr(up[i].name, name)) return i;
 }  }
 return -1;  /* not found */   return -1;  /* not found */ 
} }
   
   
static int newupvalue (FuncState *fs, TString *name, expdesc *v) { static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
 Proto *f = fs->f;  Proto *f = fs->f;
 int oldsize = f->sizeupvalues;  int oldsize = f->sizeupvalues;
 checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");  checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
 luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,  luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
                 Upvaldesc, MAXUPVAL, "upvalues");                  Upvaldesc, MAXUPVAL, "upvalues");
 while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;  while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
 f->upvalues[fs->nups].instack = (v->k == VLOCAL);  f->upvalues[fs->nups].instack = (v->k == VLOCAL);
 f->upvalues[fs->nups].idx = cast_byte(v->u.info);  f->upvalues[fs->nups].idx = cast_byte(v->u.info);
 f->upvalues[fs->nups].name = name;  f->upvalues[fs->nups].name = name;
 luaC_objbarrier(fs->ls->L, f, name);  luaC_objbarrier(fs->ls->L, f, name);
 return fs->nups++;  return fs->nups++;
} }
   
   
static int searchvar (FuncState *fs, TString *n) { static int searchvar (FuncState *fs, TString *n) {
 int i;  int i;
 for (i=fs->nactvar-1; i >= 0; i--) {  for (i=fs->nactvar-1; i >= 0; i--) {
   if (eqstr(n, getlocvar(fs, i)->varname))    if (eqstr(n, getlocvar(fs, i)->varname))
     return i;      return i;
 }  }
 return -1;  /* not found */   return -1;  /* not found */ 
} }
   
   
/* /*
 Mark block where variable at given level was defined  Mark block where variable at given level was defined
 (to emit close instructions later).  (to emit close instructions later).
*/  */ 
static void markupval (FuncState *fs, int level) { static void markupval (FuncState *fs, int level) {
 BlockCnt *bl = fs->bl;  BlockCnt *bl = fs->bl;
 while (bl->nactvar > level) bl = bl->previous;  while (bl->nactvar > level) bl = bl->previous;
 bl->upval = 1;  bl->upval = 1;
} }
   
   
/* /*
 Find variable with given name 'n'. If it is an upvalue, add this  Find variable with given name 'n'. If it is an upvalue, add this
 upvalue into all intermediate functions.  upvalue into all intermediate functions.
*/  */ 
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
 if (fs == NULL)  /* no more levels? */   if (fs == NULL)  /* no more levels? */ 
   return VVOID;  /* default is global */     return VVOID;  /* default is global */ 
 else {  else {
   int v = searchvar(fs, n);  /* look up locals at current level */     int v = searchvar(fs, n);  /* look up locals at current level */ 
   if (v >= 0) {  /* found? */     if (v >= 0) {  /* found? */ 
     init_exp(var, VLOCAL, v);  /* variable is local */       init_exp(var, VLOCAL, v);  /* variable is local */ 
     if (!base)      if (!base)
       markupval(fs, v);  /* local will be used as an upval */         markupval(fs, v);  /* local will be used as an upval */ 
     return VLOCAL;      return VLOCAL;
   }    }
   else {  /* not found as local at current level; try upvalues */     else {  /* not found as local at current level; try upvalues */ 
     int idx = searchupvalue(fs, n);  /* try existing upvalues */       int idx = searchupvalue(fs, n);  /* try existing upvalues */ 
     if (idx < 0) {  /* not found? */       if (idx < 0) {  /* not found? */ 
       if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */         if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ 
         return VVOID;  /* not found; is a global */           return VVOID;  /* not found; is a global */ 
       /* else was LOCAL or UPVAL */         /* else was LOCAL or UPVAL */ 
       idx  = newupvalue(fs, n, var);  /* will be a new upvalue */         idx  = newupvalue(fs, n, var);  /* will be a new upvalue */ 
     }      }
     init_exp(var, VUPVAL, idx);      init_exp(var, VUPVAL, idx);
     return VUPVAL;      return VUPVAL;
   }    }
 }  }
} }
   
   
static void singlevar (LexState *ls, expdesc *var) { static void singlevar (LexState *ls, expdesc *var) {
 TString *varname = str_checkname(ls);  TString *varname = str_checkname(ls);
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 if (singlevaraux(fs, varname, var, 1) == VVOID) {  /* global name? */   if (singlevaraux(fs, varname, var, 1) == VVOID) {  /* global name? */ 
   expdesc key;    expdesc key;
   singlevaraux(fs, ls->envn, var, 1);  /* get environment variable */     singlevaraux(fs, ls->envn, var, 1);  /* get environment variable */ 
   lua_assert(var->k == VLOCAL || var->k == VUPVAL);    lua_assert(var->k == VLOCAL || var->k == VUPVAL);
   codestring(ls, &key, varname);  /* key is variable name */     codestring(ls, &key, varname);  /* key is variable name */ 
   luaK_indexed(fs, var, &key);  /* env[varname] */     luaK_indexed(fs, var, &key);  /* env[varname] */ 
 }  }
} }
   
   
static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int extra = nvars - nexps;  int extra = nvars - nexps;
 if (hasmultret(e->k)) {  if (hasmultret(e->k)) {
   extra++;  /* includes call itself */     extra++;  /* includes call itself */ 
   if (extra < 0) extra = 0;    if (extra < 0) extra = 0;
   luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */     luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */ 
   if (extra > 1) luaK_reserveregs(fs, extra-1);    if (extra > 1) luaK_reserveregs(fs, extra-1);
 }  }
 else {  else {
   if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */     if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */ 
   if (extra > 0) {    if (extra > 0) {
     int reg = fs->freereg;      int reg = fs->freereg;
     luaK_reserveregs(fs, extra);      luaK_reserveregs(fs, extra);
     luaK_nil(fs, reg, extra);      luaK_nil(fs, reg, extra);
   }    }
 }  }
} }
   
   
static void enterlevel (LexState *ls) { static void enterlevel (LexState *ls) {
 lua_State *L = ls->L;  lua_State *L = ls->L;
 ++L->nCcalls;  ++L->nCcalls;
 checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels");  checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels");
} }
   
   
#define leavelevel(ls)  ((ls)->L->nCcalls--) #define leavelevel(ls)  ((ls)->L->nCcalls--)
   
   
static void closegoto (LexState *ls, int g, Labeldesc *label) { static void closegoto (LexState *ls, int g, Labeldesc *label) {
 int i;  int i;
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 Labellist *gl = &ls->dyd->gt;  Labellist *gl = &ls->dyd->gt;
 Labeldesc *gt = &gl->arr[g];  Labeldesc *gt = &gl->arr[g];
 lua_assert(eqstr(gt->name, label->name));  lua_assert(eqstr(gt->name, label->name));
 if (gt->nactvar < label->nactvar) {  if (gt->nactvar < label->nactvar) {
   TString *vname = getlocvar(fs, gt->nactvar)->varname;    TString *vname = getlocvar(fs, gt->nactvar)->varname;
   const char *msg = luaO_pushfstring(ls->L,    const char *msg = luaO_pushfstring(ls->L,
     "<goto %s> at line %d jumps into the scope of local " LUA_QS,      "<goto %s> at line %d jumps into the scope of local " LUA_QS,
     getstr(gt->name), gt->line, getstr(vname));      getstr(gt->name), gt->line, getstr(vname));
   semerror(ls, msg);    semerror(ls, msg);
 }  }
 luaK_patchlist(fs, gt->pc, label->pc);  luaK_patchlist(fs, gt->pc, label->pc);
 /* remove goto from pending list */   /* remove goto from pending list */ 
 for (i = g; i < gl->n - 1; i++)  for (i = g; i < gl->n - 1; i++)
   gl->arr[i] = gl->arr[i + 1];    gl->arr[i] = gl->arr[i + 1];
 gl->n--;  gl->n--;
} }
   
   
/* /*
** try to close a goto with existing labels; this solves backward jumps ** try to close a goto with existing labels; this solves backward jumps
*/  */ 
static int findlabel (LexState *ls, int g) { static int findlabel (LexState *ls, int g) {
 int i;  int i;
 BlockCnt *bl = ls->fs->bl;  BlockCnt *bl = ls->fs->bl;
 Dyndata *dyd = ls->dyd;  Dyndata *dyd = ls->dyd;
 Labeldesc *gt = &dyd->gt.arr[g];  Labeldesc *gt = &dyd->gt.arr[g];
 /* check labels in current block for a match */   /* check labels in current block for a match */ 
 for (i = bl->firstlabel; i < dyd->label.n; i++) {  for (i = bl->firstlabel; i < dyd->label.n; i++) {
   Labeldesc *lb = &dyd->label.arr[i];    Labeldesc *lb = &dyd->label.arr[i];
   if (eqstr(lb->name, gt->name)) {  /* correct label? */     if (eqstr(lb->name, gt->name)) {  /* correct label? */ 
     if (gt->nactvar > lb->nactvar &&      if (gt->nactvar > lb->nactvar &&
         (bl->upval || dyd->label.n > bl->firstlabel))          (bl->upval || dyd->label.n > bl->firstlabel))
       luaK_patchclose(ls->fs, gt->pc, lb->nactvar);        luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
     closegoto(ls, g, lb);  /* close it */       closegoto(ls, g, lb);  /* close it */ 
     return 1;      return 1;
   }    }
 }  }
 return 0;  /* label not found; cannot close goto */   return 0;  /* label not found; cannot close goto */ 
} }
   
   
static int newlabelentry (LexState *ls, Labellist *l, TString *name, static int newlabelentry (LexState *ls, Labellist *l, TString *name,
                         int line, int pc) {                          int line, int pc) {
 int n = l->n;  int n = l->n;
 luaM_growvector(ls->L, l->arr, n, l->size,  luaM_growvector(ls->L, l->arr, n, l->size,
                 Labeldesc, SHRT_MAX, "labels/gotos");                  Labeldesc, SHRT_MAX, "labels/gotos");
 l->arr[n].name = name;  l->arr[n].name = name;
 l->arr[n].line = line;  l->arr[n].line = line;
 l->arr[n].nactvar = ls->fs->nactvar;  l->arr[n].nactvar = ls->fs->nactvar;
 l->arr[n].pc = pc;  l->arr[n].pc = pc;
 l->n++;  l->n++;
 return n;  return n;
} }
   
   
/* /*
** check whether new label 'lb' matches any pending gotos in current ** check whether new label 'lb' matches any pending gotos in current
** block; solves forward jumps ** block; solves forward jumps
*/  */ 
static void findgotos (LexState *ls, Labeldesc *lb) { static void findgotos (LexState *ls, Labeldesc *lb) {
 Labellist *gl = &ls->dyd->gt;  Labellist *gl = &ls->dyd->gt;
 int i = ls->fs->bl->firstgoto;  int i = ls->fs->bl->firstgoto;
 while (i < gl->n) {  while (i < gl->n) {
   if (eqstr(gl->arr[i].name, lb->name))    if (eqstr(gl->arr[i].name, lb->name))
     closegoto(ls, i, lb);      closegoto(ls, i, lb);
   else    else
     i++;      i++;
 }  }
} }
   
   
/* /*
** "export" pending gotos to outer level, to check them against ** "export" pending gotos to outer level, to check them against
** outer labels; if the block being exited has upvalues, and ** outer labels; if the block being exited has upvalues, and
** the goto exits the scope of any variable (which can be the ** the goto exits the scope of any variable (which can be the
** upvalue), close those variables being exited. ** upvalue), close those variables being exited.
*/  */ 
static void movegotosout (FuncState *fs, BlockCnt *bl) { static void movegotosout (FuncState *fs, BlockCnt *bl) {
 int i = bl->firstgoto;  int i = bl->firstgoto;
 Labellist *gl = &fs->ls->dyd->gt;  Labellist *gl = &fs->ls->dyd->gt;
 /* correct pending gotos to current block and try to close it  /* correct pending gotos to current block and try to close it
    with visible labels */       with visible labels */ 
 while (i < gl->n) {  while (i < gl->n) {
   Labeldesc *gt = &gl->arr[i];    Labeldesc *gt = &gl->arr[i];
   if (gt->nactvar > bl->nactvar) {    if (gt->nactvar > bl->nactvar) {
     if (bl->upval)      if (bl->upval)
       luaK_patchclose(fs, gt->pc, bl->nactvar);        luaK_patchclose(fs, gt->pc, bl->nactvar);
     gt->nactvar = bl->nactvar;      gt->nactvar = bl->nactvar;
   }    }
   if (!findlabel(fs->ls, i))    if (!findlabel(fs->ls, i))
     i++;  /* move to next one */       i++;  /* move to next one */ 
 }  }
} }
   
   
static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
 bl->isloop = isloop;  bl->isloop = isloop;
 bl->nactvar = fs->nactvar;  bl->nactvar = fs->nactvar;
 bl->firstlabel = fs->ls->dyd->label.n;  bl->firstlabel = fs->ls->dyd->label.n;
 bl->firstgoto = fs->ls->dyd->gt.n;  bl->firstgoto = fs->ls->dyd->gt.n;
 bl->upval = 0;  bl->upval = 0;
 bl->previous = fs->bl;  bl->previous = fs->bl;
 fs->bl = bl;  fs->bl = bl;
 lua_assert(fs->freereg == fs->nactvar);  lua_assert(fs->freereg == fs->nactvar);
} }
   
   
/* /*
** create a label named "break" to resolve break statements ** create a label named "break" to resolve break statements
*/  */ 
static void breaklabel (LexState *ls) { static void breaklabel (LexState *ls) {
 TString *n = luaS_new(ls->L, "break");  TString *n = luaS_new(ls->L, "break");
 int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc);  int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc);
 findgotos(ls, &ls->dyd->label.arr[l]);  findgotos(ls, &ls->dyd->label.arr[l]);
} }
   
/* /*
** generates an error for an undefined 'goto'; choose appropriate ** generates an error for an undefined 'goto'; choose appropriate
** message when label name is a reserved word (which can only be 'break') ** message when label name is a reserved word (which can only be 'break')
*/  */ 
static l_noret undefgoto (LexState *ls, Labeldesc *gt) { static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
 const char *msg = (gt->name->tsv.reserved > 0)  const char *msg = (gt->name->tsv.reserved > 0)
                   ? "<%s> at line %d not inside a loop"                     ? "<%s> at line %d not inside a loop" 
                   : "no visible label " LUA_QS " for <goto> at line %d";                    : "no visible label " LUA_QS " for <goto> at line %d";
 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);  msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
 semerror(ls, msg);  semerror(ls, msg);
} }
   
   
static void leaveblock (FuncState *fs) { static void leaveblock (FuncState *fs) {
 BlockCnt *bl = fs->bl;  BlockCnt *bl = fs->bl;
 LexState *ls = fs->ls;  LexState *ls = fs->ls;
 if (bl->previous && bl->upval) {  if (bl->previous && bl->upval) {
   /* create a 'jump to here' to close upvalues */     /* create a 'jump to here' to close upvalues */ 
   int j = luaK_jump(fs);    int j = luaK_jump(fs);
   luaK_patchclose(fs, j, bl->nactvar);    luaK_patchclose(fs, j, bl->nactvar);
   luaK_patchtohere(fs, j);    luaK_patchtohere(fs, j);
 }  }
 if (bl->isloop)  if (bl->isloop)
   breaklabel(ls);  /* close pending breaks */     breaklabel(ls);  /* close pending breaks */ 
 fs->bl = bl->previous;  fs->bl = bl->previous;
 removevars(fs, bl->nactvar);  removevars(fs, bl->nactvar);
 lua_assert(bl->nactvar == fs->nactvar);  lua_assert(bl->nactvar == fs->nactvar);
 fs->freereg = fs->nactvar;  /* free registers */   fs->freereg = fs->nactvar;  /* free registers */ 
 ls->dyd->label.n = bl->firstlabel;  /* remove local labels */   ls->dyd->label.n = bl->firstlabel;  /* remove local labels */ 
 if (bl->previous)  /* inner block? */   if (bl->previous)  /* inner block? */ 
   movegotosout(fs, bl);  /* update pending gotos to outer block */     movegotosout(fs, bl);  /* update pending gotos to outer block */ 
 else if (bl->firstgoto < ls->dyd->gt.n)  /* pending gotos in outer block? */   else if (bl->firstgoto < ls->dyd->gt.n)  /* pending gotos in outer block? */ 
   undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]);  /* error */     undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]);  /* error */ 
} }
   
   
/* /*
** adds prototype being created into its parent list of prototypes ** adds prototype being created into its parent list of prototypes
** and codes instruction to create new closure ** and codes instruction to create new closure
*/  */ 
static void codeclosure (LexState *ls, Proto *clp, expdesc *v) { static void codeclosure (LexState *ls, Proto *clp, expdesc *v) {
 FuncState *fs = ls->fs->prev;  FuncState *fs = ls->fs->prev;
 Proto *f = fs->f;  /* prototype of function creating new closure */   Proto *f = fs->f;  /* prototype of function creating new closure */ 
 if (fs->np >= f->sizep) {  if (fs->np >= f->sizep) {
   int oldsize = f->sizep;    int oldsize = f->sizep;
   luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,    luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
                   MAXARG_Bx, "functions");                    MAXARG_Bx, "functions");
   while (oldsize < f->sizep) f->p[oldsize++] = NULL;    while (oldsize < f->sizep) f->p[oldsize++] = NULL;
 }  }
 f->p[fs->np++] = clp;  f->p[fs->np++] = clp;
 luaC_objbarrier(ls->L, f, clp);  luaC_objbarrier(ls->L, f, clp);
 init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));  init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
 luaK_exp2nextreg(fs, v);  /* fix it at stack top (for GC) */   luaK_exp2nextreg(fs, v);  /* fix it at stack top (for GC) */ 
} }
   
   
static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
 lua_State *L = ls->L;  lua_State *L = ls->L;
 Proto *f;  Proto *f;
 fs->prev = ls->fs;  /* linked list of funcstates */   fs->prev = ls->fs;  /* linked list of funcstates */ 
 fs->ls = ls;  fs->ls = ls;
 ls->fs = fs;  ls->fs = fs;
 fs->pc = 0;  fs->pc = 0;
 fs->lasttarget = 0;  fs->lasttarget = 0;
 fs->jpc = NO_JUMP;  fs->jpc = NO_JUMP;
 fs->freereg = 0;  fs->freereg = 0;
 fs->nk = 0;  fs->nk = 0;
 fs->np = 0;  fs->np = 0;
 fs->nups = 0;  fs->nups = 0;
 fs->nlocvars = 0;  fs->nlocvars = 0;
 fs->nactvar = 0;  fs->nactvar = 0;
 fs->firstlocal = ls->dyd->actvar.n;  fs->firstlocal = ls->dyd->actvar.n;
 fs->bl = NULL;  fs->bl = NULL;
 f = luaF_newproto(L);  f = luaF_newproto(L);
 fs->f = f;  fs->f = f;
 f->source = ls->source;  f->source = ls->source;
 f->maxstacksize = 2;  /* registers 0/1 are always valid */   f->maxstacksize = 2;  /* registers 0/1 are always valid */ 
 /* anchor prototype (to avoid being collected) */   /* anchor prototype (to avoid being collected) */ 
 setptvalue2s(L, L->top, f);  setptvalue2s(L, L->top, f);
 incr_top(L);  incr_top(L);
 fs->h = luaH_new(L);  fs->h = luaH_new(L);
 /* anchor table of constants (to avoid being collected) */   /* anchor table of constants (to avoid being collected) */ 
 sethvalue2s(L, L->top, fs->h);  sethvalue2s(L, L->top, fs->h);
 incr_top(L);  incr_top(L);
 enterblock(fs, bl, 0);  enterblock(fs, bl, 0);
} }
   
   
static void close_func (LexState *ls) { static void close_func (LexState *ls) {
 lua_State *L = ls->L;  lua_State *L = ls->L;
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 Proto *f = fs->f;  Proto *f = fs->f;
 luaK_ret(fs, 0, 0);  /* final return */   luaK_ret(fs, 0, 0);  /* final return */ 
 leaveblock(fs);  leaveblock(fs);
 luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);  luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
 f->sizecode = fs->pc;  f->sizecode = fs->pc;
 luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);  luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
 f->sizelineinfo = fs->pc;  f->sizelineinfo = fs->pc;
 luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);  luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
 f->sizek = fs->nk;  f->sizek = fs->nk;
 luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);  luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
 f->sizep = fs->np;  f->sizep = fs->np;
 luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);  luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
 f->sizelocvars = fs->nlocvars;  f->sizelocvars = fs->nlocvars;
 luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);  luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
 f->sizeupvalues = fs->nups;  f->sizeupvalues = fs->nups;
 lua_assert(fs->bl == NULL);  lua_assert(fs->bl == NULL);
 ls->fs = fs->prev;  ls->fs = fs->prev;
 /* last token read was anchored in defunct function; must re-anchor it */   /* last token read was anchored in defunct function; must re-anchor it */ 
 anchor_token(ls);  anchor_token(ls);
 L->top--;  /* pop table of constants */   L->top--;  /* pop table of constants */ 
 luaC_checkGC(L);  luaC_checkGC(L);
 L->top--;  /* pop prototype (after possible collection) */   L->top--;  /* pop prototype (after possible collection) */ 
} }
   
   
/* /*
** opens the main function, which is a regular vararg function with an ** opens the main function, which is a regular vararg function with an
** upvalue named LUA_ENV ** upvalue named LUA_ENV
*/  */ 
static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) { static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) {
 expdesc v;  expdesc v;
 open_func(ls, fs, bl);  open_func(ls, fs, bl);
 fs->f->is_vararg = 1;  /* main function is always vararg */   fs->f->is_vararg = 1;  /* main function is always vararg */ 
 init_exp(&v, VLOCAL, 0);  init_exp(&v, VLOCAL, 0);
 newupvalue(fs, ls->envn, &v);  /* create environment upvalue */   newupvalue(fs, ls->envn, &v);  /* create environment upvalue */ 
} }
   
   
   
/*============================================================*/  /*============================================================*/ 
/* GRAMMAR RULES */  /* GRAMMAR RULES */ 
/*============================================================*/  /*============================================================*/ 
   
   
/* /*
** check whether current token is in the follow set of a block. ** check whether current token is in the follow set of a block.
** 'until' closes syntactical blocks, but do not close scope, ** 'until' closes syntactical blocks, but do not close scope,
** so it handled in separate. ** so it handled in separate.
*/  */ 
static int block_follow (LexState *ls, int withuntil) { static int block_follow (LexState *ls, int withuntil) {
 switch (ls->t.token) {  switch (ls->t.token) {
   case TK_ELSE: case TK_ELSEIF:    case TK_ELSE: case TK_ELSEIF:
   case TK_END: case TK_EOS:    case TK_END: case TK_EOS:
     return 1;      return 1;
   case TK_UNTIL: return withuntil;    case TK_UNTIL: return withuntil;
   default: return 0;    default: return 0;
 }  }
} }
   
   
static void statlist (LexState *ls) { static void statlist (LexState *ls) {
 /* statlist -> { stat [`;'] } */   /* statlist -> { stat [`;'] } */ 
 while (!block_follow(ls, 1)) {  while (!block_follow(ls, 1)) {
   if (ls->t.token == TK_RETURN) {    if (ls->t.token == TK_RETURN) {
     statement(ls);      statement(ls);
     return;  /* 'return' must be last statement */       return;  /* 'return' must be last statement */ 
   }    }
   statement(ls);    statement(ls);
 }  }
} }
   
   
static void fieldsel (LexState *ls, expdesc *v) { static void fieldsel (LexState *ls, expdesc *v) {
 /* fieldsel -> ['.' | ':'] NAME */   /* fieldsel -> ['.' | ':'] NAME */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 expdesc key;  expdesc key;
 luaK_exp2anyregup(fs, v);  luaK_exp2anyregup(fs, v);
 luaX_next(ls);  /* skip the dot or colon */   luaX_next(ls);  /* skip the dot or colon */ 
 checkname(ls, &key);  checkname(ls, &key);
 luaK_indexed(fs, v, &key);  luaK_indexed(fs, v, &key);
} }
   
   
static void yindex (LexState *ls, expdesc *v) { static void yindex (LexState *ls, expdesc *v) {
 /* index -> '[' expr ']' */   /* index -> '[' expr ']' */ 
 luaX_next(ls);  /* skip the '[' */   luaX_next(ls);  /* skip the '[' */ 
 expr(ls, v);  expr(ls, v);
 luaK_exp2val(ls->fs, v);  luaK_exp2val(ls->fs, v);
 checknext(ls, ']');  checknext(ls, ']');
} }
   
   
/* /*
** {====================================================================== ** {======================================================================
** Rules for Constructors ** Rules for Constructors
** ======================================================================= ** =======================================================================
*/  */ 
   
   
struct ConsControl { struct ConsControl {
 expdesc v;  /* last list item read */   expdesc v;  /* last list item read */ 
 expdesc *t;  /* table descriptor */   expdesc *t;  /* table descriptor */ 
 int nh;  /* total number of `record' elements */   int nh;  /* total number of `record' elements */ 
 int na;  /* total number of array elements */   int na;  /* total number of array elements */ 
 int tostore;  /* number of array elements pending to be stored */   int tostore;  /* number of array elements pending to be stored */ 
}; };
   
   
static void recfield (LexState *ls, struct ConsControl *cc) { static void recfield (LexState *ls, struct ConsControl *cc) {
 /* recfield -> (NAME | `['exp1`]') = exp1 */   /* recfield -> (NAME | `['exp1`]') = exp1 */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int reg = ls->fs->freereg;  int reg = ls->fs->freereg;
 expdesc key, val;  expdesc key, val;
 int rkkey;  int rkkey;
 if (ls->t.token == TK_NAME) {  if (ls->t.token == TK_NAME) {
   checklimit(fs, cc->nh, MAX_INT, "items in a constructor");    checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
   checkname(ls, &key);    checkname(ls, &key);
 }  }
 else  /* ls->t.token == '[' */   else  /* ls->t.token == '[' */ 
   yindex(ls, &key);    yindex(ls, &key);
 cc->nh++;  cc->nh++;
 checknext(ls, '=');  checknext(ls, '=');
 rkkey = luaK_exp2RK(fs, &key);  rkkey = luaK_exp2RK(fs, &key);
 expr(ls, &val);  expr(ls, &val);
 luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val));  luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val));
 fs->freereg = reg;  /* free registers */   fs->freereg = reg;  /* free registers */ 
} }
   
   
static void closelistfield (FuncState *fs, struct ConsControl *cc) { static void closelistfield (FuncState *fs, struct ConsControl *cc) {
 if (cc->v.k == VVOID) return;  /* there is no list item */   if (cc->v.k == VVOID) return;  /* there is no list item */ 
 luaK_exp2nextreg(fs, &cc->v);  luaK_exp2nextreg(fs, &cc->v);
 cc->v.k = VVOID;  cc->v.k = VVOID;
 if (cc->tostore == LFIELDS_PER_FLUSH) {  if (cc->tostore == LFIELDS_PER_FLUSH) {
   luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);  /* flush */     luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);  /* flush */ 
   cc->tostore = 0;  /* no more items pending */     cc->tostore = 0;  /* no more items pending */ 
 }  }
} }
   
   
static void lastlistfield (FuncState *fs, struct ConsControl *cc) { static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
 if (cc->tostore == 0) return;  if (cc->tostore == 0) return;
 if (hasmultret(cc->v.k)) {  if (hasmultret(cc->v.k)) {
   luaK_setmultret(fs, &cc->v);    luaK_setmultret(fs, &cc->v);
   luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET);    luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET);
   cc->na--;  /* do not count last expression (unknown number of elements) */     cc->na--;  /* do not count last expression (unknown number of elements) */ 
 }  }
 else {  else {
   if (cc->v.k != VVOID)    if (cc->v.k != VVOID)
     luaK_exp2nextreg(fs, &cc->v);      luaK_exp2nextreg(fs, &cc->v);
   luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);    luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);
 }  }
} }
   
   
static void listfield (LexState *ls, struct ConsControl *cc) { static void listfield (LexState *ls, struct ConsControl *cc) {
 /* listfield -> exp */   /* listfield -> exp */ 
 expr(ls, &cc->v);  expr(ls, &cc->v);
 checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");  checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
 cc->na++;  cc->na++;
 cc->tostore++;  cc->tostore++;
} }
   
   
static void field (LexState *ls, struct ConsControl *cc) { static void field (LexState *ls, struct ConsControl *cc) {
 /* field -> listfield | recfield */   /* field -> listfield | recfield */ 
 switch(ls->t.token) {  switch(ls->t.token) {
   case TK_NAME: {  /* may be 'listfield' or 'recfield' */     case TK_NAME: {  /* may be 'listfield' or 'recfield' */ 
     if (luaX_lookahead(ls) != '=')  /* expression? */       if (luaX_lookahead(ls) != '=')  /* expression? */ 
       listfield(ls, cc);        listfield(ls, cc);
     else      else
       recfield(ls, cc);        recfield(ls, cc);
     break;      break;
   }    }
   case '[': {    case '[': {
     recfield(ls, cc);      recfield(ls, cc);
     break;      break;
   }    }
   default: {    default: {
     listfield(ls, cc);      listfield(ls, cc);
     break;      break;
   }    }
 }  }
} }
   
   
static void constructor (LexState *ls, expdesc *t) { static void constructor (LexState *ls, expdesc *t) {
 /* constructor -> '{' [ field { sep field } [sep] ] '}'  /* constructor -> '{' [ field { sep field } [sep] ] '}'
    sep -> ',' | ';' */      sep -> ',' | ';' */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int line = ls->linenumber;  int line = ls->linenumber;
 int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);  int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
 struct ConsControl cc;  struct ConsControl cc;
 cc.na = cc.nh = cc.tostore = 0;  cc.na = cc.nh = cc.tostore = 0;
 cc.t = t;  cc.t = t;
 init_exp(t, VRELOCABLE, pc);  init_exp(t, VRELOCABLE, pc);
 init_exp(&cc.v, VVOID, 0);  /* no value (yet) */   init_exp(&cc.v, VVOID, 0);  /* no value (yet) */ 
 luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top */   luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top */ 
 checknext(ls, '{');  checknext(ls, '{');
 do {  do {
   lua_assert(cc.v.k == VVOID || cc.tostore > 0);    lua_assert(cc.v.k == VVOID || cc.tostore > 0);
   if (ls->t.token == '}') break;    if (ls->t.token == '}') break;
   closelistfield(fs, &cc);    closelistfield(fs, &cc);
   field(ls, &cc);    field(ls, &cc);
 } while (testnext(ls, ',') || testnext(ls, ';'));  } while (testnext(ls, ',') || testnext(ls, ';'));
 check_match(ls, '}', '{', line);  check_match(ls, '}', '{', line);
 lastlistfield(fs, &cc);  lastlistfield(fs, &cc);
 SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */   SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ 
 SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */   SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */ 
} }
   
/* }====================================================================== */  /* }====================================================================== */ 
   
   
   
static void parlist (LexState *ls) { static void parlist (LexState *ls) {
 /* parlist -> [ param { `,' param } ] */   /* parlist -> [ param { `,' param } ] */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 Proto *f = fs->f;  Proto *f = fs->f;
 int nparams = 0;  int nparams = 0;
 f->is_vararg = 0;  f->is_vararg = 0;
 if (ls->t.token != ')') {  /* is `parlist' not empty? */   if (ls->t.token != ')') {  /* is `parlist' not empty? */ 
   do {    do {
     switch (ls->t.token) {      switch (ls->t.token) {
       case TK_NAME: {  /* param -> NAME */         case TK_NAME: {  /* param -> NAME */ 
         new_localvar(ls, str_checkname(ls));          new_localvar(ls, str_checkname(ls));
         nparams++;          nparams++;
         break;          break;
       }        }
       case TK_DOTS: {  /* param -> `...' */         case TK_DOTS: {  /* param -> `...' */ 
         luaX_next(ls);          luaX_next(ls);
         f->is_vararg = 1;          f->is_vararg = 1;
         break;          break;
       }        }
       default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");        default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");
     }      }
   } while (!f->is_vararg && testnext(ls, ','));    } while (!f->is_vararg && testnext(ls, ','));
 }  }
 adjustlocalvars(ls, nparams);  adjustlocalvars(ls, nparams);
 f->numparams = cast_byte(fs->nactvar);  f->numparams = cast_byte(fs->nactvar);
 luaK_reserveregs(fs, fs->nactvar);  /* reserve register for parameters */   luaK_reserveregs(fs, fs->nactvar);  /* reserve register for parameters */ 
} }
   
   
static void body (LexState *ls, expdesc *e, int ismethod, int line) { static void body (LexState *ls, expdesc *e, int ismethod, int line) {
 /* body ->  `(' parlist `)' block END */   /* body ->  `(' parlist `)' block END */ 
 FuncState new_fs;  FuncState new_fs;
 BlockCnt bl;  BlockCnt bl;
 open_func(ls, &new_fs, &bl);  open_func(ls, &new_fs, &bl);
 new_fs.f->linedefined = line;  new_fs.f->linedefined = line;
 checknext(ls, '(');  checknext(ls, '(');
 if (ismethod) {  if (ismethod) {
   new_localvarliteral(ls, "self");  /* create 'self' parameter */     new_localvarliteral(ls, "self");  /* create 'self' parameter */ 
   adjustlocalvars(ls, 1);    adjustlocalvars(ls, 1);
 }  }
 parlist(ls);  parlist(ls);
 checknext(ls, ')');  checknext(ls, ')');
 statlist(ls);  statlist(ls);
 new_fs.f->lastlinedefined = ls->linenumber;  new_fs.f->lastlinedefined = ls->linenumber;
 check_match(ls, TK_END, TK_FUNCTION, line);  check_match(ls, TK_END, TK_FUNCTION, line);
 codeclosure(ls, new_fs.f, e);  codeclosure(ls, new_fs.f, e);
 close_func(ls);  close_func(ls);
} }
   
   
static int explist (LexState *ls, expdesc *v) { static int explist (LexState *ls, expdesc *v) {
 /* explist -> expr { `,' expr } */   /* explist -> expr { `,' expr } */ 
 int n = 1;  /* at least one expression */   int n = 1;  /* at least one expression */ 
 expr(ls, v);  expr(ls, v);
 while (testnext(ls, ',')) {  while (testnext(ls, ',')) {
   luaK_exp2nextreg(ls->fs, v);    luaK_exp2nextreg(ls->fs, v);
   expr(ls, v);    expr(ls, v);
   n++;    n++;
 }  }
 return n;  return n;
} }
   
   
static void funcargs (LexState *ls, expdesc *f, int line) { static void funcargs (LexState *ls, expdesc *f, int line) {
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 expdesc args;  expdesc args;
 int base, nparams;  int base, nparams;
 switch (ls->t.token) {  switch (ls->t.token) {
   case '(': {  /* funcargs -> `(' [ explist ] `)' */     case '(': {  /* funcargs -> `(' [ explist ] `)' */ 
     luaX_next(ls);      luaX_next(ls);
     if (ls->t.token == ')')  /* arg list is empty? */       if (ls->t.token == ')')  /* arg list is empty? */ 
       args.k = VVOID;        args.k = VVOID;
     else {      else {
       explist(ls, &args);        explist(ls, &args);
       luaK_setmultret(fs, &args);        luaK_setmultret(fs, &args);
     }      }
     check_match(ls, ')', '(', line);      check_match(ls, ')', '(', line);
     break;      break;
   }    }
   case '{': {  /* funcargs -> constructor */     case '{': {  /* funcargs -> constructor */ 
     constructor(ls, &args);      constructor(ls, &args);
     break;      break;
   }    }
   case TK_STRING: {  /* funcargs -> STRING */     case TK_STRING: {  /* funcargs -> STRING */ 
     codestring(ls, &args, ls->t.seminfo.ts);      codestring(ls, &args, ls->t.seminfo.ts);
     luaX_next(ls);  /* must use `seminfo' before `next' */       luaX_next(ls);  /* must use `seminfo' before `next' */ 
     break;      break;
   }    }
   default: {    default: {
     luaX_syntaxerror(ls, "function arguments expected");      luaX_syntaxerror(ls, "function arguments expected");
   }    }
 }  }
 lua_assert(f->k == VNONRELOC);  lua_assert(f->k == VNONRELOC);
 base = f->u.info;  /* base register for call */   base = f->u.info;  /* base register for call */ 
 if (hasmultret(args.k))  if (hasmultret(args.k))
   nparams = LUA_MULTRET;  /* open call */     nparams = LUA_MULTRET;  /* open call */ 
 else {  else {
   if (args.k != VVOID)    if (args.k != VVOID)
     luaK_exp2nextreg(fs, &args);  /* close last argument */       luaK_exp2nextreg(fs, &args);  /* close last argument */ 
   nparams = fs->freereg - (base+1);    nparams = fs->freereg - (base+1);
 }  }
 init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
 luaK_fixline(fs, line);  luaK_fixline(fs, line);
 fs->freereg = base+1;  /* call remove function and arguments and leaves  fs->freereg = base+1;  /* call remove function and arguments and leaves
                           (unless changed) one result */                             (unless changed) one result */ 
} }
   
   
   
   
/* /*
** {====================================================================== ** {======================================================================
** Expression parsing ** Expression parsing
** ======================================================================= ** =======================================================================
*/  */ 
   
   
static void prefixexp (LexState *ls, expdesc *v) { static void prefixexp (LexState *ls, expdesc *v) {
 /* prefixexp -> NAME | '(' expr ')' */   /* prefixexp -> NAME | '(' expr ')' */ 
 switch (ls->t.token) {  switch (ls->t.token) {
   case '(': {    case '(': {
     int line = ls->linenumber;      int line = ls->linenumber;
     luaX_next(ls);      luaX_next(ls);
     expr(ls, v);      expr(ls, v);
     check_match(ls, ')', '(', line);      check_match(ls, ')', '(', line);
     luaK_dischargevars(ls->fs, v);      luaK_dischargevars(ls->fs, v);
     return;      return;
   }    }
   case TK_NAME: {    case TK_NAME: {
     singlevar(ls, v);      singlevar(ls, v);
     return;      return;
   }    }
   default: {    default: {
     luaX_syntaxerror(ls, "unexpected symbol");      luaX_syntaxerror(ls, "unexpected symbol");
   }    }
 }  }
} }
   
   
static void primaryexp (LexState *ls, expdesc *v) { static void primaryexp (LexState *ls, expdesc *v) {
 /* primaryexp ->  /* primaryexp ->
       prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */         prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int line = ls->linenumber;  int line = ls->linenumber;
 prefixexp(ls, v);  prefixexp(ls, v);
 for (;;) {  for (;;) {
   switch (ls->t.token) {    switch (ls->t.token) {
     case '.': {  /* fieldsel */       case '.': {  /* fieldsel */ 
       fieldsel(ls, v);        fieldsel(ls, v);
       break;        break;
     }      }
     case '[': {  /* `[' exp1 `]' */       case '[': {  /* `[' exp1 `]' */ 
       expdesc key;        expdesc key;
       luaK_exp2anyregup(fs, v);        luaK_exp2anyregup(fs, v);
       yindex(ls, &key);        yindex(ls, &key);
       luaK_indexed(fs, v, &key);        luaK_indexed(fs, v, &key);
       break;        break;
     }      }
     case ':': {  /* `:' NAME funcargs */       case ':': {  /* `:' NAME funcargs */ 
       expdesc key;        expdesc key;
       luaX_next(ls);        luaX_next(ls);
       checkname(ls, &key);        checkname(ls, &key);
       luaK_self(fs, v, &key);        luaK_self(fs, v, &key);
       funcargs(ls, v, line);        funcargs(ls, v, line);
       break;        break;
     }      }
     case '(': case TK_STRING: case '{': {  /* funcargs */       case '(': case TK_STRING: case '{': {  /* funcargs */ 
       luaK_exp2nextreg(fs, v);        luaK_exp2nextreg(fs, v);
       funcargs(ls, v, line);        funcargs(ls, v, line);
       break;        break;
     }      }
     default: return;      default: return;
   }    }
 }  }
} }
   
   
static void simpleexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) {
 /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |  /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
                 constructor | FUNCTION body | primaryexp */                   constructor | FUNCTION body | primaryexp */ 
 switch (ls->t.token) {  switch (ls->t.token) {
   case TK_NUMBER: {    case TK_NUMBER: {
     init_exp(v, VKNUM, 0);      init_exp(v, VKNUM, 0);
     v->u.nval = ls->t.seminfo.r;      v->u.nval = ls->t.seminfo.r;
     break;      break;
   }    }
   case TK_STRING: {    case TK_STRING: {
     codestring(ls, v, ls->t.seminfo.ts);      codestring(ls, v, ls->t.seminfo.ts);
     break;      break;
   }    }
   case TK_NIL: {    case TK_NIL: {
     init_exp(v, VNIL, 0);      init_exp(v, VNIL, 0);
     break;      break;
   }    }
   case TK_TRUE: {    case TK_TRUE: {
     init_exp(v, VTRUE, 0);      init_exp(v, VTRUE, 0);
     break;      break;
   }    }
   case TK_FALSE: {    case TK_FALSE: {
     init_exp(v, VFALSE, 0);      init_exp(v, VFALSE, 0);
     break;      break;
   }    }
   case TK_DOTS: {  /* vararg */     case TK_DOTS: {  /* vararg */ 
     FuncState *fs = ls->fs;      FuncState *fs = ls->fs;
     check_condition(ls, fs->f->is_vararg,      check_condition(ls, fs->f->is_vararg,
                     "cannot use " LUA_QL("...") " outside a vararg function");                      "cannot use " LUA_QL("...") " outside a vararg function");
     init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
     break;      break;
   }    }
   case '{': {  /* constructor */     case '{': {  /* constructor */ 
     constructor(ls, v);      constructor(ls, v);
     return;      return;
   }    }
   case TK_FUNCTION: {    case TK_FUNCTION: {
     luaX_next(ls);      luaX_next(ls);
     body(ls, v, 0, ls->linenumber);      body(ls, v, 0, ls->linenumber);
     return;      return;
   }    }
   default: {    default: {
     primaryexp(ls, v);      primaryexp(ls, v);
     return;      return;
   }    }
 }  }
 luaX_next(ls);  luaX_next(ls);
} }
   
   
static UnOpr getunopr (int op) { static UnOpr getunopr (int op) {
 switch (op) {  switch (op) {
   case TK_NOT: return OPR_NOT;    case TK_NOT: return OPR_NOT;
   case '-': return OPR_MINUS;    case '-': return OPR_MINUS;
   case '#': return OPR_LEN;    case '#': return OPR_LEN;
#ifdef GCW_BIT  
   case '~': return OPR_BNOT;  
   case '!': return OPR_LNOT;  
#endif  
   default: return OPR_NOUNOPR;    default: return OPR_NOUNOPR;
 }  }
} }
   
   
static BinOpr getbinopr (int op) { static BinOpr getbinopr (int op) {
 switch (op) {  switch (op) {
   case '+': return OPR_ADD;    case '+': return OPR_ADD;
   case '-': return OPR_SUB;    case '-': return OPR_SUB;
   case '*': return OPR_MUL;    case '*': return OPR_MUL;
   case '/': return OPR_DIV;    case '/': return OPR_DIV;
   case '%': return OPR_MOD;    case '%': return OPR_MOD;
   case '^': return OPR_POW;    case '^': return OPR_POW;
   case TK_CONCAT: return OPR_CONCAT;    case TK_CONCAT: return OPR_CONCAT;
   case TK_NE: return OPR_NE;    case TK_NE: return OPR_NE;
   case TK_EQ: return OPR_EQ;    case TK_EQ: return OPR_EQ;
   case '<': return OPR_LT;    case '<': return OPR_LT;
   case TK_LE: return OPR_LE;    case TK_LE: return OPR_LE;
   case '>': return OPR_GT;    case '>': return OPR_GT;
   case TK_GE: return OPR_GE;    case TK_GE: return OPR_GE;
   case TK_AND: return OPR_AND;    case TK_AND: return OPR_AND;
   case TK_OR: return OPR_OR;    case TK_OR: return OPR_OR;
#ifdef GCW_BIT  
   case '&': return OPR_BAND;  
   case '|': return OPR_BOR;  
   case TK_BXOR: return OPR_BXOR;  
   case TK_BLSH: return OPR_BLSH;  
   case TK_BRSH: return OPR_BRSH;  
   case TK_LAND: return OPR_LAND;  
   case TK_LOR: return OPR_LOR;  
#endif  
   default: return OPR_NOBINOPR;    default: return OPR_NOBINOPR;
 }  }
} }
   
   
static const struct { static const struct {
 lu_byte left;  /* left priority for each binary operator */   lu_byte left;  /* left priority for each binary operator */ 
 lu_byte right; /* right priority */   lu_byte right; /* right priority */ 
} priority[] = {  /* ORDER OPR */  } priority[] = {  /* ORDER OPR */ 
  {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7},  /* `+' `-' `*' `/' `%' */    {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7},  /* `+' `-' `*' `/' `%' */ 
#ifndef GCW_BIT  
  {10, 9}, {5, 4},                 /* ^, .. (right associative) */    {10, 9}, {5, 4},                 /* ^, .. (right associative) */ 
#else  
  {10,9}, /* ^ (right associative) */   
  {7,7}, {5,5}, {7,7}, {10,9}, {10,9},   /* bitwise and/or/xor/lsh/rsh */   
  {7,7}, {5,5},                      /* logical /land/lor */   
  {5,4}, /* .. (right associative) */   
#endif  
  {3, 3}, {3, 3}, {3, 3},          /* ==, <, <= */    {3, 3}, {3, 3}, {3, 3},          /* ==, <, <= */ 
  {3, 3}, {3, 3}, {3, 3},          /* ~=, >, >= */    {3, 3}, {3, 3}, {3, 3},          /* ~=, >, >= */ 
  {2, 2}, {1, 1}                   /* and, or */    {2, 2}, {1, 1}                   /* and, or */ 
}; };
   
#define UNARY_PRIORITY  8  /* priority for unary operators */  #define UNARY_PRIORITY  8  /* priority for unary operators */ 
   
   
/* /*
** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
** where `binop' is any binary operator with a priority higher than `limit' ** where `binop' is any binary operator with a priority higher than `limit'
*/  */ 
static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
 BinOpr op;  BinOpr op;
 UnOpr uop;  UnOpr uop;
 enterlevel(ls);  enterlevel(ls);
 uop = getunopr(ls->t.token);  uop = getunopr(ls->t.token);
 if (uop != OPR_NOUNOPR) {  if (uop != OPR_NOUNOPR) {
   int line = ls->linenumber;    int line = ls->linenumber;
   luaX_next(ls);    luaX_next(ls);
   subexpr(ls, v, UNARY_PRIORITY);    subexpr(ls, v, UNARY_PRIORITY);
   luaK_prefix(ls->fs, uop, v, line);    luaK_prefix(ls->fs, uop, v, line);
 }  }
 else simpleexp(ls, v);  else simpleexp(ls, v);
 /* expand while operators have priorities higher than `limit' */   /* expand while operators have priorities higher than `limit' */ 
 op = getbinopr(ls->t.token);  op = getbinopr(ls->t.token);
 while (op != OPR_NOBINOPR && priority[op].left > limit) {  while (op != OPR_NOBINOPR && priority[op].left > limit) {
   expdesc v2;    expdesc v2;
   BinOpr nextop;    BinOpr nextop;
   int line = ls->linenumber;    int line = ls->linenumber;
   luaX_next(ls);    luaX_next(ls);
   luaK_infix(ls->fs, op, v);    luaK_infix(ls->fs, op, v);
   /* read sub-expression with higher priority */     /* read sub-expression with higher priority */ 
   nextop = subexpr(ls, &v2, priority[op].right);    nextop = subexpr(ls, &v2, priority[op].right);
   luaK_posfix(ls->fs, op, v, &v2, line);    luaK_posfix(ls->fs, op, v, &v2, line);
   op = nextop;    op = nextop;
 }  }
 leavelevel(ls);  leavelevel(ls);
 return op;  /* return first untreated operator */   return op;  /* return first untreated operator */ 
} }
   
   
static void expr (LexState *ls, expdesc *v) { static void expr (LexState *ls, expdesc *v) {
 subexpr(ls, v, 0);  subexpr(ls, v, 0);
} }
   
/* }==================================================================== */  /* }==================================================================== */ 
   
   
   
/* /*
** {====================================================================== ** {======================================================================
** Rules for Statements ** Rules for Statements
** ======================================================================= ** =======================================================================
*/  */ 
   
   
static void block (LexState *ls) { static void block (LexState *ls) {
 /* block -> statlist */   /* block -> statlist */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 BlockCnt bl;  BlockCnt bl;
 enterblock(fs, &bl, 0);  enterblock(fs, &bl, 0);
 statlist(ls);  statlist(ls);
 leaveblock(fs);  leaveblock(fs);
} }
   
   
/* /*
** structure to chain all variables in the left-hand side of an ** structure to chain all variables in the left-hand side of an
** assignment ** assignment
*/  */ 
struct LHS_assign { struct LHS_assign {
 struct LHS_assign *prev;  struct LHS_assign *prev;
 expdesc v;  /* variable (global, local, upvalue, or indexed) */   expdesc v;  /* variable (global, local, upvalue, or indexed) */ 
}; };
   
   
/* /*
** check whether, in an assignment to an upvalue/local variable, the ** check whether, in an assignment to an upvalue/local variable, the
** upvalue/local variable is begin used in a previous assignment to a ** upvalue/local variable is begin used in a previous assignment to a
** table. If so, save original upvalue/local value in a safe place and ** table. If so, save original upvalue/local value in a safe place and
** use this safe copy in the previous assignment. ** use this safe copy in the previous assignment.
*/  */ 
static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int extra = fs->freereg;  /* eventual position to save local variable */   int extra = fs->freereg;  /* eventual position to save local variable */ 
 int conflict = 0;  int conflict = 0;
 for (; lh; lh = lh->prev) {  /* check all previous assignments */   for (; lh; lh = lh->prev) {  /* check all previous assignments */ 
   if (lh->v.k == VINDEXED) {  /* assigning to a table? */     if (lh->v.k == VINDEXED) {  /* assigning to a table? */ 
     /* table is the upvalue/local being assigned now? */       /* table is the upvalue/local being assigned now? */ 
   if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) {      if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) {
     conflict = 1;        conflict = 1;
     lh->v.u.ind.vt = VLOCAL;        lh->v.u.ind.vt = VLOCAL;
     lh->v.u.ind.t = extra;  /* previous assignment will use safe copy */         lh->v.u.ind.t = extra;  /* previous assignment will use safe copy */ 
   }      }
     /* index is the local being assigned? (index cannot be upvalue) */       /* index is the local being assigned? (index cannot be upvalue) */ 
   if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) {      if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) {
     conflict = 1;        conflict = 1;
     lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */         lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */ 
   }      }
 }    }
 }  }
 if (conflict) {  if (conflict) {
   /* copy upvalue/local value to a temporary (in position 'extra') */     /* copy upvalue/local value to a temporary (in position 'extra') */ 
   OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;    OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
   luaK_codeABC(fs, op, extra, v->u.info, 0);    luaK_codeABC(fs, op, extra, v->u.info, 0);
   luaK_reserveregs(fs, 1);    luaK_reserveregs(fs, 1);
 }  }
} }
   
   
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
 expdesc e;  expdesc e;
 check_condition(ls, vkisvar(lh->v.k), "syntax error");  check_condition(ls, vkisvar(lh->v.k), "syntax error");
 if (testnext(ls, ',')) {  /* assignment -> `,' primaryexp assignment */   if (testnext(ls, ',')) {  /* assignment -> `,' primaryexp assignment */ 
   struct LHS_assign nv;    struct LHS_assign nv;
   nv.prev = lh;    nv.prev = lh;
   primaryexp(ls, &nv.v);    primaryexp(ls, &nv.v);
   if (nv.v.k != VINDEXED)    if (nv.v.k != VINDEXED)
     check_conflict(ls, lh, &nv.v);      check_conflict(ls, lh, &nv.v);
   checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,    checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,
                   "C levels");                    "C levels");
   assignment(ls, &nv, nvars+1);    assignment(ls, &nv, nvars+1);
 }  }
 else {  /* assignment -> `=' explist */   else {  /* assignment -> `=' explist */ 
   int nexps;    int nexps;
   checknext(ls, '=');    checknext(ls, '=');
   nexps = explist(ls, &e);    nexps = explist(ls, &e);
   if (nexps != nvars) {    if (nexps != nvars) {
     adjust_assign(ls, nvars, nexps, &e);      adjust_assign(ls, nvars, nexps, &e);
     if (nexps > nvars)      if (nexps > nvars)
       ls->fs->freereg -= nexps - nvars;  /* remove extra values */         ls->fs->freereg -= nexps - nvars;  /* remove extra values */ 
   }    }
   else {    else {
     luaK_setoneret(ls->fs, &e);  /* close last expression */       luaK_setoneret(ls->fs, &e);  /* close last expression */ 
     luaK_storevar(ls->fs, &lh->v, &e);      luaK_storevar(ls->fs, &lh->v, &e);
     return;  /* avoid default */       return;  /* avoid default */ 
   }    }
 }  }
 init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */   init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */ 
 luaK_storevar(ls->fs, &lh->v, &e);  luaK_storevar(ls->fs, &lh->v, &e);
} }
   
   
static int cond (LexState *ls) { static int cond (LexState *ls) {
 /* cond -> exp */   /* cond -> exp */ 
 expdesc v;  expdesc v;
 expr(ls, &v);  /* read condition */   expr(ls, &v);  /* read condition */ 
 if (v.k == VNIL) v.k = VFALSE;  /* `falses' are all equal here */   if (v.k == VNIL) v.k = VFALSE;  /* `falses' are all equal here */ 
 luaK_goiftrue(ls->fs, &v);  luaK_goiftrue(ls->fs, &v);
 return v.f;  return v.f;
} }
   
   
static void gotostat (LexState *ls, int pc) { static void gotostat (LexState *ls, int pc) {
 int line = ls->linenumber;  int line = ls->linenumber;
 TString *label;  TString *label;
 int g;  int g;
 if (testnext(ls, TK_GOTO))  if (testnext(ls, TK_GOTO))
   label = str_checkname(ls);    label = str_checkname(ls);
 else {  else {
   luaX_next(ls);  /* skip break */     luaX_next(ls);  /* skip break */ 
   label = luaS_new(ls->L, "break");    label = luaS_new(ls->L, "break");
 }  }
 g = newlabelentry(ls, &ls->dyd->gt, label, line, pc);  g = newlabelentry(ls, &ls->dyd->gt, label, line, pc);
 findlabel(ls, g);  /* close it if label already defined */   findlabel(ls, g);  /* close it if label already defined */ 
} }
   
   
/* check for repeated labels on the same block */  /* check for repeated labels on the same block */ 
static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
 int i;  int i;
 for (i = fs->bl->firstlabel; i < ll->n; i++) {  for (i = fs->bl->firstlabel; i < ll->n; i++) {
   if (eqstr(label, ll->arr[i].name)) {    if (eqstr(label, ll->arr[i].name)) {
     const char *msg = luaO_pushfstring(fs->ls->L,        const char *msg = luaO_pushfstring(fs->ls->L,
                         "label " LUA_QS " already defined on line %d",                          "label " LUA_QS " already defined on line %d",
                         getstr(label), ll->arr[i].line);                          getstr(label), ll->arr[i].line);
     semerror(fs->ls, msg);      semerror(fs->ls, msg);
   }    }
 }  }
} }
   
   
static void labelstat (LexState *ls, TString *label, int line) { static void labelstat (LexState *ls, TString *label, int line) {
 /* label -> '::' NAME '::' */   /* label -> '::' NAME '::' */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 Labellist *ll = &ls->dyd->label;  Labellist *ll = &ls->dyd->label;
 int l;  /* index of new label being created */   int l;  /* index of new label being created */ 
 checkrepeated(fs, ll, label);  /* check for repeated labels */   checkrepeated(fs, ll, label);  /* check for repeated labels */ 
 checknext(ls, TK_DBCOLON);  /* skip double colon */   checknext(ls, TK_DBCOLON);  /* skip double colon */ 
 /* create new entry for this label */   /* create new entry for this label */ 
 l = newlabelentry(ls, ll, label, line, fs->pc);  l = newlabelentry(ls, ll, label, line, fs->pc);
 /* skip other no-op statements */   /* skip other no-op statements */ 
 while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)  while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)
   statement(ls);    statement(ls);
 if (block_follow(ls, 0)) {  /* label is last no-op statement in the block? */   if (block_follow(ls, 0)) {  /* label is last no-op statement in the block? */ 
   /* assume that locals are already out of scope */     /* assume that locals are already out of scope */ 
   ll->arr[l].nactvar = fs->bl->nactvar;    ll->arr[l].nactvar = fs->bl->nactvar;
 }  }
 findgotos(ls, &ll->arr[l]);  findgotos(ls, &ll->arr[l]);
} }
   
   
static void whilestat (LexState *ls, int line) { static void whilestat (LexState *ls, int line) {
 /* whilestat -> WHILE cond DO block END */   /* whilestat -> WHILE cond DO block END */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int whileinit;  int whileinit;
 int condexit;  int condexit;
 BlockCnt bl;  BlockCnt bl;
 luaX_next(ls);  /* skip WHILE */   luaX_next(ls);  /* skip WHILE */ 
 whileinit = luaK_getlabel(fs);  whileinit = luaK_getlabel(fs);
 condexit = cond(ls);  condexit = cond(ls);
 enterblock(fs, &bl, 1);  enterblock(fs, &bl, 1);
 checknext(ls, TK_DO);  checknext(ls, TK_DO);
 block(ls);  block(ls);
 luaK_jumpto(fs, whileinit);  luaK_jumpto(fs, whileinit);
 check_match(ls, TK_END, TK_WHILE, line);  check_match(ls, TK_END, TK_WHILE, line);
 leaveblock(fs);  leaveblock(fs);
 luaK_patchtohere(fs, condexit);  /* false conditions finish the loop */   luaK_patchtohere(fs, condexit);  /* false conditions finish the loop */ 
} }
   
   
static void repeatstat (LexState *ls, int line) { static void repeatstat (LexState *ls, int line) {
 /* repeatstat -> REPEAT block UNTIL cond */   /* repeatstat -> REPEAT block UNTIL cond */ 
 int condexit;  int condexit;
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int repeat_init = luaK_getlabel(fs);  int repeat_init = luaK_getlabel(fs);
 BlockCnt bl1, bl2;  BlockCnt bl1, bl2;
 enterblock(fs, &bl1, 1);  /* loop block */   enterblock(fs, &bl1, 1);  /* loop block */ 
 enterblock(fs, &bl2, 0);  /* scope block */   enterblock(fs, &bl2, 0);  /* scope block */ 
 luaX_next(ls);  /* skip REPEAT */   luaX_next(ls);  /* skip REPEAT */ 
 statlist(ls);  statlist(ls);
 check_match(ls, TK_UNTIL, TK_REPEAT, line);  check_match(ls, TK_UNTIL, TK_REPEAT, line);
 condexit = cond(ls);  /* read condition (inside scope block) */   condexit = cond(ls);  /* read condition (inside scope block) */ 
 if (bl2.upval)  /* upvalues? */   if (bl2.upval)  /* upvalues? */ 
   luaK_patchclose(fs, condexit, bl2.nactvar);    luaK_patchclose(fs, condexit, bl2.nactvar);
 leaveblock(fs);  /* finish scope */   leaveblock(fs);  /* finish scope */ 
 luaK_patchlist(fs, condexit, repeat_init);  /* close the loop */   luaK_patchlist(fs, condexit, repeat_init);  /* close the loop */ 
 leaveblock(fs);  /* finish loop */   leaveblock(fs);  /* finish loop */ 
} }
   
   
static int exp1 (LexState *ls) { static int exp1 (LexState *ls) {
 expdesc e;  expdesc e;
 int reg;  int reg;
 expr(ls, &e);  expr(ls, &e);
 luaK_exp2nextreg(ls->fs, &e);  luaK_exp2nextreg(ls->fs, &e);
 lua_assert(e.k == VNONRELOC);  lua_assert(e.k == VNONRELOC);
 reg = e.u.info;  reg = e.u.info;
 return reg;  return reg;
} }
   
   
static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
 /* forbody -> DO block */   /* forbody -> DO block */ 
 BlockCnt bl;  BlockCnt bl;
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int prep, endfor;  int prep, endfor;
 adjustlocalvars(ls, 3);  /* control variables */   adjustlocalvars(ls, 3);  /* control variables */ 
 checknext(ls, TK_DO);  checknext(ls, TK_DO);
 prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);  prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
 enterblock(fs, &bl, 0);  /* scope for declared variables */   enterblock(fs, &bl, 0);  /* scope for declared variables */ 
 adjustlocalvars(ls, nvars);  adjustlocalvars(ls, nvars);
 luaK_reserveregs(fs, nvars);  luaK_reserveregs(fs, nvars);
 block(ls);  block(ls);
 leaveblock(fs);  /* end of scope for declared variables */   leaveblock(fs);  /* end of scope for declared variables */ 
 luaK_patchtohere(fs, prep);  luaK_patchtohere(fs, prep);
 if (isnum)  /* numeric for? */   if (isnum)  /* numeric for? */ 
   endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP);    endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP);
 else {  /* generic for */   else {  /* generic for */ 
   luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);    luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);
   luaK_fixline(fs, line);    luaK_fixline(fs, line);
   endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP);    endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP);
 }  }
 luaK_patchlist(fs, endfor, prep + 1);  luaK_patchlist(fs, endfor, prep + 1);
 luaK_fixline(fs, line);  luaK_fixline(fs, line);
} }
   
   
static void fornum (LexState *ls, TString *varname, int line) { static void fornum (LexState *ls, TString *varname, int line) {
 /* fornum -> NAME = exp1,exp1[,exp1] forbody */   /* fornum -> NAME = exp1,exp1[,exp1] forbody */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int base = fs->freereg;  int base = fs->freereg;
 new_localvarliteral(ls, "(for index)");  new_localvarliteral(ls, "(for index)");
 new_localvarliteral(ls, "(for limit)");  new_localvarliteral(ls, "(for limit)");
 new_localvarliteral(ls, "(for step)");  new_localvarliteral(ls, "(for step)");
 new_localvar(ls, varname);  new_localvar(ls, varname);
 checknext(ls, '=');  checknext(ls, '=');
 exp1(ls);  /* initial value */   exp1(ls);  /* initial value */ 
 checknext(ls, ',');  checknext(ls, ',');
 exp1(ls);  /* limit */   exp1(ls);  /* limit */ 
 if (testnext(ls, ','))  if (testnext(ls, ','))
   exp1(ls);  /* optional step */     exp1(ls);  /* optional step */ 
 else {  /* default step = 1 */   else {  /* default step = 1 */ 
   luaK_codek(fs, fs->freereg, luaK_numberK(fs, 1));    luaK_codek(fs, fs->freereg, luaK_numberK(fs, 1));
   luaK_reserveregs(fs, 1);    luaK_reserveregs(fs, 1);
 }  }
 forbody(ls, base, line, 1, 1);  forbody(ls, base, line, 1, 1);
} }
   
   
static void forlist (LexState *ls, TString *indexname) { static void forlist (LexState *ls, TString *indexname) {
 /* forlist -> NAME {,NAME} IN explist forbody */   /* forlist -> NAME {,NAME} IN explist forbody */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 expdesc e;  expdesc e;
 int nvars = 4;  /* gen, state, control, plus at least one declared var */   int nvars = 4;  /* gen, state, control, plus at least one declared var */ 
 int line;  int line;
 int base = fs->freereg;  int base = fs->freereg;
 /* create control variables */   /* create control variables */ 
 new_localvarliteral(ls, "(for generator)");  new_localvarliteral(ls, "(for generator)");
 new_localvarliteral(ls, "(for state)");  new_localvarliteral(ls, "(for state)");
 new_localvarliteral(ls, "(for control)");  new_localvarliteral(ls, "(for control)");
 /* create declared variables */   /* create declared variables */ 
 new_localvar(ls, indexname);  new_localvar(ls, indexname);
 while (testnext(ls, ',')) {  while (testnext(ls, ',')) {
   new_localvar(ls, str_checkname(ls));    new_localvar(ls, str_checkname(ls));
   nvars++;    nvars++;
 }  }
 checknext(ls, TK_IN);  checknext(ls, TK_IN);
 line = ls->linenumber;  line = ls->linenumber;
 adjust_assign(ls, 3, explist(ls, &e), &e);  adjust_assign(ls, 3, explist(ls, &e), &e);
 luaK_checkstack(fs, 3);  /* extra space to call generator */   luaK_checkstack(fs, 3);  /* extra space to call generator */ 
 forbody(ls, base, line, nvars - 3, 0);  forbody(ls, base, line, nvars - 3, 0);
} }
   
   
static void forstat (LexState *ls, int line) { static void forstat (LexState *ls, int line) {
 /* forstat -> FOR (fornum | forlist) END */   /* forstat -> FOR (fornum | forlist) END */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 TString *varname;  TString *varname;
 BlockCnt bl;  BlockCnt bl;
 enterblock(fs, &bl, 1);  /* scope for loop and control variables */   enterblock(fs, &bl, 1);  /* scope for loop and control variables */ 
 luaX_next(ls);  /* skip `for' */   luaX_next(ls);  /* skip `for' */ 
 varname = str_checkname(ls);  /* first variable name */   varname = str_checkname(ls);  /* first variable name */ 
 switch (ls->t.token) {  switch (ls->t.token) {
   case '=': fornum(ls, varname, line); break;    case '=': fornum(ls, varname, line); break;
   case ',': case TK_IN: forlist(ls, varname); break;    case ',': case TK_IN: forlist(ls, varname); break;
   default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected");    default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected");
 }  }
 check_match(ls, TK_END, TK_FOR, line);  check_match(ls, TK_END, TK_FOR, line);
 leaveblock(fs);  /* loop scope (`break' jumps to this point) */   leaveblock(fs);  /* loop scope (`break' jumps to this point) */ 
} }
   
   
static void test_then_block (LexState *ls, int *escapelist) { static void test_then_block (LexState *ls, int *escapelist) {
 /* test_then_block -> [IF | ELSEIF] cond THEN block */   /* test_then_block -> [IF | ELSEIF] cond THEN block */ 
 BlockCnt bl;  BlockCnt bl;
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 expdesc v;  expdesc v;
 int jf;  /* instruction to skip 'then' code (if condition is false) */   int jf;  /* instruction to skip 'then' code (if condition is false) */ 
 luaX_next(ls);  /* skip IF or ELSEIF */   luaX_next(ls);  /* skip IF or ELSEIF */ 
 expr(ls, &v);  /* read condition */   expr(ls, &v);  /* read condition */ 
 checknext(ls, TK_THEN);  checknext(ls, TK_THEN);
 if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) {  if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) {
   luaK_goiffalse(ls->fs, &v);  /* will jump to label if condition is true */     luaK_goiffalse(ls->fs, &v);  /* will jump to label if condition is true */ 
   enterblock(fs, &bl, 0);  /* must enter block before 'goto' */     enterblock(fs, &bl, 0);  /* must enter block before 'goto' */ 
   gotostat(ls, v.t);  /* handle goto/break */     gotostat(ls, v.t);  /* handle goto/break */ 
   if (block_follow(ls, 0)) {  /* 'goto' is the entire block? */     if (block_follow(ls, 0)) {  /* 'goto' is the entire block? */ 
     leaveblock(fs);      leaveblock(fs);
     return;  /* and that is it */       return;  /* and that is it */ 
   }    }
   else  /* must skip over 'then' part if condition is false */     else  /* must skip over 'then' part if condition is false */ 
     jf = luaK_jump(fs);      jf = luaK_jump(fs);
 }  }
 else {  /* regular case (not goto/break) */   else {  /* regular case (not goto/break) */ 
   luaK_goiftrue(ls->fs, &v);  /* skip over block if condition is false */     luaK_goiftrue(ls->fs, &v);  /* skip over block if condition is false */ 
   enterblock(fs, &bl, 0);    enterblock(fs, &bl, 0);
   jf = v.f;    jf = v.f;
 }  }
 statlist(ls);  /* `then' part */   statlist(ls);  /* `then' part */ 
 leaveblock(fs);  leaveblock(fs);
 if (ls->t.token == TK_ELSE ||  if (ls->t.token == TK_ELSE ||
     ls->t.token == TK_ELSEIF)  /* followed by 'else'/'elseif'? */       ls->t.token == TK_ELSEIF)  /* followed by 'else'/'elseif'? */ 
   luaK_concat(fs, escapelist, luaK_jump(fs));  /* must jump over it */     luaK_concat(fs, escapelist, luaK_jump(fs));  /* must jump over it */ 
 luaK_patchtohere(fs, jf);  luaK_patchtohere(fs, jf);
} }
   
   
static void ifstat (LexState *ls, int line) { static void ifstat (LexState *ls, int line) {
 /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */   /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 int escapelist = NO_JUMP;  /* exit list for finished parts */   int escapelist = NO_JUMP;  /* exit list for finished parts */ 
 test_then_block(ls, &escapelist);  /* IF cond THEN block */   test_then_block(ls, &escapelist);  /* IF cond THEN block */ 
 while (ls->t.token == TK_ELSEIF)  while (ls->t.token == TK_ELSEIF)
   test_then_block(ls, &escapelist);  /* ELSEIF cond THEN block */     test_then_block(ls, &escapelist);  /* ELSEIF cond THEN block */ 
 if (testnext(ls, TK_ELSE))  if (testnext(ls, TK_ELSE))
   block(ls);  /* `else' part */     block(ls);  /* `else' part */ 
 check_match(ls, TK_END, TK_IF, line);  check_match(ls, TK_END, TK_IF, line);
 luaK_patchtohere(fs, escapelist);  /* patch escape list to 'if' end */   luaK_patchtohere(fs, escapelist);  /* patch escape list to 'if' end */ 
} }
   
   
static void localfunc (LexState *ls) { static void localfunc (LexState *ls) {
 expdesc b;  expdesc b;
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 new_localvar(ls, str_checkname(ls));  /* new local variable */   new_localvar(ls, str_checkname(ls));  /* new local variable */ 
 adjustlocalvars(ls, 1);  /* enter its scope */   adjustlocalvars(ls, 1);  /* enter its scope */ 
 body(ls, &b, 0, ls->linenumber);  /* function created in next register */   body(ls, &b, 0, ls->linenumber);  /* function created in next register */ 
 /* debug information will only see the variable after this point! */   /* debug information will only see the variable after this point! */ 
 getlocvar(fs, b.u.info)->startpc = fs->pc;  getlocvar(fs, b.u.info)->startpc = fs->pc;
} }
   
   
static void localstat (LexState *ls) { static void localstat (LexState *ls) {
 /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */   /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */ 
 int nvars = 0;  int nvars = 0;
 int nexps;  int nexps;
 expdesc e;  expdesc e;
 do {  do {
   new_localvar(ls, str_checkname(ls));    new_localvar(ls, str_checkname(ls));
   nvars++;    nvars++;
 } while (testnext(ls, ','));  } while (testnext(ls, ','));
 if (testnext(ls, '='))  if (testnext(ls, '='))
   nexps = explist(ls, &e);    nexps = explist(ls, &e);
 else {  else {
   e.k = VVOID;    e.k = VVOID;
   nexps = 0;    nexps = 0;
 }  }
 adjust_assign(ls, nvars, nexps, &e);  adjust_assign(ls, nvars, nexps, &e);
 adjustlocalvars(ls, nvars);  adjustlocalvars(ls, nvars);
} }
   
   
static int funcname (LexState *ls, expdesc *v) { static int funcname (LexState *ls, expdesc *v) {
 /* funcname -> NAME {fieldsel} [`:' NAME] */   /* funcname -> NAME {fieldsel} [`:' NAME] */ 
 int ismethod = 0;  int ismethod = 0;
 singlevar(ls, v);  singlevar(ls, v);
 while (ls->t.token == '.')  while (ls->t.token == '.')
   fieldsel(ls, v);    fieldsel(ls, v);
 if (ls->t.token == ':') {  if (ls->t.token == ':') {
   ismethod = 1;    ismethod = 1;
   fieldsel(ls, v);    fieldsel(ls, v);
 }  }
 return ismethod;  return ismethod;
} }
   
   
static void funcstat (LexState *ls, int line) { static void funcstat (LexState *ls, int line) {
 /* funcstat -> FUNCTION funcname body */   /* funcstat -> FUNCTION funcname body */ 
 int ismethod;  int ismethod;
 expdesc v, b;  expdesc v, b;
 luaX_next(ls);  /* skip FUNCTION */   luaX_next(ls);  /* skip FUNCTION */ 
 ismethod = funcname(ls, &v);  ismethod = funcname(ls, &v);
 body(ls, &b, ismethod, line);  body(ls, &b, ismethod, line);
 luaK_storevar(ls->fs, &v, &b);  luaK_storevar(ls->fs, &v, &b);
 luaK_fixline(ls->fs, line);  /* definition `happens' in the first line */   luaK_fixline(ls->fs, line);  /* definition `happens' in the first line */ 
} }
   
   
static void exprstat (LexState *ls) { static void exprstat (LexState *ls) {
 /* stat -> func | assignment */   /* stat -> func | assignment */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 struct LHS_assign v;  struct LHS_assign v;
 primaryexp(ls, &v.v);  primaryexp(ls, &v.v);
 if (v.v.k == VCALL)  /* stat -> func */   if (v.v.k == VCALL)  /* stat -> func */ 
   SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */     SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */ 
 else {  /* stat -> assignment */   else {  /* stat -> assignment */ 
   v.prev = NULL;    v.prev = NULL;
   assignment(ls, &v, 1);    assignment(ls, &v, 1);
 }  }
} }
   
   
static void retstat (LexState *ls) { static void retstat (LexState *ls) {
 /* stat -> RETURN [explist] [';'] */   /* stat -> RETURN [explist] [';'] */ 
 FuncState *fs = ls->fs;  FuncState *fs = ls->fs;
 expdesc e;  expdesc e;
 int first, nret;  /* registers with returned values */   int first, nret;  /* registers with returned values */ 
 if (block_follow(ls, 1) || ls->t.token == ';')  if (block_follow(ls, 1) || ls->t.token == ';')
   first = nret = 0;  /* return no values */     first = nret = 0;  /* return no values */ 
 else {  else {
   nret = explist(ls, &e);  /* optional return values */     nret = explist(ls, &e);  /* optional return values */ 
   if (hasmultret(e.k)) {    if (hasmultret(e.k)) {
     luaK_setmultret(fs, &e);      luaK_setmultret(fs, &e);
     if (e.k == VCALL && nret == 1) {  /* tail call? */       if (e.k == VCALL && nret == 1) {  /* tail call? */ 
       SET_OPCODE(getcode(fs,&e), OP_TAILCALL);        SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
       lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);        lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
     }      }
     first = fs->nactvar;      first = fs->nactvar;
     nret = LUA_MULTRET;  /* return all values */       nret = LUA_MULTRET;  /* return all values */ 
   }    }
   else {    else {
     if (nret == 1)  /* only one single value? */       if (nret == 1)  /* only one single value? */ 
       first = luaK_exp2anyreg(fs, &e);        first = luaK_exp2anyreg(fs, &e);
     else {      else {
       luaK_exp2nextreg(fs, &e);  /* values must go to the `stack' */         luaK_exp2nextreg(fs, &e);  /* values must go to the `stack' */ 
       first = fs->nactvar;  /* return all `active' values */         first = fs->nactvar;  /* return all `active' values */ 
       lua_assert(nret == fs->freereg - first);        lua_assert(nret == fs->freereg - first);
     }      }
   }    }
 }  }
 luaK_ret(fs, first, nret);  luaK_ret(fs, first, nret);
 testnext(ls, ';');  /* skip optional semicolon */   testnext(ls, ';');  /* skip optional semicolon */ 
} }
   
   
static void statement (LexState *ls) { static void statement (LexState *ls) {
 int line = ls->linenumber;  /* may be needed for error messages */   int line = ls->linenumber;  /* may be needed for error messages */ 
 enterlevel(ls);  enterlevel(ls);
 switch (ls->t.token) {  switch (ls->t.token) {
   case ';': {  /* stat -> ';' (empty statement) */     case ';': {  /* stat -> ';' (empty statement) */ 
     luaX_next(ls);  /* skip ';' */       luaX_next(ls);  /* skip ';' */ 
     break;      break;
   }    }
   case TK_IF: {  /* stat -> ifstat */     case TK_IF: {  /* stat -> ifstat */ 
     ifstat(ls, line);      ifstat(ls, line);
     break;      break;
   }    }
   case TK_WHILE: {  /* stat -> whilestat */     case TK_WHILE: {  /* stat -> whilestat */ 
     whilestat(ls, line);      whilestat(ls, line);
     break;      break;
   }    }
   case TK_DO: {  /* stat -> DO block END */     case TK_DO: {  /* stat -> DO block END */ 
     luaX_next(ls);  /* skip DO */       luaX_next(ls);  /* skip DO */ 
     block(ls);      block(ls);
     check_match(ls, TK_END, TK_DO, line);      check_match(ls, TK_END, TK_DO, line);
     break;      break;
   }    }
   case TK_FOR: {  /* stat -> forstat */     case TK_FOR: {  /* stat -> forstat */ 
     forstat(ls, line);      forstat(ls, line);
     break;      break;
   }    }
   case TK_REPEAT: {  /* stat -> repeatstat */     case TK_REPEAT: {  /* stat -> repeatstat */ 
     repeatstat(ls, line);      repeatstat(ls, line);
     break;      break;
   }    }
   case TK_FUNCTION: {  /* stat -> funcstat */     case TK_FUNCTION: {  /* stat -> funcstat */ 
     funcstat(ls, line);      funcstat(ls, line);
     break;      break;
   }    }
   case TK_LOCAL: {  /* stat -> localstat */     case TK_LOCAL: {  /* stat -> localstat */ 
     luaX_next(ls);  /* skip LOCAL */       luaX_next(ls);  /* skip LOCAL */ 
     if (testnext(ls, TK_FUNCTION))  /* local function? */       if (testnext(ls, TK_FUNCTION))  /* local function? */ 
       localfunc(ls);        localfunc(ls);
     else      else
       localstat(ls);        localstat(ls);
     break;      break;
   }    }
   case TK_DBCOLON: {  /* stat -> label */     case TK_DBCOLON: {  /* stat -> label */ 
     luaX_next(ls);  /* skip double colon */       luaX_next(ls);  /* skip double colon */ 
     labelstat(ls, str_checkname(ls), line);      labelstat(ls, str_checkname(ls), line);
     break;      break;
   }    }
   case TK_RETURN: {  /* stat -> retstat */     case TK_RETURN: {  /* stat -> retstat */ 
     luaX_next(ls);  /* skip RETURN */       luaX_next(ls);  /* skip RETURN */ 
     retstat(ls);      retstat(ls);
     break;      break;
   }    }
   case TK_BREAK:   /* stat -> breakstat */     case TK_BREAK:   /* stat -> breakstat */ 
   case TK_GOTO: {  /* stat -> 'goto' NAME */     case TK_GOTO: {  /* stat -> 'goto' NAME */ 
     gotostat(ls, luaK_jump(ls->fs));      gotostat(ls, luaK_jump(ls->fs));
     break;      break;
   }    }
   default: {  /* stat -> func | assignment */     default: {  /* stat -> func | assignment */ 
     exprstat(ls);      exprstat(ls);
     break;      break;
   }    }
 }  }
 lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&  lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
            ls->fs->freereg >= ls->fs->nactvar);             ls->fs->freereg >= ls->fs->nactvar);
 ls->fs->freereg = ls->fs->nactvar;  /* free registers */   ls->fs->freereg = ls->fs->nactvar;  /* free registers */ 
 leavelevel(ls);  leavelevel(ls);
} }
   
/* }====================================================================== */  /* }====================================================================== */ 
   
   
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
                   Dyndata *dyd, const char *name, int firstchar) {                    Dyndata *dyd, const char *name, int firstchar) {
 LexState lexstate;  LexState lexstate;
 FuncState funcstate;  FuncState funcstate;
 BlockCnt bl;  BlockCnt bl;
 TString *tname = luaS_new(L, name);  TString *tname = luaS_new(L, name);
 setsvalue2s(L, L->top, tname);  /* push name to protect it */   setsvalue2s(L, L->top, tname);  /* push name to protect it */ 
 incr_top(L);  incr_top(L);
 lexstate.buff = buff;  lexstate.buff = buff;
 lexstate.dyd = dyd;  lexstate.dyd = dyd;
 dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;  dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
 luaX_setinput(L, &lexstate, z, tname, firstchar);  luaX_setinput(L, &lexstate, z, tname, firstchar);
 open_mainfunc(&lexstate, &funcstate, &bl);  open_mainfunc(&lexstate, &funcstate, &bl);
 luaX_next(&lexstate);  /* read first token */   luaX_next(&lexstate);  /* read first token */ 
 statlist(&lexstate);  /* main body */   statlist(&lexstate);  /* main body */ 
 check(&lexstate, TK_EOS);  check(&lexstate, TK_EOS);
 close_func(&lexstate);  close_func(&lexstate);
 L->top--;  /* pop name */   L->top--;  /* pop name */ 
 lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);  lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
 /* all scopes should be correctly finished */   /* all scopes should be correctly finished */ 
 lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);  lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
 return funcstate.f;  return funcstate.f;
} }