X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=regexec.c;h=2da8bfd6769ebb16fc3b7d992cdf5d123fa97903;hb=2bf803e2214c46ec8286bc855080cf05bb5cf7a4;hp=8597be3f219f451a19424f90fccdf92fa974d00c;hpb=438e9bae713cc15cfa264da285aebdfaf57ad92e;p=p5sagit%2Fp5-mst-13.2.git diff --git a/regexec.c b/regexec.c index 8597be3..2da8bfd 100644 --- a/regexec.c +++ b/regexec.c @@ -218,7 +218,7 @@ STATIC char * S_regcppop(pTHX_ const regexp *rex) { dVAR; - I32 i; + U32 i; char *input; GET_RE_DEBUG_FLAGS_DECL; @@ -272,7 +272,7 @@ S_regcppop(pTHX_ const regexp *rex) * building DynaLoader will fail: * "Error: '*' not in typemap in DynaLoader.xs, line 164" * --jhi */ - for (i = *PL_reglastparen + 1; (U32)i <= rex->nparens; i++) { + for (i = *PL_reglastparen + 1; i <= rex->nparens; i++) { if (i > PL_regsize) PL_regstartp[i] = -1; PL_regendp[i] = -1; @@ -371,7 +371,8 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, I32 ml_anch; register char *other_last = NULL; /* other substr checked before this */ char *check_at = NULL; /* check substr found at this pos */ - const I32 multiline = prog->reganch & PMf_MULTILINE; + const I32 multiline = prog->extflags & RXf_PMf_MULTILINE; + RXi_GET_DECL(prog,progi); #ifdef DEBUGGING const char * const i_strpos = strpos; #endif @@ -380,7 +381,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, RX_MATCH_UTF8_set(prog,do_utf8); - if (prog->reganch & ROPT_UTF8) { + if (prog->extflags & RXf_UTF8) { PL_reg_flags |= RF_utf8; } DEBUG_EXECUTE_r( @@ -412,14 +413,14 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, "Non-utf8 string cannot match utf8 check string\n")); goto fail; } - if (prog->reganch & ROPT_ANCH) { /* Match at beg-of-str or after \n */ - ml_anch = !( (prog->reganch & ROPT_ANCH_SINGLE) - || ( (prog->reganch & ROPT_ANCH_BOL) + if (prog->extflags & RXf_ANCH) { /* Match at beg-of-str or after \n */ + ml_anch = !( (prog->extflags & RXf_ANCH_SINGLE) + || ( (prog->extflags & RXf_ANCH_BOL) && !multiline ) ); /* Check after \n? */ if (!ml_anch) { - if ( !(prog->reganch & (ROPT_ANCH_GPOS /* Checked by the caller */ - | ROPT_IMPLICIT)) /* not a real BOL */ + if ( !(prog->extflags & RXf_ANCH_GPOS) /* Checked by the caller */ + && !(prog->intflags & PREGf_IMPLICIT) /* not a real BOL */ /* SvCUR is not set on references: SvRV and SvPVX_const overlap */ && sv && !SvROK(sv) && (strpos != strbeg)) { @@ -427,7 +428,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, goto fail; } if (prog->check_offset_min == prog->check_offset_max && - !(prog->reganch & ROPT_CANY_SEEN)) { + !(prog->extflags & RXf_CANY_SEEN)) { /* Substring at constant offset from beg-of-str... */ I32 slen; @@ -528,7 +529,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, else { U8* start_point; U8* end_point; - if (prog->reganch & ROPT_CANY_SEEN) { + if (prog->extflags & RXf_CANY_SEEN) { start_point= (U8*)(s + srch_start_shift); end_point= (U8*)(strend - srch_end_shift); } else { @@ -814,17 +815,17 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, if (ml_anch && sv && !SvROK(sv) /* See prev comment on SvROK */ && (strpos != strbeg) && strpos[-1] != '\n' /* May be due to an implicit anchor of m{.*foo} */ - && !(prog->reganch & ROPT_IMPLICIT)) + && !(prog->intflags & PREGf_IMPLICIT)) { t = strpos; goto find_anchor; } DEBUG_EXECUTE_r( if (ml_anch) PerlIO_printf(Perl_debug_log, "Position at offset %ld does not contradict /%s^%s/m...\n", - (long)(strpos - i_strpos), PL_colors[0], PL_colors[1]); + (long)(strpos - i_strpos), PL_colors[0], PL_colors[1]); ); success_at_start: - if (!(prog->reganch & ROPT_NAUGHTY) /* XXXX If strpos moved? */ + if (!(prog->intflags & PREGf_NAUGHTY) /* XXXX If strpos moved? */ && (do_utf8 ? ( prog->check_utf8 /* Could be deleted already */ && --BmUSEFUL(prog->check_utf8) < 0 @@ -847,7 +848,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, /* XXXX This is a remnant of the old implementation. It looks wasteful, since now INTUIT can use many other heuristics. */ - prog->reganch &= ~RE_USE_INTUIT; + prog->extflags &= ~RXf_USE_INTUIT; } else s = strpos; @@ -857,7 +858,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, /* XXXX BmUSEFUL already changed, maybe multiple change is meaningful... */ /* trie stclasses are too expensive to use here, we are better off to leave it to regmatch itself */ - if (prog->regstclass && PL_regkind[OP(prog->regstclass)]!=TRIE) { + if (progi->regstclass && PL_regkind[OP(progi->regstclass)]!=TRIE) { /* minlen == 0 is possible if regstclass is \b or \B, and the fixed substr is ''$. Since minlen is already taken into account, s+1 is before strend; @@ -866,9 +867,9 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, regstclass does not come from lookahead... */ /* If regstclass takes bytelength more than 1: If charlength==1, OK. This leaves EXACTF only, which is dealt with in find_byclass(). */ - const U8* const str = (U8*)STRING(prog->regstclass); - const int cl_l = (PL_regkind[OP(prog->regstclass)] == EXACT - ? CHR_DIST(str+STR_LEN(prog->regstclass), str) + const U8* const str = (U8*)STRING(progi->regstclass); + const int cl_l = (PL_regkind[OP(progi->regstclass)] == EXACT + ? CHR_DIST(str+STR_LEN(progi->regstclass), str) : 1); char * endpos; if (prog->anchored_substr || prog->anchored_utf8 || ml_anch) @@ -878,11 +879,11 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, else endpos= strend; - DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "start_shift: %"IVdf" check_at: %d s: %d endpos: %d\n", - (IV)start_shift, check_at - strbeg, s - strbeg, endpos - strbeg)); + DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "start_shift: %"IVdf" check_at: %"IVdf" s: %"IVdf" endpos: %"IVdf"\n", + (IV)start_shift, (IV)(check_at - strbeg), (IV)(s - strbeg), (IV)(endpos - strbeg))); t = s; - s = find_byclass(prog, prog->regstclass, s, endpos, NULL); + s = find_byclass(prog, progi->regstclass, s, endpos, NULL); if (!s) { #ifdef DEBUGGING const char *what = NULL; @@ -894,7 +895,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, } DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log, "This position contradicts STCLASS...\n") ); - if ((prog->reganch & ROPT_ANCH) && !ml_anch) + if ((prog->extflags & RXf_ANCH) && !ml_anch) goto fail; /* Contradict one of substrings */ if (prog->anchored_substr || prog->anchored_utf8) { @@ -975,8 +976,8 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, -#define REXEC_TRIE_READ_CHAR(trie_type, trie, uc, uscan, len, uvc, charid, \ -foldlen, foldbuf, uniflags) STMT_START { \ +#define REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc, uscan, len, \ +uvc, charid, foldlen, foldbuf, uniflags) STMT_START { \ switch (trie_type) { \ case trie_utf8_fold: \ if ( foldlen>0 ) { \ @@ -1004,8 +1005,8 @@ foldlen, foldbuf, uniflags) STMT_START { \ } \ else { \ charid = 0; \ - if (trie->widecharmap) { \ - SV** const svpp = hv_fetch(trie->widecharmap, \ + if (widecharmap) { \ + SV** const svpp = hv_fetch(widecharmap, \ (char*)&uvc, sizeof(UV), 0); \ if (svpp) \ charid = (U16)SvIV(*svpp); \ @@ -1126,7 +1127,7 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, const char *strend, regmatch_info *reginfo) { dVAR; - const I32 doevery = (prog->reganch & ROPT_SKIP) == 0; + const I32 doevery = (prog->intflags & PREGf_SKIP) == 0; char *m; STRLEN ln; STRLEN lnc; @@ -1136,7 +1137,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, char *e; register I32 tmp = 1; /* Scratch variable? */ register const bool do_utf8 = PL_reg_match_utf8; - + RXi_GET_DECL(prog,progi); + /* We know what class it must start with. */ switch (OP(c)) { case ANYOF: @@ -1416,8 +1418,10 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, : trie_plain; /* what trie are we using right now */ reg_ac_data *aho - = (reg_ac_data*)prog->data->data[ ARG( c ) ]; - reg_trie_data *trie=aho->trie; + = (reg_ac_data*)progi->data->data[ ARG( c ) ]; + reg_trie_data *trie + = (reg_trie_data*)progi->data->data[ aho->trie ]; + HV *widecharmap = (HV*) progi->data->data[ aho->trie + 1 ]; const char *last_start = strend - trie->minlen; #ifdef DEBUGGING @@ -1520,8 +1524,9 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, } points[pointpos++ % maxlen]= uc; - REXEC_TRIE_READ_CHAR(trie_type, trie, uc, uscan, len, - uvc, charid, foldlen, foldbuf, uniflags); + REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc, + uscan, len, uvc, charid, foldlen, + foldbuf, uniflags); DEBUG_TRIE_EXECUTE_r({ dump_exec_pos( (char *)uc, c, strend, real_start, s, do_utf8 ); @@ -1594,8 +1599,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, s = (char*)leftmost; DEBUG_TRIE_EXECUTE_r({ PerlIO_printf( - Perl_debug_log,"Matches word #%"UVxf" at position %d. Trying full pattern...\n", - (UV)accepted_word, s - real_start + Perl_debug_log,"Matches word #%"UVxf" at position %"IVdf". Trying full pattern...\n", + (UV)accepted_word, (IV)(s - real_start) ); }); if (!reginfo || regtry(reginfo, &s)) { @@ -1635,7 +1640,9 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* strend: pointer to null at end of string */ /* strbeg: real beginning of string */ /* minend: end of match must be >=minend after stringarg. */ -/* data: May be used for some additional optimizations. */ +/* data: May be used for some additional optimizations. + Currently its only used, with a U32 cast, for transmitting + the ganch offset when doing a /g match. This will change */ /* nosave: For optimizations. */ { dVAR; @@ -1650,7 +1657,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * SV* const oreplsv = GvSV(PL_replgv); const bool do_utf8 = (bool)DO_UTF8(sv); I32 multiline; - + RXi_GET_DECL(prog,progi); regmatch_info reginfo; /* create some info to pass to regtry etc */ GET_RE_DEBUG_FLAGS_DECL; @@ -1663,7 +1670,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * return 0; } - multiline = prog->reganch & PMf_MULTILINE; + multiline = prog->extflags & RXf_PMf_MULTILINE; reginfo.prog = prog; RX_MATCH_UTF8_set(prog, do_utf8); @@ -1682,7 +1689,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* Check validity of program. */ - if (UCHARAT(prog->program) != REG_MAGIC) { + if (UCHARAT(progi->program) != REG_MAGIC) { Perl_croak(aTHX_ "corrupted regexp program"); } @@ -1690,7 +1697,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * PL_reg_eval_set = 0; PL_reg_maxiter = 0; - if (prog->reganch & ROPT_UTF8) + if (prog->extflags & RXf_UTF8) PL_reg_flags |= RF_utf8; /* Mark beginning of line for ^ and lookbehind. */ @@ -1707,26 +1714,49 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* If there is a "must appear" string, look for it. */ s = startpos; - if (prog->reganch & ROPT_GPOS_SEEN) { /* Need to set reginfo->ganch */ + if (prog->extflags & RXf_GPOS_SEEN) { /* Need to set reginfo->ganch */ MAGIC *mg; if (flags & REXEC_IGNOREPOS) /* Means: check only at start */ - reginfo.ganch = startpos; + reginfo.ganch = startpos + prog->gofs; else if (sv && SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv) && (mg = mg_find(sv, PERL_MAGIC_regex_global)) && mg->mg_len >= 0) { reginfo.ganch = strbeg + mg->mg_len; /* Defined pos() */ - if (prog->reganch & ROPT_ANCH_GPOS) { + if (prog->extflags & RXf_ANCH_GPOS) { if (s > reginfo.ganch) goto phooey; - s = reginfo.ganch; + s = reginfo.ganch - prog->gofs; } } - else /* pos() not defined */ + else if (data) { + reginfo.ganch = strbeg + PTR2UV(data); + } else /* pos() not defined */ reginfo.ganch = strbeg; } - + if (PL_curpm && (PM_GETRE(PL_curpm) == prog)) { + I32 *t; + if (!progi->swap) { + /* We have to be careful. If the previous successful match + was from this regex we don't want a subsequent paritally + successful match to clobber the old results. + So when we detect this possibility we add a swap buffer + to the re, and switch the buffer each match. If we fail + we switch it back, otherwise we leave it swapped. + */ + Newxz(progi->swap, 1, regexp_paren_ofs); + /* no need to copy these */ + Newxz(progi->swap->startp, prog->nparens + 1, I32); + Newxz(progi->swap->endp, prog->nparens + 1, I32); + } + t = progi->swap->startp; + progi->swap->startp = prog->startp; + prog->startp = t; + t = progi->swap->endp; + progi->swap->endp = prog->endp; + prog->endp = t; + } if (!(flags & REXEC_CHECKED) && (prog->check_substr != NULL || prog->check_utf8 != NULL)) { re_scream_pos_data d; @@ -1743,11 +1773,11 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* Simplest case: anchored match need be tried only once. */ /* [unless only anchor is BOL and multiline is set] */ - if (prog->reganch & (ROPT_ANCH & ~ROPT_ANCH_GPOS)) { + if (prog->extflags & (RXf_ANCH & ~RXf_ANCH_GPOS)) { if (s == startpos && regtry(®info, &startpos)) goto got_it; - else if (multiline || (prog->reganch & ROPT_IMPLICIT) - || (prog->reganch & ROPT_ANCH_MBOL)) /* XXXX SBOL? */ + else if (multiline || (prog->intflags & PREGf_IMPLICIT) + || (prog->extflags & RXf_ANCH_MBOL)) /* XXXX SBOL? */ { char *end; @@ -1764,7 +1794,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * after_try: if (s >= end) goto phooey; - if (prog->reganch & RE_USE_INTUIT) { + if (prog->extflags & RXf_USE_INTUIT) { s = re_intuit_start(prog, sv, s + 1, strend, flags, NULL); if (!s) goto phooey; @@ -1784,18 +1814,19 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * } } goto phooey; - } else if (ROPT_GPOS_CHECK == (prog->reganch & ROPT_GPOS_CHECK)) + } else if (RXf_GPOS_CHECK == (prog->extflags & RXf_GPOS_CHECK)) { /* the warning about reginfo.ganch being used without intialization - is bogus -- we set it above, when prog->reganch & ROPT_GPOS_SEEN + is bogus -- we set it above, when prog->extflags & RXf_GPOS_SEEN and we only enter this block when the same bit is set. */ - if (regtry(®info, ®info.ganch)) + char *tmp_s = reginfo.ganch - prog->gofs; + if (regtry(®info, &tmp_s)) goto got_it; goto phooey; } /* Messy cases: unanchored match. */ - if ((prog->anchored_substr || prog->anchored_utf8) && prog->reganch & ROPT_SKIP) { + if ((prog->anchored_substr || prog->anchored_utf8) && prog->intflags & PREGf_SKIP) { /* we have /x+whatever/ */ /* it must be a one character string (XXXX Except UTF?) */ char ch; @@ -1926,9 +1957,9 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * }); goto phooey; } - else if ( (c = prog->regstclass) ) { + else if ( (c = progi->regstclass) ) { if (minlen) { - const OPCODE op = OP(prog->regstclass); + const OPCODE op = OP(progi->regstclass); /* don't bother with what can't match */ if (PL_regkind[op] != EXACT && op != CANY && PL_regkind[op] != TRIE) strend = HOPc(strend, -(minlen - 1)); @@ -2074,6 +2105,16 @@ phooey: PL_colors[4], PL_colors[5])); if (PL_reg_eval_set) restore_pos(aTHX_ prog); + if (progi->swap) { + /* we failed :-( roll it back */ + I32 *t; + t = progi->swap->startp; + progi->swap->startp = prog->startp; + prog->startp = t; + t = progi->swap->endp; + progi->swap->endp = prog->endp; + prog->endp = t; + } return 0; } @@ -2089,10 +2130,11 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) register I32 *ep; CHECKPOINT lastcp; regexp *prog = reginfo->prog; + RXi_GET_DECL(prog,progi); GET_RE_DEBUG_FLAGS_DECL; reginfo->cutpoint=NULL; - if ((prog->reganch & ROPT_EVAL_SEEN) && !PL_reg_eval_set) { + if ((prog->extflags & RXf_EVAL_SEEN) && !PL_reg_eval_set) { MAGIC *mg; PL_reg_eval_set = RS_init; @@ -2119,8 +2161,8 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) && (mg = mg_find(reginfo->sv, PERL_MAGIC_regex_global)))) { /* prepare for quick setting of pos */ #ifdef PERL_OLD_COPY_ON_WRITE - if (SvIsCOW(sv)) - sv_force_normal_flags(sv, 0); + if (SvIsCOW(reginfo->sv)) + sv_force_normal_flags(reginfo->sv, 0); #endif mg = sv_magicext(reginfo->sv, NULL, PERL_MAGIC_regex_global, &PL_vtbl_mglob, NULL, 0); @@ -2195,8 +2237,8 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) * on those tests seems to be returning null fields from matches. * --jhi */ #if 1 - sp = prog->startp; - ep = prog->endp; + sp = PL_regstartp; + ep = PL_regendp; if (prog->nparens) { register I32 i; for (i = prog->nparens; i > (I32)*PL_reglastparen; i--) { @@ -2206,8 +2248,8 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) } #endif REGCP_SET(lastcp); - if (regmatch(reginfo, prog->program + 1)) { - prog->endp[0] = PL_reginput - PL_bostr; + if (regmatch(reginfo, progi->program + 1)) { + PL_regendp[0] = PL_reginput - PL_bostr; return 1; } if (reginfo->cutpoint) @@ -2418,9 +2460,14 @@ regmatch(), slabs allocated since entry are freed. DEBUG_STATE_r({ \ DUMP_EXEC_POS(locinput, scan, do_utf8); \ PerlIO_printf(Perl_debug_log, \ - " %*s"pp" %s\n", \ + " %*s"pp" %s%s%s%s%s\n", \ depth*2, "", \ - reg_name[st->resume_state] ); \ + reg_name[st->resume_state], \ + ((st==yes_state||st==mark_state) ? "[" : ""), \ + ((st==yes_state) ? "Y" : ""), \ + ((st==mark_state) ? "M" : ""), \ + ((st==yes_state||st==mark_state) ? "]" : "") \ + ); \ }); @@ -2432,7 +2479,7 @@ STATIC void S_debug_start_match(pTHX_ const regexp *prog, const bool do_utf8, const char *start, const char *end, const char *blurb) { - const bool utf8_pat= prog->reganch & ROPT_UTF8 ? 1 : 0; + const bool utf8_pat= prog->extflags & RXf_UTF8 ? 1 : 0; if (!PL_colorset) reginitcolors(); { @@ -2528,7 +2575,8 @@ S_dump_exec_pos(pTHX_ const char *locinput, 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 ) ]; + RXi_GET_DECL(rex,rexi); + SV *sv_dat=(SV*)rexi->data->data[ ARG( scan ) ]; I32 *nums=(I32*)SvPVX(sv_dat); for ( n=0; n= nums[n] && @@ -2551,7 +2599,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) const U32 uniflags = UTF8_ALLOW_DEFAULT; regexp *rex = reginfo->prog; - + RXi_GET_DECL(rex,rexi); + regmatch_slab *orig_slab; regmatch_state *orig_state; @@ -2574,14 +2623,21 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) /* mark_state piggy backs on the yes_state logic so that when we unwind the stack on success we can update the mark_state as we go */ regmatch_state *mark_state = NULL; /* last mark state we have seen */ + regmatch_state *cur_eval = NULL; /* most recent EVAL_AB state */ struct regmatch_state *cur_curlyx = NULL; /* most recent curlyx */ U32 state_num; - bool no_final = 0; + bool no_final = 0; /* prevent failure from backtracking? */ + bool do_cutgroup = 0; /* no_final only until next branch/trie entry */ char *startpoint = PL_reginput; - SV *popmark = NULL; - SV *sv_commit = NULL; - int lastopen = 0; + 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 + during a successfull match */ + U32 lastopen = 0; /* last open we saw */ + bool has_cutgroup = RX_HAS_CUTGROUP(rex) ? 1 : 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 @@ -2601,7 +2657,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) GET_RE_DEBUG_FLAGS_DECL; #endif - DEBUG_STACK_r( { + DEBUG_OPTIMISE_r( { PerlIO_printf(Perl_debug_log,"regmatch start\n"); }); /* on first ever call to regmatch, allocate first slab */ @@ -2635,10 +2691,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PerlIO_printf(Perl_debug_log, "%3"IVdf":%*s%s(%"IVdf")\n", - (IV)(scan - rex->program), depth*2, "", + (IV)(scan - rexi->program), depth*2, "", SvPVX_const(prop), (PL_regkind[OP(scan)] == END || !rnext) ? - 0 : (IV)(rnext - rex->program)); + 0 : (IV)(rnext - rexi->program)); }); next = scan + NEXT_OFF(scan); @@ -2745,7 +2801,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) /* what trie are we using right now */ reg_trie_data * const trie - = (reg_trie_data*)rex->data->data[ ARG( scan ) ]; + = (reg_trie_data*)rexi->data->data[ ARG( scan ) ]; + HV * widecharmap = (HV *)rexi->data->data[ ARG( scan ) + 1 ]; U32 state = trie->startstate; if (trie->bitmap && trie_type != trie_utf8_fold && @@ -2841,8 +2898,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) }); if ( base ) { - REXEC_TRIE_READ_CHAR(trie_type, trie, uc, uscan, len, - uvc, charid, foldlen, foldbuf, uniflags); + REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc, + uscan, len, uvc, charid, foldlen, + foldbuf, uniflags); if (charid && (base + charid > trie->uniquecharcount ) @@ -2881,44 +2939,63 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) }} /* FALL THROUGH */ - case TRIE_next_fail: /* we failed - try next alterative */ - + if (do_cutgroup) { + do_cutgroup = 0; + no_final = 0; + } if ( ST.accepted == 1 ) { /* only one choice left - just continue */ DEBUG_EXECUTE_r({ - reg_trie_data * const trie - = (reg_trie_data*)rex->data->data[ ARG(ST.me) ]; - SV ** const tmp = RX_DEBUG(reginfo->prog) - ? av_fetch( trie->words, ST.accept_buff[ 0 ].wordnum-1, 0 ) - : NULL; + AV *const trie_words + = (AV *) rexi->data->data[ARG(ST.me)+TRIE_WORDS_OFFSET]; + SV ** const tmp = av_fetch( trie_words, + ST.accept_buff[ 0 ].wordnum-1, 0 ); + SV *sv= tmp ? sv_newmortal() : NULL; + PerlIO_printf( Perl_debug_log, "%*s %sonly one match left: #%d <%s>%s\n", REPORT_CODE_OFF+depth*2, "", PL_colors[4], ST.accept_buff[ 0 ].wordnum, - tmp ? SvPV_nolen_const( *tmp ) : "not compiled under -Dr", + tmp ? pv_pretty(sv, SvPV_nolen_const(*tmp), SvCUR(*tmp), 0, + PL_colors[0], PL_colors[1], + (SvUTF8(*tmp) ? PERL_PV_ESCAPE_UNI : 0) + ) + : "not compiled under -Dr", PL_colors[5] ); }); PL_reginput = (char *)ST.accept_buff[ 0 ].endpos; /* in this case we free tmps/leave before we call regmatch as we wont be using accept_buff again. */ - FREETMPS; - LEAVE; + locinput = PL_reginput; nextchr = UCHARAT(locinput); - - if ( !ST.jump || !ST.jump[ST.accept_buff[0].wordnum]) - scan = ST.B; - else - scan = ST.me + ST.jump[ST.accept_buff[0].wordnum]; + if ( !ST.jump || !ST.jump[ST.accept_buff[0].wordnum]) + scan = ST.B; + else + scan = ST.me + ST.jump[ST.accept_buff[0].wordnum]; + if (!has_cutgroup) { + FREETMPS; + LEAVE; + } else { + ST.accepted--; + PUSH_YES_STATE_GOTO(TRIE_next, scan); + } continue; /* execute rest of RE */ } if (!ST.accepted-- ) { + DEBUG_EXECUTE_r({ + PerlIO_printf( Perl_debug_log, + "%*s %sTRIE failed...%s\n", + REPORT_CODE_OFF+depth*2, "", + PL_colors[4], + PL_colors[5] ); + }); FREETMPS; LEAVE; - sayNO; + sayNO_SILENT; } /* @@ -2951,19 +3028,23 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) } DEBUG_EXECUTE_r({ - reg_trie_data * const trie - = (reg_trie_data*)rex->data->data[ ARG(ST.me) ]; - SV ** const tmp = RX_DEBUG(reginfo->prog) - ? av_fetch( trie->words, ST.accept_buff[ best ].wordnum - 1, 0 ) - : NULL; + AV *const trie_words + = (AV *) rexi->data->data[ARG(ST.me)+TRIE_WORDS_OFFSET]; + SV ** const tmp = av_fetch( trie_words, + ST.accept_buff[ best ].wordnum - 1, 0 ); regnode *nextop=(!ST.jump || !ST.jump[ST.accept_buff[best].wordnum]) ? ST.B : ST.me + ST.jump[ST.accept_buff[best].wordnum]; + SV *sv= tmp ? sv_newmortal() : NULL; + PerlIO_printf( Perl_debug_log, "%*s %strying alternation #%d <%s> at node #%d %s\n", REPORT_CODE_OFF+depth*2, "", PL_colors[4], ST.accept_buff[best].wordnum, - tmp ? SvPV_nolen_const( *tmp ) : "not compiled under -Dr", + tmp ? pv_pretty(sv, SvPV_nolen_const(*tmp), SvCUR(*tmp), 0, + PL_colors[0], PL_colors[1], + (SvUTF8(*tmp) ? PERL_PV_ESCAPE_UNI : 0) + ) : "not compiled under -Dr", REG_NODE_NUM(nextop), PL_colors[5] ); }); @@ -2976,16 +3057,26 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) } PL_reginput = (char *)ST.accept_buff[ best ].endpos; if ( !ST.jump || !ST.jump[ST.accept_buff[best].wordnum]) { - PUSH_STATE_GOTO(TRIE_next, ST.B); + scan = ST.B; /* NOTREACHED */ } else { - PUSH_STATE_GOTO(TRIE_next, ST.me + ST.jump[ST.accept_buff[best].wordnum]); + scan = ST.me + ST.jump[ST.accept_buff[best].wordnum]; /* NOTREACHED */ } + if (has_cutgroup) { + PUSH_YES_STATE_GOTO(TRIE_next, scan); + /* NOTREACHED */ + } else { + PUSH_STATE_GOTO(TRIE_next, scan); + /* NOTREACHED */ + } /* NOTREACHED */ } /* NOTREACHED */ - + case TRIE_next: + FREETMPS; + LEAVE; + sayYES; #undef ST case EXACT: { @@ -3356,7 +3447,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) do_ref: ln = PL_regstartp[n]; PL_reg_leftiter = PL_reg_maxiter; /* Void cache */ - if ((I32)*PL_reglastparen < n || ln == -1) + if (*PL_reglastparen < n || ln == -1) sayNO; /* Do not match unless seen CLOSEn. */ if (ln == PL_regendp[n]) break; @@ -3421,6 +3512,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) { SV *ret; regexp *re; + regexp_internal *rei; regnode *startpoint; case GOSTART: @@ -3436,12 +3528,13 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) nochange_depth = 0; } re = rex; + rei = rexi; (void)ReREFCNT_inc(rex); if (OP(scan)==GOSUB) { startpoint = scan + ARG2L(scan); ST.close_paren = ARG(scan); } else { - startpoint = re->program+1; + startpoint = rei->program+1; ST.close_paren = 0; } goto eval_recurse_doit; @@ -3462,12 +3555,17 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PAD *old_comppad; n = ARG(scan); - PL_op = (OP_4tree*)rex->data->data[n]; + PL_op = (OP_4tree*)rexi->data->data[n]; DEBUG_STATE_r( PerlIO_printf(Perl_debug_log, " re_eval 0x%"UVxf"\n", PTR2UV(PL_op)) ); - PAD_SAVE_LOCAL(old_comppad, (PAD*)rex->data->data[n + 2]); + PAD_SAVE_LOCAL(old_comppad, (PAD*)rexi->data->data[n + 2]); PL_regendp[0] = PL_reg_magic->mg_len = locinput - PL_bostr; + if (sv_yes_mark) { + SV *sv_mrk = get_sv("REGMARK", 1); + sv_setsv(sv_mrk, sv_yes_mark); + } + CALLRUNOPS(aTHX); /* Scalar context. */ SPAGAIN; if (SP == before) @@ -3524,11 +3622,12 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PL_regsize = osize; } } + rei = RXi_GET(re); DEBUG_EXECUTE_r( debug_start_match(re, do_utf8, locinput, PL_regeol, "Matching embedded"); ); - startpoint = re->program + 1; + startpoint = rei->program + 1; ST.close_paren = 0; /* only used for GOSUB */ /* borrowed from regtry */ if (PL_reg_start_tmpl <= re->nparens) { @@ -3556,7 +3655,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PL_reg_maxiter = 0; ST.toggle_reg_flags = PL_reg_flags; - if (re->reganch & ROPT_UTF8) + if (re->extflags & RXf_UTF8) PL_reg_flags |= RF_utf8; else PL_reg_flags &= ~RF_utf8; @@ -3565,6 +3664,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) ST.prev_rex = rex; ST.prev_curlyx = cur_curlyx; rex = re; + rexi = rei; cur_curlyx = NULL; ST.B = next; ST.prev_eval = cur_eval; @@ -3584,6 +3684,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PL_reg_flags ^= ST.toggle_reg_flags; ReREFCNT_dec(rex); rex = ST.prev_rex; + rexi = RXi_GET(rex); regcpblow(ST.cp); cur_eval = ST.prev_eval; cur_curlyx = ST.prev_curlyx; @@ -3597,6 +3698,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PL_reg_flags ^= ST.toggle_reg_flags; ReREFCNT_dec(rex); rex = ST.prev_rex; + rexi = RXi_GET(rex); PL_reginput = locinput; REGCP_UNWIND(ST.lastcp); regcppop(rex); @@ -3620,10 +3722,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PL_regendp[n] = locinput - PL_bostr; /*if (n > PL_regsize) PL_regsize = n;*/ - if (n > (I32)*PL_reglastparen) + if (n > *PL_reglastparen) *PL_reglastparen = n; *PL_reglastcloseparen = n; - if (cur_eval && cur_eval->u.eval.close_paren == (U32)n) { + if (cur_eval && cur_eval->u.eval.close_paren == n) { goto fake_end; } break; @@ -3641,11 +3743,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PL_regendp[n] = locinput - PL_bostr; /*if (n > PL_regsize) PL_regsize = n;*/ - if (n > (I32)*PL_reglastparen) + if (n > *PL_reglastparen) *PL_reglastparen = n; *PL_reglastcloseparen = n; - if ( n == ARG(scan) || (cur_eval && - cur_eval->u.eval.close_paren == (U32)n)) + if ( n == ARG(scan) || (cur_eval && + cur_eval->u.eval.close_paren == n)) break; } } @@ -3655,7 +3757,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) /*NOTREACHED*/ case GROUPP: n = ARG(scan); /* which paren pair */ - sw = (bool)((I32)*PL_reglastparen >= n && PL_regendp[n] != -1); + sw = (bool)(*PL_reglastparen >= n && PL_regendp[n] != -1); break; case NGROUPP: /* reg_check_named_buff_matched returns 0 for no match */ @@ -3663,7 +3765,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) break; case INSUBP: n = ARG(scan); - sw = (cur_eval && (!n || cur_eval->u.eval.close_paren == (U32)n)); + sw = (cur_eval && (!n || cur_eval->u.eval.close_paren == n)); break; case DEFINEP: sw = 0; @@ -3803,7 +3905,15 @@ NULL } case CURLYX_end: /* just finished matching all of A*B */ - regcpblow(ST.cp); + if (PL_reg_eval_set){ + SV *pres= GvSV(PL_replgv); + SvREFCNT_inc(pres); + regcpblow(ST.cp); + sv_setsv(GvSV(PL_replgv), pres); + SvREFCNT_dec(pres); + } else { + regcpblow(ST.cp); + } cur_curlyx = ST.prev_curlyx; sayYES; /* NOTREACHED */ @@ -4024,19 +4134,45 @@ NULL case BRANCH: /* /(...|A|...)/ */ scan = NEXTOPER(scan); /* scan now points to inner node */ - if (!next || (OP(next) != BRANCH && OP(next) != BRANCHJ)) + if ((!next || (OP(next) != BRANCH && OP(next) != BRANCHJ)) + && !has_cutgroup) + { /* last branch; skip state push and jump direct to node */ continue; + } ST.lastparen = *PL_reglastparen; ST.next_branch = next; REGCP_SET(ST.cp); PL_reginput = locinput; /* Now go into the branch */ - PUSH_STATE_GOTO(BRANCH_next, scan); + if (has_cutgroup) { + PUSH_YES_STATE_GOTO(BRANCH_next, scan); + } else { + PUSH_STATE_GOTO(BRANCH_next, scan); + } /* NOTREACHED */ - + case CUTGROUP: + PL_reginput = locinput; + sv_yes_mark = st->u.mark.mark_name = scan->flags ? NULL : + (SV*)rexi->data->data[ ARG( scan ) ]; + PUSH_STATE_GOTO(CUTGROUP_next,next); + /* NOTREACHED */ + case CUTGROUP_next_fail: + do_cutgroup = 1; + no_final = 1; + if (st->u.mark.mark_name) + sv_commit = st->u.mark.mark_name; + sayNO; + /* NOTREACHED */ + case BRANCH_next: + sayYES; + /* NOTREACHED */ case BRANCH_next_fail: /* that branch failed; try the next, if any */ + if (do_cutgroup) { + do_cutgroup = 0; + no_final = 0; + } REGCP_UNWIND(ST.cp); for (n = *PL_reglastparen; n > ST.lastparen; n--) PL_regendp[n] = -1; @@ -4044,8 +4180,16 @@ NULL /*dmq: *PL_reglastcloseparen = n; */ scan = ST.next_branch; /* no more branches? */ - if (!scan || (OP(scan) != BRANCH && OP(scan) != BRANCHJ)) - sayNO; + if (!scan || (OP(scan) != BRANCH && OP(scan) != BRANCHJ)) { + DEBUG_EXECUTE_r({ + PerlIO_printf( Perl_debug_log, + "%*s %sBRANCH failed...%s\n", + REPORT_CODE_OFF+depth*2, "", + PL_colors[4], + PL_colors[5] ); + }); + sayNO_SILENT; + } continue; /* execute next BRANCH[J] op */ /* NOTREACHED */ @@ -4069,10 +4213,10 @@ NULL /* if paren positive, emulate an OPEN/CLOSE around A */ if (ST.me->flags) { - I32 paren = ST.me->flags; + U32 paren = ST.me->flags; if (paren > PL_regsize) PL_regsize = paren; - if (paren > (I32)*PL_reglastparen) + if (paren > *PL_reglastparen) *PL_reglastparen = paren; scan += NEXT_OFF(scan); /* Skip former OPEN. */ } @@ -4245,7 +4389,7 @@ NULL ST.paren = scan->flags; /* Which paren to set */ if (ST.paren > PL_regsize) PL_regsize = ST.paren; - if (ST.paren > (I32)*PL_reglastparen) + if (ST.paren > *PL_reglastparen) *PL_reglastparen = ST.paren; ST.min = ARG1(scan); /* min to match */ ST.max = ARG2(scan); /* max to match */ @@ -4541,7 +4685,8 @@ NULL PL_reg_flags ^= st->u.eval.toggle_reg_flags; st->u.eval.prev_rex = rex; /* inner */ - rex = cur_eval->u.eval.prev_rex; /* outer */ + rex = cur_eval->u.eval.prev_rex; /* outer */ + rexi = RXi_GET(rex); cur_curlyx = cur_eval->u.eval.prev_curlyx; ReREFCNT_inc(rex); st->u.eval.cp = regcppush(0); /* Save *all* the positions. */ @@ -4558,8 +4703,8 @@ NULL st->u.eval.prev_eval = cur_eval; cur_eval = cur_eval->u.eval.prev_eval; DEBUG_EXECUTE_r( - PerlIO_printf(Perl_debug_log, "%*s EVAL trying tail ... %x\n", - REPORT_CODE_OFF+depth*2, "",(int)cur_eval);); + PerlIO_printf(Perl_debug_log, "%*s EVAL trying tail ... %"UVxf"\n", + REPORT_CODE_OFF+depth*2, "",PTR2UV(cur_eval));); PUSH_YES_STATE_GOTO(EVAL_AB, st->u.eval.prev_eval->u.eval.B); /* match B */ } @@ -4571,6 +4716,7 @@ NULL (long)(locinput - PL_reg_starttry), (long)(reginfo->till - PL_reg_starttry), PL_colors[5])); + sayNO_SILENT; /* Cannot match: too short. */ } PL_reginput = locinput; /* put where regtry can find it */ @@ -4658,10 +4804,10 @@ NULL case COMMIT: reginfo->cutpoint = PL_regeol; /* FALLTHROUGH */ - case NOMATCH: + case PRUNE: PL_reginput = locinput; if (!scan->flags) - sv_commit = (SV*)rex->data->data[ ARG( scan ) ]; + sv_yes_mark = sv_commit = (SV*)rexi->data->data[ ARG( scan ) ]; PUSH_STATE_GOTO(COMMIT_next,next); /* NOTREACHED */ case COMMIT_next_fail: @@ -4674,8 +4820,8 @@ NULL #define ST st->u.mark case MARKPOINT: ST.prev_mark = mark_state; - ST.mark_name = scan->flags ? &PL_sv_yes : - (SV*)rex->data->data[ ARG( scan ) ]; + ST.mark_name = sv_commit = sv_yes_mark + = (SV*)rexi->data->data[ ARG( scan ) ]; mark_state = st; ST.mark_loc = PL_reginput = locinput; PUSH_YES_STATE_GOTO(MARKPOINT_next,next); @@ -4685,9 +4831,7 @@ NULL sayYES; /* NOTREACHED */ case MARKPOINT_next_fail: - if (popmark && ( popmark == &PL_sv_yes || - (ST.mark_name != &PL_sv_yes && - sv_eq(ST.mark_name,popmark)))) + if (popmark && sv_eq(ST.mark_name,popmark)) { if (ST.mark_loc > startpoint) reginfo->cutpoint = HOPBACKc(ST.mark_loc, 1); @@ -4695,40 +4839,58 @@ NULL sv_commit = ST.mark_name; DEBUG_EXECUTE_r({ - if (sv_commit != &PL_sv_yes) - PerlIO_printf(Perl_debug_log, + PerlIO_printf(Perl_debug_log, "%*s %ssetting cutpoint to mark:%"SVf"...%s\n", REPORT_CODE_OFF+depth*2, "", PL_colors[4], sv_commit, PL_colors[5]); - else - PerlIO_printf(Perl_debug_log, - "%*s %ssetting cutpoint to mark...%s\n", - REPORT_CODE_OFF+depth*2, "", - PL_colors[4], PL_colors[5]); }); } mark_state = ST.prev_mark; + sv_yes_mark = mark_state ? + mark_state->u.mark.mark_name : NULL; sayNO; /* NOTREACHED */ - case CUT: - ST.mark_name = scan->flags ? &PL_sv_yes : - (SV*)rex->data->data[ ARG( scan ) ]; - if (mark_state) { - ST.mark_loc = NULL; - } else { + case SKIP: + PL_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); + } else { + /* (*SKIP:NAME) : if there is a (*MARK:NAME) fail where it was, + otherwise do nothing. Meaning we need to scan + */ + regmatch_state *cur = mark_state; + SV *find = (SV*)rexi->data->data[ ARG( scan ) ]; + + while (cur) { + if ( sv_eq( cur->u.mark.mark_name, + find ) ) + { + ST.mark_name = find; + PUSH_STATE_GOTO( SKIP_next, next ); + } + cur = cur->u.mark.prev_mark; + } } - PL_reginput = locinput; - PUSH_STATE_GOTO(CUT_next,next); - /* NOTREACHED */ - case CUT_next_fail: - if (ST.mark_loc) { + /* Didn't find our (*MARK:NAME) so ignore this (*SKIP:NAME) */ + break; + case SKIP_next_fail: + if (ST.mark_name) { + /* (*CUT:NAME) - Set up to search for the name as we + collapse the stack*/ + popmark = ST.mark_name; + } else { + /* (*CUT) - No name, we cut here.*/ if (ST.mark_loc > startpoint) reginfo->cutpoint = HOPBACKc(ST.mark_loc, 1); - sv_commit = ST.mark_name; - } else { - popmark = ST.mark_name; - } + /* but we set sv_commit to latest mark_name if there + is one so they can test to see how things lead to this + cut */ + if (mark_state) + sv_commit=mark_state->u.mark.mark_name; + } no_final = 1; sayNO; /* NOTREACHED */ @@ -4738,10 +4900,12 @@ NULL PerlIO_printf(Perl_error_log, "%"UVxf" %d\n", PTR2UV(scan), OP(scan)); Perl_croak(aTHX_ "regexp memory corruption"); - } + + } /* end switch */ - scan = next; - continue; + /* switch break jumps here */ + scan = next; /* prepare to execute the next op and ... */ + continue; /* ... jump back to the top, reusing st */ /* NOTREACHED */ push_yes_state: @@ -4834,7 +4998,10 @@ yes: yes_state = st->u.yes.prev_yes_state; PL_regmatch_state = st; - + if (no_final) { + locinput= st->locinput; + nextchr = UCHARAT(locinput); + } state_num = st->resume_state + no_final; goto reenter_switch; } @@ -4883,13 +5050,20 @@ no_silent: result = 0; final_exit: - if (rex->reganch & ROPT_VERBARG_SEEN) { - SV *sv = get_sv("REGERROR", 1); - if (result) + if (rex->intflags & PREGf_VERBARG_SEEN) { + SV *sv_err = get_sv("REGERROR", 1); + SV *sv_mrk = get_sv("REGMARK", 1); + if (result) { sv_commit = &PL_sv_no; - else if (!sv_commit) - sv_commit = &PL_sv_yes; - sv_setsv(sv, sv_commit); + if (!sv_yes_mark) + sv_yes_mark = &PL_sv_yes; + } else { + if (!sv_commit) + sv_commit = &PL_sv_yes; + sv_yes_mark = &PL_sv_no; + } + sv_setsv(sv_err, sv_commit); + sv_setsv(sv_mrk, sv_yes_mark); } /* restore original high-water mark */ PL_regmatch_slab = orig_slab; @@ -5169,7 +5343,8 @@ Perl_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bool SV *sw = NULL; SV *si = NULL; SV *alt = NULL; - const struct reg_data * const data = prog ? prog->data : NULL; + RXi_GET_DECL(prog,progi); + const struct reg_data * const data = prog ? progi->data : NULL; if (data && data->count) { const U32 n = ARG(node);