diff options
Diffstat (limited to 'games/minimal/mods/default/textures/default_lava.png')
0 files changed, 0 insertions, 0 deletions
![]() |
index : minetest.git | |
modified minetest for gpcfs purposes | gpcf |
aboutsummaryrefslogtreecommitdiff |
/*
** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
#include <string.h>
#define lparser_c
#define LUA_CORE
#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"
#define hasmultret(k) ((k) == VCALL || (k) == VVARARG)
#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]])
#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m)
/*
** nodes for block list (list of active blocks)
*/
typedef struct BlockCnt {
struct BlockCnt *previous; /* chain */
int breaklist; /* list of jumps out of this loop */
lu_byte nactvar; /* # active locals outside the breakable structure */
lu_byte upval; /* true if some variable in the block is an upvalue */
lu_byte isbreakable; /* true if `block' is a loop */
} BlockCnt;
/*
** prototypes for recursive non-terminal functions
*/
static void chunk (LexState *ls);
static void expr (LexState *ls, expdesc *v);
static void anchor_token (LexState *ls) {
if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
TString *ts = ls->t.seminfo.ts;
luaX_newstring(ls, getstr(ts), ts->tsv.len);
}
}
static void error_expected (LexState *ls, int token) {
luaX_syntaxerror(ls,
luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token)));
}
static void errorlimit (FuncState *fs, int limit, const char *what) {
const char *msg = (fs->f->linedefined == 0) ?
luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
fs->f->linedefined, limit, what);
luaX_lexerror(fs->ls, msg, 0);
}
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,
LUA_QS " expected (to close " LUA_QS " 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.s.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, "too many 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++;
}
#define new_localvarliteral(ls,v,n) \
new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n)
static void new_localvar (LexState *ls, TString *name, int n) {
FuncState *fs = ls->fs;
luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables");
fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name));
}
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 (LexState *ls, int tolevel) {
FuncState *fs = ls->fs;
while (fs->nactvar > tolevel)
getlocvar(fs, --fs->nactvar).endpc = fs->pc;
}
static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
int i;
Proto *f = fs->f;
int oldsize = f->sizeupvalues;
for (i=0; i<f->nups; i++) {
if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) {
lua_assert(f->upvalues[i] == name);
return i;
}
}
/* new one */
luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues");
luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues,
TString *, MAX_INT, "");
while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL;
f->upvalues[f->nups] = name;
luaC_objbarrier(fs->L, f, name);
lua_assert(v->k == VLOCAL || v->k == VUPVAL);
fs->upvalues[f->nups].k = cast_byte(v->k);
fs->upvalues[f->nups].info = cast_byte(v->u.s.info);
return f->nups++;
}
static int searchvar (FuncState *fs, TString *n) {
int i;
for (i=fs->nactvar-1; i >= 0; i--) {
if (n == getlocvar(fs, i).varname)
return i;
}
return -1; /* not found */
}
static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl;
while (bl && bl->nactvar > level) bl = bl->previous;
if (bl) bl->upval = 1;
}
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) { /* no more levels? */
init_exp(var, VGLOBAL, NO_REG); /* default is global variable */
return VGLOBAL;
}
else {
int v = searchvar(fs, n); /* look up at current level */
if (v >= 0) {
init_exp(var, VLOCAL, v);
if (!base)
markupval(fs, v); /* local will be used as an upval */
return VLOCAL;
}
else { /* not found at current level; try upper one */
if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)
return VGLOBAL;
var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */
var->k = VUPVAL; /* upvalue in this level */
return VUPVAL;
}
}
}
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
if (singlevaraux(fs, varname, var, 1) == VGLOBAL)
var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */
}
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) {
if (++ls->L->nCcalls > LUAI_MAXCCALLS)
luaX_lexerror(ls, "chunk has too many syntax levels", 0);
}
#define leavelevel(ls) ((ls)->L->nCcalls--)
static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) {
bl->breaklist = NO_JUMP;
bl->isbreakable = isbreakable;
bl->nactvar = fs->nactvar;
bl->upval = 0;
bl->previous = fs->bl;
fs->bl = bl;
lua_assert(fs->freereg == fs->nactvar);
}
static void leaveblock (FuncState *fs) {
BlockCnt *bl = fs->bl;
fs->bl = bl->previous;
removevars(fs->ls, bl->nactvar);
if (bl->upval)
luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
/* a block either controls scope or breaks (never both) */
lua_assert(!bl->isbreakable || !bl->upval);
lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = fs->nactvar; /* free registers */
luaK_patchtohere(fs, bl->breaklist);
}
static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
FuncState *fs = ls->fs;
Proto *f = fs->f;
int oldsize = f->sizep;
int i;
luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
MAXARG_Bx, "constant table overflow");
while (oldsize < f->sizep) f->p[oldsize++] = NULL;
f->p[fs->np++] = func->f;
luaC_objbarrier(ls->L, f, func->f);
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
for (i=0; i<func->f->nups; i++) {
OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0);
}
}
static void open_func (LexState *ls, FuncState *fs) {
lua_State *L = ls->L;
Proto *f = luaF_newproto(L);
fs->f = f;
fs->prev = ls->fs; /* linked list of funcstates */
fs->ls = ls;
fs->L = L;
ls->fs = fs;
fs->pc = 0;
fs->lasttarget = -1;
fs->jpc = NO_JUMP;
fs->freereg = 0;
fs->nk = 0;
fs->np = 0;
fs->nlocvars = 0;
fs->nactvar = 0;
fs->bl = NULL;
f->source = ls->source;
f->maxstacksize = 2; /* registers 0/1 are always valid */
fs->h = luaH_new(L, 0, 0);
/* anchor table of constants and prototype (to avoid being collected) */
sethvalue2s(L, L->top, fs->h);
incr_top(L);
setptvalue2s(L, L->top, f);
incr_top(L);
}
static void close_func (LexState *ls) {
lua_State *L = ls->L;
FuncState *fs = ls->fs;
Proto *f = fs->f;
removevars(ls, 0);
luaK_ret(fs, 0, 0); /* final return */
luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
f->sizecode = fs->pc;
luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
f->sizelineinfo = fs->pc;
luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
f->sizek = fs->nk;
luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
f->sizep = fs->np;
luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
f->sizelocvars = fs->nlocvars;
luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *);
f->sizeupvalues = f->nups;
lua_assert(luaG_checkcode(f));
lua_assert(fs->bl == NULL);
ls->fs = fs->prev;
L->top -= 2; /* remove table and prototype from the stack */
/* last token read was anchored in defunct function; must reanchor it */
if (fs) anchor_token(ls);
}
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
struct LexState lexstate;
struct FuncState funcstate;
lexstate.buff = buff;
luaX_setinput(L, &lexstate, z, luaS_new(L, name));
open_func(&lexstate, &funcstate);
funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */
luaX_next(&lexstate); /* read first token */
chunk(&lexstate);
check(&lexstate, TK_EOS);
close_func(&lexstate);
lua_assert(funcstate.prev == NULL);
lua_assert(funcstate.f->nups == 0);
lua_assert(lexstate.fs == NULL);
return funcstate.f;
}
/*============================================================*/
/* GRAMMAR RULES */
/*============================================================*/
static void field (LexState *ls, expdesc *v) {
/* field -> ['.' | ':'] NAME */
FuncState *fs = ls->fs;
expdesc key;
luaK_exp2anyreg(fs, v);
luaX_next(ls); /* skip the dot or colon */
checkname(ls, &key);
luaK_indexed(fs, v, &key);
}
static void yindex (LexState *ls, expdesc *v) {
/* index -> '[' expr ']' */
luaX_next(ls); /* skip the '[' */
expr(ls, v);
luaK_exp2val(ls->fs, v);
checknext(ls, ']');
}
/*
** {======================================================================
** Rules for Constructors
** =======================================================================
*/
struct ConsControl {
expdesc v; /* last list item read */
expdesc *t; /* table descriptor */
int nh; /* total number of `record' elements */
int na; /* total number of array elements */
int tostore; /* number of array elements pending to be stored */
};
static void recfield (LexState *ls, struct ConsControl *cc) {
/* recfield -> (NAME | `['exp1`]') = exp1 */
FuncState *fs = ls->fs;
int reg = ls->fs->freereg;
expdesc key, val;
int rkkey;
if (ls->t.token == TK_NAME) {
luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
checkname(ls, &key);
}
else /* ls->t.token == '[' */
yindex(ls, &key);
cc->nh++;
checknext(ls, '=');
rkkey = luaK_exp2RK(fs, &key);
expr(ls, &val);
luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val));
fs->freereg = reg; /* free registers */
}
static void closelistfield (FuncState *fs, struct ConsControl *cc) {
if (cc->v.k == VVOID) return; /* there is no list item */
luaK_exp2nextreg(fs, &cc->v);
cc->v.k = VVOID;
if (cc->tostore == LFIELDS_PER_FLUSH) {
luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */
cc->tostore = 0; /* no more items pending */
}
}
static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
if (cc->tostore == 0) return;
if (hasmultret(cc->v.k)) {
luaK_setmultret(fs, &cc->v);
luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET);
cc->na--; /* do not count last expression (unknown number of elements) */
}
else {
if (cc->v.k != VVOID)
luaK_exp2nextreg(fs, &cc->v);
luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);
}
}
static void listfield (LexState *ls, struct ConsControl *cc) {
expr(ls, &cc->v);
luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
cc->na++;
cc->tostore++;
}
static void constructor (LexState *ls, expdesc *t) {
/* constructor -> ?? */
FuncState *fs = ls->fs;
int line = ls->linenumber;
int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
struct ConsControl cc;
cc.na = cc.nh = cc.tostore = 0;
cc.t = t;
init_exp(t, VRELOCABLE, pc);
init_exp(&cc.v, VVOID, 0); /* no value (yet) */
luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */
checknext(ls, '{');
do {
lua_assert(cc.v.k == VVOID || cc.tostore > 0);
if (ls->t.token == '}') break;
closelistfield(fs, &cc);
switch(ls->t.token) {
case TK_NAME: { /* may be listfields or recfields */
luaX_lookahead(ls);
if (ls->lookahead.token != '=') /* expression? */
listfield(ls, &cc);
else
recfield(ls, &cc);
break;
}
case '[': { /* constructor_item -> recfield */
recfield(ls, &cc);
break;
}
default: { /* constructor_part -> listfield */
listfield(ls, &cc);
break;
}
}
} while (testnext(ls, ',') || testnext(ls, ';'));
check_match(ls, '}', '{', line);
lastlistfield(fs, &cc);
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 */
}
/* }====================================================================== */
static void parlist (LexState *ls) {
/* parlist -> [ param { `,' param } ] */
FuncState *fs = ls->fs;
Proto *f = fs->f;
int nparams = 0;
f->is_vararg = 0;
if (ls->t.token != ')') { /* is `parlist' not empty? */
do {
switch (ls->t.token) {
case TK_NAME: { /* param -> NAME */
new_localvar(ls, str_checkname(ls), nparams++);
break;
}
case TK_DOTS: { /* param -> `...' */
luaX_next(ls);
#if defined(LUA_COMPAT_VARARG)
/* use `arg' as default name */
new_localvarliteral(ls, "arg", nparams++);
f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG;
#endif
f->is_vararg |= VARARG_ISVARARG;
break;
}
default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");
}
} while (!f->is_vararg && testnext(ls, ','));
}
adjustlocalvars(ls, nparams);
f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG));
luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */
}
static void body (LexState *ls, expdesc *e, int needself, int line) {
/* body -> `(' parlist `)' chunk END */
FuncState new_fs;
open_func(ls, &new_fs);
new_fs.f->linedefined = line;
checknext(ls, '(');
if (needself) {
new_localvarliteral(ls, "self", 0);
adjustlocalvars(ls, 1);
}
parlist(ls);
checknext(ls, ')');
chunk(ls);
new_fs.f->lastlinedefined = ls->linenumber;
check_match(ls, TK_END, TK_FUNCTION, line);
close_func(ls);
pushclosure(ls, &new_fs, e);
}
static int explist1 (LexState *ls, expdesc *v) {
/* explist1 -> expr { `,' expr } */
int n = 1; /* at least one expression */
expr(ls, v);
while (testnext(ls, ',')) {
luaK_exp2nextreg(ls->fs, v);
expr(ls, v);
n++;
}
return n;
}
static void funcargs (LexState *ls, expdesc *f) {
FuncState *fs = ls->fs;
expdesc args;
int base, nparams;
int line = ls->linenumber;
switch (ls->t.token) {
case '(': { /* funcargs -> `(' [ explist1 ] `)' */
if (line != ls->lastline)
luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
luaX_next(ls);
if (ls->t.token == ')') /* arg list is empty? */
args.k = VVOID;
else {
explist1(ls, &args);
luaK_setmultret(fs, &args);
}
check_match(ls, ')', '(', line);
break;
}
case '{': { /* funcargs -> constructor */
constructor(ls, &args);
break;
}
case TK_STRING: { /* funcargs -> STRING */
codestring(ls, &args, ls->t.seminfo.ts);
luaX_next(ls); /* must use `seminfo' before `next' */
break;
}
default: {
luaX_syntaxerror(ls, "function arguments expected");
return;
}
}
lua_assert(f->k == VNONRELOC);
base = f->u.s.info; /* base register for call */
if (hasmultret(args.k))
nparams = LUA_MULTRET; /* open call */
else {
if (args.k != VVOID)
luaK_exp2nextreg(fs, &args); /* close last argument */
nparams = fs->freereg - (base+1);
}
init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
luaK_fixline(fs, line);
fs->freereg = base+1; /* call remove function and arguments and leaves
(unless changed) one result */
}
/*
** {======================================================================
** Expression parsing
** =======================================================================
*/
static void prefixexp (LexState *ls, expdesc *v) {
/* prefixexp -> NAME | '(' expr ')' */
switch (ls->t.token) {
case '(': {
int line = ls->linenumber;
luaX_next(ls);
expr(ls, v);
check_match(ls, ')', '(', line);
luaK_dischargevars(ls->fs, v);
return;
}
case TK_NAME: {
singlevar(ls, v);
return;
}
default: {
luaX_syntaxerror(ls, "unexpected symbol");
return;
}
}
}
static void primaryexp (LexState *ls, expdesc *v) {
/* primaryexp ->
prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
FuncState *fs = ls->fs;
prefixexp(ls, v);
for (;;) {
switch (ls->t.token) {
case '.': { /* field */
field(ls, v);
break;
}
case '[': { /* `[' exp1 `]' */
expdesc key;
luaK_exp2anyreg(fs, v);
yindex(ls, &key);
luaK_indexed(fs, v, &key);
break;
}
case ':': { /* `:' NAME funcargs */
expdesc key;
luaX_next(ls);
checkname(ls, &key);
luaK_self(fs, v, &key);
funcargs(ls, v);
break;
}
case '(': case TK_STRING: case '{': { /* funcargs */
luaK_exp2nextreg(fs, v);
funcargs(ls, v);
break;
}
default: return;
}
}
}
static void simpleexp (LexState *ls, expdesc *v) {
/* simpleexp -> NUMBER | STRING | NIL | true | false | ... |
constructor | FUNCTION body | primaryexp */
switch (ls->t.token) {
case TK_NUMBER: {
init_exp(v, VKNUM, 0);
v->u.nval = ls->t.seminfo.r;
break;
}
case TK_STRING: {