Lua TeamLua 5.3.0-rc348416b811 years agoHistory
1647 lines · 45.1 KB · C
RawDownload
/*** $Id: lparser.c,v 2.147 2014/12/27 20:31:43 roberto Exp $** Lua Parser** See Copyright Notice in lua.h*/ #define lparser_c#define LUA_CORE #include "lprefix.h"  #include <string.h> #include "lua.h" #include "lcode.h"#include "ldebug.h"#include "ldo.h"#include "lfunc.h"#include "llex.h"#include "lmem.h"#include "lobject.h"#include "lopcodes.h"#include "lparser.h"#include "lstate.h"#include "lstring.h"#include "ltable.h"   /* maximum number of local variables per function (must be smaller   than 250, due to the bytecode format) */#define MAXVARS		200  #define hasmultret(k)		((k) == VCALL || (k) == VVARARG)  /* because all strings are unified by the scanner, the parser   can use pointer equality for string equality */#define eqstr(a,b)	((a) == (b))  /*** nodes for block list (list of active blocks)*/typedef struct BlockCnt {  struct BlockCnt *previous;  /* chain */  int firstlabel;  /* index of first label in this block */  int firstgoto;  /* index of first pending goto in this block */  lu_byte nactvar;  /* # active locals outside the block */  lu_byte upval;  /* true if some variable in the block is an upvalue */  lu_byte isloop;  /* true if 'block' is a loop */} BlockCnt;   /*** prototypes for recursive non-terminal functions*/static void statement (LexState *ls);static void expr (LexState *ls, expdesc *v);  /* semantic error */static l_noret semerror (LexState *ls, const char *msg) {  ls->t.token = 0;  /* remove "near <token>" from final message */  luaX_syntaxerror(ls, msg);}  static l_noret error_expected (LexState *ls, int token) {  luaX_syntaxerror(ls,      luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token)));}  static l_noret errorlimit (FuncState *fs, int limit, const char *what) {  lua_State *L = fs->ls->L;  const char *msg;  int line = fs->f->linedefined;  const char *where = (line == 0)                      ? "main function"                      : luaO_pushfstring(L, "function at line %d", line);  msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s",                             what, limit, where);  luaX_syntaxerror(fs->ls, msg);}  static void checklimit (FuncState *fs, int v, int l, const char *what) {  if (v > l) errorlimit(fs, l, what);}  static int testnext (LexState *ls, int c) {  if (ls->t.token == c) {    luaX_next(ls);    return 1;  }  else return 0;}  static void check (LexState *ls, int c) {  if (ls->t.token != c)    error_expected(ls, c);}  static void checknext (LexState *ls, int c) {  check(ls, c);  luaX_next(ls);}  #define check_condition(ls,c,msg)	{ if (!(c)) luaX_syntaxerror(ls, msg); }   static void check_match (LexState *ls, int what, int who, int where) {  if (!testnext(ls, what)) {    if (where == ls->linenumber)      error_expected(ls, what);    else {      luaX_syntaxerror(ls, luaO_pushfstring(ls->L,             "%s expected (to close %s at line %d)",              luaX_token2str(ls, what), luaX_token2str(ls, who), where));    }  }}  static TString *str_checkname (LexState *ls) {  TString *ts;  check(ls, TK_NAME);  ts = ls->t.seminfo.ts;  luaX_next(ls);  return ts;}  static void init_exp (expdesc *e, expkind k, int i) {  e->f = e->t = NO_JUMP;  e->k = k;  e->u.info = i;}  static void codestring (LexState *ls, expdesc *e, TString *s) {  init_exp(e, VK, luaK_stringK(ls->fs, s));}  static void checkname (LexState *ls, expdesc *e) {  codestring(ls, e, str_checkname(ls));}  static int registerlocalvar (LexState *ls, TString *varname) {  FuncState *fs = ls->fs;  Proto *f = fs->f;  int oldsize = f->sizelocvars;  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,                  LocVar, SHRT_MAX, "local variables");  while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;  f->locvars[fs->nlocvars].varname = varname;  luaC_objbarrier(ls->L, f, varname);  return fs->nlocvars++;}  static void new_localvar (LexState *ls, TString *name) {  FuncState *fs = ls->fs;  Dyndata *dyd = ls->dyd;  int reg = registerlocalvar(ls, name);  checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,                  MAXVARS, "local variables");  luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,                  dyd->actvar.size, Vardesc, MAX_INT, "local variables");  dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg);}  static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {  new_localvar(ls, luaX_newstring(ls, name, sz));} #define new_localvarliteral(ls,v) \	new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1)  static LocVar *getlocvar (FuncState *fs, int i) {  int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;  lua_assert(idx < fs->nlocvars);  return &fs->f->locvars[idx];}  static void adjustlocalvars (LexState *ls, int nvars) {  FuncState *fs = ls->fs;  fs->nactvar = cast_byte(fs->nactvar + nvars);  for (; nvars; nvars--) {    getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;  }}  static void removevars (FuncState *fs, int tolevel) {  fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);  while (fs->nactvar > tolevel)    getlocvar(fs, --fs->nactvar)->endpc = fs->pc;}  static int searchupvalue (FuncState *fs, TString *name) {  int i;  Upvaldesc *up = fs->f->upvalues;  for (i = 0; i < fs->nups; i++) {    if (eqstr(up[i].name, name)) return i;  }  return -1;  /* not found */}  static int newupvalue (FuncState *fs, TString *name, expdesc *v) {  Proto *f = fs->f;  int oldsize = f->sizeupvalues;  checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");  luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,                  Upvaldesc, MAXUPVAL, "upvalues");  while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;  f->upvalues[fs->nups].instack = (v->k == VLOCAL);  f->upvalues[fs->nups].idx = cast_byte(v->u.info);  f->upvalues[fs->nups].name = name;  luaC_objbarrier(fs->ls->L, f, name);  return fs->nups++;}  static int searchvar (FuncState *fs, TString *n) {  int i;  for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {    if (eqstr(n, getlocvar(fs, i)->varname))      return i;  }  return -1;  /* not found */}  /*  Mark block where variable at given level was defined  (to emit close instructions later).*/static void markupval (FuncState *fs, int level) {  BlockCnt *bl = fs->bl;  while (bl->nactvar > level) bl = bl->previous;  bl->upval = 1;}  /*  Find variable with given name 'n'. If it is an upvalue, add this  upvalue into all intermediate functions.*/static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {  if (fs == NULL)  /* no more levels? */    return VVOID;  /* default is global */  else {    int v = searchvar(fs, n);  /* look up locals at current level */    if (v >= 0) {  /* found? */      init_exp(var, VLOCAL, v);  /* variable is local */      if (!base)        markupval(fs, v);  /* local will be used as an upval */      return VLOCAL;    }    else {  /* not found as local at current level; try upvalues */      int idx = searchupvalue(fs, n);  /* try existing upvalues */      if (idx < 0) {  /* not found? */        if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */          return VVOID;  /* not found; is a global */        /* else was LOCAL or UPVAL */        idx  = newupvalue(fs, n, var);  /* will be a new upvalue */      }      init_exp(var, VUPVAL, idx);      return VUPVAL;    }  }}  static void singlevar (LexState *ls, expdesc *var) {  TString *varname = str_checkname(ls);  FuncState *fs = ls->fs;  if (singlevaraux(fs, varname, var, 1) == VVOID) {  /* global name? */    expdesc key;    singlevaraux(fs, ls->envn, var, 1);  /* get environment variable */    lua_assert(var->k == VLOCAL || var->k == VUPVAL);    codestring(ls, &key, varname);  /* key is variable name */    luaK_indexed(fs, var, &key);  /* env[varname] */  }}  static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {  FuncState *fs = ls->fs;  int extra = nvars - nexps;  if (hasmultret(e->k)) {    extra++;  /* includes call itself */    if (extra < 0) extra = 0;    luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */    if (extra > 1) luaK_reserveregs(fs, extra-1);  }  else {    if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */    if (extra > 0) {      int reg = fs->freereg;      luaK_reserveregs(fs, extra);      luaK_nil(fs, reg, extra);    }  }}  static void enterlevel (LexState *ls) {  lua_State *L = ls->L;  ++L->nCcalls;  checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels");}  #define leavelevel(ls)	((ls)->L->nCcalls--)  static void closegoto (LexState *ls, int g, Labeldesc *label) {  int i;  FuncState *fs = ls->fs;  Labellist *gl = &ls->dyd->gt;  Labeldesc *gt = &gl->arr[g];  lua_assert(eqstr(gt->name, label->name));  if (gt->nactvar < label->nactvar) {    TString *vname = getlocvar(fs, gt->nactvar)->varname;    const char *msg = luaO_pushfstring(ls->L,      "<goto %s> at line %d jumps into the scope of local '%s'",      getstr(gt->name), gt->line, getstr(vname));    semerror(ls, msg);  }  luaK_patchlist(fs, gt->pc, label->pc);  /* remove goto from pending list */  for (i = g; i < gl->n - 1; i++)    gl->arr[i] = gl->arr[i + 1];  gl->n--;}  /*** try to close a goto with existing labels; this solves backward jumps*/static int findlabel (LexState *ls, int g) {  int i;  BlockCnt *bl = ls->fs->bl;  Dyndata *dyd = ls->dyd;  Labeldesc *gt = &dyd->gt.arr[g];  /* check labels in current block for a match */  for (i = bl->firstlabel; i < dyd->label.n; i++) {    Labeldesc *lb = &dyd->label.arr[i];    if (eqstr(lb->name, gt->name)) {  /* correct label? */      if (gt->nactvar > lb->nactvar &&          (bl->upval || dyd->label.n > bl->firstlabel))        luaK_patchclose(ls->fs, gt->pc, lb->nactvar);      closegoto(ls, g, lb);  /* close it */      return 1;    }  }  return 0;  /* label not found; cannot close goto */}  static int newlabelentry (LexState *ls, Labellist *l, TString *name,                          int line, int pc) {  int n = l->n;  luaM_growvector(ls->L, l->arr, n, l->size,                  Labeldesc, SHRT_MAX, "labels/gotos");  l->arr[n].name = name;  l->arr[n].line = line;  l->arr[n].nactvar = ls->fs->nactvar;  l->arr[n].pc = pc;  l->n = n + 1;  return n;}  /*** check whether new label 'lb' matches any pending gotos in current** block; solves forward jumps*/static void findgotos (LexState *ls, Labeldesc *lb) {  Labellist *gl = &ls->dyd->gt;  int i = ls->fs->bl->firstgoto;  while (i < gl->n) {    if (eqstr(gl->arr[i].name, lb->name))      closegoto(ls, i, lb);    else      i++;  }}  /*** export pending gotos to outer level, to check them against** outer labels; if the block being exited has upvalues, and** the goto exits the scope of any variable (which can be the** upvalue), close those variables being exited.*/static void movegotosout (FuncState *fs, BlockCnt *bl) {  int i = bl->firstgoto;  Labellist *gl = &fs->ls->dyd->gt;  /* correct pending gotos to current block and try to close it     with visible labels */  while (i < gl->n) {    Labeldesc *gt = &gl->arr[i];    if (gt->nactvar > bl->nactvar) {      if (bl->upval)        luaK_patchclose(fs, gt->pc, bl->nactvar);      gt->nactvar = bl->nactvar;    }    if (!findlabel(fs->ls, i))      i++;  /* move to next one */  }}  static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {  bl->isloop = isloop;  bl->nactvar = fs->nactvar;  bl->firstlabel = fs->ls->dyd->label.n;  bl->firstgoto = fs->ls->dyd->gt.n;  bl->upval = 0;  bl->previous = fs->bl;  fs->bl = bl;  lua_assert(fs->freereg == fs->nactvar);}  /*** create a label named 'break' to resolve break statements*/static void breaklabel (LexState *ls) {  TString *n = luaS_new(ls->L, "break");  int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc);  findgotos(ls, &ls->dyd->label.arr[l]);} /*** generates an error for an undefined 'goto'; choose appropriate** message when label name is a reserved word (which can only be 'break')*/static l_noret undefgoto (LexState *ls, Labeldesc *gt) {  const char *msg = isreserved(gt->name)                    ? "<%s> at line %d not inside a loop"                    : "no visible label '%s' for <goto> at line %d";  msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);  semerror(ls, msg);}  static void leaveblock (FuncState *fs) {  BlockCnt *bl = fs->bl;  LexState *ls = fs->ls;  if (bl->previous && bl->upval) {    /* create a 'jump to here' to close upvalues */    int j = luaK_jump(fs);    luaK_patchclose(fs, j, bl->nactvar);    luaK_patchtohere(fs, j);  }  if (bl->isloop)    breaklabel(ls);  /* close pending breaks */  fs->bl = bl->previous;  removevars(fs, bl->nactvar);  lua_assert(bl->nactvar == fs->nactvar);  fs->freereg = fs->nactvar;  /* free registers */  ls->dyd->label.n = bl->firstlabel;  /* remove local labels */  if (bl->previous)  /* inner block? */    movegotosout(fs, bl);  /* update pending gotos to outer block */  else if (bl->firstgoto < ls->dyd->gt.n)  /* pending gotos in outer block? */    undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]);  /* error */}  /*** adds a new prototype into list of prototypes*/static Proto *addprototype (LexState *ls) {  Proto *clp;  lua_State *L = ls->L;  FuncState *fs = ls->fs;  Proto *f = fs->f;  /* prototype of current function */  if (fs->np >= f->sizep) {    int oldsize = f->sizep;

Lines 1–500 of 1647.