This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
De-duplicate the code that creates new GPs into Perl_newGP().
[perl5.git] / toke.c
diff --git a/toke.c b/toke.c
index f16964e..b0c0ccc 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -429,7 +429,8 @@ S_no_op(pTHX_ const char *what, char *s)
                    "\t(Missing semicolon on previous line?)\n");
        else if (PL_oldoldbufptr && isIDFIRST_lazy_if(PL_oldoldbufptr,UTF)) {
            const char *t;
-           for (t = PL_oldoldbufptr; *t && (isALNUM_lazy_if(t,UTF) || *t == ':'); t++) ;
+           for (t = PL_oldoldbufptr; *t && (isALNUM_lazy_if(t,UTF) || *t == ':'); t++)
+               /**/;
            if (t < PL_bufptr && isSPACE(*t))
                Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
                        "\t(Do you need to predeclare %.*s?)\n",
@@ -447,7 +448,7 @@ S_no_op(pTHX_ const char *what, char *s)
 /*
  * S_missingterm
  * Complain about missing quote/regexp/heredoc terminator.
- * If it's called with (char *)NULL then it cauterizes the line buffer.
+ * If it's called with NULL then it cauterizes the line buffer.
  * If we're in a delimited string and the delimiter is a control
  * character, it's reformatted into a two-char sequence like ^C.
  * This is fatal.
@@ -493,13 +494,13 @@ S_missingterm(pTHX_ char *s)
  * Check whether the named feature is enabled.
  */
 STATIC bool
-S_feature_is_enabled(pTHX_ char *name, STRLEN namelen)
+S_feature_is_enabled(pTHX_ const char *name, STRLEN namelen)
 {
     dVAR;
     HV * const hinthv = GvHV(PL_hintgv);
     char he_name[32] = "feature_";
     (void) strncpy(&he_name[8], name, 24);
-    
+
     return (hinthv && hv_exists(hinthv, he_name, 8 + namelen));
 }
 
@@ -711,7 +712,8 @@ S_incline(pTHX_ char *s)
     CopLINE_inc(PL_curcop);
     if (*s++ != '#')
        return;
-    while (SPACE_OR_TAB(*s)) s++;
+    while (SPACE_OR_TAB(*s))
+       s++;
     if (strnEQ(s, "line", 4))
        s += 4;
     else
@@ -720,9 +722,11 @@ S_incline(pTHX_ char *s)
        s++;
     else
        return;
-    while (SPACE_OR_TAB(*s)) s++;
+    while (SPACE_OR_TAB(*s))
+       s++;
     if (!isDIGIT(*s))
        return;
+
     n = s;
     while (isDIGIT(*s))
        s++;
@@ -813,7 +817,7 @@ S_skipspace0(pTHX_ register char *s)
 STATIC char *
 S_skipspace1(pTHX_ register char *s)
 {
-    char *start = s;
+    const char *start = s;
     I32 startoff = start - SvPVX(PL_linestr);
 
     s = skipspace(s);
@@ -821,7 +825,7 @@ S_skipspace1(pTHX_ register char *s)
        return s;
     start = SvPVX(PL_linestr) + startoff;
     if (!PL_thistoken && PL_realtokenstart >= 0) {
-       char *tstart = SvPVX(PL_linestr) + PL_realtokenstart;
+       const char * const tstart = SvPVX(PL_linestr) + PL_realtokenstart;
        PL_thistoken = newSVpvn(tstart, start - tstart);
     }
     PL_realtokenstart = -1;
@@ -847,7 +851,7 @@ S_skipspace2(pTHX_ register char *s, SV **svp)
        return s;
     start = SvPVX(PL_linestr) + startoff;
     if (!PL_thistoken && PL_realtokenstart >= 0) {
-       char *tstart = SvPVX(PL_linestr) + PL_realtokenstart;
+       char * const tstart = SvPVX(PL_linestr) + PL_realtokenstart;
        PL_thistoken = newSVpvn(tstart, start - tstart);
        PL_realtokenstart = -1;
     }
@@ -1064,14 +1068,15 @@ STATIC void
 S_check_uni(pTHX)
 {
     dVAR;
-    char *s;
-    char *t;
+    const char *s;
+    const char *t;
 
     if (PL_oldoldbufptr != PL_last_uni)
        return;
     while (isSPACE(*PL_last_uni))
        PL_last_uni++;
-    for (s = PL_last_uni; isALNUM_lazy_if(s,UTF) || *s == '-'; s++) ;
+    for (s = PL_last_uni; isALNUM_lazy_if(s,UTF) || *s == '-'; s++)
+       /**/;
     if ((t = strchr(s, '(')) && t < PL_bufptr)
        return;
 
@@ -1189,8 +1194,8 @@ S_curmad(pTHX_ char slot, SV *sv)
        addmad(newMADsv(slot, sv), where, 0);
 }
 #else
-#  define start_force(where)
-#  define curmad(slot, sv)
+#  define start_force(where)    NOOP
+#  define curmad(slot, sv)      NOOP
 #endif
 
 /*
@@ -1774,7 +1779,7 @@ S_scan_const(pTHX_ char *start)
     UV literal_endpoint = 0;
 #endif
 
-    const char *leaveit =      /* set of acceptably-backslashed characters */
+    const char * const leaveit = /* set of acceptably-backslashed characters */
        PL_lex_inpat
            ? "\\.^$@AGZdDwWsSbBpPXC+*?|()-nrtfeaxz0123456789[{]} \t\n\r\f\v#"
            : "";
@@ -2587,7 +2592,8 @@ Perl_filter_add(pTHX_ filter_t funcp, SV *datasv)
     IoANY(datasv) = FPTR2DPTR(void *, funcp); /* stash funcp into spare field */
     IoFLAGS(datasv) |= IOf_FAKE_DIRP;
     DEBUG_P(PerlIO_printf(Perl_debug_log, "filter_add func %p (%s)\n",
-                         IoANY(datasv), SvPV_nolen(datasv)));
+                         FPTR2DPTR(void *, IoANY(datasv)),
+                         SvPV_nolen(datasv)));
     av_unshift(PL_rsfp_filters, 1);
     av_store(PL_rsfp_filters, 0, datasv) ;
     return(datasv);
@@ -2602,7 +2608,8 @@ Perl_filter_del(pTHX_ filter_t funcp)
     SV *datasv;
 
 #ifdef DEBUGGING
-    DEBUG_P(PerlIO_printf(Perl_debug_log, "filter_del func %p", FPTR2DPTR(XPVIO *, funcp)));
+    DEBUG_P(PerlIO_printf(Perl_debug_log, "filter_del func %p",
+                         FPTR2DPTR(void*, funcp)));
 #endif
     if (!PL_rsfp_filters || AvFILLp(PL_rsfp_filters)<0)
        return;
@@ -2628,6 +2635,17 @@ Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen)
     dVAR;
     filter_t funcp;
     SV *datasv = NULL;
+    /* This API is bad. It should have been using unsigned int for maxlen.
+       Not sure if we want to change the API, but if not we should sanity
+       check the value here.  */
+    const unsigned int correct_length
+       = maxlen < 0 ?
+#ifdef PERL_MICRO
+       0x7FFFFFFF
+#else
+       INT_MAX
+#endif
+       : maxlen;
 
     if (!PL_rsfp_filters)
        return -1;
@@ -2636,14 +2654,15 @@ Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen)
        /* Note that we append to the line. This is handy.      */
        DEBUG_P(PerlIO_printf(Perl_debug_log,
                              "filter_read %d: from rsfp\n", idx));
-       if (maxlen) {
+       if (correct_length) {
            /* Want a block */
            int len ;
            const int old_len = SvCUR(buf_sv);
 
            /* ensure buf_sv is large enough */
-           SvGROW(buf_sv, (STRLEN)(old_len + maxlen)) ;
-           if ((len = PerlIO_read(PL_rsfp, SvPVX(buf_sv) + old_len, maxlen)) <= 0){
+           SvGROW(buf_sv, (STRLEN)(old_len + correct_length)) ;
+           if ((len = PerlIO_read(PL_rsfp, SvPVX(buf_sv) + old_len,
+                                  correct_length)) <= 0) {
                if (PerlIO_error(PL_rsfp))
                    return -1;          /* error */
                else
@@ -2666,17 +2685,17 @@ Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen)
        DEBUG_P(PerlIO_printf(Perl_debug_log,
                              "filter_read %d: skipped (filter deleted)\n",
                              idx));
-       return FILTER_READ(idx+1, buf_sv, maxlen); /* recurse */
+       return FILTER_READ(idx+1, buf_sv, correct_length); /* recurse */
     }
     /* Get function pointer hidden within datasv       */
     funcp = DPTR2FPTR(filter_t, IoANY(datasv));
     DEBUG_P(PerlIO_printf(Perl_debug_log,
                          "filter_read %d: via function %p (%s)\n",
-                         idx, datasv, SvPV_nolen_const(datasv)));
+                         idx, (void*)datasv, SvPV_nolen_const(datasv)));
     /* Call function. The function is expected to      */
     /* call "FILTER_READ(idx+1, buf_sv)" first.                */
     /* Return: <0:error, =0:eof, >0:not eof            */
-    return (*funcp)(aTHX_ idx, buf_sv, maxlen);
+    return (*funcp)(aTHX_ idx, buf_sv, correct_length);
 }
 
 STATIC char *
@@ -3130,7 +3149,7 @@ Perl_yylex(pTHX)
                else
                    Perl_croak(aTHX_ "panic: yylex");
                if (PL_madskills) {
-                   SV* tmpsv = newSVpvn("",0);
+                   SV* const tmpsv = newSVpvn("",0);
                    Perl_sv_catpvf(aTHX_ tmpsv, "\\%c", *s);
                    curmad('_', tmpsv);
                }
@@ -3649,7 +3668,8 @@ Perl_yylex(pTHX)
                        do {
                            if (*d == 'M' || *d == 'm' || *d == 'C') {
                                const char * const m = d;
-                               while (*d && !isSPACE(*d)) d++;
+                               while (*d && !isSPACE(*d))
+                                   d++;
                                Perl_croak(aTHX_ "Too late for \"-%.*s\" option",
                                      (int)(d - m), m);
                            }
@@ -3982,6 +4002,7 @@ Perl_yylex(pTHX)
            attrs = NULL;
            while (isIDFIRST_lazy_if(s,UTF)) {
                I32 tmp;
+               SV *sv;
                d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
                if (isLOWER(*s) && (tmp = keyword(PL_tokenbuf, len))) {
                    if (tmp < 0) tmp = -tmp;
@@ -3999,6 +4020,7 @@ Perl_yylex(pTHX)
                        break;
                    }
                }
+               sv = newSVpvn(s, len);
                if (*d == '(') {
                    d = scan_str(d,TRUE,TRUE);
                    if (!d) {
@@ -4009,11 +4031,11 @@ Perl_yylex(pTHX)
                        yyerror("Unterminated attribute parameter in attribute list");
                        if (attrs)
                            op_free(attrs);
+                       sv_free(sv);
                        return REPORT(0);       /* EOF indicator */
                    }
                }
                if (PL_lex_stuff) {
-                   SV *sv = newSVpvn(s, len);
                    sv_catsv(sv, PL_lex_stuff);
                    attrs = append_elem(OP_LIST, attrs,
                                        newSVOP(OP_CONST, 0, sv));
@@ -4021,27 +4043,38 @@ Perl_yylex(pTHX)
                    PL_lex_stuff = NULL;
                }
                else {
-                   if (len == 6 && strnEQ(s, "unique", len)) {
-                       if (PL_in_my == KEY_our)
+                   if (len == 6 && strnEQ(SvPVX(sv), "unique", len)) {
+                       sv_free(sv);
+                       if (PL_in_my == KEY_our) {
 #ifdef USE_ITHREADS
                            GvUNIQUE_on(cGVOPx_gv(yylval.opval));
 #else
-                           /*EMPTY*/;    /* skip to avoid loading attributes.pm */
+                           /* skip to avoid loading attributes.pm */
 #endif
+                           deprecate(":unique");
+                       }
                        else
                            Perl_croak(aTHX_ "The 'unique' attribute may only be applied to 'our' variables");
                    }
 
                    /* NOTE: any CV attrs applied here need to be part of
                       the CVf_BUILTIN_ATTRS define in cv.h! */
-                   else if (!PL_in_my && len == 6 && strnEQ(s, "lvalue", len))
+                   else if (!PL_in_my && len == 6 && strnEQ(SvPVX(sv), "lvalue", len)) {
+                       sv_free(sv);
                        CvLVALUE_on(PL_compcv);
-                   else if (!PL_in_my && len == 6 && strnEQ(s, "locked", len))
+                   }
+                   else if (!PL_in_my && len == 6 && strnEQ(SvPVX(sv), "locked", len)) {
+                       sv_free(sv);
                        CvLOCKED_on(PL_compcv);
-                   else if (!PL_in_my && len == 6 && strnEQ(s, "method", len))
+                   }
+                   else if (!PL_in_my && len == 6 && strnEQ(SvPVX(sv), "method", len)) {
+                       sv_free(sv);
                        CvMETHOD_on(PL_compcv);
-                   else if (!PL_in_my && len == 9 && strnEQ(s, "assertion", len))
+                   }
+                   else if (!PL_in_my && len == 9 && strnEQ(SvPVX(sv), "assertion", len)) {
+                       sv_free(sv);
                        CvASSERTION_on(PL_compcv);
+                   }
                    /* After we've set the flags, it could be argued that
                       we don't need to do the attributes.pm-based setting
                       process, and shouldn't bother appending recognized
@@ -4055,7 +4088,7 @@ Perl_yylex(pTHX)
                    else
                        attrs = append_elem(OP_LIST, attrs,
                                            newSVOP(OP_CONST, 0,
-                                                   newSVpvn(s, len)));
+                                                   sv));
                }
                s = PEEKSPACE(d);
                if (*s == ':' && s[1] != ':')
@@ -4503,7 +4536,7 @@ Perl_yylex(pTHX)
            const char tmp = *s++;
            if (tmp == '>')
                SHop(OP_RIGHT_SHIFT);
-           if (tmp == '=')
+           else if (tmp == '=')
                Rop(OP_GE);
        }
        s--;
@@ -4547,7 +4580,7 @@ Perl_yylex(pTHX)
        /* This kludge not intended to be bulletproof. */
        if (PL_tokenbuf[1] == '[' && !PL_tokenbuf[2]) {
            yylval.opval = newSVOP(OP_CONST, 0,
-                                  newSViv(PL_compiling.cop_arybase));
+                                  newSViv(CopARYBASE_get(&PL_compiling)));
            yylval.opval->op_private = OPpCONST_ARYBASE;
            TERM(THING);
        }
@@ -4773,7 +4806,7 @@ Perl_yylex(pTHX)
                no_op("String",s);
        }
        if (!s)
-           missingterm((char*)0);
+           missingterm(NULL);
        yylval.ival = OP_CONST;
        TERM(sublex_start());
 
@@ -4790,7 +4823,7 @@ Perl_yylex(pTHX)
                no_op("String",s);
        }
        if (!s)
-           missingterm((char*)0);
+           missingterm(NULL);
        yylval.ival = OP_CONST;
        /* FIXME. I think that this can be const if char *d is replaced by
           more localised variables.  */
@@ -4808,7 +4841,7 @@ Perl_yylex(pTHX)
        if (PL_expect == XOPERATOR)
            no_op("Backticks",s);
        if (!s)
-           missingterm((char*)0);
+           missingterm(NULL);
        yylval.ival = OP_BACKTICK;
        set_csh();
        TERM(sublex_start());
@@ -4835,6 +4868,7 @@ Perl_yylex(pTHX)
            else if (!isALPHA(*start) && (PL_expect == XTERM
                        || PL_expect == XREF || PL_expect == XSTATE
                        || PL_expect == XTERMORDORDOR)) {
+               /* XXX Use gv_fetchpvn rather than stomping on a const string */
                const char c = *start;
                GV *gv;
                *start = '\0';
@@ -5450,7 +5484,7 @@ Perl_yylex(pTHX)
                        PUTBACK;
                        PerlIO_apply_layers(aTHX_ PL_rsfp, NULL,
                                            Perl_form(aTHX_ ":encoding(%"SVf")",
-                                                     name));
+                                                     (void*)name));
                        FREETMPS;
                        LEAVE;
                    }
@@ -5943,7 +5977,11 @@ Perl_yylex(pTHX)
                if (!PL_in_my_stash) {
                    char tmpbuf[1024];
                    PL_bufptr = s;
+#ifdef USE_SNPRINTF
+                   snprintf(tmpbuf, sizeof(tmpbuf), "No such class %.1000s", PL_tokenbuf);
+#else
                    sprintf(tmpbuf, "No such class %.1000s", PL_tokenbuf);
+#endif /* #ifdef USE_SNPRINTF */
                    yyerror(tmpbuf);
                }
 #ifdef PERL_MAD
@@ -6038,7 +6076,7 @@ Perl_yylex(pTHX)
        case KEY_q:
            s = scan_str(s,!!PL_madskills,FALSE);
            if (!s)
-               missingterm((char*)0);
+               missingterm(NULL);
            yylval.ival = OP_CONST;
            TERM(sublex_start());
 
@@ -6048,7 +6086,7 @@ Perl_yylex(pTHX)
        case KEY_qw:
            s = scan_str(s,!!PL_madskills,FALSE);
            if (!s)
-               missingterm((char*)0);
+               missingterm(NULL);
            PL_expect = XOPERATOR;
            force_next(')');
            if (SvCUR(PL_lex_stuff)) {
@@ -6056,9 +6094,10 @@ Perl_yylex(pTHX)
                int warned = 0;
                d = SvPV_force(PL_lex_stuff, len);
                while (len) {
-                   SV *sv;
-                   for (; isSPACE(*d) && len; --len, ++d) ;
+                   for (; isSPACE(*d) && len; --len, ++d)
+                       /**/;
                    if (len) {
+                       SV *sv;
                        const char *b = d;
                        if (!warned && ckWARN(WARN_QW)) {
                            for (; !isSPACE(*d) && len; --len, ++d) {
@@ -6075,7 +6114,8 @@ Perl_yylex(pTHX)
                            }
                        }
                        else {
-                           for (; !isSPACE(*d) && len; --len, ++d) ;
+                           for (; !isSPACE(*d) && len; --len, ++d)
+                               /**/;
                        }
                        sv = newSVpvn(b, d-b);
                        if (DO_UTF8(PL_lex_stuff))
@@ -6100,7 +6140,7 @@ Perl_yylex(pTHX)
        case KEY_qq:
            s = scan_str(s,!!PL_madskills,FALSE);
            if (!s)
-               missingterm((char*)0);
+               missingterm(NULL);
            yylval.ival = OP_STRINGIFY;
            if (SvIVX(PL_lex_stuff) == '\'')
                SvIV_set(PL_lex_stuff, 0);      /* qq'$foo' should intepolate */
@@ -6113,7 +6153,7 @@ Perl_yylex(pTHX)
        case KEY_qx:
            s = scan_str(s,!!PL_madskills,FALSE);
            if (!s)
-               missingterm((char*)0);
+               missingterm(NULL);
            yylval.ival = OP_BACKTICK;
            set_csh();
            TERM(sublex_start());
@@ -6431,7 +6471,7 @@ Perl_yylex(pTHX)
                    if (bad_proto && ckWARN(WARN_SYNTAX))
                        Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
                                    "Illegal character in prototype for %"SVf" : %s",
-                                   PL_subname, d);
+                                   (void*)PL_subname, d);
                    SvCUR_set(PL_lex_stuff, tmp);
                    have_proto = TRUE;
 
@@ -6460,7 +6500,7 @@ Perl_yylex(pTHX)
                    if (!have_name)
                        Perl_croak(aTHX_ "Illegal declaration of anonymous subroutine");
                    else if (*s != ';')
-                       Perl_croak(aTHX_ "Illegal declaration of subroutine %"SVf, PL_subname);
+                       Perl_croak(aTHX_ "Illegal declaration of subroutine %"SVf, (void*)PL_subname);
                }
 
 #ifdef PERL_MAD
@@ -6647,7 +6687,7 @@ S_pending_ident(pTHX)
 {
     dVAR;
     register char *d;
-    register I32 tmp = 0;
+    register PADOFFSET tmp = 0;
     /* pit holds the identifier we read and pending_ident is reset */
     char pit = PL_pending_ident;
     PL_pending_ident = 0;
@@ -10167,8 +10207,8 @@ S_checkcomma(pTHX_ const char *s, const char *name, const char *what)
                else if (*w == ')')
                    --level;
            }
-           for (; *w && isSPACE(*w); w++)
-               /* EMPTY */;
+           while (isSPACE(*w))
+               ++w;
            if (!*w || !strchr(";|})]oaiuw!=", *w))     /* an advisory hack only... */
                Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
                            "%s (...) interpreted as function",name);
@@ -11054,7 +11094,7 @@ S_scan_inputsymbol(pTHX_ char *start)
        or if it didn't end, or if we see a newline
     */
 
-    if (len >= sizeof PL_tokenbuf)
+    if (len >= (I32)sizeof PL_tokenbuf)
        Perl_croak(aTHX_ "Excessively long <> operator");
     if (s >= end)
        Perl_croak(aTHX_ "Unterminated <> operator");
@@ -11113,7 +11153,7 @@ S_scan_inputsymbol(pTHX_ char *start)
           filehandle
        */
        if (*d == '$') {
-           I32 tmp;
+           PADOFFSET tmp;
 
            /* try to find it in the pad for this block, otherwise find
               add symbol table ops
@@ -12219,13 +12259,13 @@ Perl_yyerror(pTHX_ const char *s)
         PL_multi_end = 0;
     }
     if (PL_in_eval & EVAL_WARNONLY && ckWARN_d(WARN_SYNTAX))
-       Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "%"SVf, msg);
+       Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "%"SVf, (void*)msg);
     else
        qerror(msg);
     if (PL_error_count >= 10) {
        if (PL_in_eval && SvCUR(ERRSV))
            Perl_croak(aTHX_ "%"SVf"%s has too many errors.\n",
-            ERRSV, OutCopFILE(PL_curcop));
+                      (void*)ERRSV, OutCopFILE(PL_curcop));
        else
            Perl_croak(aTHX_ "%s has too many errors.\n",
             OutCopFILE(PL_curcop));
@@ -12369,7 +12409,8 @@ utf16_textfilter(pTHX_ int idx, SV *sv, int maxlen)
     const I32 count = FILTER_READ(idx+1, sv, maxlen);
     DEBUG_P(PerlIO_printf(Perl_debug_log,
                          "utf16_textfilter(%p): %d %d (%d)\n",
-                         utf16_textfilter, idx, maxlen, (int) count));
+                         FPTR2DPTR(void *, utf16_textfilter),
+                         idx, maxlen, (int) count));
     if (count) {
        U8* tmps;
        I32 newlen;
@@ -12391,7 +12432,8 @@ utf16rev_textfilter(pTHX_ int idx, SV *sv, int maxlen)
     const I32 count = FILTER_READ(idx+1, sv, maxlen);
     DEBUG_P(PerlIO_printf(Perl_debug_log,
                          "utf16rev_textfilter(%p): %d %d (%d)\n",
-                         utf16rev_textfilter, idx, maxlen, (int) count));
+                         FPTR2DPTR(void *, utf16rev_textfilter),
+                         idx, maxlen, (int) count));
     if (count) {
        U8* tmps;
        I32 newlen;
@@ -12444,22 +12486,20 @@ Perl_scan_vstring(pTHX_ const char *s, SV *sv)
     if (!isALPHA(*pos)) {
        U8 tmpbuf[UTF8_MAXBYTES+1];
 
-       if (*s == 'v') s++;  /* get past 'v' */
+       if (*s == 'v')
+           s++;  /* get past 'v' */
 
        sv_setpvn(sv, "", 0);
 
        for (;;) {
+           /* this is atoi() that tolerates underscores */
            U8 *tmpend;
            UV rev = 0;
-           {
-               /* this is atoi() that tolerates underscores */
-               const char *end = pos;
-               UV mult = 1;
-               while (--end >= s) {
-                   UV orev;
-                   if (*end == '_')
-                       continue;
-                   orev = rev;
+           const char *end = pos;
+           UV mult = 1;
+           while (--end >= s) {
+               if (*end != '_') {
+                   const UV orev = rev;
                    rev += (*end - '0') * mult;
                    mult *= 10;
                    if (orev > rev && ckWARN_d(WARN_OVERFLOW))