This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Protection against overwriting defsubs.h via a symlink
[perl5.git] / regexec.c
index c283b2e..c4d88cc 100644 (file)
--- a/regexec.c
+++ b/regexec.c
     } \
 } STMT_END 
 
+
 static void restore_pos(pTHX_ void *arg);
 
 STATIC CHECKPOINT
@@ -2027,6 +2028,8 @@ got_it:
                                                  the same. */
        restore_pos(aTHX_ prog);
     }
+    if (prog->paren_names) 
+        (void)hv_iterinit(prog->paren_names);
 
     /* make sure $`, $&, $', and $digit will work later */
     if ( !(flags & REXEC_NOT_FIRST) ) {
@@ -2091,7 +2094,7 @@ S_regtry(pTHX_ const regmatch_info *reginfo, char *startpos)
            PerlIO_printf(Perl_debug_log, "  setting stack tmpbase at %"IVdf"\n",
                          (IV)(PL_stack_sp - PL_stack_base));
            ));
-       SAVEI32(cxstack[cxstack_ix].blk_oldsp);
+       SAVESTACK_CXPOS();
        cxstack[cxstack_ix].blk_oldsp = PL_stack_sp - PL_stack_base;
        /* Otherwise OP_NEXTSTATE will free whatever on stack now.  */
        SAVETMPS;
@@ -2209,14 +2212,12 @@ S_regtry(pTHX_ const regmatch_info *reginfo, char *startpos)
 #define sayYES goto yes
 #define sayNO goto no
 #define sayNO_SILENT goto no_silent
-#define saySAME(x) if (x) goto yes; else goto no
 
 /* we dont use STMT_START/END here because it leads to 
    "unreachable code" warnings, which are bogus, but distracting. */
 #define CACHEsayNO \
-    if (st->u.whilem.cache_offset | st->u.whilem.cache_bit) \
-       PL_reg_poscache[st->u.whilem.cache_offset] |= \
-           (1<<st->u.whilem.cache_bit); \
+    if (ST.cache_mask) \
+       PL_reg_poscache[ST.cache_offset] |= ST.cache_mask; \
     sayNO
 
 /* this is used to determine how far from the left messages like
@@ -2254,14 +2255,6 @@ S_push_slab(pTHX)
     return SLAB_FIRST(s);
 }
 
-/* simulate a recursive call to regmatch */
-
-#define REGMATCH(ns, where) \
-    st->scan = scan; \
-    scan = (ns); \
-    st->resume_state = resume_##where; \
-    goto start_recurse; \
-    resume_point_##where:
 
 /* push a new state then goto it */
 
@@ -2280,109 +2273,137 @@ S_push_slab(pTHX)
 
 
 /*
- - regmatch - main matching routine
- *
- * Conceptually the strategy is simple:  check to see whether the current
- * node matches, call self recursively to see whether the rest matches,
- * and then act accordingly.  In practice we make some effort to avoid
- * recursion, in particular by going through "ordinary" nodes (that don't
- * need to know whether the rest of the match failed) by a loop instead of
- * by recursion.
- */
-/* [lwall] I've hoisted the register declarations to the outer block in order to
- * maybe save a little bit of pushing and popping on the stack.  It also takes
- * advantage of machines that use a register save mask on subroutine entry.
- *
- * This function used to be heavily recursive, but since this had the
- * effect of blowing the CPU stack on complex regexes, it has been
- * restructured to be iterative, and to save state onto the heap rather
- * than the stack. Essentially whereever regmatch() used to be called, it
- * pushes the current state, notes where to return, then jumps back into
- * the main loop.
- *
- * Originally the structure of this function used to look something like
 
-    S_regmatch() {
-       int a = 1, b = 2;
+regmatch() - main matching routine
+
+This is basically one big switch statement in a loop. We execute an op,
+set 'next' to point the next op, and continue. If we come to a point which
+we may need to backtrack to on failure such as (A|B|C), we push a
+backtrack state onto the backtrack stack. On failure, we pop the top
+state, and re-enter the loop at the state indicated. If there are no more
+states to pop, we return failure.
+
+Sometimes we also need to backtrack on success; for example /A+/, where
+after successfully matching one A, we need to go back and try to
+match another one; similarly for lookahead assertions: if the assertion
+completes successfully, we backtrack to the state just before the assertion
+and then carry on.  In these cases, the pushed state is marked as
+'backtrack on success too'. This marking is in fact done by a chain of
+pointers, each pointing to the previous 'yes' state. On success, we pop to
+the nearest yes state, discarding any intermediate failure-only states.
+Sometimes a yes state is pushed just to force some cleanup code to be
+called at the end of a successful match or submatch; e.g. (??{$re}) uses
+it to free the inner regex.
+
+Note that failure backtracking rewinds the cursor position, while
+success backtracking leaves it alone.
+
+A pattern is complete when the END op is executed, while a subpattern
+such as (?=foo) is complete when the SUCCESS op is executed. Both of these
+ops trigger the "pop to last yes state if any, otherwise return true"
+behaviour.
+
+A common convention in this function is to use A and B to refer to the two
+subpatterns (or to the first nodes thereof) in patterns like /A*B/: so A is
+the subpattern to be matched possibly multiple times, while B is the entire
+rest of the pattern. Variable and state names reflect this convention.
+
+The states in the main switch are the union of ops and failure/success of
+substates associated with with that op.  For example, IFMATCH is the op
+that does lookahead assertions /(?=A)B/ and so the IFMATCH state means
+'execute IFMATCH'; while IFMATCH_A is a state saying that we have just
+successfully matched A and IFMATCH_A_fail is a state saying that we have
+just failed to match A. Resume states always come in pairs. The backtrack
+state we push is marked as 'IFMATCH_A', but when that is popped, we resume
+at IFMATCH_A or IFMATCH_A_fail, depending on whether we are backtracking
+on success or failure.
+
+The struct that holds a backtracking state is actually a big union, with
+one variant for each major type of op. The variable st points to the
+top-most backtrack struct. To make the code clearer, within each
+block of code we #define ST to alias the relevant union.
+
+Here's a concrete example of a (vastly oversimplified) IFMATCH
+implementation:
+
+    switch (state) {
+    ....
+
+#define ST st->u.ifmatch
+
+    case IFMATCH: // we are executing the IFMATCH op, (?=A)B
+       ST.foo = ...; // some state we wish to save
        ...
-       while (scan != NULL) {
-           a++; // do stuff with a and b
-           ...
-           switch (OP(scan)) {
-               case FOO: {
-                   int local = 3;
-                   ...
-                   if (regmatch(...))  // recurse
-                       goto yes;
-               }
-               ...
-           }
-       }
-       yes:
-       return 1;
-    }
+       // push a yes backtrack state with a resume value of
+       // IFMATCH_A/IFMATCH_A_fail, then continue execution at the
+       // first node of A:
+       PUSH_YES_STATE_GOTO(IFMATCH_A, A);
+       // NOTREACHED
+
+    case IFMATCH_A: // we have successfully executed A; now continue with B
+       next = B;
+       bar = ST.foo; // do something with the preserved value
+       break;
+
+    case IFMATCH_A_fail: // A failed, so the assertion failed
+       ...;   // do some housekeeping, then ...
+       sayNO; // propagate the failure
 
- * Now it looks something like this:
+#undef ST
+
+    ...
+    }
 
-    typedef struct {
-       int a, b, local;
-       int resume_state;
-    } regmatch_state;
+For any old-timers reading this who are familiar with the old recursive
+approach, the code above is equivalent to:
 
-    S_regmatch() {
-       regmatch_state *st = new();
-       int depth=0;
-       st->a++; // do stuff with a and b
+    case IFMATCH: // we are executing the IFMATCH op, (?=A)B
+    {
+       int foo = ...
        ...
-       while (scan != NULL) {
-           ...
-           switch (OP(scan)) {
-               case FOO: {
-                   st->local = 3;
-                   ...
-                   st->scan = scan;
-                   scan = ...;
-                   st->resume_state = resume_FOO;
-                   goto start_recurse; // recurse
-
-                   resume_point_FOO:
-                   if (result)
-                       goto yes;
-               }
-               ...
-           }
-         start_recurse:
-           st = new(); push a new state
-           st->a = 1; st->b = 2;
-           depth++;
-       }
-      yes:
-       result = 1;
-       if (depth--) {
-           st = pop();
-           switch (resume_state) {
-           case resume_FOO:
-               goto resume_point_FOO;
-           ...
-           }
+       if (regmatch(A)) {
+           next = B;
+           bar = foo;
+           break;
        }
-       return result
+       ...;   // do some housekeeping, then ...
+       sayNO; // propagate the failure
     }
-           
- * WARNING: this means that any line in this function that contains a
- * REGMATCH() or TRYPAREN() is actually simulating a recursive call to
- * regmatch() using gotos instead. Thus the values of any local variables
- * not saved in the regmatch_state structure will have been lost when
- * execution resumes on the next line .
- *
- * States (ie the st pointer) are allocated in slabs of about 4K in size.
- * PL_regmatch_state always points to the currently active state, and
- * PL_regmatch_slab points to the slab currently containing PL_regmatch_state.
- * The first time regmatch is called, the first slab is allocated, and is
- * never freed until interpreter desctruction. When the slab is full,
- * a new one is allocated chained to the end. At exit from regmatch, slabs
- * allocated since entry are freed.
- */
+
+The topmost backtrack state, pointed to by st, is usually free. If you
+want to claim it, populate any ST.foo fields in it with values you wish to
+save, then do one of
+
+       PUSH_STATE_GOTO(resume_state, node);
+       PUSH_YES_STATE_GOTO(resume_state, node);
+
+which sets that backtrack state's resume value to 'resume_state', pushes a
+new free entry to the top of the backtrack stack, then goes to 'node'.
+On backtracking, the free slot is popped, and the saved state becomes the
+new free state. An ST.foo field in this new top state can be temporarily
+accessed to retrieve values, but once the main loop is re-entered, it
+becomes available for reuse.
+
+Note that the depth of the backtrack stack constantly increases during the
+left-to-right execution of the pattern, rather than going up and down with
+the pattern nesting. For example the stack is at its maximum at Z at the
+end of the pattern, rather than at X in the following:
+
+    /(((X)+)+)+....(Y)+....Z/
+
+The only exceptions to this are lookahead/behind assertions and the cut,
+(?>A), which pop all the backtrack states associated with A before
+continuing.
+Bascktrack state structs are allocated in slabs of about 4K in size.
+PL_regmatch_state and st always point to the currently active state,
+and PL_regmatch_slab points to the slab currently containing
+PL_regmatch_state.  The first time regmatch() is called, the first slab is
+allocated, and is never freed until interpreter destruction. When the slab
+is full, a new one is allocated and chained to the end. At exit from
+regmatch(), slabs allocated since entry are freed.
+
+*/
  
 
 #define DEBUG_STATE_pp(pp)                                 \
@@ -2487,6 +2508,30 @@ S_dump_exec_pos(pTHX_ const char *locinput,
 
 #endif
 
+/* reg_check_named_buff_matched()
+ * Checks to see if a named buffer has matched. The data array of 
+ * buffer numbers corresponding to the buffer is expected to reside
+ * in the regexp->data->data array in the slot stored in the ARG() of
+ * node involved. Note that this routine doesn't actually care about the
+ * name, that information is not preserved from compilation to execution.
+ * Returns the index of the leftmost defined buffer with the given name
+ * or 0 if non of the buffers matched.
+ */
+STATIC I32
+S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan) {
+    I32 n;
+    SV *sv_dat=(SV*)rex->data->data[ ARG( scan ) ];
+    I32 *nums=(I32*)SvPVX(sv_dat);
+    for ( n=0; n<SvIVX(sv_dat); n++ ) {
+        if ((I32)*PL_reglastparen >= nums[n] &&
+            PL_regendp[nums[n]] != -1)
+        {
+            return nums[n];
+        }
+    }
+    return 0;
+}
+
 STATIC I32                     /* 0 failure, 1 success */
 S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
 {
@@ -2508,21 +2553,34 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
     /* cache heavy used fields of st in registers */
     register regnode *scan;
     register regnode *next;
-    register I32 n = 0;        /* initialize to shut up compiler warning */
+    register I32 n = 0;        /* general value; init to avoid compiler warning */
+    register I32 ln = 0; /* len or last;  init to avoid compiler warning */
     register char *locinput = PL_reginput;
-
-    /* these variables are NOT saved during a recusive RFEGMATCH: */
     register I32 nextchr;   /* is always set to UCHARAT(locinput) */
+
     bool result = 0;       /* return value of S_regmatch */
-    int depth = 0;         /* depth of recursion */
+    int depth = 0;         /* depth of backtrack stack */
     int nochange_depth = 0; /* depth of RECURSE recursion with nochange*/
     regmatch_state *yes_state = NULL; /* state to pop to on success of
                                                            subpattern */
     regmatch_state *cur_eval = NULL; /* most recent EVAL_AB state */
     struct regmatch_state  *cur_curlyx = NULL; /* most recent curlyx */
     U32 state_num;
-    
-    I32 parenfloor = 0;
+
+    /* these three flags are set by various ops to signal information to
+     * the very next op. They have a useful lifetime of exactly one loop
+     * iteration, and are not preserved or restored by state pushes/pops
+     */
+    bool sw = 0;           /* the condition value in (?(cond)a|b) */
+    bool minmod = 0;       /* the next "{n,m}" is a "{n,m}?" */
+    int logical = 0;       /* the following EVAL is:
+                               0: (?{...})
+                               1: (?(?{...})X|Y)
+                               2: (??{...})
+                              or the following IFMATCH/UNLESSM is:
+                               false: plain (?=foo)
+                               true:  used as a condition: (?(?=foo))
+                           */
 
 #ifdef DEBUGGING
     GET_RE_DEBUG_FLAGS_DECL;
@@ -2546,11 +2604,6 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
     if (st >  SLAB_LAST(PL_regmatch_slab))
        st = PL_regmatch_state = S_push_slab(aTHX);
 
-    st->minmod = 0;
-    st->sw = 0;
-    st->logical = 0;
-    cur_curlyx = NULL;
-
     /* Note that nextchr is a byte even in UTF */
     nextchr = UCHARAT(locinput);
     scan = prog;
@@ -2924,11 +2977,11 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
 
        case EXACT: {
            char *s = STRING(scan);
-           st->ln = STR_LEN(scan);
+           ln = STR_LEN(scan);
            if (do_utf8 != UTF) {
                /* The target and the pattern have differing utf8ness. */
                char *l = locinput;
-               const char * const e = s + st->ln;
+               const char * const e = s + ln;
 
                if (do_utf8) {
                    /* The target is utf8, the pattern is not utf8. */
@@ -2966,11 +3019,11 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            /* Inline the first character, for speed. */
            if (UCHARAT(s) != nextchr)
                sayNO;
-           if (PL_regeol - locinput < st->ln)
+           if (PL_regeol - locinput < ln)
                sayNO;
-           if (st->ln > 1 && memNE(s, locinput, st->ln))
+           if (ln > 1 && memNE(s, locinput, ln))
                sayNO;
-           locinput += st->ln;
+           locinput += ln;
            nextchr = UCHARAT(locinput);
            break;
            }
@@ -2979,14 +3032,14 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            /* FALL THROUGH */
        case EXACTF: {
            char * const s = STRING(scan);
-           st->ln = STR_LEN(scan);
+           ln = STR_LEN(scan);
 
            if (do_utf8 || UTF) {
              /* Either target or the pattern are utf8. */
                const char * const l = locinput;
                char *e = PL_regeol;
 
-               if (ibcmp_utf8(s, 0,  st->ln, (bool)UTF,
+               if (ibcmp_utf8(s, 0,  ln, (bool)UTF,
                               l, &e, 0,  do_utf8)) {
                     /* One more case for the sharp s:
                      * pack("U0U*", 0xDF) =~ /ss/i,
@@ -2994,7 +3047,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                      * byte sequence for the U+00DF. */
                     if (!(do_utf8 &&
                           toLOWER(s[0]) == 's' &&
-                          st->ln >= 2 &&
+                          ln >= 2 &&
                           toLOWER(s[1]) == 's' &&
                           (U8)l[0] == 0xC3 &&
                           e - l >= 2 &&
@@ -3013,13 +3066,13 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                UCHARAT(s) != ((OP(scan) == EXACTF)
                               ? PL_fold : PL_fold_locale)[nextchr])
                sayNO;
-           if (PL_regeol - locinput < st->ln)
+           if (PL_regeol - locinput < ln)
                sayNO;
-           if (st->ln > 1 && (OP(scan) == EXACTF
-                          ? ibcmp(s, locinput, st->ln)
-                          : ibcmp_locale(s, locinput, st->ln)))
+           if (ln > 1 && (OP(scan) == EXACTF
+                          ? ibcmp(s, locinput, ln)
+                          : ibcmp_locale(s, locinput, ln)))
                sayNO;
-           locinput += st->ln;
+           locinput += ln;
            nextchr = UCHARAT(locinput);
            break;
            }
@@ -3111,35 +3164,35 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            /* was last char in word? */
            if (do_utf8) {
                if (locinput == PL_bostr)
-                   st->ln = '\n';
+                   ln = '\n';
                else {
                    const U8 * const r = reghop3((U8*)locinput, -1, (U8*)PL_bostr);
                
-                   st->ln = utf8n_to_uvchr(r, UTF8SKIP(r), 0, uniflags);
+                   ln = utf8n_to_uvchr(r, UTF8SKIP(r), 0, uniflags);
                }
                if (OP(scan) == BOUND || OP(scan) == NBOUND) {
-                   st->ln = isALNUM_uni(st->ln);
+                   ln = isALNUM_uni(ln);
                    LOAD_UTF8_CHARCLASS_ALNUM();
                    n = swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8);
                }
                else {
-                   st->ln = isALNUM_LC_uvchr(UNI_TO_NATIVE(st->ln));
+                   ln = isALNUM_LC_uvchr(UNI_TO_NATIVE(ln));
                    n = isALNUM_LC_utf8((U8*)locinput);
                }
            }
            else {
-               st->ln = (locinput != PL_bostr) ?
+               ln = (locinput != PL_bostr) ?
                    UCHARAT(locinput - 1) : '\n';
                if (OP(scan) == BOUND || OP(scan) == NBOUND) {
-                   st->ln = isALNUM(st->ln);
+                   ln = isALNUM(ln);
                    n = isALNUM(nextchr);
                }
                else {
-                   st->ln = isALNUM_LC(st->ln);
+                   ln = isALNUM_LC(ln);
                    n = isALNUM_LC(nextchr);
                }
            }
-           if (((!st->ln) == (!n)) == (OP(scan) == BOUND ||
+           if (((!ln) == (!n)) == (OP(scan) == BOUND ||
                                    OP(scan) == BOUNDL))
                    sayNO;
            break;
@@ -3261,22 +3314,42 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
               locinput++;
            nextchr = UCHARAT(locinput);
            break;
+            
+       case NREFFL:
+       {
+           char *s;
+           char type;
+           PL_reg_flags |= RF_tainted;
+           /* FALL THROUGH */
+       case NREF:
+       case NREFF:
+           type = OP(scan);
+           n = reg_check_named_buff_matched(rex,scan);
+
+            if ( n ) {
+                type = REF + ( type - NREF );
+                goto do_ref;
+            } else {
+                sayNO;
+            }
+            /* unreached */
        case REFFL:
            PL_reg_flags |= RF_tainted;
            /* FALL THROUGH */
         case REF:
-       case REFF: {
-           char *s;
+       case REFF: 
            n = ARG(scan);  /* which paren pair */
-           st->ln = PL_regstartp[n];
+           type = OP(scan);
+         do_ref:  
+           ln = PL_regstartp[n];
            PL_reg_leftiter = PL_reg_maxiter;           /* Void cache */
-           if ((I32)*PL_reglastparen < n || st->ln == -1)
+           if ((I32)*PL_reglastparen < n || ln == -1)
                sayNO;                  /* Do not match unless seen CLOSEn. */
-           if (st->ln == PL_regendp[n])
+           if (ln == PL_regendp[n])
                break;
 
-           s = PL_bostr + st->ln;
-           if (do_utf8 && OP(scan) != REF) {   /* REF can do byte comparison */
+           s = PL_bostr + ln;
+           if (do_utf8 && type != REF) {       /* REF can do byte comparison */
                char *l = locinput;
                const char *e = PL_bostr + PL_regendp[n];
                /*
@@ -3284,7 +3357,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                 * in the 8-bit case (no pun intended) because in Unicode we
                 * have to map both upper and title case to lower case.
                 */
-               if (OP(scan) == REFF) {
+               if (type == REFF) {
                    while (s < e) {
                        STRLEN ulen1, ulen2;
                        U8 tmpbuf1[UTF8_MAXBYTES_CASE+1];
@@ -3307,24 +3380,23 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
 
            /* Inline the first character, for speed. */
            if (UCHARAT(s) != nextchr &&
-               (OP(scan) == REF ||
-                (UCHARAT(s) != ((OP(scan) == REFF
-                                 ? PL_fold : PL_fold_locale)[nextchr]))))
+               (type == REF ||
+                (UCHARAT(s) != (type == REFF
+                                 ? PL_fold : PL_fold_locale)[nextchr])))
                sayNO;
-           st->ln = PL_regendp[n] - st->ln;
-           if (locinput + st->ln > PL_regeol)
+           ln = PL_regendp[n] - ln;
+           if (locinput + ln > PL_regeol)
                sayNO;
-           if (st->ln > 1 && (OP(scan) == REF
-                          ? memNE(s, locinput, st->ln)
-                          : (OP(scan) == REFF
-                             ? ibcmp(s, locinput, st->ln)
-                             : ibcmp_locale(s, locinput, st->ln))))
+           if (ln > 1 && (type == REF
+                          ? memNE(s, locinput, ln)
+                          : (type == REFF
+                             ? ibcmp(s, locinput, ln)
+                             : ibcmp_locale(s, locinput, ln))))
                sayNO;
-           locinput += st->ln;
+           locinput += ln;
            nextchr = UCHARAT(locinput);
            break;
-           }
-
+       }
        case NOTHING:
        case TAIL:
            break;
@@ -3392,14 +3464,14 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                PL_op = oop;
                PAD_RESTORE_LOCAL(old_comppad);
                PL_curcop = ocurcop;
-               if (!st->logical) {
+               if (!logical) {
                    /* /(?{...})/ */
                    sv_setsv(save_scalar(PL_replgv), ret);
                    break;
                }
            }
-           if (st->logical == 2) { /* Postponed subexpression: /(??{...})/ */
-
+           if (logical == 2) { /* Postponed subexpression: /(??{...})/ */
+               logical = 0;
                {
                    /* extract RE object from returned value; compiling if
                     * necessary */
@@ -3466,7 +3538,6 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                /* XXXX This is too dramatic a measure... */
                PL_reg_maxiter = 0;
 
-               st->logical = 0;
                ST.toggle_reg_flags = PL_reg_flags;
                if (re->reganch & ROPT_UTF8)
                    PL_reg_flags |= RF_utf8;
@@ -3485,9 +3556,9 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                PUSH_YES_STATE_GOTO(EVAL_AB, startpoint);
                /* NOTREACHED */
            }
-           /* /(?(?{...})X|Y)/ */
-           st->sw = (bool)SvTRUE(ret);
-           st->logical = 0;
+           /* logical is 1,   /(?(?{...})X|Y)/ */
+           sw = (bool)SvTRUE(ret);
+           logical = 0;
            break;
        }
 
@@ -3538,11 +3609,22 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            break;
        case GROUPP:
            n = ARG(scan);  /* which paren pair */
-           st->sw = (bool)((I32)*PL_reglastparen >= n && PL_regendp[n] != -1);
+           sw = (bool)((I32)*PL_reglastparen >= n && PL_regendp[n] != -1);
            break;
+       case NGROUPP:
+           /* reg_check_named_buff_matched returns 0 for no match */
+           sw = (bool)(0 < reg_check_named_buff_matched(rex,scan));
+           break;
+        case RECURSEP:
+            n = ARG(scan);
+            sw = (cur_eval && (!n || cur_eval->u.eval.close_paren == n));
+            break;
+        case DEFINEP:
+            sw = 0;
+            break;
        case IFTHEN:
            PL_reg_leftiter = PL_reg_maxiter;           /* Void cache */
-           if (st->sw)
+           if (sw)
                next = NEXTOPER(NEXTOPER(scan));
            else {
                next = scan + ARG(scan);
@@ -3551,212 +3633,198 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            }
            break;
        case LOGICAL:
-           st->logical = scan->flags;
+           logical = scan->flags;
            break;
+
 /*******************************************************************
- cur_curlyx points to the regmatch_state associated with the most recent CURLYX.
- This struct contains info about the innermost (...)* loop (an
- "infoblock"), and a pointer to the next outer cur_curlyx.
 
- Here is how Y(A)*Z is processed (if it is compiled into CURLYX/WHILEM):
+The CURLYX/WHILEM pair of ops handle the most generic case of the /A*B/
+pattern, where A and B are subpatterns. (For simple A, CURLYM or
+STAR/PLUS/CURLY/CURLYN are used instead.)
 
-   1) After matching Y, regnode for CURLYX is processed;
+A*B is compiled as <CURLYX><A><WHILEM><B>
 
-   2) This regnode populates cur_curlyx, and calls regmatch() recursively
-      with the starting point at WHILEM node;
+On entry to the subpattern, CURLYX is called. This pushes a CURLYX
+state, which contains the current count, initialised to -1. It also sets
+cur_curlyx to point to this state, with any previous value saved in the
+state block.
 
-   3) Each hit of WHILEM node tries to match A and Z (in the order
-      depending on the current iteration, min/max of {min,max} and
-      greediness).  The information about where are nodes for "A"
-      and "Z" is read from cur_curlyx, as is info on how many times "A"
-      was already matched, and greediness.
+CURLYX then jumps straight to the WHILEM op, rather than executing A,
+since the pattern may possibly match zero times (i.e. it's a while {} loop
+rather than a do {} while loop).
 
-   4) After A matches, the same WHILEM node is hit again.
+Each entry to WHILEM represents a successful match of A. The count in the
+CURLYX block is incremented, another WHILEM state is pushed, and execution
+passes to A or B depending on greediness and the current count.
 
-   5) Each time WHILEM is hit, cur_curlyx is the infoblock created by CURLYX
-      of the same pair.  Thus when WHILEM tries to match Z, it temporarily
-      resets cur_curlyx, since this Y(A)*Z can be a part of some other loop:
-      as in (Y(A)*Z)*.  If Z matches, the automaton will hit the WHILEM node
-      of the external loop.
+For example, if matching against the string a1a2a3b (where the aN are
+substrings that match /A/), then the match progresses as follows: (the
+pushed states are interspersed with the bits of strings matched so far):
 
- Currently present infoblocks form a tree with a stem formed by cur_curlyx
- and whatever it mentions via ->next, and additional attached trees
- corresponding to temporarily unset infoblocks as in "5" above.
+    <CURLYX cnt=-1>
+    <CURLYX cnt=0><WHILEM>
+    <CURLYX cnt=1><WHILEM> a1 <WHILEM>
+    <CURLYX cnt=2><WHILEM> a1 <WHILEM> a2 <WHILEM>
+    <CURLYX cnt=3><WHILEM> a1 <WHILEM> a2 <WHILEM> a3 <WHILEM>
+    <CURLYX cnt=3><WHILEM> a1 <WHILEM> a2 <WHILEM> a3 <WHILEM> b
 
- In the following picture, infoblocks for outer loop of
- (Y(A)*?Z)*?T are denoted O, for inner I.  NULL starting block
- is denoted by x.  The matched string is YAAZYAZT.  Temporarily postponed
- infoblocks are drawn below the "reset" infoblock.
+(Contrast this with something like CURLYM, which maintains only a single
+backtrack state:
 
- In fact in the picture below we do not show failed matches for Z and T
- by WHILEM blocks.  [We illustrate minimal matches, since for them it is
- more obvious *why* one needs to *temporary* unset infoblocks.]
+    <CURLYM cnt=0> a1
+    a1 <CURLYM cnt=1> a2
+    a1 a2 <CURLYM cnt=2> a3
+    a1 a2 a3 <CURLYM cnt=3> b
+)
 
-  Matched      REx position    InfoBlocks      Comment
-               (Y(A)*?Z)*?T    x
-               Y(A)*?Z)*?T     x <- O
-  Y            (A)*?Z)*?T      x <- O
-  Y            A)*?Z)*?T       x <- O <- I
-  YA           )*?Z)*?T        x <- O <- I
-  YA           A)*?Z)*?T       x <- O <- I
-  YAA          )*?Z)*?T        x <- O <- I
-  YAA          Z)*?T           x <- O          # Temporary unset I
-                                    I
+Each WHILEM state block marks a point to backtrack to upon partial failure
+of A or B, and also contains some minor state data related to that
+iteration.  The CURLYX block, pointed to by cur_curlyx, contains the
+overall state, such as the count, and pointers to the A and B ops.
 
-  YAAZ         Y(A)*?Z)*?T     x <- O
-                                    I
+This is complicated slightly by nested CURLYX/WHILEM's. Since cur_curlyx
+must always point to the *current* CURLYX block, the rules are:
 
-  YAAZY                (A)*?Z)*?T      x <- O
-                                    I
+When executing CURLYX, save the old cur_curlyx in the CURLYX state block,
+and set cur_curlyx to point the new block.
 
-  YAAZY                A)*?Z)*?T       x <- O <- I
-                                    I
+When popping the CURLYX block after a successful or unsuccessful match,
+restore the previous cur_curlyx.
 
-  YAAZYA       )*?Z)*?T        x <- O <- I     
-                                    I
+When WHILEM is about to execute B, save the current cur_curlyx, and set it
+to the outer one saved in the CURLYX block.
 
-  YAAZYA       Z)*?T           x <- O          # Temporary unset I
-                                    I,I
+When popping the WHILEM block after a successful or unsuccessful B match,
+restore the previous cur_curlyx.
 
-  YAAZYAZ      )*?T            x <- O
-                                    I,I
+Here's an example for the pattern (AI* BI)*BO
+I and O refer to inner and outer, C and W refer to CURLYX and WHILEM:
 
-  YAAZYAZ      T               x               # Temporary unset O
-                               O
-                               I,I
+cur_
+curlyx backtrack stack
+------ ---------------
+NULL   
+CO     <CO prev=NULL> <WO>
+CI     <CO prev=NULL> <WO> <CI prev=CO> <WI> ai 
+CO     <CO prev=NULL> <WO> <CI prev=CO> <WI> ai <WI prev=CI> bi 
+NULL   <CO prev=NULL> <WO> <CI prev=CO> <WI> ai <WI prev=CI> bi <WO prev=CO> bo
 
-  YAAZYAZT                     x
-                               O
-                               I,I
- *******************************************************************/
+At this point the pattern succeeds, and we work back down the stack to
+clean up, restoring as we go:
 
-       case CURLYX: {
-               /* No need to save/restore up to this paren */
-               parenfloor = scan->flags;
-               
-               /* Dave says:
-                  
-                  CURLYX and WHILEM are always paired: they're the moral
-                  equivalent of pp_enteriter anbd pp_iter.
-
-                  The only time next could be null is if the node tree is
-                  corrupt. This was mentioned on p5p a few days ago.
-
-                  See http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2006-04/msg00556.html
-                  So we'll assert that this is true:
-               */
-               assert(next);
-               if (OP(PREVOPER(next)) == NOTHING) /* LONGJMP */
-                   next += ARG(next);
-               /* XXXX Probably it is better to teach regpush to support
-                  parenfloor > PL_regsize... */
-               if (parenfloor > (I32)*PL_reglastparen)
-                   parenfloor = *PL_reglastparen; /* Pessimization... */
-
-               st->u.curlyx.cp = PL_savestack_ix;
-               st->u.curlyx.outercc = cur_curlyx;
-               cur_curlyx = st;
-               /* these fields contain the state of the current curly.
-                * they are accessed by subsequent WHILEMs;
-                * cur and lastloc are also updated by WHILEM */
-               st->u.curlyx.parenfloor = parenfloor;
-               st->u.curlyx.cur = -1; /* this will be updated by WHILEM */
-               st->u.curlyx.min = ARG1(scan);
-               st->u.curlyx.max  = ARG2(scan);
-               st->u.curlyx.scan = NEXTOPER(scan) + EXTRA_STEP_2ARGS;
-               st->u.curlyx.lastloc = 0;
-               /* st->next and st->minmod are also read by WHILEM */
+CO     <CO prev=NULL> <WO> <CI prev=CO> <WI> ai <WI prev=CI> bi 
+CI     <CO prev=NULL> <WO> <CI prev=CO> <WI> ai 
+CO     <CO prev=NULL> <WO>
+NULL   
 
-               PL_reginput = locinput;
-               REGMATCH(PREVOPER(next), CURLYX); /* start on the WHILEM */
-               /*** all unsaved local vars undefined at this point */
-               regcpblow(st->u.curlyx.cp);
-               cur_curlyx = st->u.curlyx.outercc;
-               saySAME(result);
-           }
+*******************************************************************/
+
+#define ST st->u.curlyx
+
+       case CURLYX:    /* start of /A*B/  (for complex A) */
+       {
+           /* No need to save/restore up to this paren */
+           I32 parenfloor = scan->flags;
+           
+           assert(next); /* keep Coverity happy */
+           if (OP(PREVOPER(next)) == NOTHING) /* LONGJMP */
+               next += ARG(next);
+
+           /* XXXX Probably it is better to teach regpush to support
+              parenfloor > PL_regsize... */
+           if (parenfloor > (I32)*PL_reglastparen)
+               parenfloor = *PL_reglastparen; /* Pessimization... */
+
+           ST.prev_curlyx= cur_curlyx;
+           cur_curlyx = st;
+           ST.cp = PL_savestack_ix;
+
+           /* these fields contain the state of the current curly.
+            * they are accessed by subsequent WHILEMs */
+           ST.parenfloor = parenfloor;
+           ST.min = ARG1(scan);
+           ST.max = ARG2(scan);
+           ST.A = NEXTOPER(scan) + EXTRA_STEP_2ARGS;
+           ST.B = next;
+           ST.minmod = minmod;
+           minmod = 0;
+           ST.count = -1;      /* this will be updated by WHILEM */
+           ST.lastloc = NULL;  /* this will be updated by WHILEM */
+
+           PL_reginput = locinput;
+           PUSH_YES_STATE_GOTO(CURLYX_end, PREVOPER(next));
            /* NOTREACHED */
-       case WHILEM: {
-               /*
-                * This is really hard to understand, because after we match
-                * what we're trying to match, we must make sure the rest of
-                * the REx is going to match for sure, and to do that we have
-                * to go back UP the parse tree by recursing ever deeper.  And
-                * if it fails, we have to reset our parent's current state
-                * that we can try again after backing off.
-                */
+       }
 
-               /* Dave says:
-
-                  cur_curlyx gets initialised by CURLYX ready for use by WHILEM.
-                  So again, unless somethings been corrupted, cur_curlyx cannot
-                  be null at that point in WHILEM.
-                  
-                  See http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2006-04/msg00556.html
-                  So we'll assert that this is true:
-               */
-               assert(cur_curlyx);
-               st->u.whilem.lastloc = cur_curlyx->u.curlyx.lastloc; /* Detection of 0-len. */
-               st->u.whilem.cache_offset = 0;
-               st->u.whilem.cache_bit = 0;
-               
-               n = cur_curlyx->u.curlyx.cur + 1; /* how many we know we matched */
-               PL_reginput = locinput;
+       case CURLYX_end: /* just finished matching all of A*B */
+           regcpblow(ST.cp);
+           cur_curlyx = ST.prev_curlyx;
+           sayYES;
+           /* NOTREACHED */
 
-               DEBUG_EXECUTE_r(
-                   PerlIO_printf(Perl_debug_log,
-                                 "%*s  %ld out of %ld..%ld  cc=%"UVxf"\n",
-                                 REPORT_CODE_OFF+depth*2, "",
-                                 (long)n, (long)cur_curlyx->u.curlyx.min,
-                                 (long)cur_curlyx->u.curlyx.max,
-                                 PTR2UV(cur_curlyx))
-                   );
+       case CURLYX_end_fail: /* just failed to match all of A*B */
+           regcpblow(ST.cp);
+           cur_curlyx = ST.prev_curlyx;
+           sayNO;
+           /* NOTREACHED */
 
-               /* If degenerate scan matches "", assume scan done. */
 
-               if (locinput == cur_curlyx->u.curlyx.lastloc && n >=
-                   cur_curlyx->u.curlyx.min)
-               {
-                   st->u.whilem.savecc = cur_curlyx;
-                   cur_curlyx = cur_curlyx->u.curlyx.outercc;
-                   DEBUG_EXECUTE_r(
-                       PerlIO_printf(Perl_debug_log,
-                          "%*s  empty match detected, try continuation...\n",
-                          REPORT_CODE_OFF+depth*2, "")
-                       );
-                   REGMATCH(st->u.whilem.savecc->next, WHILEM1);
-                   /*** all unsaved local vars undefined at this point */
-                   cur_curlyx = st->u.whilem.savecc;
-                   if (result)
-                       sayYES;
-                   sayNO;
-               }
+#undef ST
+#define ST st->u.whilem
 
-               /* First just match a string of min scans. */
-
-               if (n < cur_curlyx->u.curlyx.min) {
-                   cur_curlyx->u.curlyx.cur = n;
-                   cur_curlyx->u.curlyx.lastloc = locinput;
-                   REGMATCH(cur_curlyx->u.curlyx.scan, WHILEM2);
-                   /*** all unsaved local vars undefined at this point */
-                   if (result)
-                       sayYES;
-                   cur_curlyx->u.curlyx.cur = n - 1;
-                   cur_curlyx->u.curlyx.lastloc = st->u.whilem.lastloc;
-                   sayNO;
-               }
+       case WHILEM:     /* just matched an A in /A*B/  (for complex A) */
+       {
+           /* see the discussion above about CURLYX/WHILEM */
+           I32 n;
+           assert(cur_curlyx); /* keep Coverity happy */
+           n = ++cur_curlyx->u.curlyx.count; /* how many A's matched */
+           ST.save_lastloc = cur_curlyx->u.curlyx.lastloc;
+           ST.cache_offset = 0;
+           ST.cache_mask = 0;
+           
+           PL_reginput = locinput;
+
+           DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log,
+                 "%*s  whilem: matched %ld out of %ld..%ld\n",
+                 REPORT_CODE_OFF+depth*2, "", (long)n,
+                 (long)cur_curlyx->u.curlyx.min,
+                 (long)cur_curlyx->u.curlyx.max)
+           );
+
+           /* First just match a string of min A's. */
+
+           if (n < cur_curlyx->u.curlyx.min) {
+               cur_curlyx->u.curlyx.lastloc = locinput;
+               PUSH_STATE_GOTO(WHILEM_A_pre, cur_curlyx->u.curlyx.A);
+               /* NOTREACHED */
+           }
+
+           /* If degenerate A matches "", assume A done. */
+
+           if (locinput == cur_curlyx->u.curlyx.lastloc) {
+               DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log,
+                  "%*s  whilem: empty match detected, trying continuation...\n",
+                  REPORT_CODE_OFF+depth*2, "")
+               );
+               goto do_whilem_B_max;
+           }
+
+           /* super-linear cache processing */
+
+           if (scan->flags) {
 
-               if (scan->flags) {
-                   /* Check whether we already were at this position.
-                       Postpone detection until we know the match is not
-                       *that* much linear. */
                if (!PL_reg_maxiter) {
+                   /* start the countdown: Postpone detection until we
+                    * know the match is not *that* much linear. */
                    PL_reg_maxiter = (PL_regeol - PL_bostr + 1) * (scan->flags>>4);
                    /* possible overflow for long strings and many CURLYX's */
                    if (PL_reg_maxiter < 0)
                        PL_reg_maxiter = I32_MAX;
                    PL_reg_leftiter = PL_reg_maxiter;
                }
+
                if (PL_reg_leftiter-- == 0) {
+                   /* initialise cache */
                    const I32 size = (PL_reg_maxiter + 7)/8;
                    if (PL_reg_poscache) {
                        if ((I32)PL_reg_poscache_size < size) {
@@ -3769,124 +3837,133 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                        PL_reg_poscache_size = size;
                        Newxz(PL_reg_poscache, size, char);
                    }
-                   DEBUG_EXECUTE_r(
-                       PerlIO_printf(Perl_debug_log,
-             "%sDetected a super-linear match, switching on caching%s...\n",
-                                     PL_colors[4], PL_colors[5])
-                       );
+                   DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log,
+      "%swhilem: Detected a super-linear match, switching on caching%s...\n",
+                             PL_colors[4], PL_colors[5])
+                   );
                }
+
                if (PL_reg_leftiter < 0) {
-                   st->u.whilem.cache_offset = locinput - PL_bostr;
-
-                   st->u.whilem.cache_offset = (scan->flags & 0xf) - 1
-                           + st->u.whilem.cache_offset * (scan->flags>>4);
-                   st->u.whilem.cache_bit = st->u.whilem.cache_offset % 8;
-                   st->u.whilem.cache_offset /= 8;
-                   if (PL_reg_poscache[st->u.whilem.cache_offset] & (1<<st->u.whilem.cache_bit)) {
-                   DEBUG_EXECUTE_r(
-                       PerlIO_printf(Perl_debug_log,
-                                     "%*s  already tried at this position...\n",
-                                     REPORT_CODE_OFF+depth*2, "")
+                   /* have we already failed at this position? */
+                   I32 offset, mask;
+                   offset  = (scan->flags & 0xf) - 1
+                               + (locinput - PL_bostr)  * (scan->flags>>4);
+                   mask    = 1 << (offset % 8);
+                   offset /= 8;
+                   if (PL_reg_poscache[offset] & mask) {
+                       DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log,
+                           "%*s  whilem: (cache) already tried at this position...\n",
+                           REPORT_CODE_OFF+depth*2, "")
                        );
                        sayNO; /* cache records failure */
                    }
+                   ST.cache_offset = offset;
+                   ST.cache_mask   = mask;
                }
-               }
+           }
 
-               /* Prefer next over scan for minimal matching. */
-
-               if (cur_curlyx->minmod) {
-                   st->u.whilem.savecc = cur_curlyx;
-                   cur_curlyx = cur_curlyx->u.curlyx.outercc;
-                   st->u.whilem.cp = regcppush(st->u.whilem.savecc->u.curlyx.parenfloor);
-                   REGCP_SET(st->u.whilem.lastcp);
-                   REGMATCH(st->u.whilem.savecc->next, WHILEM3);
-                   /*** all unsaved local vars undefined at this point */
-                   cur_curlyx = st->u.whilem.savecc;
-                   if (result) {
-                       regcpblow(st->u.whilem.cp);
-                       sayYES; /* All done. */
-                   }
-                   REGCP_UNWIND(st->u.whilem.lastcp);
-                   regcppop(rex);
-
-                   if (n >= cur_curlyx->u.curlyx.max) { /* Maximum greed exceeded? */
-                       if (ckWARN(WARN_REGEXP) && n >= REG_INFTY
-                           && !(PL_reg_flags & RF_warned)) {
-                           PL_reg_flags |= RF_warned;
-                           Perl_warner(aTHX_ packWARN(WARN_REGEXP), "%s limit (%d) exceeded",
-                                "Complex regular subexpression recursion",
-                                REG_INFTY - 1);
-                       }
-                       CACHEsayNO;
-                   }
+           /* Prefer B over A for minimal matching. */
 
-                   DEBUG_EXECUTE_r(
-                       PerlIO_printf(Perl_debug_log,
-                                     "%*s  trying longer...\n",
-                                     REPORT_CODE_OFF+depth*2, "")
-                       );
-                   /* Try scanning more and see if it helps. */
-                   PL_reginput = locinput;
-                   cur_curlyx->u.curlyx.cur = n;
-                   cur_curlyx->u.curlyx.lastloc = locinput;
-                   st->u.whilem.cp = regcppush(cur_curlyx->u.curlyx.parenfloor);
-                   REGCP_SET(st->u.whilem.lastcp);
-                   REGMATCH(cur_curlyx->u.curlyx.scan, WHILEM4);
-                   /*** all unsaved local vars undefined at this point */
-                   if (result) {
-                       regcpblow(st->u.whilem.cp);
-                       sayYES;
-                   }
-                   REGCP_UNWIND(st->u.whilem.lastcp);
-                   regcppop(rex);
-                   cur_curlyx->u.curlyx.cur = n - 1;
-                   cur_curlyx->u.curlyx.lastloc = st->u.whilem.lastloc;
-                   CACHEsayNO;
-               }
+           if (cur_curlyx->u.curlyx.minmod) {
+               ST.save_curlyx = cur_curlyx;
+               cur_curlyx = cur_curlyx->u.curlyx.prev_curlyx;
+               ST.cp = regcppush(ST.save_curlyx->u.curlyx.parenfloor);
+               REGCP_SET(ST.lastcp);
+               PUSH_YES_STATE_GOTO(WHILEM_B_min, ST.save_curlyx->u.curlyx.B);
+               /* NOTREACHED */
+           }
 
-               /* Prefer scan over next for maximal matching. */
-
-               if (n < cur_curlyx->u.curlyx.max) {     /* More greed allowed? */
-                   st->u.whilem.cp = regcppush(cur_curlyx->u.curlyx.parenfloor);
-                   cur_curlyx->u.curlyx.cur = n;
-                   cur_curlyx->u.curlyx.lastloc = locinput;
-                   REGCP_SET(st->u.whilem.lastcp);
-                   REGMATCH(cur_curlyx->u.curlyx.scan, WHILEM5);
-                   /*** all unsaved local vars undefined at this point */
-                   if (result) {
-                       regcpblow(st->u.whilem.cp);
-                       sayYES;
-                   }
-                   REGCP_UNWIND(st->u.whilem.lastcp);
-                   regcppop(rex);      /* Restore some previous $<digit>s? */
-                   PL_reginput = locinput;
-                   DEBUG_EXECUTE_r(
-                       PerlIO_printf(Perl_debug_log,
-                                     "%*s  failed, try continuation...\n",
-                                     REPORT_CODE_OFF+depth*2, "")
-                       );
-               }
-               if (ckWARN(WARN_REGEXP) && n >= REG_INFTY
-                       && !(PL_reg_flags & RF_warned)) {
+           /* Prefer A over B for maximal matching. */
+
+           if (n < cur_curlyx->u.curlyx.max) { /* More greed allowed? */
+               ST.cp = regcppush(cur_curlyx->u.curlyx.parenfloor);
+               cur_curlyx->u.curlyx.lastloc = locinput;
+               REGCP_SET(ST.lastcp);
+               PUSH_STATE_GOTO(WHILEM_A_max, cur_curlyx->u.curlyx.A);
+               /* NOTREACHED */
+           }
+           goto do_whilem_B_max;
+       }
+       /* NOTREACHED */
+
+       case WHILEM_B_min: /* just matched B in a minimal match */
+       case WHILEM_B_max: /* just matched B in a maximal match */
+           cur_curlyx = ST.save_curlyx;
+           sayYES;
+           /* NOTREACHED */
+
+       case WHILEM_B_max_fail: /* just failed to match B in a maximal match */
+           cur_curlyx = ST.save_curlyx;
+           cur_curlyx->u.curlyx.lastloc = ST.save_lastloc;
+           cur_curlyx->u.curlyx.count--;
+           CACHEsayNO;
+           /* NOTREACHED */
+
+       case WHILEM_A_min_fail: /* just failed to match A in a minimal match */
+           REGCP_UNWIND(ST.lastcp);
+           regcppop(rex);
+           /* FALL THROUGH */
+       case WHILEM_A_pre_fail: /* just failed to match even minimal A */
+           cur_curlyx->u.curlyx.lastloc = ST.save_lastloc;
+           cur_curlyx->u.curlyx.count--;
+           CACHEsayNO;
+           /* NOTREACHED */
+
+       case WHILEM_A_max_fail: /* just failed to match A in a maximal match */
+           REGCP_UNWIND(ST.lastcp);
+           regcppop(rex);      /* Restore some previous $<digit>s? */
+           PL_reginput = locinput;
+           DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
+               "%*s  whilem: failed, trying continuation...\n",
+               REPORT_CODE_OFF+depth*2, "")
+           );
+         do_whilem_B_max:
+           if (cur_curlyx->u.curlyx.count >= REG_INFTY
+               && ckWARN(WARN_REGEXP)
+               && !(PL_reg_flags & RF_warned))
+           {
+               PL_reg_flags |= RF_warned;
+               Perl_warner(aTHX_ packWARN(WARN_REGEXP), "%s limit (%d) exceeded",
+                    "Complex regular subexpression recursion",
+                    REG_INFTY - 1);
+           }
+
+           /* now try B */
+           ST.save_curlyx = cur_curlyx;
+           cur_curlyx = cur_curlyx->u.curlyx.prev_curlyx;
+           PUSH_YES_STATE_GOTO(WHILEM_B_max, ST.save_curlyx->u.curlyx.B);
+           /* NOTREACHED */
+
+       case WHILEM_B_min_fail: /* just failed to match B in a minimal match */
+           cur_curlyx = ST.save_curlyx;
+           REGCP_UNWIND(ST.lastcp);
+           regcppop(rex);
+
+           if (cur_curlyx->u.curlyx.count >= cur_curlyx->u.curlyx.max) {
+               /* Maximum greed exceeded */
+               if (cur_curlyx->u.curlyx.count >= REG_INFTY
+                   && ckWARN(WARN_REGEXP)
+                   && !(PL_reg_flags & RF_warned))
+               {
                    PL_reg_flags |= RF_warned;
-                   Perl_warner(aTHX_ packWARN(WARN_REGEXP), "%s limit (%d) exceeded",
-                        "Complex regular subexpression recursion",
-                        REG_INFTY - 1);
+                   Perl_warner(aTHX_ packWARN(WARN_REGEXP),
+                       "%s limit (%d) exceeded",
+                       "Complex regular subexpression recursion",
+                       REG_INFTY - 1);
                }
-
-               /* Failed deeper matches of scan, so see if this one works. */
-               st->u.whilem.savecc = cur_curlyx;
-               cur_curlyx = cur_curlyx->u.curlyx.outercc;
-               REGMATCH(st->u.whilem.savecc->next, WHILEM6);
-               /*** all unsaved local vars undefined at this point */
-               cur_curlyx = st->u.whilem.savecc;
-               if (result)
-                   sayYES;
-               cur_curlyx->u.curlyx.cur = n - 1;
-               cur_curlyx->u.curlyx.lastloc = st->u.whilem.lastloc;
+               cur_curlyx->u.curlyx.count--;
                CACHEsayNO;
            }
+
+           DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
+               "%*s  trying longer...\n", REPORT_CODE_OFF+depth*2, "")
+           );
+           /* Try grabbing another A and see if it helps. */
+           PL_reginput = locinput;
+           cur_curlyx->u.curlyx.lastloc = locinput;
+           ST.cp = regcppush(cur_curlyx->u.curlyx.parenfloor);
+           REGCP_SET(ST.lastcp);
+           PUSH_STATE_GOTO(WHILEM_A_min, ST.save_curlyx->u.curlyx.A);
            /* NOTREACHED */
 
 #undef  ST
@@ -3918,6 +3995,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            for (n = *PL_reglastparen; n > ST.lastparen; n--)
                PL_regendp[n] = -1;
            *PL_reglastparen = n;
+           /*dmq: *PL_reglastcloseparen = n; */
            scan = ST.next_branch;
            /* no more branches? */
            if (!scan || (OP(scan) != BRANCH && OP(scan) != BRANCHJ))
@@ -3926,7 +4004,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            /* NOTREACHED */
     
        case MINMOD:
-           st->minmod = 1;
+           minmod = 1;
            break;
 
 #undef  ST
@@ -3956,8 +4034,8 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            ST.B = next;
            ST.alen = 0;
            ST.count = 0;
-           ST.minmod = st->minmod;
-           st->minmod = 0;
+           ST.minmod = minmod;
+           minmod = 0;
            ST.c1 = CHRTEST_UNINIT;
            REGCP_SET(ST.cp);
 
@@ -3997,13 +4075,21 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            );
 
            locinput = PL_reginput;
-           if (ST.count < (ST.minmod ? ARG1(ST.me) : ARG2(ST.me)))
+                       
+           if (cur_eval && cur_eval->u.eval.close_paren && 
+               cur_eval->u.eval.close_paren == ST.me->flags) 
+               goto fake_end;
+               
+           if ( ST.count < (ST.minmod ? ARG1(ST.me) : ARG2(ST.me)) )
                goto curlym_do_A; /* try to match another A */
            goto curlym_do_B; /* try to match B */
 
        case CURLYM_A_fail: /* just failed to match an A */
            REGCP_UNWIND(ST.cp);
-           if (ST.minmod || ST.count < ARG1(ST.me) /* min*/ )
+
+           if (ST.minmod || ST.count < ARG1(ST.me) /* min*/ 
+               || (cur_eval && cur_eval->u.eval.close_paren &&
+                   cur_eval->u.eval.close_paren == ST.me->flags))
                sayNO;
 
          curlym_do_B: /* execute the B in /A{m,n}B/  */
@@ -4052,10 +4138,20 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                    PL_regstartp[paren]
                        = HOPc(PL_reginput, -ST.alen) - PL_bostr;
                    PL_regendp[paren] = PL_reginput - PL_bostr;
+                   /*dmq: *PL_reglastcloseparen = paren; */
                }
                else
                    PL_regendp[paren] = -1;
+               if (cur_eval && cur_eval->u.eval.close_paren &&
+                   cur_eval->u.eval.close_paren == ST.me->flags) 
+               {
+                   if (ST.count) 
+                       goto fake_end;
+                   else
+                       sayNO;
+               }
            }
+           
            PUSH_STATE_GOTO(CURLYM_B, ST.B); /* match B */
            /* NOTREACHED */
 
@@ -4081,6 +4177,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
        if (success) { \
            PL_regstartp[paren] = HOPc(locinput, -1) - PL_bostr; \
            PL_regendp[paren] = locinput - PL_bostr; \
+           *PL_reglastcloseparen = paren; \
        } \
        else \
            PL_regendp[paren] = -1; \
@@ -4106,6 +4203,11 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                *PL_reglastparen = ST.paren;
            ST.min = ARG1(scan);  /* min to match */
            ST.max = ARG2(scan);  /* max to match */
+           if (cur_eval && cur_eval->u.eval.close_paren &&
+               cur_eval->u.eval.close_paren == ST.paren) {
+               ST.min=1;
+               ST.max=1;
+           }
             scan = regnext(NEXTOPER(scan) + NODE_STEP_REGNODE);
            goto repeat;
        case CURLY:             /*  /A{m,n}B/ where A is width 1 */
@@ -4185,8 +4287,8 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            ST.A = scan;
            ST.B = next;
            PL_reginput = locinput;
-           if (st->minmod) {
-               st->minmod = 0;
+           if (minmod) {
+               minmod = 0;
                if (ST.min && regrepeat(rex, ST.A, ST.min) < ST.min)
                    sayNO;
                ST.count = ST.min;
@@ -4311,6 +4413,10 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                }
                PL_reginput = locinput;
                CURLY_SETPAREN(ST.paren, ST.count);
+               if (cur_eval && cur_eval->u.eval.close_paren && 
+                   cur_eval->u.eval.close_paren == ST.paren) {
+                   goto fake_end;
+               }
                PUSH_STATE_GOTO(CURLY_B_min_known, ST.B);
            }
            /* NOTREACHED */
@@ -4332,6 +4438,10 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                {
                  curly_try_B_min:
                    CURLY_SETPAREN(ST.paren, ST.count);
+                   if (cur_eval && cur_eval->u.eval.close_paren &&
+                       cur_eval->u.eval.close_paren == ST.paren) {
+                        goto fake_end;
+                    }
                    PUSH_STATE_GOTO(CURLY_B_min, ST.B);
                }
            }
@@ -4350,6 +4460,10 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                /* If it could work, try it. */
                if (ST.c1 == CHRTEST_VOID || c == (UV)ST.c1 || c == (UV)ST.c2) {
                    CURLY_SETPAREN(ST.paren, ST.count);
+                   if (cur_eval && cur_eval->u.eval.close_paren &&
+                       cur_eval->u.eval.close_paren == ST.paren) {
+                        goto fake_end;
+                    }
                    PUSH_STATE_GOTO(CURLY_B_max, ST.B);
                    /* NOTREACHED */
                }
@@ -4444,9 +4558,9 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
                char * const s = HOPBACKc(locinput, scan->flags);
                if (!s) {
                    /* trivial fail */
-                   if (st->logical) {
-                       st->logical = 0;
-                       st->sw = 1 - (bool)ST.wanted;
+                   if (logical) {
+                       logical = 0;
+                       sw = 1 - (bool)ST.wanted;
                    }
                    else if (ST.wanted)
                        sayNO;
@@ -4462,6 +4576,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
 
          do_ifmatch:
            ST.me = scan;
+           ST.logical = logical;
            /* execute body of (?...A) */
            PUSH_YES_STATE_GOTO(IFMATCH_A, NEXTOPER(NEXTOPER(scan)));
            /* NOTREACHED */
@@ -4471,9 +4586,8 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            /* FALL THROUGH */
 
        case IFMATCH_A: /* body of (?...A) succeeded */
-           if (st->logical) {
-               st->logical = 0;
-               st->sw = (bool)ST.wanted;
+           if (ST.logical) {
+               sw = (bool)ST.wanted;
            }
            else if (!ST.wanted)
                sayNO;
@@ -4523,11 +4637,6 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            if (newst >  SLAB_LAST(PL_regmatch_slab))
                newst = S_push_slab(aTHX);
            PL_regmatch_state = newst;
-           /* XXX probably don't need to initialise these */
-           newst->minmod = 0;
-           newst->sw = 0;
-           newst->logical = 0;
-
 
            locinput = PL_reginput;
            nextchr = UCHARAT(locinput);
@@ -4535,39 +4644,6 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            continue;
            /* NOTREACHED */
        }
-
-       /* simulate recursively calling regmatch(), but without actually
-        * recursing - ie save the current state on the heap rather than on
-        * the stack, then re-enter the loop. This avoids complex regexes
-        * blowing the processor stack */
-
-      start_recurse:
-       {
-           /* push new state */
-           regmatch_state *oldst = st;
-
-           DEBUG_STATE_pp("push");
-           depth++;
-           st->u.yes.prev_yes_state = yes_state;
-           yes_state = st;
-
-           /* grab the next free state slot */
-           st++;
-           if (st >  SLAB_LAST(PL_regmatch_slab))
-               st = S_push_slab(aTHX);
-           PL_regmatch_state = st;
-
-           oldst->next = next;
-           oldst->n = n;
-           oldst->locinput = locinput;
-
-           locinput = PL_reginput;
-           nextchr = UCHARAT(locinput);
-           st->minmod = 0;
-           st->sw = 0;
-           st->logical = 0;
-           
-       }
     }
 
     /*
@@ -4608,52 +4684,8 @@ yes:
        yes_state = st->u.yes.prev_yes_state;
        PL_regmatch_state = st;
 
-       switch (st->resume_state) {
-       case resume_CURLYX:
-       case resume_WHILEM1:
-       case resume_WHILEM2:
-       case resume_WHILEM3:
-       case resume_WHILEM4:
-       case resume_WHILEM5:
-       case resume_WHILEM6:
-           result = 1;
-           /* restore previous state and re-enter */
-           scan        = st->scan;
-           next        = st->next;
-           n   = st->n;
-           locinput= st->locinput;
-           nextchr = UCHARAT(locinput);
-           switch (st->resume_state) {
-           case resume_CURLYX:
-               goto resume_point_CURLYX;
-           case resume_WHILEM1:
-               goto resume_point_WHILEM1;
-           case resume_WHILEM2:
-               goto resume_point_WHILEM2;
-           case resume_WHILEM3:
-               goto resume_point_WHILEM3;
-           case resume_WHILEM4:
-               goto resume_point_WHILEM4;
-           case resume_WHILEM5:
-               goto resume_point_WHILEM5;
-           case resume_WHILEM6:
-               goto resume_point_WHILEM6;
-           }
-           Perl_croak(aTHX_ "unexpected whilem resume state");
-
-       case EVAL_AB: 
-       case IFMATCH_A:
-       case CURLYM_A:
-           state_num = st->resume_state;
-           goto reenter_switch;
-
-       case CURLYM_B:
-       case BRANCH_next:
-       case TRIE_next:
-       case CURLY_B_max:
-       default:
-           Perl_croak(aTHX_ "unexpected yes resume state");
-       }
+       state_num = st->resume_state;
+       goto reenter_switch;
     }
 
     DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "%sMatch successful!%s\n",
@@ -4671,8 +4703,6 @@ no:
        );
 
 no_silent:
-    result = 0;
-
     if (depth) {
        /* there's a previous state to backtrack to */
        st--;
@@ -4681,9 +4711,6 @@ no_silent:
            st = SLAB_LAST(PL_regmatch_slab);
        }
        PL_regmatch_state = st;
-       scan    = st->scan;
-       next    = st->next;
-       n       = st->n;
        locinput= st->locinput;
        nextchr = UCHARAT(locinput);
 
@@ -4692,38 +4719,10 @@ no_silent:
        if (yes_state == st)
            yes_state = st->u.yes.prev_yes_state;
 
-       switch (st->resume_state) {
-       case resume_CURLYX:
-           goto resume_point_CURLYX;
-       case resume_WHILEM1:
-           goto resume_point_WHILEM1;
-       case resume_WHILEM2:
-           goto resume_point_WHILEM2;
-       case resume_WHILEM3:
-           goto resume_point_WHILEM3;
-       case resume_WHILEM4:
-           goto resume_point_WHILEM4;
-       case resume_WHILEM5:
-           goto resume_point_WHILEM5;
-       case resume_WHILEM6:
-           goto resume_point_WHILEM6;
-
-       case TRIE_next:
-       case EVAL_AB:
-       case BRANCH_next:
-       case CURLYM_A:
-       case CURLYM_B:
-       case IFMATCH_A:
-       case CURLY_B_max:
-       case CURLY_B_min:
-       case CURLY_B_min_known:
-           state_num = st->resume_state + 1; /* failure = success + 1 */
-           goto reenter_switch;
-
-       default:
-           Perl_croak(aTHX_ "regexp resume memory corruption");
-       }
+       state_num = st->resume_state + 1; /* failure = success + 1 */
+       goto reenter_switch;
     }
+    result = 0;
 
   final_exit: