From 22329e4cdf6c6741523099173c31b0a421825a3c Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 5 Apr 2000 14:51:58 -0300 Subject: implementation of BREAK --- lcode.c | 92 ++++++++++++++++------------------ lcode.h | 8 ++- llex.c | 5 +- llex.h | 4 +- lparser.c | 169 +++++++++++++++++++++++++++++++++++++++++--------------------- lparser.h | 7 ++- 6 files changed, 168 insertions(+), 117 deletions(-) diff --git a/lcode.c b/lcode.c index 137cfcdc..de4c3623 100644 --- a/lcode.c +++ b/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 1.18 2000/03/24 17:26:08 roberto Exp roberto $ +** $Id: lcode.c,v 1.19 2000/04/04 20:48:44 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -23,6 +23,18 @@ void luaK_error (LexState *ls, const char *msg) { luaX_error(ls, msg, ls->token); } +/* +** Returns the the previous instruction, for optimizations. +** If there is a jump target between this and the current instruction, +** returns a dummy instruction to avoid wrong optimizations. +*/ +static Instruction previous_instruction (FuncState *fs) { + if (fs->pc > fs->lasttarget) /* no jumps to current position? */ + return fs->f->code[fs->pc-1]; /* returns previous instruction */ + else + return CREATE_0(OP_END); /* no optimizations after an `END' */ +} + int luaK_code (FuncState *fs, Instruction i, int delta) { luaK_deltastack(fs, delta); @@ -48,19 +60,6 @@ int luaK_AB(FuncState *fs, OpCode o, int a, int b, int d) { } -/* -** Returns the the previous instruction, for optimizations. -** If there is a jump target between this and the current instruction, -** returns a dummy instruction to avoid wrong optimizations. -*/ -static Instruction previous_instruction (FuncState *fs) { - if (fs->pc > fs->lasttarget) /* no jumps to current position? */ - return fs->f->code[fs->pc-1]; /* returns previous instruction */ - else - return CREATE_0(OP_END); /* no optimizations after an `END' */ -} - - static Instruction prepare (FuncState *fs, Instruction i, int delta) { Instruction previous = previous_instruction(fs); luaK_code(fs, i, delta); @@ -154,7 +153,7 @@ static void luaK_setlocal (FuncState *fs, int l) { static void luaK_eq (FuncState *fs) { /* PUSHNIL 1; JMPEQ -> NOT (a==nil) */ - Instruction previous = prepare(fs, CREATE_S(OP_JMPEQ, 0), -2); + Instruction previous = prepare(fs, CREATE_S(OP_JMPEQ, NO_JUMP), -2); if (previous == CREATE_U(OP_PUSHNIL, 1)) { setprevious(fs, CREATE_0(OP_NOT)); luaK_deltastack(fs, 1); /* undo delta from `prepare' */ @@ -164,13 +163,18 @@ static void luaK_eq (FuncState *fs) { static void luaK_neq (FuncState *fs) { /* PUSHNIL 1; JMPNEQ -> JMPT (a~=nil) */ - Instruction previous = prepare(fs, CREATE_S(OP_JMPNEQ, 0), -2); + Instruction previous = prepare(fs, CREATE_S(OP_JMPNEQ, NO_JUMP), -2); if (previous == CREATE_U(OP_PUSHNIL, 1)) { - setprevious(fs, CREATE_S(OP_JMPT, 0)); + setprevious(fs, CREATE_S(OP_JMPT, NO_JUMP)); } } +int luaK_jump (FuncState *fs) { + return luaK_S(fs, OP_JMP, NO_JUMP, 0); +} + + void luaK_retcode (FuncState *fs, int nlocals, int nexps) { Instruction previous = prepare(fs, CREATE_U(OP_RETURN, nlocals), 0); if (nexps > 0 && GET_OPCODE(previous) == OP_CALL) { @@ -192,12 +196,13 @@ static void luaK_pushnil (FuncState *fs, int n) { } -void luaK_fixjump (FuncState *fs, int pc, int dest) { +static void luaK_fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; if (dest == NO_JUMP) - SETARG_S(*jmp, 0); /* absolute value to represent end of list */ + SETARG_S(*jmp, NO_JUMP); /* point to itself to represent end of list */ else { /* jump is relative to position following jump instruction */ int offset = dest-(pc+1); + LUA_ASSERT(L, offset != NO_JUMP, "cannot link to itself"); if (abs(offset) > MAXARG_S) luaK_error(fs->ls, "control structure too long"); SETARG_S(*jmp, offset); @@ -207,7 +212,7 @@ void luaK_fixjump (FuncState *fs, int pc, int dest) { static int luaK_getjump (FuncState *fs, int pc) { int offset = GETARG_S(fs->f->code[pc]); - if (offset == 0) + if (offset == NO_JUMP) /* point to itself represents end of list */ return NO_JUMP; /* end of list */ else return (pc+1)+offset; /* turn offset into absolute position */ @@ -225,11 +230,11 @@ int luaK_getlabel (FuncState *fs) { void luaK_deltastack (FuncState *fs, int delta) { - fs->stacksize += delta; - if (delta > 0 && fs->stacksize > fs->f->maxstacksize) { - if (fs->stacksize > MAXSTACK) + fs->stacklevel += delta; + if (delta > 0 && fs->stacklevel > fs->f->maxstacksize) { + if (fs->stacklevel > MAXSTACK) luaK_error(fs->ls, "function or expression too complex"); - fs->f->maxstacksize = fs->stacksize; + fs->f->maxstacksize = fs->stacklevel; } } @@ -357,29 +362,16 @@ static OpCode invertjump (OpCode op) { } -static void luaK_jump (FuncState *fs, OpCode jump) { - Instruction previous = prepare(fs, CREATE_S(jump, 0), -1); +static void luaK_condjump (FuncState *fs, OpCode jump) { + Instruction previous = prepare(fs, CREATE_S(jump, NO_JUMP), -1); switch (GET_OPCODE(previous)) { - case OP_NOT: previous = CREATE_S(invertjump(jump), 0); break; - case OP_PUSHNIL: /* optimize `repeat until nil' */ - if (GETARG_U(previous) == 1 && jump == OP_JMPF) { - previous = CREATE_S(OP_JMP, 0); - break; - } - else return; /* do not set previous */ + case OP_NOT: previous = CREATE_S(invertjump(jump), NO_JUMP); break; default: return; } setprevious(fs, previous); } -static void insert_last (FuncState *fs, int *list) { - int first = *list; - *list = fs->pc-1; /* insert last instruction in the list */ - luaK_fixjump(fs, *list, first); -} - - static void luaK_patchlistaux (FuncState *fs, int list, int target, OpCode special, int special_target) { Instruction *code = fs->f->code; @@ -414,7 +406,7 @@ static int need_value (FuncState *fs, int list, OpCode hasvalue) { } -static void concatlists (FuncState *fs, int *l1, int l2) { +void luaK_concat (FuncState *fs, int *l1, int l2) { if (*l1 == NO_JUMP) *l1 = l2; else { @@ -446,8 +438,8 @@ static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) { SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); } else - luaK_jump(fs, jump); - insert_last(fs, exitlist); + luaK_condjump(fs, jump); + luaK_concat(fs, exitlist, fs->pc-1); /* insert last jump in `exitlist' */ luaK_patchlist(fs, *golist, luaK_getlabel(fs)); *golist = NO_JUMP; } @@ -478,7 +470,7 @@ void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { int p_1 = 0; /* position of an eventual PUSHINT */ int final; /* position after whole expression */ if (ISJUMP(previous)) { - insert_last(fs, &v->u.l.t); /* put `previous' in true list */ + luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in true list */ p_nil = luaK_0(fs, OP_PUSHNILJMP, 0); p_1 = luaK_S(fs, OP_PUSHINT, 1, 1); } @@ -544,13 +536,13 @@ void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) { LUA_ASSERT(ls->L, v1->u.l.t == NO_JUMP, "list must be closed"); discharge1(fs, v2); v1->u.l.t = v2->u.l.t; - concatlists(fs, &v1->u.l.f, v2->u.l.f); + luaK_concat(fs, &v1->u.l.f, v2->u.l.f); } else if (op == TK_OR) { LUA_ASSERT(ls->L, v1->u.l.f == NO_JUMP, "list must be closed"); discharge1(fs, v2); v1->u.l.f = v2->u.l.f; - concatlists(fs, &v1->u.l.t, v2->u.l.t); + luaK_concat(fs, &v1->u.l.t, v2->u.l.t); } else { luaK_tostack(ls, v2, 1); /* `v2' must be a value */ @@ -563,10 +555,10 @@ void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) { case TK_CONC: luaK_conc(fs); break; case TK_EQ: luaK_eq(fs); break; case TK_NE: luaK_neq(fs); break; - case '>': luaK_S(fs, OP_JMPGT, 0, -2); break; - case '<': luaK_S(fs, OP_JMPLT, 0, -2); break; - case TK_GE: luaK_S(fs, OP_JMPGE, 0, -2); break; - case TK_LE: luaK_S(fs, OP_JMPLE, 0, -2); break; + case '>': luaK_S(fs, OP_JMPGT, NO_JUMP, -2); break; + case '<': luaK_S(fs, OP_JMPLT, NO_JUMP, -2); break; + case TK_GE: luaK_S(fs, OP_JMPGE, NO_JUMP, -2); break; + case TK_LE: luaK_S(fs, OP_JMPLE, NO_JUMP, -2); break; } } } diff --git a/lcode.h b/lcode.h index ce3901db..287977d2 100644 --- a/lcode.h +++ b/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.8 2000/03/15 20:50:33 roberto Exp roberto $ +** $Id: lcode.h,v 1.9 2000/03/17 13:09:46 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -13,6 +13,9 @@ #include "lparser.h" +#define NO_JUMP (-1) /* marks end of patch list */ + + void luaK_error (LexState *ls, const char *msg); int luaK_0(FuncState *fs, OpCode o, int d); int luaK_U(FuncState *fs, OpCode o, int u, int d); @@ -20,8 +23,9 @@ int luaK_S(FuncState *fs, OpCode o, int s, int d); int luaK_AB(FuncState *fs, OpCode o, int a, int b, int d); int luaK_code (FuncState *fs, Instruction i, int delta); void luaK_retcode (FuncState *fs, int nlocals, int nexps); -void luaK_fixjump (FuncState *fs, int pc, int dest); +int luaK_jump (FuncState *fs); void luaK_patchlist (FuncState *fs, int list, int target); +void luaK_concat (FuncState *fs, int *l1, int l2); void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue); void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue); int luaK_getlabel (FuncState *fs); diff --git a/llex.c b/llex.c index f56b0a21..ec8231a2 100644 --- a/llex.c +++ b/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 1.53 2000/03/10 18:37:44 roberto Exp roberto $ +** $Id: llex.c,v 1.54 2000/03/24 17:26:08 roberto Exp roberto $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -31,7 +31,8 @@ /* ORDER RESERVED */ -static const char *const token2string [] = {"and", "do", "else", "elseif", "end", +static const char *const token2string [] = { + "and", "break", "do", "else", "elseif", "end", "function", "if", "local", "nil", "not", "or", "repeat", "return", "then", "until", "while", "", "..", "...", "==", ">=", "<=", "~=", "", "", ""}; diff --git a/llex.h b/llex.h index 87e6511a..a09da136 100644 --- a/llex.h +++ b/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.20 2000/03/10 18:37:44 roberto Exp roberto $ +** $Id: llex.h,v 1.21 2000/03/24 17:26:08 roberto Exp roberto $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -23,7 +23,7 @@ */ enum RESERVED { /* terminal symbols denoted by reserved words */ - TK_AND = FIRST_RESERVED, + TK_AND = FIRST_RESERVED, TK_BREAK, TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FUNCTION, TK_IF, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_UNTIL, TK_WHILE, /* other terminal symbols */ diff --git a/lparser.c b/lparser.c index 05832288..1bb0c0cc 100644 --- a/lparser.c +++ b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.74 2000/03/29 20:19:20 roberto Exp roberto $ +** $Id: lparser.c,v 1.75 2000/04/03 13:44:55 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -28,10 +28,17 @@ ** it is a list constructor (k = 0) or a record constructor (k = 1) ** or empty (k = ';' or '}') */ -typedef struct constdesc { +typedef struct Constdesc { int n; int k; -} constdesc; +} Constdesc; + + +typedef struct Breaklabel { + struct Breaklabel *previous; /* chain */ + int breaklist; + int stacklevel; +} Breaklabel; @@ -311,6 +318,21 @@ static int getvarname (LexState *ls, expdesc *var) { } +static void enterbreak (FuncState *fs, Breaklabel *bl) { + bl->stacklevel = fs->stacklevel; + bl->breaklist = NO_JUMP; + bl->previous = fs->bl; + fs->bl = bl; +} + + +static void leavebreak (FuncState *fs, Breaklabel *bl) { + fs->bl = bl->previous; + LUA_ASSERT(fs->L, bl->stacklevel == fs->stacklevel, "wrong levels"); + luaK_patchlist(fs, bl->breaklist, luaK_getlabel(fs)); +} + + static void func_onstack (LexState *ls, FuncState *func) { FuncState *fs = ls->fs; Proto *f = fs->f; @@ -332,10 +354,11 @@ static void init_state (LexState *ls, FuncState *fs, TString *source) { fs->ls = ls; fs->L = ls->L; ls->fs = fs; - fs->stacksize = 0; + fs->stacklevel = 0; fs->nlocalvar = 0; fs->nupvalues = 0; fs->lastsetline = 0; + fs->bl = NULL; fs->f = f; f->source = source; fs->pc = 0; @@ -362,6 +385,7 @@ static void close_func (LexState *ls) { luaM_reallocvector(L, f->locvars, fs->nvars, LocVar); } ls->fs = fs->prev; + LUA_ASSERT(L, fs->bl == NULL, "wrong list end"); } @@ -375,6 +399,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z) { if (lexstate.token != TK_EOS) luaK_error(&lexstate, " expected"); close_func(&lexstate); + LUA_ASSERT(L, funcstate.prev == NULL, "wrong list end"); return funcstate.f; } @@ -416,7 +441,7 @@ static int explist (LexState *ls) { static void funcargs (LexState *ls, int slf) { FuncState *fs = ls->fs; - int slevel = fs->stacksize - slf - 1; /* where is func in the stack */ + int slevel = fs->stacklevel - slf - 1; /* where is func in the stack */ switch (ls->token) { case '(': { /* funcargs -> '(' explist ')' */ int line = ls->linenumber; @@ -444,7 +469,7 @@ static void funcargs (LexState *ls, int slf) { luaK_error(ls, "function arguments expected"); break; } - fs->stacksize = slevel; /* call will remove function and arguments */ + fs->stacklevel = slevel; /* call will remove function and arguments */ luaK_AB(fs, OP_CALL, slevel, MULT_RET, 0); } @@ -581,7 +606,7 @@ static int listfields (LexState *ls) { -static void constructor_part (LexState *ls, constdesc *cd) { +static void constructor_part (LexState *ls, Constdesc *cd) { switch (ls->token) { case ';': case '}': /* constructor_part -> empty */ cd->n = 0; @@ -627,12 +652,12 @@ static void constructor (LexState *ls) { int line = ls->linenumber; int pc = luaK_U(fs, OP_CREATETABLE, 0, 1); int nelems; - constdesc cd; + Constdesc cd; check(ls, '{'); constructor_part(ls, &cd); nelems = cd.n; if (ls->token == ';') { - constdesc other_cd; + Constdesc other_cd; next(ls); constructor_part(ls, &other_cd); if (cd.k == other_cd.k) /* repeated parts? */ @@ -825,14 +850,17 @@ static void whilestat (LexState *ls, int line) { FuncState *fs = ls->fs; int while_init = luaK_getlabel(fs); expdesc v; + Breaklabel bl; + enterbreak(fs, &bl); setline_and_next(ls); /* trace WHILE when looping */ expr(ls, &v); /* read condition */ luaK_goiftrue(fs, &v, 0); check(ls, TK_DO); block(ls); - luaK_fixjump(fs, luaK_S(fs, OP_JMP, 0, 0), while_init); + luaK_patchlist(fs, luaK_jump(fs), while_init); luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); check_END(ls, TK_WHILE, line); + leavebreak(fs, &bl); } @@ -841,12 +869,55 @@ static void repeatstat (LexState *ls, int line) { FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); expdesc v; + Breaklabel bl; + enterbreak(fs, &bl); setline_and_next(ls); /* trace REPEAT when looping */ block(ls); - check_match(ls, TK_UNTIL, TK_REPEAT, line); - expr(ls, &v); - luaK_goiftrue(fs, &v, 0); - luaK_patchlist(fs, v.u.l.f, repeat_init); + if (ls->token == TK_END) { + luaK_patchlist(fs, luaK_jump(fs), repeat_init); + next(ls); + } + else { + check_match(ls, TK_UNTIL, TK_REPEAT, line); + expr(ls, &v); + luaK_goiftrue(fs, &v, 0); + luaK_patchlist(fs, v.u.l.f, repeat_init); + } + leavebreak(fs, &bl); +} + + +static void test_and_bock (LexState *ls, expdesc *v) { + setline_and_next(ls); /* skip IF or ELSEIF */ + expr(ls, v); /* cond */ + luaK_goiftrue(ls->fs, v, 0); + setline(ls); /* to trace the THEN */ + check(ls, TK_THEN); + block(ls); /* `then' part */ +} + + +static void ifstat (LexState *ls, int line) { + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState *fs = ls->fs; + expdesc v; + int escapelist = NO_JUMP; + test_and_bock(ls, &v); /* IF cond THEN block */ + while (ls->token == TK_ELSEIF) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + test_and_bock(ls, &v); /* ELSEIF cond THEN block */ + } + if (ls->token == TK_ELSE) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + setline_and_next(ls); /* skip ELSE */ + block(ls); /* `else' part */ + } + else + luaK_concat(fs, &escapelist, v.u.l.f); + luaK_patchlist(fs, escapelist, luaK_getlabel(fs)); + check_END(ls, TK_IF, line); } @@ -932,42 +1003,11 @@ static void namestat (LexState *ls) { } -static void ifpart (LexState *ls) { - /* ifpart -> cond THEN block (ELSEIF ifpart | [ELSE block] END) */ - FuncState *fs = ls->fs; - expdesc v; - int elseinit; - setline_and_next(ls); /* skip IF or ELSEIF */ - expr(ls, &v); /* cond */ - luaK_goiftrue(fs, &v, 0); - setline(ls); /* to trace the THEN */ - check(ls, TK_THEN); - block(ls); /* `then' part */ - luaK_S(fs, OP_JMP, 0, 0); /* 2nd jump: over `else' part */ - elseinit = luaK_getlabel(fs); /* address of 2nd jump == elseinit-1 */ - if (ls->token == TK_ELSEIF) - ifpart(ls); - else if (ls->token == TK_ELSE) { - setline_and_next(ls); /* skip ELSE */ - block(ls); /* `else' part */ - } - if (fs->pc > elseinit) { /* is there an `else' part? */ - luaK_fixjump(fs, elseinit-1, luaK_getlabel(fs)); /* fix 2nd jump */ - } - else { /* no else part */ - fs->pc--; /* remove 2nd jump */ - elseinit = luaK_getlabel(fs); /* `elseinit' points to end */ - } - luaK_patchlist(fs, v.u.l.f, elseinit); /* fix 1st jump to `else' part */ -} - - static int stat (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->token) { - case TK_IF: /* stat -> IF ifpart END */ - ifpart(ls); - check_END(ls, TK_IF, line); + case TK_IF: /* stat -> ifstat */ + ifstat(ls, line); break; case TK_WHILE: /* stat -> whilestat */ @@ -1058,15 +1098,30 @@ static void body (LexState *ls, int needself, int line) { static void ret (LexState *ls) { - /* ret -> [RETURN explist sc] */ - if (ls->token == TK_RETURN) { - FuncState *fs = ls->fs; - int nexps; /* number of expressions returned */ - setline_and_next(ls); /* skip RETURN */ - nexps = explist(ls); - luaK_retcode(fs, ls->fs->nlocalvar, nexps); - fs->stacksize = fs->nlocalvar; /* removes all temp values */ - optional(ls, ';'); + /* ret -> [RETURN explist sc | BREAK sc] */ + FuncState *fs = ls->fs; + switch (ls->token) { + case TK_RETURN: { + int nexps; /* number of expressions returned */ + setline_and_next(ls); /* skip RETURN */ + nexps = explist(ls); + luaK_retcode(fs, ls->fs->nlocalvar, nexps); + fs->stacklevel = fs->nlocalvar; /* removes all temp values */ + optional(ls, ';'); + break; + } + case TK_BREAK: { + Breaklabel *bl = fs->bl; + int currentlevel = fs->stacklevel; + if (bl == NULL) + luaK_error(ls, "no breakable structure to break"); + setline_and_next(ls); /* skip BREAK */ + luaK_adjuststack(fs, currentlevel - bl->stacklevel); + luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); + optional(ls, ';'); + fs->stacklevel = currentlevel; + break; + } } } @@ -1076,7 +1131,7 @@ static void ret (LexState *ls) { static void chunk (LexState *ls) { /* chunk -> { stat [;] } ret */ while (stat(ls)) { - LUA_ASSERT(ls->L, ls->fs->stacksize == ls->fs->nlocalvar, + LUA_ASSERT(ls->L, ls->fs->stacklevel == ls->fs->nlocalvar, "stack size != # local vars"); optional(ls, ';'); } diff --git a/lparser.h b/lparser.h index 896b1eb9..64214861 100644 --- a/lparser.h +++ b/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.13 2000/03/13 20:37:16 roberto Exp roberto $ +** $Id: lparser.h,v 1.14 2000/03/24 17:26:08 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -34,8 +34,6 @@ typedef struct expdesc { } expdesc; -#define NO_JUMP (-1) /* marks end of patch list */ - /* state needed to generate code for a given function */ typedef struct FuncState { @@ -45,11 +43,12 @@ typedef struct FuncState { struct lua_State *L; /* copy of the Lua state */ int pc; /* next position to code */ int lasttarget; /* `pc' of last `jump target' */ - int stacksize; /* number of values on activation register */ + int stacklevel; /* number of values on activation register */ int nlocalvar; /* number of active local variables */ int nupvalues; /* number of upvalues */ int nvars; /* number of entries in f->locvars (-1 if no debug information) */ int lastsetline; /* line where last SETLINE was issued */ + struct Breaklabel *bl; /* chain of breakable blocks */ expdesc upvalues[MAXUPVALUES]; /* upvalues */ TString *localvar[MAXLOCALS]; /* store local variable names */ } FuncState; -- cgit v1.2.3-55-g6feb