summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Mitchell <davem@fdisolutions.com>2006-04-19 13:56:07 +0000
committerDave Mitchell <davem@fdisolutions.com>2006-04-19 13:56:07 +0000
commitdad790286e318c5c7f4b6ccd52b4fd512c87c763 (patch)
tree43031f05803caa3558f62fdf49ceafe403e9f64b
parent20f9f807e1e82c57258ff80abead8fc8ae928a83 (diff)
downloadperl-dad790286e318c5c7f4b6ccd52b4fd512c87c763.tar.gz
regmatch(): make IFMATCH use PUSH_STACK rather than fake recursion
p4raw-id: //depot/perl@27903
-rw-r--r--regexec.c170
-rw-r--r--regexp.h8
-rw-r--r--t/op/re_tests2
3 files changed, 124 insertions, 56 deletions
diff --git a/regexec.c b/regexec.c
index 53ec117bd0..890736cc13 100644
--- a/regexec.c
+++ b/regexec.c
@@ -2234,7 +2234,6 @@ typedef union re_unwind_t {
#define sayNO goto no
#define sayNO_ANYOF goto no_anyof
#define sayYES_FINAL goto yes_final
-#define sayYES_LOUD goto yes_loud
#define sayNO_FINAL goto no_final
#define sayNO_SILENT goto do_no
#define saySAME(x) if (x) goto yes; else goto no
@@ -3875,7 +3874,11 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
st->u.curlym.maxwanted = st->minmod ? st->ln : n;
if (st->u.curlym.maxwanted) {
while (PL_reginput < PL_regeol && st->u.curlym.matches < st->u.curlym.maxwanted) {
+ /* resume to current state on success */
+ st->u.yes.prev_yes_state = yes_state;
+ yes_state = st;
REGMATCH(scan, CURLYM1);
+ yes_state = st->u.yes.prev_yes_state;
/*** all unsaved local vars undefined at this point */
if (!result)
break;
@@ -3945,15 +3948,24 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
else
PL_regendp[st->u.curlym.paren] = -1;
}
+ /* resume to current state on success */
+ st->u.yes.prev_yes_state = yes_state;
+ yes_state = st;
REGMATCH(next, CURLYM2);
+ yes_state = st->u.yes.prev_yes_state;
/*** all unsaved local vars undefined at this point */
if (result)
- sayYES;
+ /* XXX tmp sayYES; */
+ sayYES_FINAL;
REGCP_UNWIND(st->u.curlym.lastcp);
}
/* Couldn't or didn't -- move forward. */
PL_reginput = locinput;
+ /* resume to current state on success */
+ st->u.yes.prev_yes_state = yes_state;
+ yes_state = st;
REGMATCH(scan, CURLYM3);
+ yes_state = st->u.yes.prev_yes_state;
/*** all unsaved local vars undefined at this point */
if (result) {
st->ln++;
@@ -4018,10 +4030,15 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
else
PL_regendp[st->u.curlym.paren] = -1;
}
+ /* resume to current state on success */
+ st->u.yes.prev_yes_state = yes_state;
+ yes_state = st;
REGMATCH(next, CURLYM4);
+ yes_state = st->u.yes.prev_yes_state;
/*** all unsaved local vars undefined at this point */
if (result)
- sayYES;
+ /* XXX tmp sayYES; */
+ sayYES_FINAL;
REGCP_UNWIND(st->u.curlym.lastcp);
}
/* Couldn't or didn't -- back up. */
@@ -4298,60 +4315,57 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
}
PL_reginput = locinput; /* put where regtry can find it */
sayYES_FINAL; /* Success! */
- case SUCCEED:
+
+ case SUCCEED: /* successful SUSPEND/UNLESSM/IFMATCH/CURLYM */
+ DEBUG_EXECUTE_r(
+ PerlIO_printf(Perl_debug_log,
+ "%*s %ssubpattern success...%s\n",
+ REPORT_CODE_OFF+PL_regindent*2, "", PL_colors[4], PL_colors[5]));
PL_reginput = locinput; /* put where regtry can find it */
- sayYES_LOUD; /* Success! */
- case SUSPEND:
- n = 1;
+ sayYES_FINAL; /* Success! */
+
+ case SUSPEND: /* (?>FOO) */
+ st->u.ifmatch.wanted = 1;
PL_reginput = locinput;
goto do_ifmatch;
- case UNLESSM:
- n = 0;
- if (scan->flags) {
- char * const s = HOPBACKc(locinput, scan->flags);
- if (!s)
- goto say_yes;
- PL_reginput = s;
- }
- else
- PL_reginput = locinput;
- goto do_ifmatch;
- case IFMATCH:
- n = 1;
+
+ case UNLESSM: /* -ve lookaround: (?!FOO), or with flags, (?<!foo) */
+ st->u.ifmatch.wanted = 0;
+ goto ifmatch_trivial_fail_test;
+
+ case IFMATCH: /* +ve lookaround: (?=FOO), or with flags, (?<=foo) */
+ st->u.ifmatch.wanted = 1;
+ ifmatch_trivial_fail_test:
if (scan->flags) {
char * const s = HOPBACKc(locinput, scan->flags);
- if (!s)
- goto say_no;
+ if (!s) {
+ /* trivial fail */
+ if (st->logical) {
+ st->logical = 0;
+ st->sw = 1 - st->u.ifmatch.wanted;
+ }
+ else if (st->u.ifmatch.wanted)
+ sayNO;
+ next = scan + ARG(scan);
+ if (next == scan)
+ next = NULL;
+ break;
+ }
PL_reginput = s;
}
else
PL_reginput = locinput;
do_ifmatch:
- REGMATCH(NEXTOPER(NEXTOPER(scan)), IFMATCH);
- /*** all unsaved local vars undefined at this point */
- if (result != n) {
- say_no:
- if (st->logical) {
- st->logical = 0;
- st->sw = 0;
- goto do_longjump;
- }
- else
- sayNO;
- }
- say_yes:
- if (st->logical) {
- st->logical = 0;
- st->sw = 1;
- }
- if (OP(scan) == SUSPEND) {
- locinput = PL_reginput;
- nextchr = UCHARAT(locinput);
- }
- /* FALL THROUGH. */
+ /* resume to current state on success */
+ st->u.yes.prev_yes_state = yes_state;
+ yes_state = st;
+ PUSH_STATE(newst, resume_IFMATCH);
+ st = newst;
+ next = NEXTOPER(NEXTOPER(scan));
+ break;
+
case LONGJMP:
- do_longjump:
next = scan + ARG(scan);
if (next == scan)
next = NULL;
@@ -4412,19 +4426,17 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
/*NOTREACHED*/
sayNO;
-yes_loud:
- DEBUG_EXECUTE_r(
- PerlIO_printf(Perl_debug_log,
- "%*s %scould match...%s\n",
- REPORT_CODE_OFF+PL_regindent*2, "", PL_colors[4], PL_colors[5])
- );
- goto yes;
yes_final:
if (yes_state) {
/* we have successfully completed a subexpression, but we must now
* pop to the state marked by yes_state and continue from there */
+ /*XXX tmp for CURLYM*/
+ regmatch_slab *oslab = PL_regmatch_slab;
+ regmatch_state *ost = st, *oys=yes_state;
+ int odepth = depth;
+
assert(st != yes_state);
while (yes_state < SLAB_FIRST(PL_regmatch_slab)
|| yes_state > SLAB_LAST(PL_regmatch_slab))
@@ -4435,7 +4447,7 @@ yes_final:
st = SLAB_LAST(PL_regmatch_slab);
}
depth -= (st - yes_state);
- DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "POP STATE TO (%d)\n", depth)); \
+ DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "POP STATE TO (%d)\n", depth));
st = yes_state;
yes_state = st->u.yes.prev_yes_state;
PL_regmatch_state = st;
@@ -4461,6 +4473,38 @@ yes_final:
next = st->next;
goto reenter;
+ case resume_IFMATCH:
+ if (st->logical) {
+ st->logical = 0;
+ st->sw = st->u.ifmatch.wanted;
+ }
+ else if (!st->u.ifmatch.wanted)
+ sayNO;
+
+ if (OP(st->scan) == SUSPEND)
+ locinput = PL_reginput;
+ else {
+ locinput = PL_reginput = st->locinput;
+ nextchr = UCHARAT(locinput);
+ }
+ next = st->scan + ARG(st->scan);
+ if (next == st->scan)
+ next = NULL;
+ goto reenter;
+
+ /* XXX tmp don't handle yes_state yet */
+ case resume_CURLYM1:
+ case resume_CURLYM2:
+ case resume_CURLYM3:
+ case resume_CURLYM4:
+ PL_regmatch_slab =oslab;
+ st = ost;
+ PL_regmatch_state = st;
+ depth = odepth;
+ yes_state = oys;
+ DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "XXX revering a CURLYM\n"));
+ goto yes;
+
default:
Perl_croak(aTHX_ "unexpected yes reume state");
}
@@ -4508,8 +4552,6 @@ yes:
goto resume_point_CURLYM3;
case resume_CURLYM4:
goto resume_point_CURLYM4;
- case resume_IFMATCH:
- goto resume_point_IFMATCH;
case resume_PLUS1:
goto resume_point_PLUS1;
case resume_PLUS2:
@@ -4519,6 +4561,7 @@ yes:
case resume_PLUS4:
goto resume_point_PLUS4;
+ case resume_IFMATCH:
case resume_EVAL:
default:
Perl_croak(aTHX_ "regexp resume memory corruption");
@@ -4638,7 +4681,22 @@ do_no:
case resume_CURLYM4:
goto resume_point_CURLYM4;
case resume_IFMATCH:
- goto resume_point_IFMATCH;
+ yes_state = st->u.yes.prev_yes_state;
+ if (st->logical) {
+ st->logical = 0;
+ st->sw = !st->u.ifmatch.wanted;
+ }
+ else if (st->u.ifmatch.wanted)
+ sayNO;
+
+ assert(OP(scan) != SUSPEND); /* XXX DAPM tmp */
+ locinput = PL_reginput = st->locinput;
+ nextchr = UCHARAT(locinput);
+ next = scan + ARG(scan);
+ if (next == scan)
+ next = NULL;
+ goto reenter;
+
case resume_PLUS1:
goto resume_point_PLUS1;
case resume_PLUS2:
diff --git a/regexp.h b/regexp.h
index 455f04838a..5667d1fbec 100644
--- a/regexp.h
+++ b/regexp.h
@@ -260,6 +260,8 @@ typedef struct regmatch_state {
} whilem;
struct {
+ /* this first element must match u.yes */
+ struct regmatch_state *prev_yes_state;
I32 paren;
I32 c1, c2; /* case fold search */
CHECKPOINT lastcp;
@@ -276,6 +278,12 @@ typedef struct regmatch_state {
char *old;
int count;
} plus; /* and CURLYN/CURLY/STAR */
+
+ struct {
+ /* this first element must match u.yes */
+ struct regmatch_state *prev_yes_state;
+ I32 wanted;
+ } ifmatch; /* and SUSPEND/UNLESSM */
} u;
} regmatch_state;
diff --git a/t/op/re_tests b/t/op/re_tests
index a87f81c203..8c8beb14b9 100644
--- a/t/op/re_tests
+++ b/t/op/re_tests
@@ -962,3 +962,5 @@ x(?# x c - Sequence (?#... not terminated
(?:r?)*?r|(.{2,4}) abcde y $1 abcd
(?!)+?|(.{2,4}) abcde y $1 abcd
^(a*?)(?!(a{6}|a{5})*$) aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa y $+[1] 12 # super-linear cache bug may return 18
+^((?>(?:aa)?b)?) aab y $1 aab
+^((?:aa)*)(?:X+((?:\d+|-)(?:X+(.+))?))?$ aaaaX5 y $1 aaaa