aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2011-02-10 12:50:41 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2011-02-10 12:50:41 -0200
commitbf8b08295aa2f4b66aeb7d8313d464ccd80c0b0c (patch)
tree5965feb819f09902846bcb5af86ed4b5e7af85b9
parent3f5b56c48b51b0e4e2c439f1d0bf717b018c1aee (diff)
downloadlua-bf8b08295aa2f4b66aeb7d8313d464ccd80c0b0c.tar.gz
lua-bf8b08295aa2f4b66aeb7d8313d464ccd80c0b0c.tar.bz2
lua-bf8b08295aa2f4b66aeb7d8313d464ccd80c0b0c.zip
'break' coded as 'goto' + small bug when closing multiple gotos
to the same label
-rw-r--r--lparser.c111
1 files changed, 52 insertions, 59 deletions
diff --git a/lparser.c b/lparser.c
index cf0882f8..9da2e2c1 100644
--- a/lparser.c
+++ b/lparser.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lparser.c,v 2.102 2011/02/09 16:51:28 roberto Exp roberto $ 2** $Id: lparser.c,v 2.103 2011/02/09 17:03:18 roberto Exp $
3** Lua Parser 3** Lua Parser
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -41,7 +41,6 @@
41*/ 41*/
42typedef struct BlockCnt { 42typedef struct BlockCnt {
43 struct BlockCnt *previous; /* chain */ 43 struct BlockCnt *previous; /* chain */
44 int breaklist; /* list of jumps out of this loop */
45 int firstlabel; /* index of first label in this block */ 44 int firstlabel; /* index of first label in this block */
46 int firstgoto; /* index of first pending goto in this block */ 45 int firstgoto; /* index of first pending goto in this block */
47 lu_byte nactvar; /* # active locals outside the block */ 46 lu_byte nactvar; /* # active locals outside the block */
@@ -380,16 +379,31 @@ static int findlabel (LexState *ls, int g) {
380} 379}
381 380
382 381
382static int newlabelentry (LexState *ls, Labellist *l, TString *name,
383 int line, int pc) {
384 int n = l->n;
385 luaM_growvector(ls->L, l->arr, n, l->size, Labeldesc, MAX_INT, "labels");
386 l->arr[n].name = name;
387 l->arr[n].line = line;
388 l->arr[n].nactvar = ls->fs->nactvar;
389 l->arr[n].pc = pc;
390 l->n++;
391 return n;
392}
393
394
383/* 395/*
384** check whether new label 'lb' matches any pending goto in current 396** check whether new label 'lb' matches any pending gotos in current
385** block; solves forward jumps 397** block; solves forward jumps
386*/ 398*/
387static void findgotos (LexState *ls, Labeldesc *lb) { 399static void findgotos (LexState *ls, Labeldesc *lb) {
388 int i;
389 Dyndata *dyd = ls->dyd; 400 Dyndata *dyd = ls->dyd;
390 for (i = ls->fs->bl->firstgoto; i < dyd->gt.n; i++) { 401 int i = ls->fs->bl->firstgoto;
402 while (i < dyd->gt.n) {
391 if (eqstr(dyd->gt.arr[i].name, lb->name)) 403 if (eqstr(dyd->gt.arr[i].name, lb->name))
392 closegoto(ls, i, lb); 404 closegoto(ls, i, lb);
405 else
406 i++;
393 } 407 }
394} 408}
395 409
@@ -419,7 +433,6 @@ static void movegotosout (FuncState *fs, BlockCnt *bl) {
419 433
420 434
421static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { 435static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
422 bl->breaklist = NO_JUMP;
423 bl->isloop = isloop; 436 bl->isloop = isloop;
424 bl->nactvar = fs->nactvar; 437 bl->nactvar = fs->nactvar;
425 bl->firstlabel = fs->ls->dyd->label.n; 438 bl->firstlabel = fs->ls->dyd->label.n;
@@ -431,30 +444,48 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
431} 444}
432 445
433 446
447/*
448** create a label named "break" to resolve break statements
449*/
450static void breaklabel (LexState *ls) {
451 TString *n = luaS_new(ls->L, "break");
452 int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc);
453 findgotos(ls, &ls->dyd->label.arr[l]);
454}
455
456/*
457** generates an error for an undefined 'goto'; choose appropriate
458** message when label name is a resserved word (which can only be 'break')
459*/
460static void undefgoto (LexState *ls, Labeldesc *gt) {
461 const char *msg = (gt->name->tsv.reserved > 0)
462 ? "<%s> at line %d not inside a loop"
463 : "label " LUA_QS " (<goto> at line %d) undefined";
464 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
465 semerror(ls, msg);
466}
467
468
434static void leaveblock (FuncState *fs) { 469static void leaveblock (FuncState *fs) {
435 BlockCnt *bl = fs->bl; 470 BlockCnt *bl = fs->bl;
436 LexState *ls = fs->ls; 471 LexState *ls = fs->ls;
437 fs->bl = bl->previous;
438 removevars(fs, bl->nactvar);
439 ls->dyd->label.n = bl->firstlabel; /* remove local labels */
440 if (bl->previous) /* inner block? */
441 movegotosout(fs, bl); /* update pending gotos to outer block */
442 else if (bl->firstgoto < ls->dyd->gt.n) { /* pending gotos in outer block? */
443 Labeldesc *gt = &ls->dyd->gt.arr[bl->firstgoto];
444 const char *msg = luaO_pushfstring(ls->L,
445 "label " LUA_QS " (<goto> at line %d) undefined",
446 getstr(gt->name), gt->line);
447 semerror(ls, msg);
448 }
449 if (bl->previous && bl->upval) { 472 if (bl->previous && bl->upval) {
450 /* create a 'jump to here' to close upvalues */ 473 /* create a 'jump to here' to close upvalues */
451 int j = luaK_jump(fs); 474 int j = luaK_jump(fs);
452 luaK_patchclose(fs, j, bl->nactvar); 475 luaK_patchclose(fs, j, bl->nactvar);
453 luaK_patchtohere(fs, j); 476 luaK_patchtohere(fs, j);
454 } 477 }
478 if (bl->isloop)
479 breaklabel(ls); /* close pending breaks */
480 fs->bl = bl->previous;
481 removevars(fs, bl->nactvar);
455 lua_assert(bl->nactvar == fs->nactvar); 482 lua_assert(bl->nactvar == fs->nactvar);
456 fs->freereg = fs->nactvar; /* free registers */ 483 fs->freereg = fs->nactvar; /* free registers */
457 luaK_patchtohere(fs, bl->breaklist); 484 ls->dyd->label.n = bl->firstlabel; /* remove local labels */
485 if (bl->previous) /* inner block? */
486 movegotosout(fs, bl); /* update pending gotos to outer block */
487 else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
488 undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
458} 489}
459 490
460 491
@@ -1070,7 +1101,6 @@ static void block (LexState *ls) {
1070 BlockCnt bl; 1101 BlockCnt bl;
1071 enterblock(fs, &bl, 0); 1102 enterblock(fs, &bl, 0);
1072 statlist(ls); 1103 statlist(ls);
1073 lua_assert(bl.breaklist == NO_JUMP);
1074 leaveblock(fs); 1104 leaveblock(fs);
1075} 1105}
1076 1106
@@ -1159,44 +1189,6 @@ static int cond (LexState *ls) {
1159} 1189}
1160 1190
1161 1191
1162/* code a break statement. The last 'if' decides the need to close
1163 upvalues when leaving the block. If the block has upvalues, it
1164 must be closed. If it has local variables and any label
1165 before the break, those variables must be closed too, as they
1166 may be used as upvalues after the break and through a goto
1167 be exited through this break.
1168*/
1169static void breakstat (LexState *ls) {
1170 FuncState *fs = ls->fs;
1171 BlockCnt *bl = fs->bl;
1172 int upval = 0;
1173 while (bl && !bl->isloop) {
1174 upval |= bl->upval;
1175 bl = bl->previous;
1176 }
1177 if (!bl)
1178 semerror(ls, "no loop to break");
1179 luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
1180 if (upval ||
1181 (fs->nactvar > bl->nactvar &&
1182 ls->dyd->label.n > bl->firstlabel))
1183 luaK_patchclose(fs, bl->breaklist, bl->nactvar);
1184}
1185
1186
1187static int newlabelentry (LexState *ls, Labellist *l, TString *name,
1188 int line, int pc) {
1189 int n = l->n;
1190 luaM_growvector(ls->L, l->arr, l->n, l->size, Labeldesc, MAX_INT, "labels");
1191 l->arr[n].name = name;
1192 l->arr[n].line = line;
1193 l->arr[n].nactvar = ls->fs->nactvar;
1194 l->arr[n].pc = pc;
1195 l->n++;
1196 return n;
1197}
1198
1199
1200static void gotostat (LexState *ls, TString *label, int line) { 1192static void gotostat (LexState *ls, TString *label, int line) {
1201 /* create new entry for this goto */ 1193 /* create new entry for this goto */
1202 int g = newlabelentry(ls, &ls->dyd->gt, label, line, luaK_jump(ls->fs)); 1194 int g = newlabelentry(ls, &ls->dyd->gt, label, line, luaK_jump(ls->fs));
@@ -1551,7 +1543,8 @@ static int statement (LexState *ls) {
1551 } 1543 }
1552 case TK_BREAK: { /* stat -> breakstat */ 1544 case TK_BREAK: { /* stat -> breakstat */
1553 luaX_next(ls); /* skip BREAK */ 1545 luaX_next(ls); /* skip BREAK */
1554 breakstat(ls); 1546 /* code it as "goto 'break'" */
1547 gotostat(ls, luaS_new(ls->L, "break"), line);
1555 return 1; /* must be last statement */ 1548 return 1; /* must be last statement */
1556 } 1549 }
1557 case TK_GOTO: { /* stat -> 'goto' NAME */ 1550 case TK_GOTO: { /* stat -> 'goto' NAME */