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 735a27d..c4d88cc 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -2028,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) ) {
@@ -2092,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;
@@ -2271,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
+
+#undef ST
 
- * Now it looks something like this:
+    ...
+    }
 
-    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)                                 \
@@ -2478,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)
 {
@@ -2499,13 +2553,13 @@ 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 */
@@ -2513,6 +2567,21 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
     struct regmatch_state  *cur_curlyx = NULL; /* most recent curlyx */
     U32 state_num;
 
+    /* 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;
 #endif
@@ -2535,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;
@@ -2913,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. */
@@ -2955,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;
            }
@@ -2968,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,
@@ -2983,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 &&
@@ -3002,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;
            }
@@ -3100,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;
@@ -3250,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];
                /*
@@ -3273,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];
@@ -3296,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;
@@ -3381,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 */
@@ -3455,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;
@@ -3474,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;
        }
 
@@ -3527,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);
@@ -3540,7 +3633,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog)
            }
            break;
        case LOGICAL:
-           st->logical = scan->flags;
+           logical = scan->flags;
            break;
 
 /*******************************************************************
@@ -3653,7 +3746,8 @@ NULL
            ST.max = ARG2(scan);
            ST.A = NEXTOPER(scan) + EXTRA_STEP_2ARGS;
            ST.B = next;
-           ST.minmod = st->minmod;
+           ST.minmod = minmod;
+           minmod = 0;
            ST.count = -1;      /* this will be updated by WHILEM */
            ST.lastloc = NULL;  /* this will be updated by WHILEM */
 
@@ -3681,7 +3775,6 @@ NULL
        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 */
@@ -3902,6 +3995,7 @@ NULL
            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))
@@ -3910,7 +4004,7 @@ NULL
            /* NOTREACHED */
     
        case MINMOD:
-           st->minmod = 1;
+           minmod = 1;
            break;
 
 #undef  ST
@@ -3940,8 +4034,8 @@ NULL
            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);
 
@@ -3981,13 +4075,21 @@ NULL
            );
 
            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/  */
@@ -4036,10 +4138,20 @@ NULL
                    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 */
 
@@ -4065,6 +4177,7 @@ NULL
        if (success) { \
            PL_regstartp[paren] = HOPc(locinput, -1) - PL_bostr; \
            PL_regendp[paren] = locinput - PL_bostr; \
+           *PL_reglastcloseparen = paren; \
        } \
        else \
            PL_regendp[paren] = -1; \
@@ -4090,6 +4203,11 @@ NULL
                *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 */
@@ -4169,8 +4287,8 @@ NULL
            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;
@@ -4295,6 +4413,10 @@ NULL
                }
                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 */
@@ -4316,6 +4438,10 @@ NULL
                {
                  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);
                }
            }
@@ -4334,6 +4460,10 @@ NULL
                /* 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 */
                }
@@ -4428,9 +4558,9 @@ NULL
                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;
@@ -4446,6 +4576,7 @@ NULL
 
          do_ifmatch:
            ST.me = scan;
+           ST.logical = logical;
            /* execute body of (?...A) */
            PUSH_YES_STATE_GOTO(IFMATCH_A, NEXTOPER(NEXTOPER(scan)));
            /* NOTREACHED */
@@ -4455,9 +4586,8 @@ NULL
            /* 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;
@@ -4507,11 +4637,6 @@ NULL
            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);
@@ -4559,27 +4684,8 @@ yes:
        yes_state = st->u.yes.prev_yes_state;
        PL_regmatch_state = st;
 
-       switch (st->resume_state) {
-
-       case EVAL_AB: 
-       case IFMATCH_A:
-       case CURLYM_A:
-       case CURLYX_end:
-       case WHILEM_B_min:
-       case WHILEM_B_max:
-           state_num = st->resume_state;
-           goto reenter_switch;
-
-       case CURLYM_B:
-       case BRANCH_next:
-       case TRIE_next:
-       case CURLY_B_max:
-       case WHILEM_A_pre:
-       case WHILEM_A_min:
-       case WHILEM_A_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",
@@ -4597,8 +4703,6 @@ no:
        );
 
 no_silent:
-    result = 0;
-
     if (depth) {
        /* there's a previous state to backtrack to */
        st--;
@@ -4607,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);
 
@@ -4618,29 +4719,10 @@ no_silent:
        if (yes_state == st)
            yes_state = st->u.yes.prev_yes_state;
 
-       switch (st->resume_state) {
-       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:
-       case CURLYX_end:
-       case WHILEM_A_pre:
-       case WHILEM_A_min:
-       case WHILEM_A_max:
-       case WHILEM_B_min:
-       case WHILEM_B_max:
-           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: