diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-08-30 13:38:58 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-08-30 13:38:58 -0300 |
commit | c8f47c293459c1173154a23b9f2713c3dbd8ed36 (patch) | |
tree | e7cf117daa3e488fc437eea585d960a3088ff097 | |
parent | ca458f1f525b15806e95c1b94c10df69a9e6c27d (diff) | |
download | lua-c8f47c293459c1173154a23b9f2713c3dbd8ed36.tar.gz lua-c8f47c293459c1173154a23b9f2713c3dbd8ed36.tar.bz2 lua-c8f47c293459c1173154a23b9f2713c3dbd8ed36.zip |
optimization for |if cond then goto|
-rw-r--r-- | lparser.c | 55 |
1 files changed, 37 insertions, 18 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lparser.c,v 2.116 2011/08/23 17:24:34 roberto Exp roberto $ | 2 | ** $Id: lparser.c,v 2.117 2011/08/25 13:45:24 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 | */ |
@@ -383,7 +383,8 @@ static int findlabel (LexState *ls, int g) { | |||
383 | static int newlabelentry (LexState *ls, Labellist *l, TString *name, | 383 | static int newlabelentry (LexState *ls, Labellist *l, TString *name, |
384 | int line, int pc) { | 384 | int line, int pc) { |
385 | int n = l->n; | 385 | int n = l->n; |
386 | luaM_growvector(ls->L, l->arr, n, l->size, Labeldesc, SHRT_MAX, "labels"); | 386 | luaM_growvector(ls->L, l->arr, n, l->size, |
387 | Labeldesc, SHRT_MAX, "labels/gotos"); | ||
387 | l->arr[n].name = name; | 388 | l->arr[n].name = name; |
388 | l->arr[n].line = line; | 389 | l->arr[n].line = line; |
389 | l->arr[n].nactvar = ls->fs->nactvar; | 390 | l->arr[n].nactvar = ls->fs->nactvar; |
@@ -1178,10 +1179,18 @@ static int cond (LexState *ls) { | |||
1178 | } | 1179 | } |
1179 | 1180 | ||
1180 | 1181 | ||
1181 | static void gotostat (LexState *ls, TString *label, int line) { | 1182 | static void gotostat (LexState *ls, int pc) { |
1182 | /* create new entry for this goto */ | 1183 | int line = ls->linenumber; |
1183 | int g = newlabelentry(ls, &ls->dyd->gt, label, line, luaK_jump(ls->fs)); | 1184 | TString *label; |
1184 | findlabel(ls, g); | 1185 | int g; |
1186 | if (testnext(ls, TK_GOTO)) | ||
1187 | label = str_checkname(ls); | ||
1188 | else { | ||
1189 | luaX_next(ls); /* skip break */ | ||
1190 | label = luaS_new(ls->L, "break"); | ||
1191 | } | ||
1192 | g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); | ||
1193 | findlabel(ls, g); /* close it if label already defined */ | ||
1185 | } | 1194 | } |
1186 | 1195 | ||
1187 | 1196 | ||
@@ -1362,16 +1371,32 @@ static void forstat (LexState *ls, int line) { | |||
1362 | 1371 | ||
1363 | static void test_then_block (LexState *ls, int *escapelist) { | 1372 | static void test_then_block (LexState *ls, int *escapelist) { |
1364 | /* test_then_block -> [IF | ELSEIF] cond THEN block */ | 1373 | /* test_then_block -> [IF | ELSEIF] cond THEN block */ |
1374 | BlockCnt bl; | ||
1365 | FuncState *fs = ls->fs; | 1375 | FuncState *fs = ls->fs; |
1366 | int condexit; | 1376 | expdesc v; |
1377 | int jf; /* instruction to skip 'then' code (if condition is false) */ | ||
1367 | luaX_next(ls); /* skip IF or ELSEIF */ | 1378 | luaX_next(ls); /* skip IF or ELSEIF */ |
1368 | condexit = cond(ls); /* 'if' condition */ | 1379 | enterblock(fs, &bl, 0); |
1380 | expr(ls, &v); /* read condition */ | ||
1369 | checknext(ls, TK_THEN); | 1381 | checknext(ls, TK_THEN); |
1370 | block(ls); /* `then' part */ | 1382 | if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { |
1383 | luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ | ||
1384 | gotostat(ls, v.t); /* handle goto/break */ | ||
1385 | if (block_follow(ls, 0)) /* no more code after 'goto'? */ | ||
1386 | goto leave; /* that is it */ | ||
1387 | else /* must skip over 'then' part if condition is false */ | ||
1388 | jf = luaK_jump(fs); | ||
1389 | } | ||
1390 | else { /* regular case (not goto/break) */ | ||
1391 | luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ | ||
1392 | jf = v.f; | ||
1393 | } | ||
1394 | statlist(ls); /* `then' part */ | ||
1371 | if (ls->t.token == TK_ELSE || | 1395 | if (ls->t.token == TK_ELSE || |
1372 | ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ | 1396 | ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ |
1373 | luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ | 1397 | luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ |
1374 | luaK_patchtohere(fs, condexit); /* 'if' condition jumps to here */ | 1398 | luaK_patchtohere(fs, jf); |
1399 | leave: leaveblock(fs); | ||
1375 | } | 1400 | } |
1376 | 1401 | ||
1377 | 1402 | ||
@@ -1545,15 +1570,9 @@ static void statement (LexState *ls) { | |||
1545 | retstat(ls); | 1570 | retstat(ls); |
1546 | break; | 1571 | break; |
1547 | } | 1572 | } |
1548 | case TK_BREAK: { /* stat -> breakstat */ | 1573 | case TK_BREAK: /* stat -> breakstat */ |
1549 | luaX_next(ls); /* skip BREAK */ | ||
1550 | /* code it as "goto 'break'" */ | ||
1551 | gotostat(ls, luaS_new(ls->L, "break"), line); | ||
1552 | break; | ||
1553 | } | ||
1554 | case TK_GOTO: { /* stat -> 'goto' NAME */ | 1574 | case TK_GOTO: { /* stat -> 'goto' NAME */ |
1555 | luaX_next(ls); /* skip GOTO */ | 1575 | gotostat(ls, luaK_jump(ls->fs)); |
1556 | gotostat(ls, str_checkname(ls), line); | ||
1557 | break; | 1576 | break; |
1558 | } | 1577 | } |
1559 | default: { /* stat -> func | assignment */ | 1578 | default: { /* stat -> func | assignment */ |