Roberto Ierusalimschy 25 роки тому
батько
коміт
22329e4cdf
6 змінених файлів з 168 додано та 117 видалено
  1. 42 50
      lcode.c
  2. 6 2
      lcode.h
  3. 3 2
      llex.c
  4. 2 2
      llex.h
  5. 112 57
      lparser.c
  6. 3 4
      lparser.h

+ 42 - 50
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;
     }
   }
 }

+ 6 - 2
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);

+ 3 - 2
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", "", "..", "...", "==", ">=", "<=", "~=", "", "", "<eof>"};
 

+ 2 - 2
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 */

+ 112 - 57
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, "<eof> 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, ';');
   }

+ 3 - 4
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;