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 |