diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-02-04 15:34:43 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-02-04 15:34:43 -0200 |
| commit | 7cc0e63d8a5bd45eabd328c398f02a933e07746d (patch) | |
| tree | 94a00b4e19c3c1ea0c6e3ee2e3dbb036d960f5c0 | |
| parent | a4a8914c2097bdcaaa4e82c5fd1c9b0c7371e432 (diff) | |
| download | lua-7cc0e63d8a5bd45eabd328c398f02a933e07746d.tar.gz lua-7cc0e63d8a5bd45eabd328c398f02a933e07746d.tar.bz2 lua-7cc0e63d8a5bd45eabd328c398f02a933e07746d.zip | |
first implementation of 'goto'
| -rw-r--r-- | ldo.c | 11 | ||||
| -rw-r--r-- | llex.h | 4 | ||||
| -rw-r--r-- | lparser.c | 188 | ||||
| -rw-r--r-- | lparser.h | 47 |
4 files changed, 227 insertions, 23 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldo.c,v 2.89 2010/09/30 17:21:31 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.90 2010/10/25 19:01:37 roberto Exp roberto $ |
| 3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -617,6 +617,8 @@ struct SParser { /* data to `f_parser' */ | |||
| 617 | ZIO *z; | 617 | ZIO *z; |
| 618 | Mbuffer buff; /* buffer to be used by the scanner */ | 618 | Mbuffer buff; /* buffer to be used by the scanner */ |
| 619 | Varlist varl; /* list of local variables (to be used by the parser) */ | 619 | Varlist varl; /* list of local variables (to be used by the parser) */ |
| 620 | Gotolist gtl; /* list of pending gotos (") */ | ||
| 621 | Labellist labell; /* list of active labels (") */ | ||
| 620 | const char *name; | 622 | const char *name; |
| 621 | }; | 623 | }; |
| 622 | 624 | ||
| @@ -628,7 +630,8 @@ static void f_parser (lua_State *L, void *ud) { | |||
| 628 | int c = luaZ_lookahead(p->z); | 630 | int c = luaZ_lookahead(p->z); |
| 629 | tf = (c == LUA_SIGNATURE[0]) | 631 | tf = (c == LUA_SIGNATURE[0]) |
| 630 | ? luaU_undump(L, p->z, &p->buff, p->name) | 632 | ? luaU_undump(L, p->z, &p->buff, p->name) |
| 631 | : luaY_parser(L, p->z, &p->buff, &p->varl, p->name); | 633 | : luaY_parser(L, p->z, &p->buff, &p->varl, |
| 634 | &p->gtl, &p->labell, p->name); | ||
| 632 | setptvalue2s(L, L->top, tf); | 635 | setptvalue2s(L, L->top, tf); |
| 633 | incr_top(L); | 636 | incr_top(L); |
| 634 | cl = luaF_newLclosure(L, tf); | 637 | cl = luaF_newLclosure(L, tf); |
| @@ -644,10 +647,14 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { | |||
| 644 | L->nny++; /* cannot yield during parsing */ | 647 | L->nny++; /* cannot yield during parsing */ |
| 645 | p.z = z; p.name = name; | 648 | p.z = z; p.name = name; |
| 646 | p.varl.actvar = NULL; p.varl.nactvar = p.varl.actvarsize = 0; | 649 | p.varl.actvar = NULL; p.varl.nactvar = p.varl.actvarsize = 0; |
| 650 | p.gtl.gt = NULL; p.gtl.ngt = p.gtl.gtsize = 0; | ||
| 651 | p.labell.label = NULL; p.labell.nlabel = p.labell.labelsize = 0; | ||
| 647 | luaZ_initbuffer(L, &p.buff); | 652 | luaZ_initbuffer(L, &p.buff); |
| 648 | status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); | 653 | status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); |
| 649 | luaZ_freebuffer(L, &p.buff); | 654 | luaZ_freebuffer(L, &p.buff); |
| 650 | luaM_freearray(L, p.varl.actvar, p.varl.actvarsize); | 655 | luaM_freearray(L, p.varl.actvar, p.varl.actvarsize); |
| 656 | luaM_freearray(L, p.gtl.gt, p.gtl.gtsize); | ||
| 657 | luaM_freearray(L, p.labell.label, p.labell.labelsize); | ||
| 651 | L->nny--; | 658 | L->nny--; |
| 652 | return status; | 659 | return status; |
| 653 | } | 660 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: llex.h,v 1.65 2010/04/05 16:35:37 roberto Exp roberto $ | 2 | ** $Id: llex.h,v 1.66 2011/02/02 14:55:17 roberto Exp roberto $ |
| 3 | ** Lexical Analyzer | 3 | ** Lexical Analyzer |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -59,6 +59,8 @@ typedef struct LexState { | |||
| 59 | ZIO *z; /* input stream */ | 59 | ZIO *z; /* input stream */ |
| 60 | Mbuffer *buff; /* buffer for tokens */ | 60 | Mbuffer *buff; /* buffer for tokens */ |
| 61 | struct Varlist *varl; /* list of all active local variables */ | 61 | struct Varlist *varl; /* list of all active local variables */ |
| 62 | struct Gotolist *gtl; /* list of pending gotos */ | ||
| 63 | struct Labellist *labell; /* list of active labels */ | ||
| 62 | TString *source; /* current source name */ | 64 | TString *source; /* current source name */ |
| 63 | TString *envn; /* environment variable name */ | 65 | TString *envn; /* environment variable name */ |
| 64 | char decpoint; /* locale decimal point */ | 66 | char decpoint; /* locale decimal point */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lparser.c,v 2.95 2011/01/26 16:30:02 roberto Exp roberto $ | 2 | ** $Id: lparser.c,v 2.96 2011/02/01 18:03:10 roberto Exp roberto $ |
| 3 | ** Lua Parser | 3 | ** Lua Parser |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -42,7 +42,9 @@ | |||
| 42 | typedef struct BlockCnt { | 42 | typedef struct BlockCnt { |
| 43 | struct BlockCnt *previous; /* chain */ | 43 | struct BlockCnt *previous; /* chain */ |
| 44 | int breaklist; /* list of jumps out of this loop */ | 44 | int breaklist; /* list of jumps out of this loop */ |
| 45 | lu_byte nactvar; /* # active locals outside the breakable structure */ | 45 | int firstlabel; /* index (in Labellist) of first label in this block */ |
| 46 | int firstgoto; /* index (in Gotolist) of first pending goto in this block */ | ||
| 47 | lu_byte nactvar; /* # active locals outside the block */ | ||
| 46 | lu_byte upval; /* true if some variable in the block is an upvalue */ | 48 | lu_byte upval; /* true if some variable in the block is an upvalue */ |
| 47 | lu_byte isbreakable; /* true if `block' is a loop */ | 49 | lu_byte isbreakable; /* true if `block' is a loop */ |
| 48 | } BlockCnt; | 50 | } BlockCnt; |
| @@ -52,7 +54,7 @@ typedef struct BlockCnt { | |||
| 52 | /* | 54 | /* |
| 53 | ** prototypes for recursive non-terminal functions | 55 | ** prototypes for recursive non-terminal functions |
| 54 | */ | 56 | */ |
| 55 | static void chunk (LexState *ls); | 57 | static void statlist (LexState *ls); |
| 56 | static void expr (LexState *ls, expdesc *v); | 58 | static void expr (LexState *ls, expdesc *v); |
| 57 | 59 | ||
| 58 | 60 | ||
| @@ -172,7 +174,7 @@ static void new_localvar (LexState *ls, TString *name) { | |||
| 172 | checklimit(fs, vl->nactvar + 1 - fs->firstlocal, | 174 | checklimit(fs, vl->nactvar + 1 - fs->firstlocal, |
| 173 | MAXVARS, "local variables"); | 175 | MAXVARS, "local variables"); |
| 174 | luaM_growvector(ls->L, vl->actvar, vl->nactvar + 1, | 176 | luaM_growvector(ls->L, vl->actvar, vl->nactvar + 1, |
| 175 | vl->actvarsize, vardesc, MAX_INT, "local variables"); | 177 | vl->actvarsize, Vardesc, MAX_INT, "local variables"); |
| 176 | vl->actvar[vl->nactvar++].idx = cast(unsigned short, reg); | 178 | vl->actvar[vl->nactvar++].idx = cast(unsigned short, reg); |
| 177 | } | 179 | } |
| 178 | 180 | ||
| @@ -327,10 +329,93 @@ static void enterlevel (LexState *ls) { | |||
| 327 | #define leavelevel(ls) (G((ls)->L)->nCcalls--) | 329 | #define leavelevel(ls) (G((ls)->L)->nCcalls--) |
| 328 | 330 | ||
| 329 | 331 | ||
| 332 | static void closegoto (LexState *ls, int g, Labeldesc *label) { | ||
| 333 | int i; | ||
| 334 | FuncState *fs = ls->fs; | ||
| 335 | Gotodesc *gt = &ls->gtl->gt[g]; | ||
| 336 | lua_assert(gt->name == label->name); | ||
| 337 | if (gt->currlevel < label->nactvar) { | ||
| 338 | const char *msg = luaO_pushfstring(ls->L, | ||
| 339 | "<goto> at line %d attemps to jump into the scope of local " LUA_QS, | ||
| 340 | gt->line, getstr(getlocvar(fs, gt->currlevel)->varname));; | ||
| 341 | luaX_syntaxerror(ls, msg); | ||
| 342 | } | ||
| 343 | luaK_patchlist(fs, gt->pc, label->pc); | ||
| 344 | /* remove goto from pending list */ | ||
| 345 | for (i = g; i < ls->gtl->ngt - 1; i++) | ||
| 346 | ls->gtl->gt[i] = ls->gtl->gt[i + 1]; | ||
| 347 | ls->gtl->ngt--; | ||
| 348 | } | ||
| 349 | |||
| 350 | |||
| 351 | /* | ||
| 352 | ** try to close a goto with existing labels; this solves backward jumps | ||
| 353 | */ | ||
| 354 | static int findlabel (LexState *ls, int g) { | ||
| 355 | int i; | ||
| 356 | BlockCnt *bl = ls->fs->bl; | ||
| 357 | Labellist *labell = ls->labell; | ||
| 358 | Gotodesc *gt = &ls->gtl->gt[g]; | ||
| 359 | /* check labels in current block for a match */ | ||
| 360 | for (i = bl->firstlabel; i < labell->nlabel; i++) { | ||
| 361 | Labeldesc *lb = &labell->label[i]; | ||
| 362 | if (lb->name == gt->name) { | ||
| 363 | lua_assert(labell->label[i].pc <= gt->pc); | ||
| 364 | if (gt->currlevel > lb->nactvar && | ||
| 365 | (bl->upval || ls->labell->nlabel > bl->firstlabel)) | ||
| 366 | luaK_patchclose(ls->fs, gt->pc, lb->nactvar); | ||
| 367 | closegoto(ls, g, lb); /* close it */ | ||
| 368 | return 1; | ||
| 369 | } | ||
| 370 | } | ||
| 371 | return 0; /* label not found; cannot close goto */ | ||
| 372 | } | ||
| 373 | |||
| 374 | |||
| 375 | /* | ||
| 376 | ** check whether new label 'lb' matches any pending goto in current | ||
| 377 | ** block; solves forward jumps | ||
| 378 | */ | ||
| 379 | static void findgotos (LexState *ls, Labeldesc *lb) { | ||
| 380 | int i; | ||
| 381 | Gotolist *gtl = ls->gtl; | ||
| 382 | for (i = ls->fs->bl->firstgoto; i < gtl->ngt; i++) { | ||
| 383 | if (gtl->gt[i].name == lb->name) | ||
| 384 | closegoto(ls, i, lb); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 388 | |||
| 389 | /* | ||
| 390 | ** "export" pending gotos to outer level, to check them against | ||
| 391 | ** outer labels; if the block being exited has upvalues, and | ||
| 392 | ** the goto exists the scope of any variable (which can be the | ||
| 393 | ** upvalue), close those variables being exited. | ||
| 394 | */ | ||
| 395 | static void movegotosout (FuncState *fs, BlockCnt *bl) { | ||
| 396 | int i = bl->firstgoto; | ||
| 397 | LexState *ls = fs->ls; | ||
| 398 | /* correct pending gotos to current block and try to close it | ||
| 399 | with visible labels */ | ||
| 400 | while (i < ls->gtl->ngt) { | ||
| 401 | Gotodesc *gt = &ls->gtl->gt[i]; | ||
| 402 | if (gt->currlevel > bl->nactvar) { | ||
| 403 | if (bl->upval) | ||
| 404 | luaK_patchclose(fs, gt->pc, bl->nactvar); | ||
| 405 | gt->currlevel = bl->nactvar; | ||
| 406 | } | ||
| 407 | if (!findlabel(ls, i)) | ||
| 408 | i++; /* move to next one */ | ||
| 409 | } | ||
| 410 | } | ||
| 411 | |||
| 412 | |||
| 330 | static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { | 413 | static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { |
| 331 | bl->breaklist = NO_JUMP; | 414 | bl->breaklist = NO_JUMP; |
| 332 | bl->isbreakable = isbreakable; | 415 | bl->isbreakable = isbreakable; |
| 333 | bl->nactvar = fs->nactvar; | 416 | bl->nactvar = fs->nactvar; |
| 417 | bl->firstlabel = fs->ls->labell->nlabel; | ||
| 418 | bl->firstgoto = fs->ls->gtl->ngt; | ||
| 334 | bl->upval = 0; | 419 | bl->upval = 0; |
| 335 | bl->previous = fs->bl; | 420 | bl->previous = fs->bl; |
| 336 | fs->bl = bl; | 421 | fs->bl = bl; |
| @@ -342,6 +427,8 @@ static void leaveblock (FuncState *fs) { | |||
| 342 | BlockCnt *bl = fs->bl; | 427 | BlockCnt *bl = fs->bl; |
| 343 | fs->bl = bl->previous; | 428 | fs->bl = bl->previous; |
| 344 | removevars(fs, bl->nactvar); | 429 | removevars(fs, bl->nactvar); |
| 430 | fs->ls->labell->nlabel = bl->firstlabel; /* remove local labels */ | ||
| 431 | movegotosout(fs, bl); | ||
| 345 | if (bl->upval) | 432 | if (bl->upval) |
| 346 | luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); | 433 | luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); |
| 347 | /* a block either controls scope or breaks (never both) */ | 434 | /* a block either controls scope or breaks (never both) */ |
| @@ -445,8 +532,24 @@ static void open_mainfunc (LexState *ls, FuncState *fs) { | |||
| 445 | } | 532 | } |
| 446 | 533 | ||
| 447 | 534 | ||
| 535 | static void mainblock (LexState *ls, FuncState *fs) { | ||
| 536 | BlockCnt bl; | ||
| 537 | enterblock(fs, &bl, 0); | ||
| 538 | statlist(ls); /* read main block */ | ||
| 539 | if (bl.firstgoto < ls->gtl->ngt) { /* check pending gotos */ | ||
| 540 | Gotodesc *gt = &ls->gtl->gt[bl.firstgoto]; | ||
| 541 | const char *msg = luaO_pushfstring(ls->L, | ||
| 542 | "label " LUA_QS " (<goto> at line %d) undefined", | ||
| 543 | getstr(gt->name), gt->line); | ||
| 544 | luaX_syntaxerror(ls, msg); | ||
| 545 | } | ||
| 546 | bl.upval = 0; /* RETURN will close any pending upvalue */ | ||
| 547 | leaveblock(fs); | ||
| 548 | } | ||
| 549 | |||
| 550 | |||
| 448 | Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, | 551 | Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, |
| 449 | const char *name) { | 552 | Gotolist *gtl, Labellist *labell, const char *name) { |
| 450 | LexState lexstate; | 553 | LexState lexstate; |
| 451 | FuncState funcstate; | 554 | FuncState funcstate; |
| 452 | TString *tname = luaS_new(L, name); | 555 | TString *tname = luaS_new(L, name); |
| @@ -454,10 +557,12 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, | |||
| 454 | incr_top(L); | 557 | incr_top(L); |
| 455 | lexstate.buff = buff; | 558 | lexstate.buff = buff; |
| 456 | lexstate.varl = varl; | 559 | lexstate.varl = varl; |
| 560 | lexstate.gtl = gtl; | ||
| 561 | lexstate.labell = labell; | ||
| 457 | luaX_setinput(L, &lexstate, z, tname); | 562 | luaX_setinput(L, &lexstate, z, tname); |
| 458 | open_mainfunc(&lexstate, &funcstate); | 563 | open_mainfunc(&lexstate, &funcstate); |
| 459 | luaX_next(&lexstate); /* read first token */ | 564 | luaX_next(&lexstate); /* read first token */ |
| 460 | chunk(&lexstate); /* read main chunk */ | 565 | mainblock(&lexstate, &funcstate); |
| 461 | check(&lexstate, TK_EOS); | 566 | check(&lexstate, TK_EOS); |
| 462 | close_func(&lexstate); | 567 | close_func(&lexstate); |
| 463 | L->top--; /* pop name */ | 568 | L->top--; /* pop name */ |
| @@ -645,7 +750,7 @@ static void parlist (LexState *ls) { | |||
| 645 | 750 | ||
| 646 | 751 | ||
| 647 | static void body (LexState *ls, expdesc *e, int needself, int line) { | 752 | static void body (LexState *ls, expdesc *e, int needself, int line) { |
| 648 | /* body -> `(' parlist `)' chunk END */ | 753 | /* body -> `(' parlist `)' block END */ |
| 649 | FuncState new_fs; | 754 | FuncState new_fs; |
| 650 | open_func(ls, &new_fs); | 755 | open_func(ls, &new_fs); |
| 651 | new_fs.f->linedefined = line; | 756 | new_fs.f->linedefined = line; |
| @@ -656,7 +761,7 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { | |||
| 656 | } | 761 | } |
| 657 | parlist(ls); | 762 | parlist(ls); |
| 658 | checknext(ls, ')'); | 763 | checknext(ls, ')'); |
| 659 | chunk(ls); | 764 | mainblock(ls, &new_fs); |
| 660 | new_fs.f->lastlinedefined = ls->linenumber; | 765 | new_fs.f->lastlinedefined = ls->linenumber; |
| 661 | check_match(ls, TK_END, TK_FUNCTION, line); | 766 | check_match(ls, TK_END, TK_FUNCTION, line); |
| 662 | codeclosure(ls, new_fs.f, e); | 767 | codeclosure(ls, new_fs.f, e); |
| @@ -949,11 +1054,11 @@ static int block_follow (int token) { | |||
| 949 | 1054 | ||
| 950 | 1055 | ||
| 951 | static void block (LexState *ls) { | 1056 | static void block (LexState *ls) { |
| 952 | /* block -> chunk */ | 1057 | /* block -> statlist */ |
| 953 | FuncState *fs = ls->fs; | 1058 | FuncState *fs = ls->fs; |
| 954 | BlockCnt bl; | 1059 | BlockCnt bl; |
| 955 | enterblock(fs, &bl, 0); | 1060 | enterblock(fs, &bl, 0); |
| 956 | chunk(ls); | 1061 | statlist(ls); |
| 957 | lua_assert(bl.breaklist == NO_JUMP); | 1062 | lua_assert(bl.breaklist == NO_JUMP); |
| 958 | leaveblock(fs); | 1063 | leaveblock(fs); |
| 959 | } | 1064 | } |
| @@ -1043,6 +1148,13 @@ static int cond (LexState *ls) { | |||
| 1043 | } | 1148 | } |
| 1044 | 1149 | ||
| 1045 | 1150 | ||
| 1151 | /* code a break statement. The last 'if' decides the need to close | ||
| 1152 | upvalues when leaving the block. If the block has upvalues, it | ||
| 1153 | must be closed. If it has local variables and any label | ||
| 1154 | before the break, those variables must be closed too, as they | ||
| 1155 | may be used as upvalues after the break and through a goto | ||
| 1156 | be exited through this break. | ||
| 1157 | */ | ||
| 1046 | static void breakstat (LexState *ls) { | 1158 | static void breakstat (LexState *ls) { |
| 1047 | FuncState *fs = ls->fs; | 1159 | FuncState *fs = ls->fs; |
| 1048 | BlockCnt *bl = fs->bl; | 1160 | BlockCnt *bl = fs->bl; |
| @@ -1054,11 +1166,49 @@ static void breakstat (LexState *ls) { | |||
| 1054 | if (!bl) | 1166 | if (!bl) |
| 1055 | luaX_syntaxerror(ls, "no loop to break"); | 1167 | luaX_syntaxerror(ls, "no loop to break"); |
| 1056 | luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); | 1168 | luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); |
| 1057 | if (upval) | 1169 | if (upval || |
| 1170 | (fs->nactvar > bl->nactvar && | ||
| 1171 | ls->labell->nlabel > bl->firstlabel)) | ||
| 1058 | luaK_patchclose(fs, bl->breaklist, bl->nactvar); | 1172 | luaK_patchclose(fs, bl->breaklist, bl->nactvar); |
| 1059 | } | 1173 | } |
| 1060 | 1174 | ||
| 1061 | 1175 | ||
| 1176 | static void gotostat (LexState *ls, TString *label, int line) { | ||
| 1177 | Gotolist *gtl = ls->gtl; | ||
| 1178 | int g = gtl->ngt; /* index of new goto being created */ | ||
| 1179 | /* create new entry for this goto */ | ||
| 1180 | luaM_growvector(ls->L, gtl->gt, gtl->ngt, gtl->gtsize, | ||
| 1181 | Gotodesc, MAX_INT, "labels"); | ||
| 1182 | gtl->gt[g].name = label; | ||
| 1183 | gtl->gt[g].line = line; | ||
| 1184 | gtl->gt[g].currlevel = ls->fs->nactvar; | ||
| 1185 | gtl->gt[g].pc = luaK_jump(ls->fs); /* create jump instruction */ | ||
| 1186 | gtl->ngt++; | ||
| 1187 | findlabel(ls, g); | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | |||
| 1191 | static void labelstat (LexState *ls, TString *label) { | ||
| 1192 | /* label -> '@' NAME ':' */ | ||
| 1193 | FuncState *fs = ls->fs; | ||
| 1194 | Labellist *labell = ls->labell; | ||
| 1195 | int l = labell->nlabel; /* index of new label being created */ | ||
| 1196 | checknext(ls, ':'); | ||
| 1197 | /* create new entry for this label */ | ||
| 1198 | luaM_growvector(ls->L, labell->label, labell->nlabel, labell->labelsize, | ||
| 1199 | Labeldesc, MAX_INT, "labels"); | ||
| 1200 | labell->label[l].name = label; | ||
| 1201 | labell->label[l].pc = fs->pc; | ||
| 1202 | /* if label is last statement in the block, | ||
| 1203 | assume that local variables are already out of scope */ | ||
| 1204 | labell->label[l].nactvar = (ls->t.token == TK_END) | ||
| 1205 | ? fs->bl->nactvar | ||
| 1206 | : fs->nactvar; | ||
| 1207 | labell->nlabel++; | ||
| 1208 | findgotos(ls, &labell->label[l]); | ||
| 1209 | } | ||
| 1210 | |||
| 1211 | |||
| 1062 | static void whilestat (LexState *ls, int line) { | 1212 | static void whilestat (LexState *ls, int line) { |
| 1063 | /* whilestat -> WHILE cond DO block END */ | 1213 | /* whilestat -> WHILE cond DO block END */ |
| 1064 | FuncState *fs = ls->fs; | 1214 | FuncState *fs = ls->fs; |
| @@ -1087,7 +1237,7 @@ static void repeatstat (LexState *ls, int line) { | |||
| 1087 | enterblock(fs, &bl1, 1); /* loop block */ | 1237 | enterblock(fs, &bl1, 1); /* loop block */ |
| 1088 | enterblock(fs, &bl2, 0); /* scope block */ | 1238 | enterblock(fs, &bl2, 0); /* scope block */ |
| 1089 | luaX_next(ls); /* skip REPEAT */ | 1239 | luaX_next(ls); /* skip REPEAT */ |
| 1090 | chunk(ls); | 1240 | statlist(ls); |
| 1091 | check_match(ls, TK_UNTIL, TK_REPEAT, line); | 1241 | check_match(ls, TK_UNTIL, TK_REPEAT, line); |
| 1092 | condexit = cond(ls); /* read condition (inside scope block) */ | 1242 | condexit = cond(ls); /* read condition (inside scope block) */ |
| 1093 | if (!bl2.upval) { /* no upvalues? */ | 1243 | if (!bl2.upval) { /* no upvalues? */ |
| @@ -1382,6 +1532,11 @@ static int statement (LexState *ls) { | |||
| 1382 | localstat(ls); | 1532 | localstat(ls); |
| 1383 | return 0; | 1533 | return 0; |
| 1384 | } | 1534 | } |
| 1535 | case '@': { /* stat -> label */ | ||
| 1536 | luaX_next(ls); /* skip '@' */ | ||
| 1537 | labelstat(ls, str_checkname(ls)); | ||
| 1538 | return 0; | ||
| 1539 | } | ||
| 1385 | case TK_RETURN: { /* stat -> retstat */ | 1540 | case TK_RETURN: { /* stat -> retstat */ |
| 1386 | luaX_next(ls); /* skip RETURN */ | 1541 | luaX_next(ls); /* skip RETURN */ |
| 1387 | retstat(ls); | 1542 | retstat(ls); |
| @@ -1392,6 +1547,11 @@ static int statement (LexState *ls) { | |||
| 1392 | breakstat(ls); | 1547 | breakstat(ls); |
| 1393 | return 1; /* must be last statement */ | 1548 | return 1; /* must be last statement */ |
| 1394 | } | 1549 | } |
| 1550 | case TK_GOTO: { /* stat -> 'goto' NAME */ | ||
| 1551 | luaX_next(ls); /* skip GOTO */ | ||
| 1552 | gotostat(ls, str_checkname(ls), line); | ||
| 1553 | return 0; | ||
| 1554 | } | ||
| 1395 | default: { /* stat -> func | assignment */ | 1555 | default: { /* stat -> func | assignment */ |
| 1396 | exprstat(ls); | 1556 | exprstat(ls); |
| 1397 | return 0; | 1557 | return 0; |
| @@ -1400,8 +1560,8 @@ static int statement (LexState *ls) { | |||
| 1400 | } | 1560 | } |
| 1401 | 1561 | ||
| 1402 | 1562 | ||
| 1403 | static void chunk (LexState *ls) { | 1563 | static void statlist (LexState *ls) { |
| 1404 | /* chunk -> { stat [`;'] } */ | 1564 | /* statlist -> { stat [`;'] } */ |
| 1405 | int islast = 0; | 1565 | int islast = 0; |
| 1406 | enterlevel(ls); | 1566 | enterlevel(ls); |
| 1407 | while (!islast && !block_follow(ls->t.token)) { | 1567 | while (!islast && !block_follow(ls->t.token)) { |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lparser.h,v 1.64 2010/07/02 20:42:40 roberto Exp roberto $ | 2 | ** $Id: lparser.h,v 1.65 2010/07/07 16:27:29 roberto Exp roberto $ |
| 3 | ** Lua Parser | 3 | ** Lua Parser |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -53,19 +53,53 @@ typedef struct expdesc { | |||
| 53 | } expdesc; | 53 | } expdesc; |
| 54 | 54 | ||
| 55 | 55 | ||
| 56 | typedef struct vardesc { | 56 | /* description of active local variable */ |
| 57 | unsigned short idx; | 57 | typedef struct Vardesc { |
| 58 | } vardesc; | 58 | unsigned short idx; /* variable index in stack */ |
| 59 | } Vardesc; | ||
| 59 | 60 | ||
| 60 | 61 | ||
| 61 | /* list of all active local variables */ | 62 | /* list of all active local variables */ |
| 62 | typedef struct Varlist { | 63 | typedef struct Varlist { |
| 63 | vardesc *actvar; | 64 | Vardesc *actvar; |
| 64 | int nactvar; | 65 | int nactvar; |
| 65 | int actvarsize; | 66 | int actvarsize; |
| 66 | } Varlist; | 67 | } Varlist; |
| 67 | 68 | ||
| 68 | 69 | ||
| 70 | /* description of pending goto statement */ | ||
| 71 | typedef struct Gotodesc { | ||
| 72 | TString *name; | ||
| 73 | int pc; /* where it is coded */ | ||
| 74 | int line; /* line where it appeared */ | ||
| 75 | lu_byte currlevel; /* variable level where it appears in current block */ | ||
| 76 | } Gotodesc; | ||
| 77 | |||
| 78 | |||
| 79 | /* list of pending gotos */ | ||
| 80 | typedef struct Gotolist { | ||
| 81 | Gotodesc *gt; | ||
| 82 | int ngt; | ||
| 83 | int gtsize; | ||
| 84 | } Gotolist; | ||
| 85 | |||
| 86 | |||
| 87 | /* description of active labels */ | ||
| 88 | typedef struct Labeldesc { | ||
| 89 | TString *name; | ||
| 90 | int pc; /* label position */ | ||
| 91 | lu_byte nactvar; /* variable level where it appears in current block */ | ||
| 92 | } Labeldesc; | ||
| 93 | |||
| 94 | |||
| 95 | /* list of active labels */ | ||
| 96 | typedef struct Labellist { | ||
| 97 | Labeldesc *label; | ||
| 98 | int nlabel; | ||
| 99 | int labelsize; | ||
| 100 | } Labellist; | ||
| 101 | |||
| 102 | |||
| 69 | struct BlockCnt; /* defined in lparser.c */ | 103 | struct BlockCnt; /* defined in lparser.c */ |
| 70 | 104 | ||
| 71 | 105 | ||
| @@ -91,7 +125,8 @@ typedef struct FuncState { | |||
| 91 | 125 | ||
| 92 | 126 | ||
| 93 | LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, | 127 | LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, |
| 94 | Varlist *varl, const char *name); | 128 | Varlist *varl, Gotolist *gtl, |
| 129 | Labellist *labell, const char *name); | ||
| 95 | 130 | ||
| 96 | 131 | ||
| 97 | #endif | 132 | #endif |
