This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
C++: regcomp.c and ext/Time/Piece/Piece.xs
[perl5.git] / toke.c
diff --git a/toke.c b/toke.c
index 03bc682..32edd1d 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -23,8 +23,7 @@
 #define PERL_IN_TOKE_C
 #include "perl.h"
 
-#define yychar (*PL_yycharp)
-#define yylval (*PL_yylvalp)
+#define yylval (PL_parser->yylval)
 
 static const char ident_too_long[] = "Identifier too long";
 static const char commaless_variable_list[] = "comma-less variable list";
@@ -662,13 +661,11 @@ Perl_lex_start(pTHX_ SV *line)
     PL_lex_inwhat = 0;
     PL_sublex_info.sub_inwhat = 0;
     PL_linestr = line;
-    if (SvREADONLY(PL_linestr))
-       PL_linestr = sv_2mortal(newSVsv(PL_linestr));
     s = SvPV_const(PL_linestr, len);
-    if (!len || s[len-1] != ';') {
-       if (!(SvFLAGS(PL_linestr) & SVs_TEMP))
-           PL_linestr = sv_2mortal(newSVsv(PL_linestr));
-       sv_catpvs(PL_linestr, "\n;");
+    if (SvREADONLY(PL_linestr) || !len || s[len-1] != ';') {
+       PL_linestr = sv_2mortal(len ? newSVsv(PL_linestr) : newSVpvn(s, 0));
+       if (!len || s[len-1] != ';')
+           sv_catpvs(PL_linestr, "\n;");
     }
     SvTEMP_off(PL_linestr);
     PL_oldoldbufptr = PL_oldbufptr = PL_bufptr = PL_linestart = SvPVX(PL_linestr);
@@ -776,12 +773,13 @@ S_incline(pTHX_ char *s)
            gvp = (GV**)hv_fetch(PL_defstash, tmpbuf, tmplen, FALSE);
            if (gvp) {
                gv2 = *(GV**)hv_fetch(PL_defstash, tmpbuf2, tmplen2, TRUE);
-               if (!isGV(gv2))
+               if (!isGV(gv2)) {
                    gv_init(gv2, PL_defstash, tmpbuf2, tmplen2, FALSE);
-               /* adjust ${"::_<newfilename"} to store the new file name */
-               GvSV(gv2) = newSVpvn(tmpbuf2 + 2, tmplen2 - 2);
-               GvHV(gv2) = (HV*)SvREFCNT_inc(GvHV(*gvp));
-               GvAV(gv2) = (AV*)SvREFCNT_inc(GvAV(*gvp));
+                   /* adjust ${"::_<newfilename"} to store the new file name */
+                   GvSV(gv2) = newSVpvn(tmpbuf2 + 2, tmplen2 - 2);
+                   GvHV(gv2) = (HV*)SvREFCNT_inc(GvHV(*gvp));
+                   GvAV(gv2) = (AV*)SvREFCNT_inc(GvAV(*gvp));
+               }
            }
            if (tmpbuf != smallbuf) Safefree(tmpbuf);
            if (tmpbuf2 != smallbuf2) Safefree(tmpbuf2);
@@ -805,7 +803,7 @@ S_skipspace0(pTHX_ register char *s)
        return s;
     if (PL_skipwhite) {
        if (!PL_thiswhite)
-           PL_thiswhite = newSVpvn("",0);
+           PL_thiswhite = newSVpvs("");
        sv_catsv(PL_thiswhite, PL_skipwhite);
        sv_free(PL_skipwhite);
        PL_skipwhite = 0;
@@ -833,7 +831,7 @@ S_skipspace1(pTHX_ register char *s)
     PL_realtokenstart = -1;
     if (PL_skipwhite) {
        if (!PL_nextwhite)
-           PL_nextwhite = newSVpvn("",0);
+           PL_nextwhite = newSVpvs("");
        sv_catsv(PL_nextwhite, PL_skipwhite);
        sv_free(PL_skipwhite);
        PL_skipwhite = 0;
@@ -860,7 +858,7 @@ S_skipspace2(pTHX_ register char *s, SV **svp)
     }
     if (PL_skipwhite) {
        if (!*svp)
-           *svp = newSVpvn("",0);
+           *svp = newSVpvs("");
        sv_setsv(*svp, PL_skipwhite);
        sv_free(PL_skipwhite);
        PL_skipwhite = 0;
@@ -870,6 +868,34 @@ S_skipspace2(pTHX_ register char *s, SV **svp)
 }
 #endif
 
+STATIC void
+S_update_debugger_info_pv(pTHX_ const char *buf, STRLEN len)
+{
+    AV *av = CopFILEAVx(PL_curcop);
+    if (av) {
+       SV * const sv = newSV(0);
+       sv_upgrade(sv, SVt_PVMG);
+       sv_setpvn(sv, buf, len);
+       (void)SvIOK_on(sv);
+       SvIV_set(sv, 0);
+       av_store(av, (I32)CopLINE(PL_curcop), sv);
+    }
+}
+
+STATIC void
+S_update_debugger_info_sv(pTHX_ SV *orig_sv)
+{
+    AV *av = CopFILEAVx(PL_curcop);
+    if (av) {
+       SV * const sv = newSV(0);
+       sv_upgrade(sv, SVt_PVMG);
+       sv_setsv(sv, orig_sv);
+       (void)SvIOK_on(sv);
+       SvIV_set(sv, 0);
+       av_store(av, (I32)CopLINE(PL_curcop), sv);
+    }
+}
+
 /*
  * S_skipspace
  * Called to gobble the appropriate amount and type of whitespace.
@@ -944,7 +970,7 @@ S_skipspace(pTHX_ register char *s)
 #ifdef PERL_MAD
            if (PL_madskills && curoff != startoff) {
                if (!PL_skipwhite)
-                   PL_skipwhite = newSVpvn("",0);
+                   PL_skipwhite = newSVpvs("");
                sv_catpvn(PL_skipwhite, SvPVX(PL_linestr) + startoff,
                                        curoff - startoff);
            }
@@ -1033,22 +1059,15 @@ S_skipspace(pTHX_ register char *s)
        /* debugger active and we're not compiling the debugger code,
         * so store the line into the debugger's array of lines
         */
-       if (PERLDB_LINE && PL_curstash != PL_debstash) {
-           SV * const sv = newSV(0);
-
-           sv_upgrade(sv, SVt_PVMG);
-           sv_setpvn(sv,PL_bufptr,PL_bufend-PL_bufptr);
-            (void)SvIOK_on(sv);
-            SvIV_set(sv, 0);
-           av_store(CopFILEAVx(PL_curcop),(I32)CopLINE(PL_curcop),sv);
-       }
+       if (PERLDB_LINE && PL_curstash != PL_debstash)
+           update_debugger_info_pv(PL_bufptr, PL_bufend - PL_bufptr);
     }
 
 #ifdef PERL_MAD
   done:
     if (PL_madskills) {
        if (!PL_skipwhite)
-           PL_skipwhite = newSVpvn("",0);
+           PL_skipwhite = newSVpvs("");
        curoff = s - SvPVX(PL_linestr);
        if (curoff - startoff)
            sv_catpvn(PL_skipwhite, SvPVX(PL_linestr) + startoff,
@@ -1159,7 +1178,7 @@ S_start_force(pTHX_ int where)
     PL_curforce = where;
     if (PL_nextwhite) {
        if (PL_madskills)
-           curmad('^', newSVpvn("",0));
+           curmad('^', newSVpvs(""));
        CURMAD('_', PL_nextwhite);
     }
 }
@@ -1275,7 +1294,7 @@ S_force_word(pTHX_ register char *start, int token, int check_keyword, int allow
        (allow_initial_tick && *s == '\'') )
     {
        s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, allow_pack, &len);
-       if (check_keyword && keyword(PL_tokenbuf, len))
+       if (check_keyword && keyword(PL_tokenbuf, len, 0))
            return start;
        start_force(PL_curforce);
        if (PL_madskills)
@@ -1541,6 +1560,14 @@ S_sublex_start(pTHX)
            PL_expect = XTERMORDORDOR;
        return THING;
     }
+    else if (op_type == OP_BACKTICK && PL_lex_op) {
+       /* readpipe() vas overriden */
+       cSVOPx(cLISTOPx(cUNOPx(PL_lex_op)->op_first)->op_first->op_sibling)->op_sv = tokeq(PL_lex_stuff);
+       yylval.opval = PL_lex_op;
+       PL_lex_op = NULL;
+       PL_lex_stuff = NULL;
+       return THING;
+    }
 
     PL_sublex_info.super_state = PL_lex_state;
     PL_sublex_info.sub_inwhat = op_type;
@@ -1674,7 +1701,7 @@ S_sublex_done(pTHX)
        if (PL_madskills) {
            if (PL_thiswhite) {
                if (!PL_endwhite)
-                   PL_endwhite = newSVpvn("",0);
+                   PL_endwhite = newSVpvs("");
                sv_catsv(PL_endwhite, PL_thiswhite);
                PL_thiswhite = 0;
            }
@@ -1790,12 +1817,6 @@ S_scan_const(pTHX_ char *start)
     bool native_range = TRUE; /* turned to FALSE if the first endpoint is Unicode. */
 #endif
 
-    const char * const leaveit = /* set of acceptably-backslashed characters */
-       (const char *)
-       (PL_lex_inpat
-        ? "\\.^$@AGZdDwWsSbBpPXC+*?|()-nrtfeaxcz0123456789[{]} \t\n\r\f\v#"
-        : "");
-
     if (PL_lex_inwhat == OP_TRANS && PL_sublex_info.sub_op) {
        /* If we are doing a trans and we know we want UTF8 set expectation */
        has_utf8   = PL_sublex_info.sub_op->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF);
@@ -2020,13 +2041,6 @@ S_scan_const(pTHX_ char *start)
        if (*s == '\\' && s+1 < send) {
            s++;
 
-           /* some backslashes we leave behind */
-           if (*leaveit && *s && strchr(leaveit, *s)) {
-               *d++ = NATIVE_TO_NEED(has_utf8,'\\');
-               *d++ = NATIVE_TO_NEED(has_utf8,*s++);
-               continue;
-           }
-
            /* deprecate \1 in strings and substitution replacements */
            if (PL_lex_inwhat == OP_SUBST && !PL_lex_inpat &&
                isDIGIT(*s) && *s != '0' && !isDIGIT(s[1]))
@@ -2042,6 +2056,11 @@ S_scan_const(pTHX_ char *start)
                --s;
                break;
            }
+           /* skip any other backslash escapes in a pattern */
+           else if (PL_lex_inpat) {
+               *d++ = NATIVE_TO_NEED(has_utf8,'\\');
+               goto default_action;
+           }
 
            /* if we get here, it's either a quoted -, or a digit */
            switch (*s) {
@@ -2179,6 +2198,7 @@ S_scan_const(pTHX_ char *start)
                    SV *res;
                    STRLEN len;
                    const char *str;
+                   SV *type;
 
                    if (!e) {
                        yyerror("Missing right brace on \\N{}");
@@ -2192,12 +2212,17 @@ S_scan_const(pTHX_ char *start)
                        s += 3;
                        len = e - s;
                        uv = grok_hex(s, &len, &flags, NULL);
+                       if ( e > s && len != (STRLEN)(e - s) ) {
+                           uv = 0xFFFD;
+                       }
                        s = e + 1;
                        goto NUM_ESCAPE_INSERT;
                    }
                    res = newSVpvn(s + 1, e - s - 1);
+                   type = newSVpvn(s - 2,e - s + 3);
                    res = new_constant( NULL, 0, "charnames",
-                                       res, NULL, "\\N{...}" );
+                                       res, NULL, SvPVX(type) );
+                   SvREFCNT_dec(type);         
                    if (has_utf8)
                        sv_utf8_upgrade(res);
                    str = SvPV_const(res,len);
@@ -2508,7 +2533,7 @@ S_intuit_more(pTHX_ register char *s)
                    while (isALPHA(*s))
                        *d++ = *s++;
                    *d = '\0';
-                   if (keyword(tmpbuf, d - tmpbuf))
+                   if (keyword(tmpbuf, d - tmpbuf, 0))
                        weight -= 150;
                }
                if (un_char == last_un_char + 1)
@@ -2587,14 +2612,14 @@ S_intuit_method(pTHX_ char *start, GV *gv, CV *cv)
        len = start - SvPVX(PL_linestr);
 #endif
        s = PEEKSPACE(s);
-#ifdef PERLMAD
+#ifdef PERL_MAD
        start = SvPVX(PL_linestr) + len;
 #endif
        PL_bufptr = start;
        PL_expect = XREF;
        return *s == '(' ? FUNCMETH : METHOD;
     }
-    if (!keyword(tmpbuf, len)) {
+    if (!keyword(tmpbuf, len, 0)) {
        if (len > 2 && tmpbuf[len - 2] == ':' && tmpbuf[len - 1] == ':') {
            len -= 2;
            tmpbuf[len] = '\0';
@@ -2842,6 +2867,34 @@ S_find_in_my_stash(pTHX_ const char *pkgname, I32 len)
     return gv_stashpv(pkgname, FALSE);
 }
 
+/*
+ * S_readpipe_override
+ * Check whether readpipe() is overriden, and generates the appropriate
+ * optree, provided sublex_start() is called afterwards.
+ */
+STATIC void
+S_readpipe_override(pTHX)
+{
+    GV **gvp;
+    GV *gv_readpipe = gv_fetchpvs("readpipe", GV_NOTQUAL, SVt_PVCV);
+    yylval.ival = OP_BACKTICK;
+    if ((gv_readpipe
+               && GvCVu(gv_readpipe) && GvIMPORTED_CV(gv_readpipe))
+           ||
+           ((gvp = (GV**)hv_fetchs(PL_globalstash, "readpipe", FALSE))
+            && (gv_readpipe = *gvp) != (GV*)&PL_sv_undef
+            && GvCVu(gv_readpipe) && GvIMPORTED_CV(gv_readpipe)))
+    {
+       PL_lex_op = (OP*)newUNOP(OP_ENTERSUB, OPf_STACKED,
+           append_elem(OP_LIST,
+               newSVOP(OP_CONST, 0, &PL_sv_undef), /* value will be read later */
+               newCVREF(0, newGVOP(OP_GV, 0, gv_readpipe))));
+    }
+    else {
+       set_csh();
+    }
+}
+
 #ifdef PERL_MAD 
  /*
  * Perl_madlex
@@ -2880,7 +2933,7 @@ Perl_madlex(pTHX)
     if (!PL_thismad || PL_thismad->mad_key == '^') {   /* not forced already? */
        if (!PL_thistoken) {
            if (PL_realtokenstart < 0 || !CopLINE(PL_curcop))
-               PL_thistoken = newSVpvn("",0);
+               PL_thistoken = newSVpvs("");
            else {
                char * const tstart = SvPVX(PL_linestr) + PL_realtokenstart;
                PL_thistoken = newSVpvn(tstart, s - tstart);
@@ -3186,7 +3239,7 @@ Perl_yylex(pTHX)
                    PL_lex_state = LEX_INTERPCONCAT;
 #ifdef PERL_MAD
                    if (PL_madskills)
-                       PL_thistoken = newSVpvn("\\E",2);
+                       PL_thistoken = newSVpvs("\\E");
 #endif
                }
                return REPORT(')');
@@ -3195,7 +3248,7 @@ Perl_yylex(pTHX)
            while (PL_bufptr != PL_bufend &&
              PL_bufptr[0] == '\\' && PL_bufptr[1] == 'E') {
                if (!PL_thiswhite)
-                   PL_thiswhite = newSVpvn("",0);
+                   PL_thiswhite = newSVpvs("");
                sv_catpvn(PL_thiswhite, PL_bufptr, 2);
                PL_bufptr += 2;
            }
@@ -3213,7 +3266,7 @@ Perl_yylex(pTHX)
            if (s[1] == '\\' && s[2] == 'E') {
 #ifdef PERL_MAD
                if (!PL_thiswhite)
-                   PL_thiswhite = newSVpvn("",0);
+                   PL_thiswhite = newSVpvs("");
                sv_catpvn(PL_thiswhite, PL_bufptr, 4);
 #endif
                PL_bufptr = s + 3;
@@ -3252,7 +3305,7 @@ Perl_yylex(pTHX)
                else
                    Perl_croak(aTHX_ "panic: yylex");
                if (PL_madskills) {
-                   SV* const tmpsv = newSVpvn("",0);
+                   SV* const tmpsv = newSVpvs("");
                    Perl_sv_catpvf(aTHX_ tmpsv, "\\%c", *s);
                    curmad('_', tmpsv);
                }
@@ -3266,7 +3319,7 @@ Perl_yylex(pTHX)
                if (PL_madskills) {
                    if (PL_thistoken)
                        sv_free(PL_thistoken);
-                   PL_thistoken = newSVpvn("",0);
+                   PL_thistoken = newSVpvs("");
                }
 #endif
                /* commas only at base level: /$a\Ub$c/ => ($a,uc(b.$c)) */
@@ -3312,7 +3365,7 @@ Perl_yylex(pTHX)
            if (PL_madskills) {
                if (PL_thistoken)
                    sv_free(PL_thistoken);
-               PL_thistoken = newSVpvn("",0);
+               PL_thistoken = newSVpvs("");
            }
 #endif
            /* commas only at base level: /$a\Ub$c/ => ($a,uc(b.$c)) */
@@ -3338,7 +3391,7 @@ Perl_yylex(pTHX)
            if (PL_madskills) {
                if (PL_thistoken)
                    sv_free(PL_thistoken);
-               PL_thistoken = newSVpvn("",0);
+               PL_thistoken = newSVpvs("");
            }
 #endif
            return REPORT(')');
@@ -3389,7 +3442,7 @@ Perl_yylex(pTHX)
                if (PL_madskills) {
                    if (PL_thistoken)
                        sv_free(PL_thistoken);
-                   PL_thistoken = newSVpvn("",0);
+                   PL_thistoken = newSVpvs("");
                }
 #endif
                /* commas only at base level: /$a\Ub$c/ => ($a,uc(b.$c)) */
@@ -3512,15 +3565,8 @@ Perl_yylex(pTHX)
            PL_oldoldbufptr = PL_oldbufptr = s = PL_linestart = SvPVX(PL_linestr);
            PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
            PL_last_lop = PL_last_uni = NULL;
-           if (PERLDB_LINE && PL_curstash != PL_debstash) {
-               SV * const sv = newSV(0);
-
-               sv_upgrade(sv, SVt_PVMG);
-               sv_setsv(sv,PL_linestr);
-                (void)SvIOK_on(sv);
-                SvIV_set(sv, 0);
-               av_store(CopFILEAVx(PL_curcop),(I32)CopLINE(PL_curcop),sv);
-           }
+           if (PERLDB_LINE && PL_curstash != PL_debstash)
+               update_debugger_info_sv(PL_linestr);
            goto retry;
        }
        do {
@@ -3612,15 +3658,8 @@ Perl_yylex(pTHX)
            incline(s);
        } while (PL_doextract);
        PL_oldoldbufptr = PL_oldbufptr = PL_bufptr = PL_linestart = s;
-       if (PERLDB_LINE && PL_curstash != PL_debstash) {
-           SV * const sv = newSV(0);
-
-           sv_upgrade(sv, SVt_PVMG);
-           sv_setsv(sv,PL_linestr);
-            (void)SvIOK_on(sv);
-            SvIV_set(sv, 0);
-           av_store(CopFILEAVx(PL_curcop),(I32)CopLINE(PL_curcop),sv);
-       }
+       if (PERLDB_LINE && PL_curstash != PL_debstash)
+           update_debugger_info_sv(PL_linestr);
        PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
        PL_last_lop = PL_last_uni = NULL;
        if (CopLINE(PL_curcop) == 1) {
@@ -3892,7 +3931,7 @@ Perl_yylex(pTHX)
                      Perl_croak(aTHX_ "panic: input overflow");
                    if (PL_madskills && CopLINE(PL_curcop) >= 1) {
                        if (!PL_thiswhite)
-                           PL_thiswhite = newSVpvn("",0);
+                           PL_thiswhite = newSVpvs("");
                        if (CopLINE(PL_curcop) == 1) {
                            sv_setpvn(PL_thiswhite, "", 0);
                            PL_faketokens = 0;
@@ -4110,7 +4149,7 @@ Perl_yylex(pTHX)
                I32 tmp;
                SV *sv;
                d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
-               if (isLOWER(*s) && (tmp = keyword(PL_tokenbuf, len))) {
+               if (isLOWER(*s) && (tmp = keyword(PL_tokenbuf, len, 0))) {
                    if (tmp < 0) tmp = -tmp;
                    switch (tmp) {
                    case KEY_or:
@@ -4460,7 +4499,7 @@ Perl_yylex(pTHX)
 #if 0
                    if (PL_madskills) {
                        if (!PL_thiswhite)
-                           PL_thiswhite = newSVpvn("",0);
+                           PL_thiswhite = newSVpvs("");
                        sv_catpvn(PL_thiswhite,"}",1);
                    }
 #endif
@@ -4485,7 +4524,7 @@ Perl_yylex(pTHX)
        force_next('}');
 #ifdef PERL_MAD
        if (!PL_thistoken)
-           PL_thistoken = newSVpvn("",0);
+           PL_thistoken = newSVpvs("");
 #endif
        TOKEN(';');
     case '&':
@@ -4559,7 +4598,7 @@ Perl_yylex(pTHX)
 #ifdef PERL_MAD
                    if (PL_madskills) {
                        if (!PL_thiswhite)
-                           PL_thiswhite = newSVpvn("",0);
+                           PL_thiswhite = newSVpvs("");
                        sv_catpvn(PL_thiswhite, PL_linestart,
                                  PL_bufend - PL_linestart);
                    }
@@ -4756,7 +4795,7 @@ Perl_yylex(pTHX)
                    char tmpbuf[sizeof PL_tokenbuf];
                    int t2;
                    scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len);
-                   if ((t2 = keyword(tmpbuf, len))) {
+                   if ((t2 = keyword(tmpbuf, len, 0))) {
                        /* binary operators exclude handle interpretations */
                        switch (t2) {
                        case -KEY_x:
@@ -4953,8 +4992,7 @@ Perl_yylex(pTHX)
            no_op("Backticks",s);
        if (!s)
            missingterm(NULL);
-       yylval.ival = OP_BACKTICK;
-       set_csh();
+       readpipe_override();
        TERM(sublex_start());
 
     case '\\':
@@ -5061,7 +5099,7 @@ Perl_yylex(pTHX)
        }
 
        /* Check for keywords */
-       tmp = keyword(PL_tokenbuf, len);
+       tmp = keyword(PL_tokenbuf, len, 0);
 
        /* Is this a word before a => operator? */
        if (*d == '=' && d[1] == '>') {
@@ -5341,7 +5379,7 @@ Perl_yylex(pTHX)
                    if (PL_madskills) {
                        PL_nextwhite = nextPL_nextwhite;
                        curmad('X', PL_thistoken);
-                       PL_thistoken = newSVpvn("",0);
+                       PL_thistoken = newSVpvs("");
                    }
 #endif
                    force_next(WORD);
@@ -5399,12 +5437,13 @@ Perl_yylex(pTHX)
 #ifdef PERL_MAD
                        cv &&
 #endif
-                       SvPOK(cv)) {
+                       SvPOK(cv))
+                   {
                        STRLEN protolen;
                        const char *proto = SvPV_const((SV*)cv, protolen);
                        if (!protolen)
                            TERM(FUNC0SUB);
-                       if (*proto == '$' && proto[1] == '\0')
+                       if ((*proto == '$' || *proto == '_') && proto[1] == '\0')
                            OPERATOR(UNIOPSUB);
                        while (*proto == ';')
                            proto++;
@@ -5428,7 +5467,7 @@ Perl_yylex(pTHX)
                        if (PL_madskills) {
                            PL_nextwhite = nextPL_nextwhite;
                            curmad('X', PL_thistoken);
-                           PL_thistoken = newSVpvn("",0);
+                           PL_thistoken = newSVpvs("");
                        }
                        force_next(WORD);
                        TOKEN(NOAMP);
@@ -5445,7 +5484,7 @@ Perl_yylex(pTHX)
                        STRLEN tmplen;
                        d = s;
                        d = scan_word(d, tmpbuf, sizeof tmpbuf, TRUE, &tmplen);
-                       if (!keyword(tmpbuf,tmplen))
+                       if (!keyword(tmpbuf, tmplen, 0))
                            probable_sub = 1;
                        else {
                            while (d < PL_bufend && isSPACE(*d))
@@ -5468,7 +5507,7 @@ Perl_yylex(pTHX)
                        PL_expect = XTERM;
                        PL_nextwhite = nextPL_nextwhite;
                        curmad('X', PL_thistoken);
-                       PL_thistoken = newSVpvn("",0);
+                       PL_thistoken = newSVpvs("");
                        force_next(WORD);
                        TOKEN(NOAMP);
                    }
@@ -5613,7 +5652,7 @@ Perl_yylex(pTHX)
                    if (PL_realtokenstart >= 0) {
                        char *tstart = SvPVX(PL_linestr) + PL_realtokenstart;
                        if (!PL_endwhite)
-                           PL_endwhite = newSVpvn("",0);
+                           PL_endwhite = newSVpvs("");
                        sv_catsv(PL_endwhite, PL_thiswhite);
                        PL_thiswhite = 0;
                        sv_catpvn(PL_endwhite, tstart, PL_bufend - tstart);
@@ -5631,6 +5670,7 @@ Perl_yylex(pTHX)
        case KEY_AUTOLOAD:
        case KEY_DESTROY:
        case KEY_BEGIN:
+       case KEY_UNITCHECK:
        case KEY_CHECK:
        case KEY_INIT:
        case KEY_END:
@@ -5645,7 +5685,7 @@ Perl_yylex(pTHX)
                s += 2;
                d = s;
                s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
-               if (!(tmp = keyword(PL_tokenbuf, len)))
+               if (!(tmp = keyword(PL_tokenbuf, len, 0)))
                    Perl_croak(aTHX_ "CORE::%s is not a keyword", PL_tokenbuf);
                if (tmp < 0)
                    tmp = -tmp;
@@ -6271,8 +6311,7 @@ Perl_yylex(pTHX)
            s = scan_str(s,!!PL_madskills,FALSE);
            if (!s)
                missingterm(NULL);
-           yylval.ival = OP_BACKTICK;
-           set_csh();
+           readpipe_override();
            TERM(sublex_start());
 
        case KEY_return:
@@ -6489,7 +6528,7 @@ Perl_yylex(pTHX)
                char tmpbuf[sizeof PL_tokenbuf];
                SSize_t tboffset = 0;
                expectation attrful;
-               bool have_name, have_proto, bad_proto;
+               bool have_name, have_proto;
                const int key = tmp;
 
 #ifdef PERL_MAD
@@ -6569,6 +6608,8 @@ Perl_yylex(pTHX)
                /* Look for a prototype */
                if (*s == '(') {
                    char *p;
+                   bool bad_proto = FALSE;
+                   const bool warnsyntax = ckWARN(WARN_SYNTAX);
 
                    s = scan_str(s,!!PL_madskills,FALSE);
                    if (!s)
@@ -6576,16 +6617,15 @@ Perl_yylex(pTHX)
                    /* strip spaces and check for bad characters */
                    d = SvPVX(PL_lex_stuff);
                    tmp = 0;
-                   bad_proto = FALSE;
                    for (p = d; *p; ++p) {
                        if (!isSPACE(*p)) {
                            d[tmp++] = *p;
-                           if (!strchr("$@%*;[]&\\", *p))
+                           if (warnsyntax && !strchr("$@%*;[]&\\_", *p))
                                bad_proto = TRUE;
                        }
                    }
                    d[tmp] = '\0';
-                   if (bad_proto && ckWARN(WARN_SYNTAX))
+                   if (bad_proto)
                        Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
                                    "Illegal character in prototype for %"SVf" : %s",
                                    (void*)PL_subname, d);
@@ -6624,7 +6664,7 @@ Perl_yylex(pTHX)
                start_force(0);
                if (tmpwhite) {
                    if (PL_madskills)
-                       curmad('^', newSVpvn("",0));
+                       curmad('^', newSVpvs(""));
                    CURMAD('_', tmpwhite);
                }
                force_next(0);
@@ -6947,7 +6987,7 @@ S_pending_ident(pTHX)
  */
 
 I32
-Perl_keyword (pTHX_ const char *name, I32 len)
+Perl_keyword (pTHX_ const char *name, I32 len, bool all_keywords)
 {
     dVAR;
   switch (len)
@@ -7219,7 +7259,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
             case 'r':
               if (name[2] == 'r')
               {                                   /* err        */
-                return (FEATURE_IS_ENABLED("err") ? -KEY_err : 0);
+                return (all_keywords || FEATURE_IS_ENABLED("err") ? -KEY_err : 0);
               }
 
               goto unknown;
@@ -7358,7 +7398,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
             case 'a':
               if (name[2] == 'y')
               {                                   /* say        */
-                return (FEATURE_IS_ENABLED("say") ? -KEY_say : 0);
+                return (all_keywords || FEATURE_IS_ENABLED("say") ? KEY_say : 0);
               }
 
               goto unknown;
@@ -7882,7 +7922,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
               if (name[2] == 'e' &&
                   name[3] == 'n')
               {                                   /* when       */
-                return (FEATURE_IS_ENABLED("switch") ? KEY_when : 0);
+                return (all_keywords || FEATURE_IS_ENABLED("switch") ? KEY_when : 0);
               }
 
               goto unknown;
@@ -7965,7 +8005,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
                   name[3] == 'a' &&
                   name[4] == 'k')
               {                                   /* break      */
-                return (FEATURE_IS_ENABLED("switch") ? -KEY_break : 0);
+                return (all_keywords || FEATURE_IS_ENABLED("switch") ? -KEY_break : 0);
               }
 
               goto unknown;
@@ -8093,7 +8133,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
               name[3] == 'e' &&
               name[4] == 'n')
           {                                       /* given      */
-            return (FEATURE_IS_ENABLED("switch") ? KEY_given : 0);
+            return (all_keywords || FEATURE_IS_ENABLED("switch") ? KEY_given : 0);
           }
 
           goto unknown;
@@ -8261,7 +8301,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
                   if (name[3] == 't' &&
                       name[4] == 'e')
                   {                               /* state      */
-                    return (FEATURE_IS_ENABLED("state") ? KEY_state : 0);
+                    return (all_keywords || FEATURE_IS_ENABLED("state") ? KEY_state : 0);
                   }
 
                   goto unknown;
@@ -8929,7 +8969,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
                         name[5] == 'l' &&
                         name[6] == 't')
                     {                             /* default    */
-                      return (FEATURE_IS_ENABLED("switch") ? KEY_default : 0);
+                      return (all_keywords || FEATURE_IS_ENABLED("switch") ? KEY_default : 0);
                     }
 
                     goto unknown;
@@ -9683,9 +9723,24 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           goto unknown;
       }
 
-    case 9: /* 8 tokens of length 9 */
+    case 9: /* 9 tokens of length 9 */
       switch (name[0])
       {
+        case 'U':
+          if (name[1] == 'N' &&
+              name[2] == 'I' &&
+              name[3] == 'T' &&
+              name[4] == 'C' &&
+              name[5] == 'H' &&
+              name[6] == 'E' &&
+              name[7] == 'C' &&
+              name[8] == 'K')
+          {                                       /* UNITCHECK  */
+            return KEY_UNITCHECK;
+          }
+
+          goto unknown;
+
         case 'e':
           if (name[1] == 'n' &&
               name[2] == 'd' &&
@@ -10362,7 +10417,7 @@ S_checkcomma(pTHX_ const char *s, const char *name, const char *what)
            s++;
        if (*s == ',') {
            GV* gv;
-           if (keyword(w, s - w))
+           if (keyword(w, s - w, 0))
                return;
 
            gv = gv_fetchpvn_flags(w, s - w, 0, SVt_PVCV);
@@ -10622,7 +10677,7 @@ S_scan_ident(pTHX_ register char *s, register const char *send, char *dest, STRL
            while (s < send && SPACE_OR_TAB(*s))
                s++;
            if ((*s == '[' || (*s == '{' && strNE(dest, "sub")))) {
-               if (ckWARN(WARN_AMBIGUOUS) && keyword(dest, d - dest)) {
+               if (ckWARN(WARN_AMBIGUOUS) && keyword(dest, d - dest, 0)) {
                    const char * const brack =
                        (const char *)
                        ((*s == '[') ? "[...]" : "{...}");
@@ -10656,7 +10711,7 @@ S_scan_ident(pTHX_ register char *s, register const char *send, char *dest, STRL
            }
            if (PL_lex_state == LEX_NORMAL) {
                if (ckWARN(WARN_AMBIGUOUS) &&
-                   (keyword(dest, d - dest) || get_cv(dest, FALSE)))
+                   (keyword(dest, d - dest, 0) || get_cv(dest, FALSE)))
                {
                    if (funny == '#')
                        funny = '@';
@@ -11166,15 +11221,8 @@ S_scan_heredoc(pTHX_ register char *s)
        else if (PL_bufend - PL_linestart == 1 && PL_bufend[-1] == '\r')
            PL_bufend[-1] = '\n';
 #endif
-       if (PERLDB_LINE && PL_curstash != PL_debstash) {
-           SV * const sv = newSV(0);
-
-           sv_upgrade(sv, SVt_PVMG);
-           sv_setsv(sv,PL_linestr);
-            (void)SvIOK_on(sv);
-            SvIV_set(sv, 0);
-           av_store(CopFILEAVx(PL_curcop), (I32)CopLINE(PL_curcop),sv);
-       }
+       if (PERLDB_LINE && PL_curstash != PL_debstash)
+           update_debugger_info_sv(PL_linestr);
        if (*s == term && memEQ(s,PL_tokenbuf,len)) {
            STRLEN off = PL_bufend - 1 - SvPVX_const(PL_linestr);
            *(SvPVX(PL_linestr) + off ) = ' ';
@@ -11414,7 +11462,7 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
 {
     dVAR;
     SV *sv;                            /* scalar value: string */
-    char *tmps;                                /* temp string, used for delimiter matching */
+    const char *tmps;                  /* temp string, used for delimiter matching */
     register char *s = start;          /* current position in the buffer */
     register char term;                        /* terminating character */
     register char *to;                 /* current position in the sv's data */
@@ -11423,7 +11471,7 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
     I32 termcode;                      /* terminating char. code */
     U8 termstr[UTF8_MAXBYTES];         /* terminating string */
     STRLEN termlen;                    /* length of terminating string */
-    char *last = NULL;                 /* last position for nesting bracket */
+    int last_off = 0;                  /* last position for nesting bracket */
 #ifdef PERL_MAD
     int stuffstart;
     char *tstart;
@@ -11524,9 +11572,7 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
                    else {
                        const char *t;
                        char *w;
-                       if (!last)
-                           last = SvPVX(sv);
-                       for (t = w = last; t < svlast; w++, t++) {
+                       for (t = w = SvPVX(sv)+last_off; t < svlast; w++, t++) {
                            /* At here, all closes are "was quoted" one,
                               so we don't check PL_multi_close. */
                            if (*t == '\\') {
@@ -11545,7 +11591,7 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
                            *w = '\0';
                            SvCUR_set(sv, w - SvPVX_const(sv));
                        }
-                       last = w;
+                       last_off = w - SvPVX(sv);
                        if (--brackets <= 0)
                            cont = FALSE;
                    }
@@ -11672,15 +11718,8 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
        CopLINE_inc(PL_curcop);
 
        /* update debugger info */
-       if (PERLDB_LINE && PL_curstash != PL_debstash) {
-           SV * const line_sv = newSV(0);
-
-           sv_upgrade(line_sv, SVt_PVMG);
-           sv_setsv(line_sv,PL_linestr);
-           (void)SvIOK_on(line_sv);
-           SvIV_set(line_sv, 0);
-           av_store(CopFILEAVx(PL_curcop), (I32)CopLINE(PL_curcop), line_sv);
-       }
+       if (PERLDB_LINE && PL_curstash != PL_debstash)
+           update_debugger_info_sv(PL_linestr);
 
        /* having changed the buffer, we must update PL_bufend */
        PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
@@ -11693,7 +11732,7 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
 #ifdef PERL_MAD
        if (PL_madskills) {
            char * const tstart = SvPVX(PL_linestr) + stuffstart;
-           const int len = s - start;
+           const int len = s - tstart;
            if (PL_thisstuff)
                sv_catpvn(PL_thisstuff, tstart, len);
            else
@@ -12341,6 +12380,7 @@ Perl_yyerror(pTHX_ const char *s)
     const char *context = NULL;
     int contlen = -1;
     SV *msg;
+    int yychar  = PL_parser->yychar;
 
     if (!yychar || (yychar == ';' && !PL_rsfp))
        where = "at EOF";