19 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
20 |
USA. */ |
USA. */ |
21 |
|
|
22 |
/* BUGS: |
/* TODO: |
|
- (x?)*y\1z should match both xxxxyxz and xxxyz. |
|
|
TODO: |
|
23 |
- structure the opcode space into opcode+flag. |
- structure the opcode space into opcode+flag. |
24 |
- merge with glibc's regex.[ch]. |
- merge with glibc's regex.[ch]. |
25 |
- replace (succeed_n + jump_n + set_number_at) with something that doesn't |
- replace (succeed_n + jump_n + set_number_at) with something that doesn't |
1518 |
} \ |
} \ |
1519 |
} while (0) |
} while (0) |
1520 |
|
|
|
/* Discard a saved register off the stack. */ |
|
|
#define DISCARD_FAILURE_REG_OR_COUNT() \ |
|
|
do { \ |
|
|
int reg = POP_FAILURE_INT (); \ |
|
|
if (reg == -1) \ |
|
|
{ \ |
|
|
/* It's a counter. */ \ |
|
|
POP_FAILURE_POINTER (); \ |
|
|
reg = POP_FAILURE_INT (); \ |
|
|
DEBUG_PRINT3 (" Discard counter %p = %d\n", ptr, reg); \ |
|
|
} \ |
|
|
else \ |
|
|
{ \ |
|
|
POP_FAILURE_POINTER (); \ |
|
|
POP_FAILURE_POINTER (); \ |
|
|
DEBUG_PRINT4 (" Discard reg %d (spanning %p -> %p)\n", \ |
|
|
reg, regstart[reg], regend[reg]); \ |
|
|
} \ |
|
|
} while (0) |
|
|
|
|
1521 |
/* Check that we are not stuck in an infinite loop. */ |
/* Check that we are not stuck in an infinite loop. */ |
1522 |
#define CHECK_INFINITE_LOOP(pat_cur, string_place) \ |
#define CHECK_INFINITE_LOOP(pat_cur, string_place) \ |
1523 |
do { \ |
do { \ |
1531 |
&& FAILURE_PAT (failure) <= bufp->buffer + bufp->used); \ |
&& FAILURE_PAT (failure) <= bufp->buffer + bufp->used); \ |
1532 |
if (FAILURE_PAT (failure) == pat_cur) \ |
if (FAILURE_PAT (failure) == pat_cur) \ |
1533 |
{ \ |
{ \ |
1534 |
while (fail_stack.frame < fail_stack.avail) \ |
cycle = 1; \ |
1535 |
DISCARD_FAILURE_REG_OR_COUNT (); \ |
break; \ |
|
goto fail; \ |
|
1536 |
} \ |
} \ |
1537 |
DEBUG_PRINT2 (" Other pattern: %p\n", FAILURE_PAT (failure)); \ |
DEBUG_PRINT2 (" Other pattern: %p\n", FAILURE_PAT (failure)); \ |
1538 |
failure = NEXT_FAILURE_HANDLE(failure); \ |
failure = NEXT_FAILURE_HANDLE(failure); \ |
1539 |
} \ |
} \ |
1540 |
DEBUG_PRINT2 (" Other string: %p\n", FAILURE_STR (failure)); \ |
DEBUG_PRINT2 (" Other string: %p\n", FAILURE_STR (failure)); \ |
1541 |
} while (0) |
} while (0) |
1542 |
|
|
1543 |
/* Push the information about the state we will need |
/* Push the information about the state we will need |
1544 |
if we ever fail back to it. |
if we ever fail back to it. |
1545 |
|
|
2622 |
unsigned int startoffset = 0; |
unsigned int startoffset = 0; |
2623 |
re_opcode_t ofj = |
re_opcode_t ofj = |
2624 |
/* Check if the loop can match the empty string. */ |
/* Check if the loop can match the empty string. */ |
2625 |
(simple || !analyse_first (laststart, b, NULL, 0)) ? |
(simple || !analyse_first (laststart, b, NULL, 0)) |
2626 |
on_failure_jump : on_failure_jump_loop; |
? on_failure_jump : on_failure_jump_loop; |
2627 |
assert (skip_one_char (laststart) <= b); |
assert (skip_one_char (laststart) <= b); |
2628 |
|
|
2629 |
if (!zero_times_ok && simple) |
if (!zero_times_ok && simple) |
2671 |
{ |
{ |
2672 |
boolean emptyp = analyse_first (laststart, b, NULL, 0); |
boolean emptyp = analyse_first (laststart, b, NULL, 0); |
2673 |
|
|
2674 |
/* The non-greedy multiple match looks like a repeat..until: |
/* The non-greedy multiple match looks like |
2675 |
we only need a conditional jump at the end of the loop */ |
a repeat..until: we only need a conditional jump |
2676 |
|
at the end of the loop. */ |
2677 |
if (emptyp) BUF_PUSH (no_op); |
if (emptyp) BUF_PUSH (no_op); |
2678 |
STORE_JUMP (emptyp ? on_failure_jump_nastyloop |
STORE_JUMP (emptyp ? on_failure_jump_nastyloop |
2679 |
: on_failure_jump, b, laststart); |
: on_failure_jump, b, laststart); |
2682 |
{ |
{ |
2683 |
/* The repeat...until naturally matches one or more. |
/* The repeat...until naturally matches one or more. |
2684 |
To also match zero times, we need to first jump to |
To also match zero times, we need to first jump to |
2685 |
the end of the loop (its conditional jump). */ |
the end of the loop (its conditional jump). */ |
2686 |
INSERT_JUMP (jump, laststart, b); |
INSERT_JUMP (jump, laststart, b); |
2687 |
b += 3; |
b += 3; |
2688 |
} |
} |
3219 |
goto unfetch_interval; |
goto unfetch_interval; |
3220 |
} |
} |
3221 |
|
|
3222 |
if (upper_bound == 0) |
if (upper_bound == 0) |
3223 |
/* If the upper bound is zero, just drop the sub pattern |
/* If the upper bound is zero, just drop the sub pattern |
3224 |
altogether. */ |
altogether. */ |
3225 |
b = laststart; |
b = laststart; |
3226 |
else if (lower_bound == 1 && upper_bound == 1) |
else if (lower_bound == 1 && upper_bound == 1) |
3227 |
/* Just match it once: nothing to do here. */ |
/* Just match it once: nothing to do here. */ |
3228 |
; |
; |
3229 |
|
|
3230 |
/* Otherwise, we have a nontrivial interval. When |
/* Otherwise, we have a nontrivial interval. When |
3231 |
we're all done, the pattern will look like: |
we're all done, the pattern will look like: |
3232 |
set_number_at <jump count> <upper bound> |
set_number_at <jump count> <upper bound> |
3233 |
set_number_at <succeed_n count> <lower bound> |
set_number_at <succeed_n count> <lower bound> |
3234 |
succeed_n <after jump addr> <succeed_n count> |
succeed_n <after jump addr> <succeed_n count> |
3235 |
<body of loop> |
<body of loop> |
3236 |
jump_n <succeed_n addr> <jump count> |
jump_n <succeed_n addr> <jump count> |
3237 |
(The upper bound and `jump_n' are omitted if |
(The upper bound and `jump_n' are omitted if |
3238 |
`upper_bound' is 1, though.) */ |
`upper_bound' is 1, though.) */ |
3239 |
else |
else |
3240 |
{ /* If the upper bound is > 1, we need to insert |
{ /* If the upper bound is > 1, we need to insert |
3241 |
more at the end of the loop. */ |
more at the end of the loop. */ |
3242 |
unsigned int nbytes = (upper_bound < 0 ? 3 |
unsigned int nbytes = (upper_bound < 0 ? 3 |
3243 |
: upper_bound > 1 ? 5 : 0); |
: upper_bound > 1 ? 5 : 0); |
3244 |
unsigned int startoffset = 0; |
unsigned int startoffset = 0; |
3245 |
|
|
3246 |
GET_BUFFER_SPACE (20); /* We might use less. */ |
GET_BUFFER_SPACE (20); /* We might use less. */ |
3247 |
|
|
3248 |
if (lower_bound == 0) |
if (lower_bound == 0) |
3249 |
{ |
{ |
3250 |
/* A succeed_n that starts with 0 is really a |
/* A succeed_n that starts with 0 is really a |
3251 |
a simple on_failure_jump_loop. */ |
a simple on_failure_jump_loop. */ |
3252 |
INSERT_JUMP (on_failure_jump_loop, laststart, |
INSERT_JUMP (on_failure_jump_loop, laststart, |
3253 |
b + 3 + nbytes); |
b + 3 + nbytes); |
3254 |
b += 3; |
b += 3; |
3255 |
} |
} |
3256 |
else |
else |
3257 |
{ |
{ |
3258 |
/* Initialize lower bound of the `succeed_n', even |
/* Initialize lower bound of the `succeed_n', even |
3259 |
though it will be set during matching by its |
though it will be set during matching by its |
3260 |
attendant `set_number_at' (inserted next), |
attendant `set_number_at' (inserted next), |
3261 |
because `re_compile_fastmap' needs to know. |
because `re_compile_fastmap' needs to know. |
3262 |
Jump to the `jump_n' we might insert below. */ |
Jump to the `jump_n' we might insert below. */ |
3263 |
INSERT_JUMP2 (succeed_n, laststart, |
INSERT_JUMP2 (succeed_n, laststart, |
3264 |
b + 5 + nbytes, |
b + 5 + nbytes, |
3265 |
lower_bound); |
lower_bound); |
3266 |
b += 5; |
b += 5; |
3267 |
|
|
3268 |
/* Code to initialize the lower bound. Insert |
/* Code to initialize the lower bound. Insert |
3269 |
before the `succeed_n'. The `5' is the last two |
before the `succeed_n'. The `5' is the last two |
3270 |
bytes of this `set_number_at', plus 3 bytes of |
bytes of this `set_number_at', plus 3 bytes of |
3271 |
the following `succeed_n'. */ |
the following `succeed_n'. */ |
3272 |
insert_op2 (set_number_at, laststart, 5, lower_bound, b); |
insert_op2 (set_number_at, laststart, 5, lower_bound, b); |
3273 |
b += 5; |
b += 5; |
3274 |
startoffset += 5; |
startoffset += 5; |
3275 |
} |
} |
3276 |
|
|
3277 |
if (upper_bound < 0) |
if (upper_bound < 0) |
3278 |
{ |
{ |
3279 |
/* A negative upper bound stands for infinity, |
/* A negative upper bound stands for infinity, |
3280 |
in which case it degenerates to a plain jump. */ |
in which case it degenerates to a plain jump. */ |
3281 |
STORE_JUMP (jump, b, laststart + startoffset); |
STORE_JUMP (jump, b, laststart + startoffset); |
3282 |
b += 3; |
b += 3; |
3283 |
} |
} |
3284 |
else if (upper_bound > 1) |
else if (upper_bound > 1) |
3285 |
{ /* More than one repetition is allowed, so |
{ /* More than one repetition is allowed, so |
3286 |
append a backward jump to the `succeed_n' |
append a backward jump to the `succeed_n' |
3287 |
that starts this interval. |
that starts this interval. |
3288 |
|
|
3289 |
When we've reached this during matching, |
When we've reached this during matching, |
3290 |
we'll have matched the interval once, so |
we'll have matched the interval once, so |
3291 |
jump back only `upper_bound - 1' times. */ |
jump back only `upper_bound - 1' times. */ |
3292 |
STORE_JUMP2 (jump_n, b, laststart + startoffset, |
STORE_JUMP2 (jump_n, b, laststart + startoffset, |
3293 |
upper_bound - 1); |
upper_bound - 1); |
3294 |
b += 5; |
b += 5; |
3295 |
|
|
3296 |
/* The location we want to set is the second |
/* The location we want to set is the second |
3297 |
parameter of the `jump_n'; that is `b-2' as |
parameter of the `jump_n'; that is `b-2' as |
3298 |
an absolute address. `laststart' will be |
an absolute address. `laststart' will be |
3299 |
the `set_number_at' we're about to insert; |
the `set_number_at' we're about to insert; |
3300 |
`laststart+3' the number to set, the source |
`laststart+3' the number to set, the source |
3301 |
for the relative address. But we are |
for the relative address. But we are |
3302 |
inserting into the middle of the pattern -- |
inserting into the middle of the pattern -- |
3303 |
so everything is getting moved up by 5. |
so everything is getting moved up by 5. |
3304 |
Conclusion: (b - 2) - (laststart + 3) + 5, |
Conclusion: (b - 2) - (laststart + 3) + 5, |
3305 |
i.e., b - laststart. |
i.e., b - laststart. |
3306 |
|
|
3307 |
We insert this at the beginning of the loop |
We insert this at the beginning of the loop |
3308 |
so that if we fail during matching, we'll |
so that if we fail during matching, we'll |
3309 |
reinitialize the bounds. */ |
reinitialize the bounds. */ |
3310 |
insert_op2 (set_number_at, laststart, b - laststart, |
insert_op2 (set_number_at, laststart, b - laststart, |
3311 |
upper_bound - 1, b); |
upper_bound - 1, b); |
3312 |
b += 5; |
b += 5; |
3313 |
} |
} |
3314 |
} |
} |
3315 |
pending_exact = 0; |
pending_exact = 0; |
3316 |
beg_interval = NULL; |
beg_interval = NULL; |
3317 |
} |
} |
5496 |
cycle detection cannot work. Worse yet, such a detection |
cycle detection cannot work. Worse yet, such a detection |
5497 |
can not only fail to detect a cycle, but it can also wrongly |
can not only fail to detect a cycle, but it can also wrongly |
5498 |
detect a cycle (between different instantiations of the same |
detect a cycle (between different instantiations of the same |
5499 |
loop. |
loop). |
5500 |
So the method used for those nasty loops is a little different: |
So the method used for those nasty loops is a little different: |
5501 |
We use a special cycle-detection-stack-frame which is pushed |
We use a special cycle-detection-stack-frame which is pushed |
5502 |
when the on_failure_jump_nastyloop failure-point is *popped*. |
when the on_failure_jump_nastyloop failure-point is *popped*. |
5510 |
mcnt, p + mcnt); |
mcnt, p + mcnt); |
5511 |
|
|
5512 |
assert ((re_opcode_t)p[-4] == no_op); |
assert ((re_opcode_t)p[-4] == no_op); |
5513 |
CHECK_INFINITE_LOOP (p - 4, d); |
{ |
5514 |
PUSH_FAILURE_POINT (p - 3, d); |
int cycle = 0; |
5515 |
|
CHECK_INFINITE_LOOP (p - 4, d); |
5516 |
|
if (!cycle) |
5517 |
|
/* If there's a cycle, just continue without pushing |
5518 |
|
this failure point. The failure point is the "try again" |
5519 |
|
option, which shouldn't be tried. |
5520 |
|
We want (x?)*?y\1z to match both xxyz and xxyxz. */ |
5521 |
|
PUSH_FAILURE_POINT (p - 3, d); |
5522 |
|
} |
5523 |
break; |
break; |
5524 |
|
|
|
|
|
5525 |
/* Simple loop detecting on_failure_jump: just check on the |
/* Simple loop detecting on_failure_jump: just check on the |
5526 |
failure stack if the same spot was already hit earlier. */ |
failure stack if the same spot was already hit earlier. */ |
5527 |
case on_failure_jump_loop: |
case on_failure_jump_loop: |
5529 |
EXTRACT_NUMBER_AND_INCR (mcnt, p); |
EXTRACT_NUMBER_AND_INCR (mcnt, p); |
5530 |
DEBUG_PRINT3 ("EXECUTING on_failure_jump_loop %d (to %p):\n", |
DEBUG_PRINT3 ("EXECUTING on_failure_jump_loop %d (to %p):\n", |
5531 |
mcnt, p + mcnt); |
mcnt, p + mcnt); |
5532 |
|
{ |
5533 |
CHECK_INFINITE_LOOP (p - 3, d); |
int cycle = 0; |
5534 |
PUSH_FAILURE_POINT (p - 3, d); |
CHECK_INFINITE_LOOP (p - 3, d); |
5535 |
|
if (cycle) |
5536 |
|
/* If there's a cycle, get out of the loop, as if the matching |
5537 |
|
had failed. We used to just `goto fail' here, but that was |
5538 |
|
aborting the search a bit too early: we want to keep the |
5539 |
|
empty-loop-match and keep matching after the loop. |
5540 |
|
We want (x?)*y\1z to match both xxyz and xxyxz. */ |
5541 |
|
p += mcnt; |
5542 |
|
else |
5543 |
|
PUSH_FAILURE_POINT (p - 3, d); |
5544 |
|
} |
5545 |
break; |
break; |
5546 |
|
|
5547 |
|
|