This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Look up state subs in the pad
[perl5.git] / regexec.c
index 55db855..322e596 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -2881,20 +2881,23 @@ S_push_slab(pTHX)
 
 /* push a new state then goto it */
 
-#define PUSH_STATE_GOTO(state, node) \
+#define PUSH_STATE_GOTO(state, node, input) \
+    pushinput = input; \
     scan = node; \
     st->resume_state = state; \
     goto push_state;
 
 /* push a new state with success backtracking, then goto it */
 
-#define PUSH_YES_STATE_GOTO(state, node) \
+#define PUSH_YES_STATE_GOTO(state, node, input) \
+    pushinput = input; \
     scan = node; \
     st->resume_state = state; \
     goto push_yes_state;
 
 
 
+
 /*
 
 regmatch() - main matching routine
@@ -2960,7 +2963,7 @@ implementation:
        // 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);
+       PUSH_YES_STATE_GOTO(IFMATCH_A, A, newinput);
        // NOTREACHED
 
     case IFMATCH_A: // we have successfully executed A; now continue with B
@@ -2997,8 +3000,8 @@ 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);
+       PUSH_STATE_GOTO(resume_state, node, newinput);
+       PUSH_YES_STATE_GOTO(resume_state, node, newinput);
 
 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'.
@@ -3211,8 +3214,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
     regnode *next;
     U32 n = 0; /* general value; init to avoid compiler warning */
     I32 ln = 0; /* len or last;  init to avoid compiler warning */
-    char *reginput = startpos;
-    char *locinput = reginput;
+    char *locinput = startpos;
+    char *pushinput; /* where to continue after a PUSH */
     I32 nextchr;   /* is always set to UCHARAT(locinput) */
 
     bool result = 0;       /* return value of S_regmatch */
@@ -3231,7 +3234,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
     U32 state_num;
     bool no_final = 0;      /* prevent failure from backtracking? */
     bool do_cutgroup = 0;   /* no_final only until next branch/trie entry */
-    char *startpoint = reginput;
+    char *startpoint = locinput;
     SV *popmark = NULL;     /* are we looking for a mark? */
     SV *sv_commit = NULL;   /* last mark name seen in failure */
     SV *sv_yes_mark = NULL; /* last mark name we have seen 
@@ -3348,9 +3351,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
        case KEEPS:
            /* update the startpoint */
            st->u.keeper.val = rex->offs[0].start;
-           reginput = locinput;
            rex->offs[0].start = locinput - PL_bostr;
-           PUSH_STATE_GOTO(KEEPS_next, next);
+           PUSH_STATE_GOTO(KEEPS_next, next, locinput);
            /*NOT-REACHED*/
        case KEEPS_next_fail:
            /* rollback the start point change */
@@ -3605,6 +3607,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
            assert(0); /* NOTREACHED */
 
        case TRIE_next_fail: /* we failed - try next alternative */
+        {
+            U8 *uc;
             if ( ST.jump) {
                 REGCP_UNWIND(ST.cp);
                 UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
@@ -3649,7 +3653,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
            /* find start char of end of current word */
            {
                U32 chars; /* how many chars to skip */
-               U8 *uc = ST.firstpos;
                reg_trie_data * const trie
                    = (reg_trie_data*)rexi->data->data[ARG(ST.me)];
 
@@ -3657,6 +3660,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
                            >=  ST.firstchars);
                chars = (trie->wordinfo[ST.nextword].len - trie->prefixlen)
                            - ST.firstchars;
+               uc = ST.firstpos;
 
                if (ST.longfold) {
                    /* the hard option - fold each char in turn and find
@@ -3696,7 +3700,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
                    else
                        uc += chars;
                }
-               reginput = (char *)uc;
            }
 
            scan = ST.me + ((ST.jump && ST.jump[ST.nextword])
@@ -3714,7 +3717,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
            });
 
            if (ST.accepted > 1 || has_cutgroup) {
-               PUSH_STATE_GOTO(TRIE_next, scan);
+               PUSH_STATE_GOTO(TRIE_next, scan, (char*)uc);
                assert(0); /* NOTREACHED */
            }
            /* only one choice left - just continue */
@@ -3737,10 +3740,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
                    PL_colors[5] );
            });
 
-           locinput = reginput;
+           locinput = (char*)uc;
            nextchr = UCHARAT(locinput);
            continue; /* execute rest of RE */
            assert(0); /* NOTREACHED */
+        }
 #undef  ST
 
        case EXACT: {
@@ -4626,7 +4630,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
                re->lastparen = 0;
                re->lastcloseparen = 0;
 
-               reginput = locinput;
                PL_regsize = 0;
 
                /* XXXX This is too dramatic a measure... */
@@ -4650,7 +4653,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
                ST.prev_eval = cur_eval;
                cur_eval = st;
                /* now continue from first node in postoned RE */
-               PUSH_YES_STATE_GOTO(EVAL_AB, startpoint);
+               PUSH_YES_STATE_GOTO(EVAL_AB, startpoint, locinput);
                assert(0); /* NOTREACHED */
        }
 
@@ -4680,7 +4683,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
            rex = (struct regexp *)SvANY(rex_sv);
            rexi = RXi_GET(rex); 
 
-           reginput = locinput;
            REGCP_UNWIND(ST.lastcp);
            regcppop(rex);
            cur_eval = ST.prev_eval;
@@ -4900,8 +4902,7 @@ NULL
            ST.count = -1;      /* this will be updated by WHILEM */
            ST.lastloc = NULL;  /* this will be updated by WHILEM */
 
-           reginput = locinput;
-           PUSH_YES_STATE_GOTO(CURLYX_end, PREVOPER(next));
+           PUSH_YES_STATE_GOTO(CURLYX_end, PREVOPER(next), locinput);
            assert(0); /* NOTREACHED */
        }
 
@@ -4934,7 +4935,6 @@ NULL
            ST.cache_offset = 0;
            ST.cache_mask = 0;
            
-           reginput = locinput;
 
            DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log,
                  "%*s  whilem: matched %ld out of %d..%d\n",
@@ -4948,7 +4948,7 @@ NULL
                cur_curlyx->u.curlyx.lastloc = locinput;
                REGCP_SET(ST.lastcp);
 
-               PUSH_STATE_GOTO(WHILEM_A_pre, A);
+               PUSH_STATE_GOTO(WHILEM_A_pre, A, locinput);
                assert(0); /* NOTREACHED */
            }
 
@@ -5022,7 +5022,8 @@ NULL
                cur_curlyx = cur_curlyx->u.curlyx.prev_curlyx;
                ST.cp = regcppush(rex, ST.save_curlyx->u.curlyx.parenfloor);
                REGCP_SET(ST.lastcp);
-               PUSH_YES_STATE_GOTO(WHILEM_B_min, ST.save_curlyx->u.curlyx.B);
+               PUSH_YES_STATE_GOTO(WHILEM_B_min, ST.save_curlyx->u.curlyx.B,
+                                    locinput);
                assert(0); /* NOTREACHED */
            }
 
@@ -5032,7 +5033,7 @@ NULL
                ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
                cur_curlyx->u.curlyx.lastloc = locinput;
                REGCP_SET(ST.lastcp);
-               PUSH_STATE_GOTO(WHILEM_A_max, A);
+               PUSH_STATE_GOTO(WHILEM_A_max, A, locinput);
                assert(0); /* NOTREACHED */
            }
            goto do_whilem_B_max;
@@ -5065,7 +5066,6 @@ NULL
        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? */
-           reginput = locinput;
            DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
                "%*s  whilem: failed, trying continuation...\n",
                REPORT_CODE_OFF+depth*2, "")
@@ -5085,7 +5085,8 @@ NULL
            /* 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);
+           PUSH_YES_STATE_GOTO(WHILEM_B_max, ST.save_curlyx->u.curlyx.B,
+                                locinput);
            assert(0); /* NOTREACHED */
 
        case WHILEM_B_min_fail: /* just failed to match B in a minimal match */
@@ -5113,12 +5114,12 @@ NULL
                "%*s  trying longer...\n", REPORT_CODE_OFF+depth*2, "")
            );
            /* Try grabbing another A and see if it helps. */
-           reginput = locinput;
            cur_curlyx->u.curlyx.lastloc = locinput;
            ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
            REGCP_SET(ST.lastcp);
            PUSH_STATE_GOTO(WHILEM_A_min,
-               /*A*/ NEXTOPER(ST.save_curlyx->u.curlyx.me) + EXTRA_STEP_2ARGS);
+               /*A*/ NEXTOPER(ST.save_curlyx->u.curlyx.me) + EXTRA_STEP_2ARGS,
+                locinput);
            assert(0); /* NOTREACHED */
 
 #undef  ST
@@ -5137,20 +5138,18 @@ NULL
            ST.lastcloseparen = rex->lastcloseparen;
            ST.next_branch = next;
            REGCP_SET(ST.cp);
-           reginput = locinput;
 
            /* Now go into the branch */
            if (has_cutgroup) {
-               PUSH_YES_STATE_GOTO(BRANCH_next, scan);    
+               PUSH_YES_STATE_GOTO(BRANCH_next, scan, locinput);
            } else {
-               PUSH_STATE_GOTO(BRANCH_next, scan);
+               PUSH_STATE_GOTO(BRANCH_next, scan, locinput);
            }
            assert(0); /* NOTREACHED */
         case CUTGROUP:
-            reginput = locinput;
             sv_yes_mark = st->u.mark.mark_name = scan->flags ? NULL :
                 MUTABLE_SV(rexi->data->data[ ARG( scan ) ]);
-            PUSH_STATE_GOTO(CUTGROUP_next,next);
+            PUSH_STATE_GOTO(CUTGROUP_next, next, locinput);
             assert(0); /* NOTREACHED */
         case CUTGROUP_next_fail:
             do_cutgroup = 1;
@@ -5225,26 +5224,22 @@ NULL
                goto curlym_do_B;
 
          curlym_do_A: /* execute the A in /A{m,n}B/  */
-           reginput = locinput;
-           PUSH_YES_STATE_GOTO(CURLYM_A, ST.A); /* match A */
+           PUSH_YES_STATE_GOTO(CURLYM_A, ST.A, locinput); /* match A */
            assert(0); /* NOTREACHED */
 
        case CURLYM_A: /* we've just matched an A */
-           locinput = st->locinput;
-           nextchr = UCHARAT(locinput);
-
            ST.count++;
            /* after first match, determine A's length: u.curlym.alen */
            if (ST.count == 1) {
                if (PL_reg_match_utf8) {
-                   char *s = locinput;
-                   while (s < reginput) {
+                   char *s = st->locinput;
+                   while (s < locinput) {
                        ST.alen++;
                        s += UTF8SKIP(s);
                    }
                }
                else {
-                   ST.alen = reginput - locinput;
+                   ST.alen = locinput - st->locinput;
                }
                if (ST.alen == 0)
                    ST.count = ST.minmod ? ARG1(ST.me) : ARG2(ST.me);
@@ -5256,8 +5251,6 @@ NULL
                          (IV) ST.count, (IV)ST.alen)
            );
 
-           locinput = reginput;
-                       
            if (cur_eval && cur_eval->u.eval.close_paren && 
                cur_eval->u.eval.close_paren == (U32)ST.me->flags) 
                goto fake_end;
@@ -5278,7 +5271,6 @@ NULL
                sayNO;
 
          curlym_do_B: /* execute the B in /A{m,n}B/  */
-           reginput = locinput;
            if (ST.c1 == CHRTEST_UNINIT) {
                /* calculate c1 and c2 for possible match of 1st char
                 * following curly */
@@ -5320,8 +5312,8 @@ NULL
                    "", (IV)ST.count)
                );
            if (ST.c1 != CHRTEST_VOID
-                   && UCHARAT(reginput) != ST.c1
-                   && UCHARAT(reginput) != ST.c2)
+                   && nextchr != ST.c1
+                   && nextchr != ST.c2)
            {
                /* simulate B failing */
                DEBUG_OPTIMISE_r(
@@ -5339,8 +5331,8 @@ NULL
                I32 paren = ST.me->flags;
                if (ST.count) {
                    rex->offs[paren].start
-                       = HOPc(reginput, -ST.alen) - PL_bostr;
-                   rex->offs[paren].end = reginput - PL_bostr;
+                       = HOPc(locinput, -ST.alen) - PL_bostr;
+                   rex->offs[paren].end = locinput - PL_bostr;
                    if ((U32)paren > rex->lastparen)
                        rex->lastparen = paren;
                    rex->lastcloseparen = paren;
@@ -5357,7 +5349,7 @@ NULL
                }
            }
            
-           PUSH_STATE_GOTO(CURLYM_B, ST.B); /* match B */
+           PUSH_STATE_GOTO(CURLYM_B, ST.B, locinput); /* match B */
            assert(0); /* NOTREACHED */
 
        case CURLYM_B_fail: /* just failed to match a B */
@@ -5374,6 +5366,7 @@ NULL
                sayNO;
            ST.count--;
            locinput = HOPc(locinput, -ST.alen);
+            nextchr = UCHARAT(locinput);
            goto curlym_do_B; /* try to match B */
 
 #undef ST
@@ -5496,17 +5489,14 @@ NULL
 
            ST.A = scan;
            ST.B = next;
-           reginput = locinput;
            if (minmod) {
-                /* avoid taking address of reginput, so it can remain
-                 * a register var */
-                char *ri = reginput;
+                char *li = locinput;
                minmod = 0;
-               if (ST.min && regrepeat(rex, &ri, ST.A, ST.min, depth) < ST.min)
+               if (ST.min && regrepeat(rex, &li, ST.A, ST.min, depth) < ST.min)
                    sayNO;
-                reginput = ri;
+                locinput = li;
+                nextchr = UCHARAT(locinput);
                ST.count = ST.min;
-               locinput = reginput;
                REGCP_SET(ST.cp);
                if (ST.c1 == CHRTEST_VOID)
                    goto curly_try_B_min;
@@ -5536,12 +5526,14 @@ NULL
 
            }
            else {
-                char *ri = reginput;
-               ST.count = regrepeat(rex, &ri, ST.A, ST.max, depth);
-                reginput = ri;
-               locinput = reginput;
+                /* avoid taking address of locinput, so it can remain
+                 * a register var */
+                char *li = locinput;
+               ST.count = regrepeat(rex, &li, ST.A, ST.max, depth);
                if (ST.count < ST.min)
                    sayNO;
+                locinput = li;
+                nextchr = UCHARAT(locinput);
                if ((ST.count > ST.min)
                    && (PL_regkind[OP(ST.B)] == EOL) && (OP(ST.B) != MEOL))
                {
@@ -5551,7 +5543,7 @@ NULL
                    /* ...except that $ and \Z can match before *and* after
                       newline at the end.  Consider "\n\n" =~ /\n+\Z\n/.
                       We may back off by one in this case. */
-                   if (UCHARAT(reginput - 1) == '\n' && OP(ST.B) != EOS)
+                   if (UCHARAT(locinput - 1) == '\n' && OP(ST.B) != EOS)
                        ST.min--;
                }
                REGCP_SET(ST.cp);
@@ -5563,7 +5555,6 @@ NULL
        case CURLY_B_min_known_fail:
            /* failed to find B in a non-greedy match where c1,c2 valid */
 
-           reginput = locinput;        /* Could be reset... */
            REGCP_UNWIND(ST.cp);
             if (ST.paren) {
                 UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
@@ -5622,21 +5613,22 @@ NULL
                }
                if (locinput > ST.maxpos)
                    sayNO;
-               /* reginput == oldloc now */
                if (n) {
-                    char *ri = reginput;
+                    /* In /a{m,n}b/, ST.oldloc is at "a" x m, locinput is
+                     * at b; check that everything between oldloc and
+                     * locinput matches */
+                    char *li = ST.oldloc;
                    ST.count += n;
-                   if (regrepeat(rex, &ri, ST.A, n, depth) < n)
+                   if (regrepeat(rex, &li, ST.A, n, depth) < n)
                        sayNO;
-                    reginput = ri;
+                    assert(n == REG_INFTY || locinput == li);
                }
-               reginput = locinput;
                CURLY_SETPAREN(ST.paren, ST.count);
                if (cur_eval && cur_eval->u.eval.close_paren && 
                    cur_eval->u.eval.close_paren == (U32)ST.paren) {
                    goto fake_end;
                }
-               PUSH_STATE_GOTO(CURLY_B_min_known, ST.B);
+               PUSH_STATE_GOTO(CURLY_B_min_known, ST.B, locinput);
            }
            assert(0); /* NOTREACHED */
 
@@ -5649,17 +5641,15 @@ NULL
                 UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
             }
            /* failed -- move forward one */
-           reginput = locinput;
             {
-                char *ri = reginput;
-                if (!regrepeat(rex, &ri, ST.A, 1, depth)) {
+                char *li = locinput;
+                if (!regrepeat(rex, &li, ST.A, 1, depth)) {
                     sayNO;
                 }
-                reginput = ri;
+                locinput = li;
             }
             {
                ST.count++;
-               locinput = reginput;
                if (ST.count <= ST.max || (ST.max == REG_INFTY &&
                        ST.count > 0)) /* count overflow ? */
                {
@@ -5669,7 +5659,7 @@ NULL
                        cur_eval->u.eval.close_paren == (U32)ST.paren) {
                         goto fake_end;
                     }
-                   PUSH_STATE_GOTO(CURLY_B_min, ST.B);
+                   PUSH_STATE_GOTO(CURLY_B_min, ST.B, locinput);
                }
            }
            assert(0); /* NOTREACHED */
@@ -5684,13 +5674,13 @@ NULL
            {
                UV c = 0;
                if (ST.c1 != CHRTEST_VOID)
-                   c = utf8_target ? utf8n_to_uvchr((U8*)reginput,
+                   c = utf8_target ? utf8n_to_uvchr((U8*)locinput,
                                           UTF8_MAXBYTES, 0, uniflags)
-                               : (UV) UCHARAT(reginput);
+                               : (UV) UCHARAT(locinput);
                /* 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);
-                   PUSH_STATE_GOTO(CURLY_B_max, ST.B);
+                   PUSH_STATE_GOTO(CURLY_B_max, ST.B, locinput);
                    assert(0); /* NOTREACHED */
                }
            }
@@ -5705,7 +5695,7 @@ NULL
            /*  back up. */
            if (--ST.count < ST.min)
                sayNO;
-           reginput = locinput = HOPc(locinput, -1);
+           locinput = HOPc(locinput, -1);
            goto curly_try_B_max;
 
 #undef ST
@@ -5727,7 +5717,6 @@ NULL
                cur_curlyx = cur_eval->u.eval.prev_curlyx;
 
                REGCP_SET(st->u.eval.lastcp);
-               reginput = locinput;
 
                /* Restore parens of the outer rex without popping the
                 * savestack */
@@ -5741,8 +5730,8 @@ NULL
                 if ( nochange_depth )
                    nochange_depth--;
 
-                PUSH_YES_STATE_GOTO(EVAL_AB,
-                       st->u.eval.prev_eval->u.eval.B); /* match B */
+                PUSH_YES_STATE_GOTO(EVAL_AB, st->u.eval.prev_eval->u.eval.B,
+                                    locinput); /* match B */
            }
 
            if (locinput < reginfo->till) {
@@ -5755,7 +5744,6 @@ NULL
                                                      
                sayNO_SILENT;           /* Cannot match: too short. */
            }
-           reginput = locinput;        /* put where regtry can find it */
            sayYES;                     /* Success! */
 
        case SUCCEED: /* successful SUSPEND/UNLESSM/IFMATCH/CURLYM */
@@ -5763,15 +5751,17 @@ NULL
            PerlIO_printf(Perl_debug_log,
                "%*s  %ssubpattern success...%s\n",
                REPORT_CODE_OFF+depth*2, "", PL_colors[4], PL_colors[5]));
-           reginput = locinput;        /* put where regtry can find it */
            sayYES;                     /* Success! */
 
 #undef  ST
 #define ST st->u.ifmatch
 
+        {
+            char *newstart;
+
        case SUSPEND:   /* (?>A) */
            ST.wanted = 1;
-           reginput = locinput;
+           newstart = locinput;
            goto do_ifmatch;    
 
        case UNLESSM:   /* -ve lookaround: (?!A), or with flags, (?<!A) */
@@ -5796,10 +5786,10 @@ NULL
                        next = NULL;
                    break;
                }
-               reginput = s;
+               newstart = s;
            }
            else
-               reginput = locinput;
+               newstart = locinput;
 
          do_ifmatch:
            ST.me = scan;
@@ -5807,8 +5797,9 @@ NULL
            logical = 0; /* XXX: reset state of logical once it has been saved into ST */
            
            /* execute body of (?...A) */
-           PUSH_YES_STATE_GOTO(IFMATCH_A, NEXTOPER(NEXTOPER(scan)));
+           PUSH_YES_STATE_GOTO(IFMATCH_A, NEXTOPER(NEXTOPER(scan)), newstart);
            assert(0); /* NOTREACHED */
+        }
 
        case IFMATCH_A_fail: /* body of (?...A) failed */
            ST.wanted = !ST.wanted;
@@ -5821,10 +5812,9 @@ NULL
            else if (!ST.wanted)
                sayNO;
 
-           if (OP(ST.me) == SUSPEND)
-               locinput = reginput;
-           else {
-               locinput = reginput = st->locinput;
+           if (OP(ST.me) != SUSPEND) {
+                /* restore old position except for (?>...) */
+               locinput = st->locinput;
                nextchr = UCHARAT(locinput);
            }
            scan = ST.me + ARG(ST.me);
@@ -5843,10 +5833,9 @@ NULL
            reginfo->cutpoint = PL_regeol;
            /* FALLTHROUGH */
        case PRUNE:
-           reginput = locinput;
            if (!scan->flags)
                sv_yes_mark = sv_commit = MUTABLE_SV(rexi->data->data[ ARG( scan ) ]);
-           PUSH_STATE_GOTO(COMMIT_next,next);
+           PUSH_STATE_GOTO(COMMIT_next, next, locinput);
            assert(0); /* NOTREACHED */
        case COMMIT_next_fail:
            no_final = 1;    
@@ -5861,8 +5850,8 @@ NULL
             ST.mark_name = sv_commit = sv_yes_mark 
                 = MUTABLE_SV(rexi->data->data[ ARG( scan ) ]);
             mark_state = st;
-            ST.mark_loc = reginput = locinput;
-            PUSH_YES_STATE_GOTO(MARKPOINT_next,next);
+            ST.mark_loc = locinput;
+            PUSH_YES_STATE_GOTO(MARKPOINT_next, next, locinput);
             assert(0); /* NOTREACHED */
         case MARKPOINT_next:
             mark_state = ST.prev_mark;
@@ -5889,12 +5878,11 @@ NULL
             sayNO;
             assert(0); /* NOTREACHED */
         case SKIP:
-            reginput = locinput;
             if (scan->flags) {
                 /* (*SKIP) : if we fail we cut here*/
                 ST.mark_name = NULL;
                 ST.mark_loc = locinput;
-                PUSH_STATE_GOTO(SKIP_next,next);    
+                PUSH_STATE_GOTO(SKIP_next,next, locinput);
             } else {
                 /* (*SKIP:NAME) : if there is a (*MARK:NAME) fail where it was, 
                    otherwise do nothing.  Meaning we need to scan 
@@ -5907,7 +5895,7 @@ NULL
                                 find ) ) 
                     {
                         ST.mark_name = find;
-                        PUSH_STATE_GOTO( SKIP_next, next );
+                        PUSH_STATE_GOTO( SKIP_next, next, locinput);
                     }
                     cur = cur->u.mark.prev_mark;
                 }
@@ -6016,7 +6004,7 @@ NULL
                newst = S_push_slab(aTHX);
            PL_regmatch_state = newst;
 
-           locinput = reginput;
+           locinput = pushinput;
            nextchr = UCHARAT(locinput);
            st = newst;
            continue;
@@ -6155,17 +6143,19 @@ no_silent:
     /* clean up; in particular, free all slabs above current one */
     LEAVE_SCOPE(oldsave);
 
-    assert(!result ||  reginput - PL_bostr >= 0);
-    return result ?  reginput - PL_bostr : -1;
+    assert(!result ||  locinput - PL_bostr >= 0);
+    return result ?  locinput - PL_bostr : -1;
 }
 
 /*
  - regrepeat - repeatedly match something simple, report how many
- */
-/*
- * [This routine now assumes that it will only match on things of length 1.
- * That was true before, but now we assume scan - reginput is the count,
- * rather than incrementing count on every character.  [Er, except utf8.]]
+ *
+ * startposp - pointer a pointer to the start position.  This is updated
+ *             to point to the byte following the highest successful
+ *             match.
+ * p         - the regnode to be repeatedly matched against.
+ * max       - maximum number of characters to match.
+ * depth     - (for debugging) backtracking depth.
  */
 STATIC I32
 S_regrepeat(pTHX_ const regexp *prog, char **startposp, const regnode *p, I32 max, int depth)