diff options
Diffstat (limited to 'lpcode.c')
-rw-r--r-- | lpcode.c | 143 |
1 files changed, 84 insertions, 59 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lpcode.c,v 1.18 2013/04/12 16:30:33 roberto Exp $ | 2 | ** $Id: lpcode.c,v 1.21 2014/12/12 17:01:29 roberto Exp $ |
3 | ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) | 3 | ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) |
4 | */ | 4 | */ |
5 | 5 | ||
@@ -33,26 +33,30 @@ static const Charset *fullset = &fullset_; | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | /* | 35 | /* |
36 | ** Check whether a charset is empty (IFail), singleton (IChar), | 36 | ** Check whether a charset is empty (returns IFail), singleton (IChar), |
37 | ** full (IAny), or none of those (ISet). | 37 | ** full (IAny), or none of those (ISet). When singleton, '*c' returns |
38 | ** which character it is. (When generic set, the set was the input, | ||
39 | ** so there is no need to return it.) | ||
38 | */ | 40 | */ |
39 | static Opcode charsettype (const byte *cs, int *c) { | 41 | static Opcode charsettype (const byte *cs, int *c) { |
40 | int count = 0; | 42 | int count = 0; /* number of characters in the set */ |
41 | int i; | 43 | int i; |
42 | int candidate = -1; /* candidate position for a char */ | 44 | int candidate = -1; /* candidate position for the singleton char */ |
43 | for (i = 0; i < CHARSETSIZE; i++) { | 45 | for (i = 0; i < CHARSETSIZE; i++) { /* for each byte */ |
44 | int b = cs[i]; | 46 | int b = cs[i]; |
45 | if (b == 0) { | 47 | if (b == 0) { /* is byte empty? */ |
46 | if (count > 1) return ISet; /* else set is still empty */ | 48 | if (count > 1) /* was set neither empty nor singleton? */ |
49 | return ISet; /* neither full nor empty nor singleton */ | ||
50 | /* else set is still empty or singleton */ | ||
47 | } | 51 | } |
48 | else if (b == 0xFF) { | 52 | else if (b == 0xFF) { /* is byte full? */ |
49 | if (count < (i * BITSPERCHAR)) | 53 | if (count < (i * BITSPERCHAR)) /* was set not full? */ |
50 | return ISet; | 54 | return ISet; /* neither full nor empty nor singleton */ |
51 | else count += BITSPERCHAR; /* set is still full */ | 55 | else count += BITSPERCHAR; /* set is still full */ |
52 | } | 56 | } |
53 | else if ((b & (b - 1)) == 0) { /* byte has only one bit? */ | 57 | else if ((b & (b - 1)) == 0) { /* has byte only one bit? */ |
54 | if (count > 0) | 58 | if (count > 0) /* was set not empty? */ |
55 | return ISet; /* set is neither full nor empty */ | 59 | return ISet; /* neither full nor empty nor singleton */ |
56 | else { /* set has only one char till now; track it */ | 60 | else { /* set has only one char till now; track it */ |
57 | count++; | 61 | count++; |
58 | candidate = i; | 62 | candidate = i; |
@@ -77,6 +81,7 @@ static Opcode charsettype (const byte *cs, int *c) { | |||
77 | } | 81 | } |
78 | } | 82 | } |
79 | 83 | ||
84 | |||
80 | /* | 85 | /* |
81 | ** A few basic operations on Charsets | 86 | ** A few basic operations on Charsets |
82 | */ | 87 | */ |
@@ -84,16 +89,11 @@ static void cs_complement (Charset *cs) { | |||
84 | loopset(i, cs->cs[i] = ~cs->cs[i]); | 89 | loopset(i, cs->cs[i] = ~cs->cs[i]); |
85 | } | 90 | } |
86 | 91 | ||
87 | |||
88 | static int cs_equal (const byte *cs1, const byte *cs2) { | 92 | static int cs_equal (const byte *cs1, const byte *cs2) { |
89 | loopset(i, if (cs1[i] != cs2[i]) return 0); | 93 | loopset(i, if (cs1[i] != cs2[i]) return 0); |
90 | return 1; | 94 | return 1; |
91 | } | 95 | } |
92 | 96 | ||
93 | |||
94 | /* | ||
95 | ** computes whether sets cs1 and cs2 are disjoint | ||
96 | */ | ||
97 | static int cs_disjoint (const Charset *cs1, const Charset *cs2) { | 97 | static int cs_disjoint (const Charset *cs1, const Charset *cs2) { |
98 | loopset(i, if ((cs1->cs[i] & cs2->cs[i]) != 0) return 0;) | 98 | loopset(i, if ((cs1->cs[i] & cs2->cs[i]) != 0) return 0;) |
99 | return 1; | 99 | return 1; |
@@ -101,7 +101,8 @@ static int cs_disjoint (const Charset *cs1, const Charset *cs2) { | |||
101 | 101 | ||
102 | 102 | ||
103 | /* | 103 | /* |
104 | ** Convert a 'char' pattern (TSet, TChar, TAny) to a charset | 104 | ** If 'tree' is a 'char' pattern (TSet, TChar, TAny), convert it into a |
105 | ** charset and return 1; else return 0. | ||
105 | */ | 106 | */ |
106 | int tocharset (TTree *tree, Charset *cs) { | 107 | int tocharset (TTree *tree, Charset *cs) { |
107 | switch (tree->tag) { | 108 | switch (tree->tag) { |
@@ -116,7 +117,7 @@ int tocharset (TTree *tree, Charset *cs) { | |||
116 | return 1; | 117 | return 1; |
117 | } | 118 | } |
118 | case TAny: { | 119 | case TAny: { |
119 | loopset(i, cs->cs[i] = 0xFF); /* add all to the set */ | 120 | loopset(i, cs->cs[i] = 0xFF); /* add all characters to the set */ |
120 | return 1; | 121 | return 1; |
121 | } | 122 | } |
122 | default: return 0; | 123 | default: return 0; |
@@ -125,13 +126,16 @@ int tocharset (TTree *tree, Charset *cs) { | |||
125 | 126 | ||
126 | 127 | ||
127 | /* | 128 | /* |
128 | ** Checks whether a pattern has captures | 129 | ** Check whether a pattern tree has captures |
129 | */ | 130 | */ |
130 | int hascaptures (TTree *tree) { | 131 | int hascaptures (TTree *tree) { |
131 | tailcall: | 132 | tailcall: |
132 | switch (tree->tag) { | 133 | switch (tree->tag) { |
133 | case TCapture: case TRunTime: | 134 | case TCapture: case TRunTime: |
134 | return 1; | 135 | return 1; |
136 | case TCall: | ||
137 | tree = sib2(tree); goto tailcall; /* return hascaptures(sib2(tree)); */ | ||
138 | case TOpenCall: assert(0); | ||
135 | default: { | 139 | default: { |
136 | switch (numsiblings[tree->tag]) { | 140 | switch (numsiblings[tree->tag]) { |
137 | case 1: /* return hascaptures(sib1(tree)); */ | 141 | case 1: /* return hascaptures(sib1(tree)); */ |
@@ -161,7 +165,7 @@ int hascaptures (TTree *tree) { | |||
161 | ** p is nullable => nullable(p) | 165 | ** p is nullable => nullable(p) |
162 | ** nofail(p) => p cannot fail | 166 | ** nofail(p) => p cannot fail |
163 | ** The function assumes that TOpenCall is not nullable; | 167 | ** The function assumes that TOpenCall is not nullable; |
164 | ** this will be checked again when the grammar is fixed.) | 168 | ** this will be checked again when the grammar is fixed. |
165 | ** Run-time captures can do whatever they want, so the result | 169 | ** Run-time captures can do whatever they want, so the result |
166 | ** is conservative. | 170 | ** is conservative. |
167 | */ | 171 | */ |
@@ -188,7 +192,7 @@ int checkaux (TTree *tree, int pred) { | |||
188 | if (!checkaux(sib1(tree), pred)) return 0; | 192 | if (!checkaux(sib1(tree), pred)) return 0; |
189 | /* else return checkaux(sib2(tree), pred); */ | 193 | /* else return checkaux(sib2(tree), pred); */ |
190 | tree = sib2(tree); goto tailcall; | 194 | tree = sib2(tree); goto tailcall; |
191 | case TChoice: case TLabChoice: /* labeled failure */ | 195 | case TChoice: case TLabChoice: /* labeled failure */ |
192 | if (checkaux(sib2(tree), pred)) return 1; | 196 | if (checkaux(sib2(tree), pred)) return 1; |
193 | /* else return checkaux(sib1(tree), pred); */ | 197 | /* else return checkaux(sib1(tree), pred); */ |
194 | tree = sib1(tree); goto tailcall; | 198 | tree = sib1(tree); goto tailcall; |
@@ -198,7 +202,7 @@ int checkaux (TTree *tree, int pred) { | |||
198 | case TCall: /* return checkaux(sib2(tree), pred); */ | 202 | case TCall: /* return checkaux(sib2(tree), pred); */ |
199 | tree = sib2(tree); goto tailcall; | 203 | tree = sib2(tree); goto tailcall; |
200 | default: assert(0); return 0; | 204 | default: assert(0); return 0; |
201 | }; | 205 | } |
202 | } | 206 | } |
203 | 207 | ||
204 | 208 | ||
@@ -246,16 +250,20 @@ int fixedlenx (TTree *tree, int count, int len) { | |||
246 | /* | 250 | /* |
247 | ** Computes the 'first set' of a pattern. | 251 | ** Computes the 'first set' of a pattern. |
248 | ** The result is a conservative aproximation: | 252 | ** The result is a conservative aproximation: |
249 | ** match p ax -> x' for some x ==> a in first(p). | 253 | ** match p ax -> x (for some x) ==> a belongs to first(p) |
254 | ** or | ||
255 | ** a not in first(p) ==> match p ax -> fail (for all x) | ||
256 | ** | ||
250 | ** The set 'follow' is the first set of what follows the | 257 | ** The set 'follow' is the first set of what follows the |
251 | ** pattern (full set if nothing follows it). | 258 | ** pattern (full set if nothing follows it). |
252 | ** The function returns 0 when this set can be used for | 259 | ** |
253 | ** tests that avoid the pattern altogether. | 260 | ** The function returns 0 when this resulting set can be used for |
261 | ** test instructions that avoid the pattern altogether. | ||
254 | ** A non-zero return can happen for two reasons: | 262 | ** A non-zero return can happen for two reasons: |
255 | ** 1) match p '' -> '' ==> returns 1. | 263 | ** 1) match p '' -> '' ==> return has bit 1 set |
256 | ** (tests cannot be used because they always fail for an empty input) | 264 | ** (tests cannot be used because they would always fail for an empty input); |
257 | ** 2) there is a match-time capture ==> returns 2. | 265 | ** 2) there is a match-time capture ==> return has bit 2 set |
258 | ** (match-time captures should not be avoided by optimizations) | 266 | ** (optimizations should not bypass match-time captures). |
259 | */ | 267 | */ |
260 | static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) { | 268 | static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) { |
261 | tailcall: | 269 | tailcall: |
@@ -266,16 +274,16 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) { | |||
266 | } | 274 | } |
267 | case TTrue: { | 275 | case TTrue: { |
268 | loopset(i, firstset->cs[i] = follow->cs[i]); | 276 | loopset(i, firstset->cs[i] = follow->cs[i]); |
269 | return 1; | 277 | return 1; /* accepts the empty string */ |
270 | } | 278 | } |
271 | case TFalse: { | 279 | case TFalse: { |
272 | loopset(i, firstset->cs[i] = 0); | 280 | loopset(i, firstset->cs[i] = 0); |
273 | return 0; | 281 | return 0; |
274 | } | 282 | } |
275 | case TThrow: { /* labeled failure: must always throw the label */ | 283 | case TThrow: { /* labeled failure: must always throw the label */ |
276 | loopset(i, firstset->cs[i] = follow->cs[i]); /* follow = fullset(?) */ | 284 | loopset(i, firstset->cs[i] = follow->cs[i]); /* follow = fullset(?) */ |
277 | return 1; | 285 | return 1; |
278 | } | 286 | } |
279 | case TChoice: case TLabChoice: { /*(?) labeled failure */ | 287 | case TChoice: case TLabChoice: { /*(?) labeled failure */ |
280 | Charset csaux; | 288 | Charset csaux; |
281 | int e1 = getfirst(sib1(tree), follow, firstset); | 289 | int e1 = getfirst(sib1(tree), follow, firstset); |
@@ -285,7 +293,8 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) { | |||
285 | } | 293 | } |
286 | case TSeq: { | 294 | case TSeq: { |
287 | if (!nullable(sib1(tree))) { | 295 | if (!nullable(sib1(tree))) { |
288 | /* return getfirst(sib1(tree), fullset, firstset); */ | 296 | /* when p1 is not nullable, p2 has nothing to contribute; |
297 | return getfirst(sib1(tree), fullset, firstset); */ | ||
289 | tree = sib1(tree); follow = fullset; goto tailcall; | 298 | tree = sib1(tree); follow = fullset; goto tailcall; |
290 | } | 299 | } |
291 | else { /* FIRST(p1 p2, fl) = FIRST(p1, FIRST(p2, fl)) */ | 300 | else { /* FIRST(p1 p2, fl) = FIRST(p1, FIRST(p2, fl)) */ |
@@ -329,7 +338,7 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) { | |||
329 | /* else go through */ | 338 | /* else go through */ |
330 | } | 339 | } |
331 | case TBehind: { /* instruction gives no new information */ | 340 | case TBehind: { /* instruction gives no new information */ |
332 | /* call 'getfirst' to check for math-time captures */ | 341 | /* call 'getfirst' only to check for math-time captures */ |
333 | int e = getfirst(sib1(tree), follow, firstset); | 342 | int e = getfirst(sib1(tree), follow, firstset); |
334 | loopset(i, firstset->cs[i] = follow->cs[i]); /* uses follow */ | 343 | loopset(i, firstset->cs[i] = follow->cs[i]); /* uses follow */ |
335 | return e | 1; /* always can accept the empty string */ | 344 | return e | 1; /* always can accept the empty string */ |
@@ -340,13 +349,13 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) { | |||
340 | 349 | ||
341 | 350 | ||
342 | /* | 351 | /* |
343 | ** If it returns true, then pattern can fail only depending on the next | 352 | ** If 'headfail(tree)' true, then 'tree' can fail only depending on the |
344 | ** character of the subject | 353 | ** next character of the subject. |
345 | */ | 354 | */ |
346 | static int headfail (TTree *tree) { | 355 | static int headfail (TTree *tree) { |
347 | tailcall: | 356 | tailcall: |
348 | switch (tree->tag) { | 357 | switch (tree->tag) { |
349 | case TChar: case TSet: case TAny: case TFalse: | 358 | case TChar: case TSet: case TAny: case TFalse: |
350 | return 1; | 359 | return 1; |
351 | case TTrue: case TRep: case TRunTime: case TNot: | 360 | case TTrue: case TRep: case TRunTime: case TNot: |
352 | case TBehind: | 361 | case TBehind: |
@@ -410,10 +419,12 @@ int sizei (const Instruction *i) { | |||
410 | switch((Opcode)i->i.code) { | 419 | switch((Opcode)i->i.code) { |
411 | case ISet: case ISpan: return CHARSETINSTSIZE; | 420 | case ISet: case ISpan: return CHARSETINSTSIZE; |
412 | case ITestSet: return CHARSETINSTSIZE + 1; | 421 | case ITestSet: return CHARSETINSTSIZE + 1; |
413 | case ITestChar: case ITestAny: case IChoice: case IJmp: | 422 | case ITestChar: case ITestAny: case IChoice: case IJmp: case ICall: |
414 | case ICall: case IOpenCall: case ICommit: case IPartialCommit: | 423 | case IOpenCall: case ICommit: case IPartialCommit: case IBackCommit: |
415 | case IBackCommit: case IThrow: return 2; /* labeled failure */ | 424 | case IThrow: /* labeled failure */ |
425 | return 2; | ||
416 | case ILabChoice: return 3; /* labeled failure */ | 426 | case ILabChoice: return 3; /* labeled failure */ |
427 | return 2; | ||
417 | default: return 1; | 428 | default: return 1; |
418 | } | 429 | } |
419 | } | 430 | } |
@@ -431,7 +442,8 @@ typedef struct CompileState { | |||
431 | 442 | ||
432 | /* | 443 | /* |
433 | ** code generation is recursive; 'opt' indicates that the code is | 444 | ** code generation is recursive; 'opt' indicates that the code is |
434 | ** being generated under a 'IChoice' operator jumping to its end. | 445 | ** being generated under a 'IChoice' operator jumping to its end |
446 | ** (that is, the match is "optional"). | ||
435 | ** 'tt' points to a previous test protecting this code. 'fl' is | 447 | ** 'tt' points to a previous test protecting this code. 'fl' is |
436 | ** the follow set of the pattern. | 448 | ** the follow set of the pattern. |
437 | */ | 449 | */ |
@@ -439,7 +451,7 @@ static void codegen (CompileState *compst, TTree *tree, int opt, int tt, | |||
439 | const Charset *fl); | 451 | const Charset *fl); |
440 | 452 | ||
441 | 453 | ||
442 | void reallocprog (lua_State *L, Pattern *p, int nsize) { | 454 | void realloccode (lua_State *L, Pattern *p, int nsize) { |
443 | void *ud; | 455 | void *ud; |
444 | lua_Alloc f = lua_getallocf(L, &ud); | 456 | lua_Alloc f = lua_getallocf(L, &ud); |
445 | void *newblock = f(ud, p->code, p->codesize * sizeof(Instruction), | 457 | void *newblock = f(ud, p->code, p->codesize * sizeof(Instruction), |
@@ -454,7 +466,7 @@ void reallocprog (lua_State *L, Pattern *p, int nsize) { | |||
454 | static int nextinstruction (CompileState *compst) { | 466 | static int nextinstruction (CompileState *compst) { |
455 | int size = compst->p->codesize; | 467 | int size = compst->p->codesize; |
456 | if (compst->ncode >= size) | 468 | if (compst->ncode >= size) |
457 | reallocprog(compst->L, compst->p, size * 2); | 469 | realloccode(compst->L, compst->p, size * 2); |
458 | return compst->ncode++; | 470 | return compst->ncode++; |
459 | } | 471 | } |
460 | 472 | ||
@@ -470,6 +482,9 @@ static int addinstruction (CompileState *compst, Opcode op, int aux) { | |||
470 | } | 482 | } |
471 | 483 | ||
472 | 484 | ||
485 | /* | ||
486 | ** Add an instruction followed by space for an offset (to be set later) | ||
487 | */ | ||
473 | static int addoffsetinst (CompileState *compst, Opcode op) { | 488 | static int addoffsetinst (CompileState *compst, Opcode op) { |
474 | int i = addinstruction(compst, op, 0); /* instruction */ | 489 | int i = addinstruction(compst, op, 0); /* instruction */ |
475 | addinstruction(compst, (Opcode)0, 0); /* open space for offset */ | 490 | addinstruction(compst, (Opcode)0, 0); /* open space for offset */ |
@@ -496,7 +511,9 @@ static int addoffsetlabinst (CompileState *compst, Labelset ls) { | |||
496 | } | 511 | } |
497 | /* labeled failure end */ | 512 | /* labeled failure end */ |
498 | 513 | ||
499 | 514 | /* | |
515 | ** Set the offset of an instruction | ||
516 | */ | ||
500 | static void setoffset (CompileState *compst, int instruction, int offset) { | 517 | static void setoffset (CompileState *compst, int instruction, int offset) { |
501 | getinstr(compst, instruction + 1).offset = offset; | 518 | getinstr(compst, instruction + 1).offset = offset; |
502 | } | 519 | } |
@@ -505,7 +522,7 @@ static void setoffset (CompileState *compst, int instruction, int offset) { | |||
505 | /* | 522 | /* |
506 | ** Add a capture instruction: | 523 | ** Add a capture instruction: |
507 | ** 'op' is the capture instruction; 'cap' the capture kind; | 524 | ** 'op' is the capture instruction; 'cap' the capture kind; |
508 | ** 'key' the key into ktable; 'aux' is optional offset | 525 | ** 'key' the key into ktable; 'aux' is the optional capture offset |
509 | ** | 526 | ** |
510 | */ | 527 | */ |
511 | static int addinstcap (CompileState *compst, Opcode op, int cap, int key, | 528 | static int addinstcap (CompileState *compst, Opcode op, int cap, int key, |
@@ -521,12 +538,18 @@ static int addinstcap (CompileState *compst, Opcode op, int cap, int key, | |||
521 | #define target(code,i) ((i) + code[i + 1].offset) | 538 | #define target(code,i) ((i) + code[i + 1].offset) |
522 | 539 | ||
523 | 540 | ||
541 | /* | ||
542 | ** Patch 'instruction' to jump to 'target' | ||
543 | */ | ||
524 | static void jumptothere (CompileState *compst, int instruction, int target) { | 544 | static void jumptothere (CompileState *compst, int instruction, int target) { |
525 | if (instruction >= 0) | 545 | if (instruction >= 0) |
526 | setoffset(compst, instruction, target - instruction); | 546 | setoffset(compst, instruction, target - instruction); |
527 | } | 547 | } |
528 | 548 | ||
529 | 549 | ||
550 | /* | ||
551 | ** Patch 'instruction' to jump to current position | ||
552 | */ | ||
530 | static void jumptohere (CompileState *compst, int instruction) { | 553 | static void jumptohere (CompileState *compst, int instruction) { |
531 | jumptothere(compst, instruction, gethere(compst)); | 554 | jumptothere(compst, instruction, gethere(compst)); |
532 | } | 555 | } |
@@ -594,7 +617,7 @@ static int codetestset (CompileState *compst, Charset *cs, int e) { | |||
594 | else { | 617 | else { |
595 | int c = 0; | 618 | int c = 0; |
596 | Opcode op = charsettype(cs->cs, &c); | 619 | Opcode op = charsettype(cs->cs, &c); |
597 | switch (op) { | 620 | switch (op) { |
598 | case IFail: return addoffsetinst(compst, IJmp); /* always jump */ | 621 | case IFail: return addoffsetinst(compst, IJmp); /* always jump */ |
599 | case IAny: return addoffsetinst(compst, ITestAny); | 622 | case IAny: return addoffsetinst(compst, ITestAny); |
600 | case IChar: { | 623 | case IChar: { |
@@ -658,8 +681,7 @@ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt, | |||
658 | Charset cs1, cs2; | 681 | Charset cs1, cs2; |
659 | int e1 = getfirst(p1, fullset, &cs1); | 682 | int e1 = getfirst(p1, fullset, &cs1); |
660 | if (headfail(p1) || | 683 | if (headfail(p1) || |
661 | (!e1 && (getfirst(p2, fl, &cs2), cs_disjoint(&cs1, &cs2)))) { | 684 | (!e1 && (getfirst(p2, fl, &cs2), cs_disjoint(&cs1, &cs2)))) { |
662 | /*if (0) {*/ | ||
663 | /* <p1 / p2> == test (fail(p1)) -> L1 ; p1 ; jmp L2; L1: p2; L2: */ | 685 | /* <p1 / p2> == test (fail(p1)) -> L1 ; p1 ; jmp L2; L1: p2; L2: */ |
664 | int test = codetestset(compst, &cs1, 0); | 686 | int test = codetestset(compst, &cs1, 0); |
665 | int jmp = NOINST; | 687 | int jmp = NOINST; |
@@ -690,6 +712,7 @@ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt, | |||
690 | } | 712 | } |
691 | } | 713 | } |
692 | 714 | ||
715 | |||
693 | /* labeled failure begin */ | 716 | /* labeled failure begin */ |
694 | static void codelabchoice (CompileState *compst, TTree *p1, TTree *p2, int opt, | 717 | static void codelabchoice (CompileState *compst, TTree *p1, TTree *p2, int opt, |
695 | const Charset *fl, Labelset ls) { | 718 | const Charset *fl, Labelset ls) { |
@@ -707,6 +730,7 @@ static void codelabchoice (CompileState *compst, TTree *p1, TTree *p2, int opt, | |||
707 | } | 730 | } |
708 | /* labeled failure end */ | 731 | /* labeled failure end */ |
709 | 732 | ||
733 | |||
710 | /* | 734 | /* |
711 | ** And predicate | 735 | ** And predicate |
712 | ** optimization: fixedlen(p) = n ==> <&p> == <p>; behind n | 736 | ** optimization: fixedlen(p) = n ==> <&p> == <p>; behind n |
@@ -907,7 +931,8 @@ static int codeseq1 (CompileState *compst, TTree *p1, TTree *p2, | |||
907 | 931 | ||
908 | /* | 932 | /* |
909 | ** Main code-generation function: dispatch to auxiliar functions | 933 | ** Main code-generation function: dispatch to auxiliar functions |
910 | ** according to kind of tree | 934 | ** according to kind of tree. ('needfollow' should return true |
935 | ** only for consructions that use 'fl'.) | ||
911 | */ | 936 | */ |
912 | static void codegen (CompileState *compst, TTree *tree, int opt, int tt, | 937 | static void codegen (CompileState *compst, TTree *tree, int opt, int tt, |
913 | const Charset *fl) { | 938 | const Charset *fl) { |
@@ -932,7 +957,7 @@ static void codegen (CompileState *compst, TTree *tree, int opt, int tt, | |||
932 | /* codegen(compst, p2, opt, tt, fl); */ | 957 | /* codegen(compst, p2, opt, tt, fl); */ |
933 | tree = sib2(tree); goto tailcall; | 958 | tree = sib2(tree); goto tailcall; |
934 | } | 959 | } |
935 | case TThrow: { /* labeled failure */ | 960 | case TThrow: { /* labeled failure */ |
936 | addthrowinstruction(compst, tree->labels); | 961 | addthrowinstruction(compst, tree->labels); |
937 | break; | 962 | break; |
938 | } | 963 | } |
@@ -958,6 +983,7 @@ static void peephole (CompileState *compst) { | |||
958 | Instruction *code = compst->p->code; | 983 | Instruction *code = compst->p->code; |
959 | int i; | 984 | int i; |
960 | for (i = 0; i < compst->ncode; i += sizei(&code[i])) { | 985 | for (i = 0; i < compst->ncode; i += sizei(&code[i])) { |
986 | redo: | ||
961 | switch (code[i].i.code) { | 987 | switch (code[i].i.code) { |
962 | case IChoice: case ICall: case ICommit: case IPartialCommit: | 988 | case IChoice: case ICall: case ICommit: case IPartialCommit: |
963 | case IBackCommit: case ITestChar: case ITestSet: case ILabChoice: /* labeled failure */ | 989 | case IBackCommit: case ITestChar: case ITestSet: case ILabChoice: /* labeled failure */ |
@@ -979,8 +1005,7 @@ static void peephole (CompileState *compst) { | |||
979 | int fft = finallabel(code, ft); | 1005 | int fft = finallabel(code, ft); |
980 | code[i] = code[ft]; /* jump becomes that instruction... */ | 1006 | code[i] = code[ft]; /* jump becomes that instruction... */ |
981 | jumptothere(compst, i, fft); /* but must correct its offset */ | 1007 | jumptothere(compst, i, fft); /* but must correct its offset */ |
982 | i--; /* reoptimize its label */ | 1008 | goto redo; /* reoptimize its label */ |
983 | break; | ||
984 | } | 1009 | } |
985 | default: { | 1010 | default: { |
986 | jumptothere(compst, i, ft); /* optimize label */ | 1011 | jumptothere(compst, i, ft); /* optimize label */ |
@@ -1002,11 +1027,11 @@ static void peephole (CompileState *compst) { | |||
1002 | Instruction *compile (lua_State *L, Pattern *p) { | 1027 | Instruction *compile (lua_State *L, Pattern *p) { |
1003 | CompileState compst; | 1028 | CompileState compst; |
1004 | compst.p = p; compst.ncode = 0; compst.L = L; | 1029 | compst.p = p; compst.ncode = 0; compst.L = L; |
1005 | reallocprog(L, p, 2); /* minimum initial size */ | 1030 | realloccode(L, p, 2); /* minimum initial size */ |
1006 | codegen(&compst, p->tree, 0, NOINST, fullset); | 1031 | codegen(&compst, p->tree, 0, NOINST, fullset); |
1007 | addinstruction(&compst, IEnd, 0); | 1032 | addinstruction(&compst, IEnd, 0); |
1008 | reallocprog(L, p, compst.ncode); /* set final size */ | 1033 | realloccode(L, p, compst.ncode); /* set final size */ |
1009 | peephole(&compst); /* labeled failure */ | 1034 | peephole(&compst); |
1010 | return p->code; | 1035 | return p->code; |
1011 | } | 1036 | } |
1012 | 1037 | ||