This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
performance tweaking op.c
[perl5.git] / toke.c
diff --git a/toke.c b/toke.c
index 93623f6..6280145 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -1,7 +1,7 @@
 /*    toke.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, 2005, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
 #define yychar (*PL_yycharp)
 #define yylval (*PL_yylvalp)
 
-static const char ident_too_long[] =
-  "Identifier too long";
-static const char c_without_g[] =
-  "Use of /c modifier is meaningless without /g";
-static const char c_in_subst[] =
-  "Use of /c modifier is meaningless in s///";
+static const char ident_too_long[] = "Identifier too long";
+static const char commaless_variable_list[] = "comma-less variable list";
 
 static void restore_rsfp(pTHX_ void *f);
 #ifndef PERL_NO_UTF16_FILTER
@@ -66,17 +62,22 @@ static I32 utf16rev_textfilter(pTHX_ int idx, SV *sv, int maxlen);
 
 /* #define LEX_NOTPARSING              11 is done in perl.h. */
 
-#define LEX_NORMAL             10
-#define LEX_INTERPNORMAL        9
-#define LEX_INTERPCASEMOD       8
-#define LEX_INTERPPUSH          7
-#define LEX_INTERPSTART                 6
-#define LEX_INTERPEND           5
-#define LEX_INTERPENDMAYBE      4
-#define LEX_INTERPCONCAT        3
-#define LEX_INTERPCONST                 2
-#define LEX_FORMLINE            1
-#define LEX_KNOWNEXT            0
+#define LEX_NORMAL             10 /* normal code (ie not within "...")     */
+#define LEX_INTERPNORMAL        9 /* code within a string, eg "$foo[$x+1]" */
+#define LEX_INTERPCASEMOD       8 /* expecting a \U, \Q or \E etc          */
+#define LEX_INTERPPUSH          7 /* starting a new sublex parse level     */
+#define LEX_INTERPSTART                 6 /* expecting the start of a $var         */
+
+                                  /* at end of code, eg "$x" followed by:  */
+#define LEX_INTERPEND           5 /* ... eg not one of [, { or ->          */
+#define LEX_INTERPENDMAYBE      4 /* ... eg one of [, { or ->              */
+
+#define LEX_INTERPCONCAT        3 /* expecting anything, eg at start of
+                                       string or after \E, $foo, etc       */
+#define LEX_INTERPCONST                 2 /* NOT USED */
+#define LEX_FORMLINE            1 /* expecting a format line               */
+#define LEX_KNOWNEXT            0 /* next token known; just return it      */
+
 
 #ifdef DEBUGGING
 static const char* const lex_state_names[] = {
@@ -136,7 +137,7 @@ static const char* const lex_state_names[] = {
  */
 
 #ifdef DEBUGGING /* Serve -DT. */
-#   define REPORT(retval) tokereport(s,(int)retval)
+#   define REPORT(retval) tokereport((I32)retval)
 #else
 #   define REPORT(retval) (retval)
 #endif
@@ -219,6 +220,7 @@ static struct debug_tokens { const int token, type; const char *name; }
     { BITOROP,         TOKENTYPE_OPNUM,        "BITOROP" },
     { COLONATTR,       TOKENTYPE_NONE,         "COLONATTR" },
     { CONTINUE,                TOKENTYPE_NONE,         "CONTINUE" },
+    { DEFAULT,         TOKENTYPE_NONE,         "DEFAULT" },
     { DO,              TOKENTYPE_NONE,         "DO" },
     { DOLSHARP,                TOKENTYPE_NONE,         "DOLSHARP" },
     { DORDOR,          TOKENTYPE_NONE,         "DORDOR" },
@@ -234,6 +236,7 @@ static struct debug_tokens { const int token, type; const char *name; }
     { FUNC0SUB,                TOKENTYPE_OPVAL,        "FUNC0SUB" },
     { FUNC1,           TOKENTYPE_OPNUM,        "FUNC1" },
     { FUNCMETH,                TOKENTYPE_OPVAL,        "FUNCMETH" },
+    { GIVEN,           TOKENTYPE_IVAL,         "GIVEN" },
     { HASHBRACK,       TOKENTYPE_NONE,         "HASHBRACK" },
     { IF,              TOKENTYPE_IVAL,         "IF" },
     { LABEL,           TOKENTYPE_PVAL,         "LABEL" },
@@ -269,6 +272,7 @@ static struct debug_tokens { const int token, type; const char *name; }
     { UNLESS,          TOKENTYPE_IVAL,         "UNLESS" },
     { UNTIL,           TOKENTYPE_IVAL,         "UNTIL" },
     { USE,             TOKENTYPE_IVAL,         "USE" },
+    { WHEN,            TOKENTYPE_IVAL,         "WHEN" },
     { WHILE,           TOKENTYPE_IVAL,         "WHILE" },
     { WORD,            TOKENTYPE_OPVAL,        "WORD" },
     { 0,               TOKENTYPE_NONE,         0 }
@@ -277,13 +281,13 @@ static struct debug_tokens { const int token, type; const char *name; }
 /* dump the returned token in rv, plus any optional arg in yylval */
 
 STATIC int
-S_tokereport(pTHX_ const char* s, I32 rv)
+S_tokereport(pTHX_ I32 rv)
 {
     if (DEBUG_T_TEST) {
        const char *name = Nullch;
        enum token_type type = TOKENTYPE_NONE;
        const struct debug_tokens *p;
-       SV* const report = newSVpvn("<== ", 4);
+       SV* const report = newSVpvs("<== ");
 
        for (p = debug_tokens; p->token; p++) {
            if (p->token == (int)rv) {
@@ -297,7 +301,7 @@ S_tokereport(pTHX_ const char* s, I32 rv)
        else if ((char)rv > ' ' && (char)rv < '~')
            Perl_sv_catpvf(aTHX_ report, "'%c'", (char)rv);
        else if (!rv)
-           Perl_sv_catpv(aTHX_ report, "EOF");
+           sv_catpvs(report, "EOF");
        else
            Perl_sv_catpvf(aTHX_ report, "?? %"IVdf, (IV)rv);
        switch (type) {
@@ -315,25 +319,35 @@ S_tokereport(pTHX_ const char* s, I32 rv)
            Perl_sv_catpvf(aTHX_ report, "(pval=\"%s\")", yylval.pval);
            break;
        case TOKENTYPE_OPVAL:
-           if (yylval.opval)
+           if (yylval.opval) {
                Perl_sv_catpvf(aTHX_ report, "(opval=op_%s)",
                                    PL_op_name[yylval.opval->op_type]);
+               if (yylval.opval->op_type == OP_CONST) {
+                   Perl_sv_catpvf(aTHX_ report, " %s",
+                       SvPEEK(cSVOPx_sv(yylval.opval)));
+               }
+
+           }
            else
-               Perl_sv_catpv(aTHX_ report, "(opval=null)");
+               sv_catpvs(report, "(opval=null)");
            break;
        }
-        Perl_sv_catpvf(aTHX_ report, " at line %"IVdf" [", (IV)CopLINE(PL_curcop));
-        if (s - PL_bufptr > 0)
-            sv_catpvn(report, PL_bufptr, s - PL_bufptr);
-        else {
-            if (PL_oldbufptr && *PL_oldbufptr)
-                sv_catpv(report, PL_tokenbuf);
-        }
-        PerlIO_printf(Perl_debug_log, "### %s]\n", SvPV_nolen_const(report));
+        PerlIO_printf(Perl_debug_log, "### %s\n\n", SvPV_nolen_const(report));
     };
     return (int)rv;
 }
 
+
+/* print the buffer with suitable escapes */
+
+STATIC void
+S_printbuf(pTHX_ const char* fmt, const char* s)
+{
+    SV* const tmp = newSVpvs("");
+    PerlIO_printf(Perl_debug_log, fmt, pv_display(tmp, s, strlen(s), 0, 60));
+    SvREFCNT_dec(tmp);
+}
+
 #endif
 
 /*
@@ -393,12 +407,12 @@ S_no_op(pTHX_ const char *what, char *s)
            if (t < PL_bufptr && isSPACE(*t))
                Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
                        "\t(Do you need to predeclare %.*s?)\n",
-                   t - PL_oldoldbufptr, PL_oldoldbufptr);
+                   (int)(t - PL_oldoldbufptr), PL_oldoldbufptr);
        }
        else {
            assert(s >= oldbp);
            Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
-                   "\t(Missing operator before %.*s?)\n", s - oldbp, oldbp);
+                   "\t(Missing operator before %.*s?)\n", (int)(s - oldbp), oldbp);
        }
     }
     PL_bufptr = oldbp;
@@ -431,7 +445,7 @@ S_missingterm(pTHX_ char *s)
 #endif
        ) {
        *tmpbuf = '^';
-       tmpbuf[1] = toCTRL(PL_multi_close);
+       tmpbuf[1] = (char)toCTRL(PL_multi_close);
        tmpbuf[2] = '\0';
        s = tmpbuf;
     }
@@ -444,6 +458,23 @@ S_missingterm(pTHX_ char *s)
     Perl_croak(aTHX_ "Can't find string terminator %c%s%c anywhere before EOF",q,s,q);
 }
 
+#define FEATURE_IS_ENABLED(name)                                       \
+       ((0 != (PL_hints & HINT_LOCALIZE_HH))                           \
+           && S_feature_is_enabled(aTHX_ STR_WITH_LEN(name)))
+/*
+ * S_feature_is_enabled
+ * Check whether the named feature is enabled.
+ */
+STATIC bool
+S_feature_is_enabled(pTHX_ char *name, STRLEN namelen)
+{
+    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));
+}
+
 /*
  * Perl_deprecate
  */
@@ -472,17 +503,6 @@ Perl_deprecate_old(pTHX_ const char *s)
 }
 
 /*
- * depcom
- * Deprecate a comma-less variable list.
- */
-
-STATIC void
-S_depcom(pTHX)
-{
-    deprecate_old("comma-less variable list");
-}
-
-/*
  * experimental text filters for win32 carriage-returns, utf16-to-utf8 and
  * utf16-to-utf8-reversed.
  */
@@ -589,7 +609,7 @@ Perl_lex_start(pTHX_ SV *line)
     if (!len || s[len-1] != ';') {
        if (!(SvFLAGS(PL_linestr) & SVs_TEMP))
            PL_linestr = sv_2mortal(newSVsv(PL_linestr));
-       sv_catpvn(PL_linestr, "\n;", 2);
+       sv_catpvs(PL_linestr, "\n;");
     }
     SvTEMP_off(PL_linestr);
     PL_oldoldbufptr = PL_oldbufptr = PL_bufptr = PL_linestart = SvPVX(PL_linestr);
@@ -665,14 +685,14 @@ S_incline(pTHX_ char *s)
     *t = '\0';
     if (t - s > 0) {
 #ifndef USE_ITHREADS
-       const char *cf = CopFILE(PL_curcop);
-       if (cf && strlen(cf) > 7 && strnEQ(cf, "(eval ", 6)) {
+       const char * const cf = CopFILE(PL_curcop);
+       STRLEN tmplen = cf ? strlen(cf) : 0;
+       if (tmplen > 7 && strnEQ(cf, "(eval ", 6)) {
            /* must copy *{"::_<(eval N)[oldfilename:L]"}
             * to *{"::_<newfilename"} */
            char smallbuf[256], smallbuf2[256];
            char *tmpbuf, *tmpbuf2;
            GV **gvp, *gv2;
-           STRLEN tmplen = strlen(cf);
            STRLEN tmplen2 = strlen(s);
            if (tmplen + 3 < sizeof smallbuf)
                tmpbuf = smallbuf;
@@ -821,7 +841,7 @@ S_skipspace(pTHX_ register char *s)
            sv_setpvn(sv,PL_bufptr,PL_bufend-PL_bufptr);
             (void)SvIOK_on(sv);
             SvIV_set(sv, 0);
-           av_store(CopFILEAV(PL_curcop),(I32)CopLINE(PL_curcop),sv);
+           av_store(CopFILEAVx(PL_curcop),(I32)CopLINE(PL_curcop),sv);
        }
     }
 }
@@ -992,7 +1012,7 @@ S_force_ident(pTHX_ register const char *s, int kind)
            /* XXX see note in pp_entereval() for why we forgo typo
               warnings if the symbol must be introduced in an eval.
               GSAR 96-10-12 */
-           gv_fetchpv(s, PL_in_eval ? (GV_ADDMULTI | GV_ADDINEVAL) : TRUE,
+           gv_fetchpv(s, PL_in_eval ? (GV_ADDMULTI | GV_ADDINEVAL) : GV_ADD,
                kind == '$' ? SVt_PV :
                kind == '@' ? SVt_PVAV :
                kind == '%' ? SVt_PVHV :
@@ -1155,7 +1175,7 @@ S_tokeq(pTHX_ SV *sv)
 STATIC I32
 S_sublex_start(pTHX)
 {
-    const register I32 op_type = yylval.ival;
+    register const I32 op_type = yylval.ival;
 
     if (op_type == OP_NULL) {
        yylval.opval = PL_lex_op;
@@ -1270,7 +1290,7 @@ S_sublex_done(pTHX)
 {
     dVAR;
     if (!PL_lex_starts++) {
-       SV * const sv = newSVpvn("",0);
+       SV * const sv = newSVpvs("");
        if (SvUTF8(PL_linestr))
            SvUTF8_on(sv);
        PL_expect = XOPERATOR;
@@ -1989,7 +2009,8 @@ S_intuit_more(pTHX_ register char *s)
                weight -= seen[un_char] * 10;
                if (isALNUM_lazy_if(s+1,UTF)) {
                    scan_ident(s, send, tmpbuf, sizeof tmpbuf, FALSE);
-                   if ((int)strlen(tmpbuf) > 1 && gv_fetchpv(tmpbuf,FALSE, SVt_PV))
+                   if ((int)strlen(tmpbuf) > 1
+                       && gv_fetchpv(tmpbuf, 0, SVt_PV))
                        weight -= 100;
                    else
                        weight -= 10;
@@ -2078,7 +2099,7 @@ S_intuit_more(pTHX_ register char *s)
  */
 
 STATIC int
-S_intuit_method(pTHX_ char *start, GV *gv)
+S_intuit_method(pTHX_ char *start, GV *gv, CV *cv)
 {
     char *s = start + (*start == '$');
     char tmpbuf[sizeof PL_tokenbuf];
@@ -2086,16 +2107,17 @@ S_intuit_method(pTHX_ char *start, GV *gv)
     GV* indirgv;
 
     if (gv) {
-       CV *cv;
-       if (GvIO(gv))
+       if (SvTYPE(gv) == SVt_PVGV && GvIO(gv))
            return 0;
-       if ((cv = GvCVu(gv))) {
-           const char *proto = SvPVX_const(cv);
-           if (proto) {
-               if (*proto == ';')
-                   proto++;
-               if (*proto == '*')
-                   return 0;
+       if (cv) {
+           if (SvPOK(cv)) {
+               const char *proto = SvPVX_const(cv);
+               if (proto) {
+                   if (*proto == ';')
+                       proto++;
+                   if (*proto == '*')
+                       return 0;
+               }
            }
        } else
            gv = 0;
@@ -2120,7 +2142,7 @@ S_intuit_method(pTHX_ char *start, GV *gv)
            tmpbuf[len] = '\0';
            goto bare_package;
        }
-       indirgv = gv_fetchpv(tmpbuf, FALSE, SVt_PVCV);
+       indirgv = gv_fetchpv(tmpbuf, 0, SVt_PVCV);
        if (indirgv && GvCVu(indirgv))
            return 0;
        /* filehandle or package name makes it a method */
@@ -2314,13 +2336,13 @@ S_find_in_my_stash(pTHX_ const char *pkgname, I32 len)
 
     if (len > 2 &&
         (pkgname[len - 2] == ':' && pkgname[len - 1] == ':') &&
-        (gv = gv_fetchpv(pkgname, FALSE, SVt_PVHV)))
+        (gv = gv_fetchpv(pkgname, 0, SVt_PVHV)))
     {
         return GvHV(gv);                       /* Foo:: */
     }
 
     /* use constant CLASS => 'MyClass' */
-    if ((gv = gv_fetchpv(pkgname, FALSE, SVt_PVCV))) {
+    if ((gv = gv_fetchpv(pkgname, 0, SVt_PVCV))) {
         SV *sv;
         if (GvCV(gv) && (sv = cv_const_sv(GvCV(gv)))) {
             pkgname = SvPV_nolen_const(sv);
@@ -2395,16 +2417,17 @@ Perl_yylex(pTHX)
 {
     register char *s = PL_bufptr;
     register char *d;
-    register I32 tmp;
     STRLEN len;
-    GV *gv = Nullgv;
-    GV **gvp = 0;
     bool bof = FALSE;
-    I32 orig_keyword = 0;
 
     DEBUG_T( {
-       PerlIO_printf(Perl_debug_log, "### LEX_%s\n",
-                                       lex_state_names[PL_lex_state]);
+       SV* tmp = newSVpvs("");
+       PerlIO_printf(Perl_debug_log, "### %"IVdf":LEX_%s/X%s %s\n",
+           (IV)CopLINE(PL_curcop),
+           lex_state_names[PL_lex_state],
+           exp_name[PL_expect],
+           pv_display(tmp, s, strlen(s), 0, 60));
+       SvREFCNT_dec(tmp);
     } );
     /* check if there's an identifier for us to look at */
     if (PL_pending_ident)
@@ -2428,10 +2451,6 @@ Perl_yylex(pTHX)
            PL_expect = PL_lex_expect;
            PL_lex_defer = LEX_NORMAL;
        }
-       DEBUG_T({ PerlIO_printf(Perl_debug_log,
-              "### Next token after '%s' was known, type %"IVdf"\n", PL_bufptr,
-              (IV)PL_nexttype[PL_nexttoke]); });
-
        return REPORT(PL_nexttype[PL_nexttoke]);
 
     /* interpolated case modifiers like \L \U, including \Q and \E.
@@ -2463,7 +2482,7 @@ Perl_yylex(pTHX)
        }
        else {
            DEBUG_T({ PerlIO_printf(Perl_debug_log,
-              "### Saw case modifier at '%s'\n", PL_bufptr); });
+              "### Saw case modifier\n"); });
            s = PL_bufptr + 1;
            if (s[1] == '\\' && s[2] == 'E') {
                PL_bufptr = s + 3;
@@ -2471,6 +2490,7 @@ Perl_yylex(pTHX)
                return yylex();
            }
            else {
+               I32 tmp;
                if (strnEQ(s, "L\\u", 3) || strnEQ(s, "U\\l", 3))
                    tmp = *s, *s = s[2], s[2] = (char)tmp;      /* misordered... */
                if ((*s == 'L' || *s == 'U') &&
@@ -2520,7 +2540,7 @@ Perl_yylex(pTHX)
        if (PL_bufptr == PL_bufend)
            return REPORT(sublex_done());
        DEBUG_T({ PerlIO_printf(Perl_debug_log,
-              "### Interpolated variable at '%s'\n", PL_bufptr); });
+              "### Interpolated variable\n"); });
        PL_expect = XTERM;
        PL_lex_dojoin = (*PL_bufptr == '@');
        PL_lex_state = LEX_INTERPNORMAL;
@@ -2620,10 +2640,6 @@ Perl_yylex(pTHX)
     s = PL_bufptr;
     PL_oldoldbufptr = PL_oldbufptr;
     PL_oldbufptr = s;
-    DEBUG_T( {
-       PerlIO_printf(Perl_debug_log, "### Tokener expecting %s at [%s]\n",
-                     exp_name[PL_expect], s);
-    } );
 
   retry:
     switch (*s) {
@@ -2639,10 +2655,9 @@ Perl_yylex(pTHX)
            PL_last_uni = 0;
            PL_last_lop = 0;
            if (PL_lex_brackets) {
-               if (PL_lex_formbrack)
-                   yyerror("Format not terminated");
-                else
-                   yyerror("Missing right curly or square bracket");
+               yyerror(PL_lex_formbrack
+                   ? "Format not terminated"
+                   : "Missing right curly or square bracket");
            }
             DEBUG_T( { PerlIO_printf(Perl_debug_log,
                         "### Tokener got EOF\n");
@@ -2657,21 +2672,21 @@ Perl_yylex(pTHX)
            PL_preambled = TRUE;
            sv_setpv(PL_linestr,incl_perldb());
            if (SvCUR(PL_linestr))
-               sv_catpvn(PL_linestr,";", 1);
+               sv_catpvs(PL_linestr,";");
            if (PL_preambleav){
                while(AvFILLp(PL_preambleav) >= 0) {
                    SV *tmpsv = av_shift(PL_preambleav);
                    sv_catsv(PL_linestr, tmpsv);
-                   sv_catpvn(PL_linestr, ";", 1);
+                   sv_catpvs(PL_linestr, ";");
                    sv_free(tmpsv);
                }
                sv_free((SV*)PL_preambleav);
                PL_preambleav = NULL;
            }
            if (PL_minus_n || PL_minus_p) {
-               sv_catpv(PL_linestr, "LINE: while (<>) {");
+               sv_catpvs(PL_linestr, "LINE: while (<>) {");
                if (PL_minus_l)
-                   sv_catpv(PL_linestr,"chomp;");
+                   sv_catpvs(PL_linestr,"chomp;");
                if (PL_minus_a) {
                    if (PL_minus_F) {
                        if ((*PL_splitstr == '/' || *PL_splitstr == '\''
@@ -2681,11 +2696,8 @@ Perl_yylex(pTHX)
                        else {
                            /* "q\0${splitstr}\0" is legal perl. Yes, even NUL
                               bytes can be used as quoting characters.  :-) */
-                           /* The count here deliberately includes the NUL
-                              that terminates the C string constant.  This
-                              embeds the opening NUL into the string.  */
                            const char *splits = PL_splitstr;
-                           sv_catpvn(PL_linestr, "our @F=split(q", 15);
+                           sv_catpvs(PL_linestr, "our @F=split(q\0");
                            do {
                                /* Need to \ \s  */
                                if (*splits == '\\')
@@ -2695,14 +2707,16 @@ Perl_yylex(pTHX)
                            /* This loop will embed the trailing NUL of
                               PL_linestr as the last thing it does before
                               terminating.  */
-                           sv_catpvn(PL_linestr, ");", 2);
+                           sv_catpvs(PL_linestr, ");");
                        }
                    }
                    else
-                       sv_catpv(PL_linestr,"our @F=split(' ');");
+                       sv_catpvs(PL_linestr,"our @F=split(' ');");
                }
            }
-           sv_catpvn(PL_linestr, "\n", 1);
+           if (PL_minus_E)
+               sv_catpvs(PL_linestr,"use feature ':5.10';");
+           sv_catpvs(PL_linestr, "\n");
            PL_oldoldbufptr = PL_oldbufptr = s = PL_linestart = SvPVX(PL_linestr);
            PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
            PL_last_lop = PL_last_uni = Nullch;
@@ -2713,7 +2727,7 @@ Perl_yylex(pTHX)
                sv_setsv(sv,PL_linestr);
                 (void)SvIOK_on(sv);
                 SvIV_set(sv, 0);
-               av_store(CopFILEAV(PL_curcop),(I32)CopLINE(PL_curcop),sv);
+               av_store(CopFILEAVx(PL_curcop),(I32)CopLINE(PL_curcop),sv);
            }
            goto retry;
        }
@@ -2800,7 +2814,7 @@ Perl_yylex(pTHX)
            sv_setsv(sv,PL_linestr);
             (void)SvIOK_on(sv);
             SvIV_set(sv, 0);
-           av_store(CopFILEAV(PL_curcop),(I32)CopLINE(PL_curcop),sv);
+           av_store(CopFILEAVx(PL_curcop),(I32)CopLINE(PL_curcop),sv);
        }
        PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
        PL_last_lop = PL_last_uni = Nullch;
@@ -2840,7 +2854,8 @@ Perl_yylex(pTHX)
                     * at least, set argv[0] to the basename of the Perl
                     * interpreter. So, having found "#!", we'll set it right.
                     */
-                   SV *x = GvSV(gv_fetchpv("\030", TRUE, SVt_PV)); /* $^X */
+                   SV * const x
+                       = GvSV(gv_fetchpv("\030", GV_ADD, SVt_PV)); /* $^X */
                    assert(SvPOK(x) || SvGMAGICAL(x));
                    if (sv_eq(x, CopFILESV(PL_curcop))) {
                        sv_setpvn(x, ipath, ipathend - ipath);
@@ -2978,14 +2993,6 @@ Perl_yylex(pTHX)
                                (void)gv_fetchfile(PL_origfilename);
                            goto retry;
                        }
-                       if (PL_doswitches && !switches_done) {
-                           int argc = PL_origargc;
-                           char **argv = PL_origargv;
-                           do {
-                               argc--,argv++;
-                           } while (argc && argv[0][0] == '-' && argv[0][1]);
-                           init_argv_symbols(argc,argv);
-                       }
                    }
                }
            }
@@ -3038,6 +3045,7 @@ Perl_yylex(pTHX)
     case '-':
        if (s[1] && isALPHA(s[1]) && !isALNUM(s[2])) {
            I32 ftst = 0;
+           char tmp;
 
            s++;
            PL_bufptr = s;
@@ -3048,8 +3056,8 @@ Perl_yylex(pTHX)
 
            if (strnEQ(s,"=>",2)) {
                s = force_word(PL_bufptr,WORD,FALSE,FALSE,FALSE);
-                DEBUG_T( { PerlIO_printf(Perl_debug_log,
-                            "### Saw unary minus before =>, forcing word '%s'\n", s);
+                DEBUG_T( { S_printbuf(aTHX_
+                       "### Saw unary minus before =>, forcing word %s\n", s);
                 } );
                OPERATOR('-');          /* unary minus */
            }
@@ -3080,7 +3088,7 @@ Perl_yylex(pTHX)
            case 'T': ftst = OP_FTTEXT;         break;
            case 'B': ftst = OP_FTBINARY;       break;
            case 'M': case 'A': case 'C':
-               gv_fetchpv("\024",TRUE, SVt_PV);
+               gv_fetchpv("\024",GV_ADD, SVt_PV);
                switch (tmp) {
                case 'M': ftst = OP_FTMTIME;    break;
                case 'A': ftst = OP_FTATIME;    break;
@@ -3094,7 +3102,7 @@ Perl_yylex(pTHX)
            if (ftst) {
                PL_last_lop_op = (OPCODE)ftst;
                DEBUG_T( { PerlIO_printf(Perl_debug_log,
-                        "### Saw file test %c\n", (int)ftst);
+                        "### Saw file test %c\n", (int)tmp);
                } );
                FTST(ftst);
            }
@@ -3108,49 +3116,53 @@ Perl_yylex(pTHX)
                s = --PL_bufptr;
            }
        }
-       tmp = *s++;
-       if (*s == tmp) {
-           s++;
+       {
+           const char tmp = *s++;
+           if (*s == tmp) {
+               s++;
+               if (PL_expect == XOPERATOR)
+                   TERM(POSTDEC);
+               else
+                   OPERATOR(PREDEC);
+           }
+           else if (*s == '>') {
+               s++;
+               s = skipspace(s);
+               if (isIDFIRST_lazy_if(s,UTF)) {
+                   s = force_word(s,METHOD,FALSE,TRUE,FALSE);
+                   TOKEN(ARROW);
+               }
+               else if (*s == '$')
+                   OPERATOR(ARROW);
+               else
+                   TERM(ARROW);
+           }
            if (PL_expect == XOPERATOR)
-               TERM(POSTDEC);
-           else
-               OPERATOR(PREDEC);
-       }
-       else if (*s == '>') {
-           s++;
-           s = skipspace(s);
-           if (isIDFIRST_lazy_if(s,UTF)) {
-               s = force_word(s,METHOD,FALSE,TRUE,FALSE);
-               TOKEN(ARROW);
+               Aop(OP_SUBTRACT);
+           else {
+               if (isSPACE(*s) || !isSPACE(*PL_bufptr))
+                   check_uni();
+               OPERATOR('-');          /* unary minus */
            }
-           else if (*s == '$')
-               OPERATOR(ARROW);
-           else
-               TERM(ARROW);
-       }
-       if (PL_expect == XOPERATOR)
-           Aop(OP_SUBTRACT);
-       else {
-           if (isSPACE(*s) || !isSPACE(*PL_bufptr))
-               check_uni();
-           OPERATOR('-');              /* unary minus */
        }
 
     case '+':
-       tmp = *s++;
-       if (*s == tmp) {
-           s++;
+       {
+           const char tmp = *s++;
+           if (*s == tmp) {
+               s++;
+               if (PL_expect == XOPERATOR)
+                   TERM(POSTINC);
+               else
+                   OPERATOR(PREINC);
+           }
            if (PL_expect == XOPERATOR)
-               TERM(POSTINC);
-           else
-               OPERATOR(PREINC);
-       }
-       if (PL_expect == XOPERATOR)
-           Aop(OP_ADD);
-       else {
-           if (isSPACE(*s) || !isSPACE(*PL_bufptr))
-               check_uni();
-           OPERATOR('+');
+               Aop(OP_ADD);
+           else {
+               if (isSPACE(*s) || !isSPACE(*PL_bufptr))
+                   check_uni();
+               OPERATOR('+');
+           }
        }
 
     case '*':
@@ -3189,13 +3201,22 @@ Perl_yylex(pTHX)
        PL_lex_brackets++;
        /* FALL THROUGH */
     case '~':
+       if (s[1] == '~'
+       && (PL_expect == XOPERATOR || PL_expect == XTERMORDORDOR)
+       && FEATURE_IS_ENABLED("~~"))
+       {
+           s += 2;
+           Eop(OP_SMARTMATCH);
+       }
     case ',':
-       tmp = *s++;
-       OPERATOR(tmp);
+       {
+           const char tmp = *s++;
+           OPERATOR(tmp);
+       }
     case ':':
        if (s[1] == ':') {
            len = 0;
-           goto just_a_word;
+           goto just_a_word_zero_gv;
        }
        s++;
        switch (PL_expect) {
@@ -3214,6 +3235,7 @@ Perl_yylex(pTHX)
            s = skipspace(s);
            attrs = Nullop;
            while (isIDFIRST_lazy_if(s,UTF)) {
+               I32 tmp;
                d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
                if (isLOWER(*s) && (tmp = keyword(PL_tokenbuf, len))) {
                    if (tmp < 0) tmp = -tmp;
@@ -3295,26 +3317,30 @@ Perl_yylex(pTHX)
                else if (s == d)
                    break;      /* require real whitespace or :'s */
            }
-           tmp = (PL_expect == XOPERATOR ? '=' : '{'); /*'}(' for vi */
-           if (*s != ';' && *s != '}' && *s != tmp && (tmp != '=' || *s != ')')) {
-               const char q = ((*s == '\'') ? '"' : '\'');
-               /* If here for an expression, and parsed no attrs, back off. */
-               if (tmp == '=' && !attrs) {
-                   s = PL_bufptr;
-                   break;
+           {
+               const char tmp
+                   = (PL_expect == XOPERATOR ? '=' : '{'); /*'}(' for vi */
+               if (*s != ';' && *s != '}' && *s != tmp
+                   && (tmp != '=' || *s != ')')) {
+                   const char q = ((*s == '\'') ? '"' : '\'');
+                   /* If here for an expression, and parsed no attrs, back
+                      off. */
+                   if (tmp == '=' && !attrs) {
+                       s = PL_bufptr;
+                       break;
+                   }
+                   /* MUST advance bufptr here to avoid bogus "at end of line"
+                      context messages from yyerror().
+                   */
+                   PL_bufptr = s;
+                   yyerror( *s
+                            ? Perl_form(aTHX_ "Invalid separator character "
+                                        "%c%c%c in attribute list", q, *s, q)
+                            : "Unterminated attribute list" );
+                   if (attrs)
+                       op_free(attrs);
+                   OPERATOR(':');
                }
-               /* MUST advance bufptr here to avoid bogus "at end of line"
-                  context messages from yyerror().
-                */
-               PL_bufptr = s;
-               if (!*s)
-                   yyerror("Unterminated attribute list");
-               else
-                   yyerror(Perl_form(aTHX_ "Invalid separator character %c%c%c in attribute list",
-                                     q, *s, q));
-               if (attrs)
-                   op_free(attrs);
-               OPERATOR(':');
            }
        got_attrs:
            if (attrs) {
@@ -3334,14 +3360,18 @@ Perl_yylex(pTHX)
        TOKEN('(');
     case ';':
        CLINE;
-       tmp = *s++;
-       OPERATOR(tmp);
+       {
+           const char tmp = *s++;
+           OPERATOR(tmp);
+       }
     case ')':
-       tmp = *s++;
-       s = skipspace(s);
-       if (*s == '{')
-           PREBLOCK(tmp);
-       TERM(tmp);
+       {
+           const char tmp = *s++;
+           s = skipspace(s);
+           if (*s == '{')
+               PREBLOCK(tmp);
+           TERM(tmp);
+       }
     case ']':
        s++;
        if (PL_lex_brackets <= 0)
@@ -3549,8 +3579,7 @@ Perl_yylex(pTHX)
        TOKEN(';');
     case '&':
        s++;
-       tmp = *s++;
-       if (tmp == '&')
+       if (*s++ == '&')
            AOPERATOR(ANDAND);
        s--;
        if (PL_expect == XOPERATOR) {
@@ -3576,47 +3605,50 @@ Perl_yylex(pTHX)
 
     case '|':
        s++;
-       tmp = *s++;
-       if (tmp == '|')
+       if (*s++ == '|')
            AOPERATOR(OROR);
        s--;
        BOop(OP_BIT_OR);
     case '=':
        s++;
-       tmp = *s++;
-       if (tmp == '=')
-           Eop(OP_EQ);
-       if (tmp == '>')
-           OPERATOR(',');
-       if (tmp == '~')
-           PMop(OP_MATCH);
-       if (tmp && isSPACE(*s) && ckWARN(WARN_SYNTAX) && strchr("+-*/%.^&|<",tmp))
-           Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Reversed %c= operator",(int)tmp);
-       s--;
-       if (PL_expect == XSTATE && isALPHA(tmp) &&
-               (s == PL_linestart+1 || s[-2] == '\n') )
        {
-           if (PL_in_eval && !PL_rsfp) {
-               d = PL_bufend;
-               while (s < d) {
-                   if (*s++ == '\n') {
-                       incline(s);
-                       if (strnEQ(s,"=cut",4)) {
-                           s = strchr(s,'\n');
-                           if (s)
-                               s++;
-                           else
-                               s = d;
-                           incline(s);
-                           goto retry;
+           const char tmp = *s++;
+           if (tmp == '=')
+               Eop(OP_EQ);
+           if (tmp == '>')
+               OPERATOR(',');
+           if (tmp == '~')
+               PMop(OP_MATCH);
+           if (tmp && isSPACE(*s) && ckWARN(WARN_SYNTAX)
+               && strchr("+-*/%.^&|<",tmp))
+               Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
+                           "Reversed %c= operator",(int)tmp);
+           s--;
+           if (PL_expect == XSTATE && isALPHA(tmp) &&
+               (s == PL_linestart+1 || s[-2] == '\n') )
+               {
+                   if (PL_in_eval && !PL_rsfp) {
+                       d = PL_bufend;
+                       while (s < d) {
+                           if (*s++ == '\n') {
+                               incline(s);
+                               if (strnEQ(s,"=cut",4)) {
+                                   s = strchr(s,'\n');
+                                   if (s)
+                                       s++;
+                                   else
+                                       s = d;
+                                   incline(s);
+                                   goto retry;
+                               }
+                           }
                        }
+                       goto retry;
                    }
+                   s = PL_bufend;
+                   PL_doextract = TRUE;
+                   goto retry;
                }
-               goto retry;
-           }
-           s = PL_bufend;
-           PL_doextract = TRUE;
-           goto retry;
        }
        if (PL_lex_brackets < PL_lex_formbrack) {
            const char *t;
@@ -3635,27 +3667,30 @@ Perl_yylex(pTHX)
        OPERATOR(ASSIGNOP);
     case '!':
        s++;
-       tmp = *s++;
-       if (tmp == '=') {
-            /* was this !=~ where !~ was meant?
-             * warn on m:!=~\s+([/?]|[msy]\W|tr\W): */
-
-            if (*s == '~' && ckWARN(WARN_SYNTAX)) {
-               const char *t = s+1;
-
-                while (t < PL_bufend && isSPACE(*t))
-                    ++t;
-
-                if (*t == '/' || *t == '?' ||
-                    ((*t == 'm' || *t == 's' || *t == 'y') && !isALNUM(t[1])) ||
-                    (*t == 't' && t[1] == 'r' && !isALNUM(t[2])))
-                    Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
-                                "!=~ should be !~");
-            }
-           Eop(OP_NE);
-        }
-       if (tmp == '~')
-           PMop(OP_NOT);
+       {
+           const char tmp = *s++;
+           if (tmp == '=') {
+               /* was this !=~ where !~ was meant?
+                * warn on m:!=~\s+([/?]|[msy]\W|tr\W): */
+
+               if (*s == '~' && ckWARN(WARN_SYNTAX)) {
+                   const char *t = s+1;
+
+                   while (t < PL_bufend && isSPACE(*t))
+                       ++t;
+
+                   if (*t == '/' || *t == '?' ||
+                       ((*t == 'm' || *t == 's' || *t == 'y')
+                        && !isALNUM(t[1])) ||
+                       (*t == 't' && t[1] == 'r' && !isALNUM(t[2])))
+                       Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
+                                   "!=~ should be !~");
+               }
+               Eop(OP_NE);
+           }
+           if (tmp == '~')
+               PMop(OP_NOT);
+       }
        s--;
        OPERATOR('!');
     case '<':
@@ -3669,25 +3704,29 @@ Perl_yylex(pTHX)
            TERM(sublex_start());
        }
        s++;
-       tmp = *s++;
-       if (tmp == '<')
-           SHop(OP_LEFT_SHIFT);
-       if (tmp == '=') {
-           tmp = *s++;
-           if (tmp == '>')
-               Eop(OP_NCMP);
-           s--;
-           Rop(OP_LE);
+       {
+           char tmp = *s++;
+           if (tmp == '<')
+               SHop(OP_LEFT_SHIFT);
+           if (tmp == '=') {
+               tmp = *s++;
+               if (tmp == '>')
+                   Eop(OP_NCMP);
+               s--;
+               Rop(OP_LE);
+           }
        }
        s--;
        Rop(OP_LT);
     case '>':
        s++;
-       tmp = *s++;
-       if (tmp == '>')
-           SHop(OP_RIGHT_SHIFT);
-       if (tmp == '=')
-           Rop(OP_GE);
+       {
+           const char tmp = *s++;
+           if (tmp == '>')
+               SHop(OP_RIGHT_SHIFT);
+           if (tmp == '=')
+               Rop(OP_GE);
+       }
        s--;
        Rop(OP_GT);
 
@@ -3697,7 +3736,7 @@ Perl_yylex(pTHX)
        if (PL_expect == XOPERATOR) {
            if (PL_lex_formbrack && PL_lex_brackets == PL_lex_formbrack) {
                PL_expect = XTERM;
-               depcom();
+               deprecate_old(commaless_variable_list);
                return REPORT(','); /* grandfather non-comma-format format */
            }
        }
@@ -3735,93 +3774,102 @@ Perl_yylex(pTHX)
        }
 
        d = s;
-       tmp = (I32)*s;
-       if (PL_lex_state == LEX_NORMAL)
-           s = skipspace(s);
+       {
+           const char tmp = *s;
+           if (PL_lex_state == LEX_NORMAL)
+               s = skipspace(s);
 
-       if ((PL_expect != XREF || PL_oldoldbufptr == PL_last_lop) && intuit_more(s)) {
-           if (*s == '[') {
-               PL_tokenbuf[0] = '@';
-               if (ckWARN(WARN_SYNTAX)) {
-                   char *t;
-                   for(t = s + 1;
-                       isSPACE(*t) || isALNUM_lazy_if(t,UTF) || *t == '$';
-                       t++) ;
-                   if (*t++ == ',') {
-                       PL_bufptr = skipspace(PL_bufptr);
-                       while (t < PL_bufend && *t != ']')
-                           t++;
-                       Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
-                               "Multidimensional syntax %.*s not supported",
-                               (t - PL_bufptr) + 1, PL_bufptr);
-                   }
-               }
-           }
-           else if (*s == '{') {
-               char *t;
-               PL_tokenbuf[0] = '%';
-               if (strEQ(PL_tokenbuf+1, "SIG")  && ckWARN(WARN_SYNTAX)
-                   && (t = strchr(s, '}')) && (t = strchr(t, '=')))
-               {
-                   char tmpbuf[sizeof PL_tokenbuf];
-                   for (t++; isSPACE(*t); t++) ;
-                   if (isIDFIRST_lazy_if(t,UTF)) {
-                       STRLEN len;
-                       t = scan_word(t, tmpbuf, sizeof tmpbuf, TRUE, &len);
-                       for (; isSPACE(*t); t++) ;
-                       if (*t == ';' && get_cv(tmpbuf, FALSE))
+           if ((PL_expect != XREF || PL_oldoldbufptr == PL_last_lop)
+               && intuit_more(s)) {
+               if (*s == '[') {
+                   PL_tokenbuf[0] = '@';
+                   if (ckWARN(WARN_SYNTAX)) {
+                       char *t;
+                       for(t = s + 1;
+                           isSPACE(*t) || isALNUM_lazy_if(t,UTF) || *t == '$';
+                           t++) ;
+                       if (*t++ == ',') {
+                           PL_bufptr = skipspace(PL_bufptr);
+                           while (t < PL_bufend && *t != ']')
+                               t++;
                            Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
-                               "You need to quote \"%s\"", tmpbuf);
+                                       "Multidimensional syntax %.*s not supported",
+                                   (int)((t - PL_bufptr) + 1), PL_bufptr);
+                       }
                    }
                }
+               else if (*s == '{') {
+                   char *t;
+                   PL_tokenbuf[0] = '%';
+                   if (strEQ(PL_tokenbuf+1, "SIG")  && ckWARN(WARN_SYNTAX)
+                       && (t = strchr(s, '}')) && (t = strchr(t, '=')))
+                       {
+                           char tmpbuf[sizeof PL_tokenbuf];
+                           for (t++; isSPACE(*t); t++) ;
+                           if (isIDFIRST_lazy_if(t,UTF)) {
+                               STRLEN len;
+                               t = scan_word(t, tmpbuf, sizeof tmpbuf, TRUE,
+                                             &len);
+                               for (; isSPACE(*t); t++) ;
+                               if (*t == ';' && get_cv(tmpbuf, FALSE))
+                                   Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
+                                               "You need to quote \"%s\"",
+                                               tmpbuf);
+                           }
+                       }
+               }
            }
-       }
 
-       PL_expect = XOPERATOR;
-       if (PL_lex_state == LEX_NORMAL && isSPACE((char)tmp)) {
-           const bool islop = (PL_last_lop == PL_oldoldbufptr);
-           if (!islop || PL_last_lop_op == OP_GREPSTART)
-               PL_expect = XOPERATOR;
-           else if (strchr("$@\"'`q", *s))
-               PL_expect = XTERM;              /* e.g. print $fh "foo" */
-           else if (strchr("&*<%", *s) && isIDFIRST_lazy_if(s+1,UTF))
-               PL_expect = XTERM;              /* e.g. print $fh &sub */
-           else if (isIDFIRST_lazy_if(s,UTF)) {
-               char tmpbuf[sizeof PL_tokenbuf];
-               scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len);
-               if ((tmp = keyword(tmpbuf, len))) {
-                   /* binary operators exclude handle interpretations */
-                   switch (tmp) {
-                   case -KEY_x:
-                   case -KEY_eq:
-                   case -KEY_ne:
-                   case -KEY_gt:
-                   case -KEY_lt:
-                   case -KEY_ge:
-                   case -KEY_le:
-                   case -KEY_cmp:
-                       break;
-                   default:
-                       PL_expect = XTERM;      /* e.g. print $fh length() */
-                       break;
+           PL_expect = XOPERATOR;
+           if (PL_lex_state == LEX_NORMAL && isSPACE((char)tmp)) {
+               const bool islop = (PL_last_lop == PL_oldoldbufptr);
+               if (!islop || PL_last_lop_op == OP_GREPSTART)
+                   PL_expect = XOPERATOR;
+               else if (strchr("$@\"'`q", *s))
+                   PL_expect = XTERM;          /* e.g. print $fh "foo" */
+               else if (strchr("&*<%", *s) && isIDFIRST_lazy_if(s+1,UTF))
+                   PL_expect = XTERM;          /* e.g. print $fh &sub */
+               else if (isIDFIRST_lazy_if(s,UTF)) {
+                   char tmpbuf[sizeof PL_tokenbuf];
+                   int t2;
+                   scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len);
+                   if ((t2 = keyword(tmpbuf, len))) {
+                       /* binary operators exclude handle interpretations */
+                       switch (t2) {
+                       case -KEY_x:
+                       case -KEY_eq:
+                       case -KEY_ne:
+                       case -KEY_gt:
+                       case -KEY_lt:
+                       case -KEY_ge:
+                       case -KEY_le:
+                       case -KEY_cmp:
+                           break;
+                       default:
+                           PL_expect = XTERM;  /* e.g. print $fh length() */
+                           break;
+                       }
+                   }
+                   else {
+                       PL_expect = XTERM;      /* e.g. print $fh subr() */
                    }
                }
-               else {
-                   PL_expect = XTERM;          /* e.g. print $fh subr() */
-               }
+               else if (isDIGIT(*s))
+                   PL_expect = XTERM;          /* e.g. print $fh 3 */
+               else if (*s == '.' && isDIGIT(s[1]))
+                   PL_expect = XTERM;          /* e.g. print $fh .3 */
+               else if ((*s == '?' || *s == '-' || *s == '+')
+                        && !isSPACE(s[1]) && s[1] != '=')
+                   PL_expect = XTERM;          /* e.g. print $fh -1 */
+               else if (*s == '/' && !isSPACE(s[1]) && s[1] != '='
+                        && s[1] != '/')
+                   PL_expect = XTERM;          /* e.g. print $fh /.../
+                                                  XXX except DORDOR operator
+                                               */
+               else if (*s == '<' && s[1] == '<' && !isSPACE(s[2])
+                        && s[2] != '=')
+                   PL_expect = XTERM;          /* print $fh <<"EOF" */
            }
-           else if (isDIGIT(*s))
-               PL_expect = XTERM;              /* e.g. print $fh 3 */
-           else if (*s == '.' && isDIGIT(s[1]))
-               PL_expect = XTERM;              /* e.g. print $fh .3 */
-           else if ((*s == '?' || *s == '-' || *s == '+')
-                    && !isSPACE(s[1]) && s[1] != '=')
-               PL_expect = XTERM;              /* e.g. print $fh -1 */
-           else if (*s == '/' && !isSPACE(s[1]) && s[1] != '=' && s[1] != '/')
-               PL_expect = XTERM;              /* e.g. print $fh /.../
-                                                XXX except DORDOR operator */
-           else if (*s == '<' && s[1] == '<' && !isSPACE(s[2]) && s[2] != '=')
-               PL_expect = XTERM;              /* print $fh <<"EOF" */
        }
        PL_pending_ident = '$';
        TOKEN('$');
@@ -3851,7 +3899,8 @@ Perl_yylex(pTHX)
                        PL_bufptr = skipspace(PL_bufptr);
                        Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
                            "Scalar value %.*s better written as $%.*s",
-                           t-PL_bufptr, PL_bufptr, t-PL_bufptr-1, PL_bufptr+1);
+                           (int)(t-PL_bufptr), PL_bufptr,
+                           (int)(t-PL_bufptr-1), PL_bufptr+1);
                    }
                }
            }
@@ -3866,7 +3915,7 @@ Perl_yylex(pTHX)
        }
      case '?':                 /* may either be conditional or pattern */
         if(PL_expect == XOPERATOR) {
-            tmp = *s++;
+            char tmp = *s++;
             if(tmp == '?') {
                  OPERATOR('?');
             }
@@ -3908,7 +3957,7 @@ Perl_yylex(pTHX)
            goto rightbracket;
        }
        if (PL_expect == XOPERATOR || !isDIGIT(s[1])) {
-           tmp = *s++;
+           char tmp = *s++;
            if (*s == tmp) {
                s++;
                if (*s == tmp) {
@@ -3927,22 +3976,18 @@ Perl_yylex(pTHX)
     case '0': case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9':
        s = scan_num(s, &yylval);
-        DEBUG_T( { PerlIO_printf(Perl_debug_log,
-                    "### Saw number in '%s'\n", s);
-        } );
+       DEBUG_T( { S_printbuf(aTHX_ "### Saw number in %s\n", s); } );
        if (PL_expect == XOPERATOR)
            no_op("Number",s);
        TERM(THING);
 
     case '\'':
        s = scan_str(s,FALSE,FALSE);
-        DEBUG_T( { PerlIO_printf(Perl_debug_log,
-                    "### Saw string before '%s'\n", s);
-        } );
+       DEBUG_T( { S_printbuf(aTHX_ "### Saw string before %s\n", s); } );
        if (PL_expect == XOPERATOR) {
            if (PL_lex_formbrack && PL_lex_brackets == PL_lex_formbrack) {
                PL_expect = XTERM;
-               depcom();
+               deprecate_old(commaless_variable_list);
                return REPORT(','); /* grandfather non-comma-format format */
            }
            else
@@ -3955,13 +4000,11 @@ Perl_yylex(pTHX)
 
     case '"':
        s = scan_str(s,FALSE,FALSE);
-        DEBUG_T( { PerlIO_printf(Perl_debug_log,
-                    "### Saw string before '%s'\n", s);
-        } );
+       DEBUG_T( { S_printbuf(aTHX_ "### Saw string before %s\n", s); } );
        if (PL_expect == XOPERATOR) {
            if (PL_lex_formbrack && PL_lex_brackets == PL_lex_formbrack) {
                PL_expect = XTERM;
-               depcom();
+               deprecate_old(commaless_variable_list);
                return REPORT(','); /* grandfather non-comma-format format */
            }
            else
@@ -3982,9 +4025,7 @@ Perl_yylex(pTHX)
 
     case '`':
        s = scan_str(s,FALSE,FALSE);
-        DEBUG_T( { PerlIO_printf(Perl_debug_log,
-                    "### Saw backtick string before '%s'\n", s);
-        } );
+       DEBUG_T( { S_printbuf(aTHX_ "### Saw backtick string before %s\n", s); } );
        if (PL_expect == XOPERATOR)
            no_op("Backticks",s);
        if (!s)
@@ -4018,7 +4059,7 @@ Perl_yylex(pTHX)
                const char c = *start;
                GV *gv;
                *start = '\0';
-               gv = gv_fetchpv(s, FALSE, SVt_PVCV);
+               gv = gv_fetchpv(s, 0, SVt_PVCV);
                *start = c;
                if (!gv) {
                    s = scan_num(s, &yylval);
@@ -4063,9 +4104,10 @@ Perl_yylex(pTHX)
     case 'z': case 'Z':
 
       keylookup: {
-       orig_keyword = 0;
-       gv = Nullgv;
-       gvp = 0;
+       I32 tmp;
+       I32 orig_keyword = 0;
+       GV *gv = NULL;
+       GV **gvp = NULL;
 
        PL_bufptr = s;
        s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
@@ -4107,11 +4149,11 @@ Perl_yylex(pTHX)
        }
 
        if (tmp < 0) {                  /* second-class keyword? */
-           GV *ogv = Nullgv;   /* override (winner) */
-           GV *hgv = Nullgv;   /* hidden (loser) */
+           GV *ogv = NULL;     /* override (winner) */
+           GV *hgv = NULL;     /* hidden (loser) */
            if (PL_expect != XOPERATOR && (*s != ':' || s[1] != ':')) {
                CV *cv;
-               if ((gv = gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVCV)) &&
+               if ((gv = gv_fetchpv(PL_tokenbuf, 0, SVt_PVCV)) &&
                    (cv = GvCVu(gv)))
                {
                    if (GvIMPORTED_CV(gv))
@@ -4138,16 +4180,6 @@ Perl_yylex(pTHX)
            {
                tmp = 0;                /* any sub overrides "weak" keyword */
            }
-           else if (gv && !gvp
-                   && tmp == -KEY_err
-                   && GvCVu(gv)
-                   && PL_expect != XOPERATOR
-                   && PL_expect != XTERMORDORDOR)
-           {
-               /* any sub overrides the "err" keyword, except when really an
-                * operator is expected */
-               tmp = 0;
-           }
            else {                      /* no override */
                tmp = -tmp;
                if (tmp == KEY_dump && ckWARN(WARN_MISC)) {
@@ -4168,10 +4200,20 @@ Perl_yylex(pTHX)
        switch (tmp) {
 
        default:                        /* not a keyword */
+           /* Trade off - by using this evil construction we can pull the
+              variable gv into the block labelled keylookup. If not, then
+              we have to give it function scope so that the goto from the
+              earlier ':' case doesn't bypass the initialisation.  */
+           if (0) {
+           just_a_word_zero_gv:
+               gv = NULL;
+               gvp = NULL;
+           }
          just_a_word: {
                SV *sv;
                int pkgname = 0;
                const char lastchar = (PL_bufptr == PL_oldoldbufptr ? 0 : PL_bufptr[-1]);
+               CV *cv;
 
                /* Get the rest if it looks like a package qualifier */
 
@@ -4203,7 +4245,8 @@ Perl_yylex(pTHX)
                if (len > 2 &&
                    PL_tokenbuf[len - 2] == ':' && PL_tokenbuf[len - 1] == ':')
                {
-                   if (ckWARN(WARN_BAREWORD) && ! gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVHV))
+                   if (ckWARN(WARN_BAREWORD)
+                       && ! gv_fetchpv(PL_tokenbuf, 0, SVt_PVHV))
                        Perl_warner(aTHX_ packWARN(WARN_BAREWORD),
                            "Bareword \"%s\" refers to nonexistent package",
                             PL_tokenbuf);
@@ -4214,14 +4257,20 @@ Perl_yylex(pTHX)
                }
                else {
                    len = 0;
-                   if (!gv)
-                       gv = gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVCV);
+                   if (!gv) {
+                       /* Mustn't actually add anything to a symbol table.
+                          But also don't want to "initialise" any placeholder
+                          constants that might already be there into full
+                          blown PVGVs with attached PVCV.  */
+                       gv = gv_fetchpv(PL_tokenbuf, GV_NOADD_NOINIT,
+                                       SVt_PVCV);
+                   }
                }
 
                /* if we saw a global override before, get the right name */
 
                if (gvp) {
-                   sv = newSVpvn("CORE::GLOBAL::",14);
+                   sv = newSVpvs("CORE::GLOBAL::");
                    sv_catpv(sv,PL_tokenbuf);
                }
                else {
@@ -4246,6 +4295,20 @@ Perl_yylex(pTHX)
                if (len)
                    goto safe_bareword;
 
+               /* Do the explicit type check so that we don't need to force
+                  the initialisation of the symbol table to have a real GV.
+                  Beware - gv may not really be a PVGV, cv may not really be
+                  a PVCV, (because of the space optimisations that gv_init
+                  understands) But they're true if for this symbol there is
+                  respectively a typeglob and a subroutine.
+               */
+               cv = gv ? ((SvTYPE(gv) == SVt_PVGV)
+                   /* Real typeglob, so get the real subroutine: */
+                          ? GvCVu(gv)
+                   /* A proxy for a subroutine in this package? */
+                          : SvOK(gv) ? (CV *) gv : NULL)
+                   : NULL;
+
                /* See if it's the indirect object for a list operator. */
 
                if (PL_oldoldbufptr &&
@@ -4263,16 +4326,22 @@ Perl_yylex(pTHX)
 
                    /* Two barewords in a row may indicate method call. */
 
-                   if ((isIDFIRST_lazy_if(s,UTF) || *s == '$') && (tmp=intuit_method(s,gv)))
+                   if ((isIDFIRST_lazy_if(s,UTF) || *s == '$') &&
+                       (tmp = intuit_method(s, gv, cv)))
                        return REPORT(tmp);
 
                    /* If not a declared subroutine, it's an indirect object. */
                    /* (But it's an indir obj regardless for sort.) */
+                   /* Also, if "_" follows a filetest operator, it's a bareword */
 
-                   if ( !immediate_paren && (PL_last_lop_op == OP_SORT ||
-                         ((!gv || !GvCVu(gv)) &&
+                   if (
+                       ( !immediate_paren && (PL_last_lop_op == OP_SORT ||
+                         ((!gv || !cv) &&
                         (PL_last_lop_op != OP_MAPSTART &&
                         PL_last_lop_op != OP_GREPSTART))))
+                      || (PL_tokenbuf[0] == '_' && PL_tokenbuf[1] == '\0'
+                           && ((PL_opargs[PL_last_lop_op] & OA_CLASS_MASK) == OA_FILESTATOP))
+                      )
                    {
                        PL_expect = (PL_last_lop == PL_oldoldbufptr) ? XTERM : XOPERATOR;
                        goto bareword;
@@ -4294,9 +4363,9 @@ Perl_yylex(pTHX)
                /* If followed by a paren, it's certainly a subroutine. */
                if (*s == '(') {
                    CLINE;
-                   if (gv && GvCVu(gv)) {
+                   if (cv) {
                        for (d = s + 1; SPACE_OR_TAB(*d); d++) ;
-                       if (*d == ')' && (sv = cv_const_sv(GvCV(gv)))) {
+                       if (*d == ')' && (sv = gv_const_sv(gv))) {
                            s = d + 1;
                            goto its_constant;
                        }
@@ -4310,7 +4379,7 @@ Perl_yylex(pTHX)
 
                /* If followed by var or block, call it a method (unless sub) */
 
-               if ((*s == '$' || *s == '{') && (!gv || !GvCVu(gv))) {
+               if ((*s == '$' || *s == '{') && (!gv || !cv)) {
                    PL_last_lop = PL_oldbufptr;
                    PL_last_lop_op = OP_METHOD;
                    PREBLOCK(METHOD);
@@ -4320,20 +4389,18 @@ Perl_yylex(pTHX)
 
                if (!orig_keyword
                        && (isIDFIRST_lazy_if(s,UTF) || *s == '$')
-                       && (tmp = intuit_method(s,gv)))
+                       && (tmp = intuit_method(s, gv, cv)))
                    return REPORT(tmp);
 
                /* Not a method, so call it a subroutine (if defined) */
 
-               if (gv && GvCVu(gv)) {
-                   CV* cv;
+               if (cv) {
                    if (lastchar == '-' && ckWARN_d(WARN_AMBIGUOUS))
                        Perl_warner(aTHX_ packWARN(WARN_AMBIGUOUS),
                                "Ambiguous use of -%s resolved as -&%s()",
                                PL_tokenbuf, PL_tokenbuf);
                    /* Check for a constant sub */
-                   cv = GvCV(gv);
-                   if ((sv = cv_const_sv(cv))) {
+                   if ((sv = gv_const_sv(gv))) {
                  its_constant:
                        SvREFCNT_dec(((SVOP*)yylval.opval)->op_sv);
                        ((SVOP*)yylval.opval)->op_sv = SvREFCNT_inc(sv);
@@ -4342,6 +4409,14 @@ Perl_yylex(pTHX)
                    }
 
                    /* Resolve to GV now. */
+                   if (SvTYPE(gv) != SVt_PVGV) {
+                       gv = gv_fetchpv(PL_tokenbuf, 0, SVt_PVCV);
+                       assert (SvTYPE(gv) == SVt_PVGV);
+                       /* cv must have been some sort of placeholder, so
+                          now needs replacing with a real code reference.  */
+                       cv = GvCV(gv);
+                   }
+
                    op_free(yylval.opval);
                    yylval.opval = newCVREF(0, newGVOP(OP_GV, 0, gv));
                    yylval.opval->op_private |= OPpENTERSUB_NOPAREN;
@@ -4422,7 +4497,8 @@ Perl_yylex(pTHX)
                const char *pname = "main";
                if (PL_tokenbuf[2] == 'D')
                    pname = HvNAME_get(PL_curstash ? PL_curstash : PL_defstash);
-               gv = gv_fetchpv(Perl_form(aTHX_ "%s::DATA", pname), TRUE, SVt_PVIO);
+               gv = gv_fetchpv(Perl_form(aTHX_ "%s::DATA", pname), GV_ADD,
+                               SVt_PVIO);
                GvMULTI_on(gv);
                if (!GvIO(gv))
                    GvIOp(gv) = newIO();
@@ -4520,9 +4596,9 @@ Perl_yylex(pTHX)
                    Perl_croak(aTHX_ "CORE::%s is not a keyword", PL_tokenbuf);
                if (tmp < 0)
                    tmp = -tmp;
-               else if (tmp == KEY_require)
+               else if (tmp == KEY_require || tmp == KEY_do)
                    /* that's a way to remember we saw "CORE::" */
-                   orig_keyword = KEY_require;
+                   orig_keyword = tmp;
                goto reserved_word;
            }
            goto just_a_word;
@@ -4551,14 +4627,34 @@ Perl_yylex(pTHX)
        case KEY_bless:
            LOP(OP_BLESS,XTERM);
 
+       case KEY_break:
+           FUN0(OP_BREAK);
+
        case KEY_chop:
            UNI(OP_CHOP);
 
        case KEY_continue:
+           /* When 'use switch' is in effect, continue has a dual
+              life as a control operator. */
+           {
+               if (!FEATURE_IS_ENABLED("switch"))
+                   PREBLOCK(CONTINUE);
+               else {
+                   /* We have to disambiguate the two senses of
+                     "continue". If the next token is a '{' then
+                     treat it as the start of a continue block;
+                     otherwise treat it as a control operator.
+                    */
+                   s = skipspace(s);
+                   if (*s == '{')
            PREBLOCK(CONTINUE);
+                   else
+                       FUN0(OP_CONTINUE);
+               }
+           }
 
        case KEY_chdir:
-           (void)gv_fetchpv("ENV",TRUE, SVt_PVHV);     /* may use HOME */
+           (void)gv_fetchpv("ENV", GV_ADD, SVt_PVHV);  /* may use HOME */
            UNI(OP_CHDIR);
 
        case KEY_close:
@@ -4600,12 +4696,21 @@ Perl_yylex(pTHX)
        case KEY_chroot:
            UNI(OP_CHROOT);
 
+       case KEY_default:
+           PREBLOCK(DEFAULT);
+
        case KEY_do:
            s = skipspace(s);
            if (*s == '{')
                PRETERMBLOCK(DO);
            if (*s != '\'')
                s = force_word(s,WORD,TRUE,TRUE,FALSE);
+           if (orig_keyword == KEY_do) {
+               orig_keyword = 0;
+               yylval.ival = 1;
+           }
+           else
+               yylval.ival = 0;
            OPERATOR(DO);
 
        case KEY_die:
@@ -4816,6 +4921,10 @@ Perl_yylex(pTHX)
        case KEY_getlogin:
            FUN0(OP_GETLOGIN);
 
+       case KEY_given:
+           yylval.ival = CopLINE(PL_curcop);
+           OPERATOR(GIVEN);
+
        case KEY_glob:
            set_csh();
            LOP(OP_GLOB,XTERM);
@@ -4954,9 +5063,10 @@ Perl_yylex(pTHX)
                    /* [perl #16184] */
                    && !(t[0] == '=' && t[1] == '>')
                ) {
+                   int len = (int)(d-s);
                    Perl_warner(aTHX_ packWARN(WARN_PRECEDENCE),
                           "Precedence problem: open %.*s should be open(%.*s)",
-                           d - s, s, d - s, s);
+                           len, s, len, s);
                }
            }
            LOP(OP_OPEN,XTERM);
@@ -5172,6 +5282,10 @@ Perl_yylex(pTHX)
            else
                TOKEN(1);       /* force error */
 
+       case KEY_say:
+           checkcomma(s,PL_tokenbuf,"filehandle");
+           LOP(OP_SAY,XREF);
+
        case KEY_chomp:
            UNI(OP_CHOMP);
        
@@ -5313,7 +5427,7 @@ Perl_yylex(pTHX)
                        sv_setpv(PL_subname, tmpbuf);
                    else {
                        sv_setsv(PL_subname,PL_curstname);
-                       sv_catpvn(PL_subname,"::",2);
+                       sv_catpvs(PL_subname,"::");
                        sv_catpvn(PL_subname,tmpbuf,len);
                    }
                    s = skipspace(d);
@@ -5487,6 +5601,10 @@ Perl_yylex(pTHX)
        case KEY_vec:
            LOP(OP_VEC,XTERM);
 
+       case KEY_when:
+           yylval.ival = CopLINE(PL_curcop);
+           OPERATOR(WHEN);
+
        case KEY_while:
            yylval.ival = CopLINE(PL_curcop);
            OPERATOR(WHILE);
@@ -5510,10 +5628,10 @@ Perl_yylex(pTHX)
            char ctl_l[2];
            ctl_l[0] = toCTRL('L');
            ctl_l[1] = '\0';
-           gv_fetchpv(ctl_l,TRUE, SVt_PV);
+           gv_fetchpv(ctl_l, GV_ADD, SVt_PV);
        }
 #else
-           gv_fetchpv("\f",TRUE, SVt_PV);      /* Make sure $^L is defined */
+           gv_fetchpv("\f", GV_ADD, SVt_PV);    /* Make sure $^L is defined */
 #endif
            UNI(OP_ENTERWRITE);
 
@@ -5547,7 +5665,7 @@ S_pending_ident(pTHX)
     PL_pending_ident = 0;
 
     DEBUG_T({ PerlIO_printf(Perl_debug_log,
-          "### Tokener saw identifier '%s'\n", PL_tokenbuf); });
+          "### Pending identifier '%s'\n", PL_tokenbuf); });
 
     /* if we're in a my(), we can't allow dynamics here.
        $foo'bar has already been turned into $foo::bar, so
@@ -5595,7 +5713,7 @@ S_pending_ident(pTHX)
                HV *  const stash = PAD_COMPNAME_OURSTASH(tmp);
                HEK * const stashname = HvNAME_HEK(stash);
                SV *  const sym = newSVhek(stashname);
-                sv_catpvn(sym, "::", 2);
+                sv_catpvs(sym, "::");
                 sv_catpv(sym, PL_tokenbuf+1);
                 yylval.opval = (OP*)newSVOP(OP_CONST, 0, sym);
                 yylval.opval->op_private = OPpCONST_ENTERED;
@@ -5639,7 +5757,7 @@ S_pending_ident(pTHX)
        table.
     */
     if (pit == '@' && PL_lex_state != LEX_NORMAL && !PL_lex_brackets) {
-        GV *gv = gv_fetchpv(PL_tokenbuf+1, FALSE, SVt_PVAV);
+        GV *gv = gv_fetchpv(PL_tokenbuf+1, 0, SVt_PVAV);
         if ((!gv || ((PL_tokenbuf[0] == '@') ? !GvAV(gv) : !GvHV(gv)))
              && ckWARN(WARN_AMBIGUOUS))
         {
@@ -5653,10 +5771,26 @@ S_pending_ident(pTHX)
     /* build ops for a bareword */
     yylval.opval = (OP*)newSVOP(OP_CONST, 0, newSVpv(PL_tokenbuf+1, 0));
     yylval.opval->op_private = OPpCONST_ENTERED;
-    gv_fetchpv(PL_tokenbuf+1, PL_in_eval ? (GV_ADDMULTI | GV_ADDINEVAL) : TRUE,
-               ((PL_tokenbuf[0] == '$') ? SVt_PV
-                : (PL_tokenbuf[0] == '@') ? SVt_PVAV
-                : SVt_PVHV));
+    gv_fetchpv(
+           PL_tokenbuf+1,
+           PL_in_eval
+               ? (GV_ADDMULTI | GV_ADDINEVAL)
+               /* If the identifier refers to a stash, don't autovivify it.
+                * Change 24660 had the side effect of causing symbol table
+                * hashes to always be defined, even if they were freshly
+                * created and the only reference in the entire program was
+                * the single statement with the defined %foo::bar:: test.
+                * It appears that all code in the wild doing this actually
+                * wants to know whether sub-packages have been loaded, so
+                * by avoiding auto-vivifying symbol tables, we ensure that
+                * defined %foo::bar:: continues to be false, and the existing
+                * tests still give the expected answers, even though what
+                * they're actually testing has now changed subtly.
+                */
+               : !(*PL_tokenbuf == '%' && *(d = PL_tokenbuf + strlen(PL_tokenbuf) - 1) == ':' && d[-1] == ':'),
+           ((PL_tokenbuf[0] == '$') ? SVt_PV
+            : (PL_tokenbuf[0] == '@') ? SVt_PVAV
+            : SVt_PVHV));
     return WORD;
 }
 
@@ -5847,7 +5981,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           goto unknown;
       }
 
-    case 3: /* 28 tokens of length 3 */
+    case 3: /* 29 tokens of length 3 */
       switch (name[0])
       {
         case 'E':
@@ -5936,7 +6070,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
             case 'r':
               if (name[2] == 'r')
               {                                   /* err        */
-                return -KEY_err;
+                return (FEATURE_IS_ENABLED("err") ? -KEY_err : 0);
               }
 
               goto unknown;
@@ -6072,6 +6206,14 @@ Perl_keyword (pTHX_ const char *name, I32 len)
         case 's':
           switch (name[1])
           {
+            case 'a':
+              if (name[2] == 'y')
+              {                                   /* say        */
+                return (FEATURE_IS_ENABLED("say") ? -KEY_say : 0);
+              }
+
+              goto unknown;
+
             case 'i':
               if (name[2] == 'n')
               {                                   /* sin        */
@@ -6132,7 +6274,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           goto unknown;
       }
 
-    case 4: /* 40 tokens of length 4 */
+    case 4: /* 41 tokens of length 4 */
       switch (name[0])
       {
         case 'C':
@@ -6562,8 +6704,9 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           }
 
         case 'w':
-          if (name[1] == 'a')
+          switch (name[1])
           {
+            case 'a':
             switch (name[2])
             {
               case 'i':
@@ -6585,6 +6728,12 @@ Perl_keyword (pTHX_ const char *name, I32 len)
               default:
                 goto unknown;
             }
+
+            case 'h':
+              if (name[2] == 'e' &&
+                  name[3] == 'n')
+              {                                   /* when       */
+                return (FEATURE_IS_ENABLED("switch") ? KEY_when : 0);
           }
 
           goto unknown;
@@ -6593,7 +6742,11 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           goto unknown;
       }
 
-    case 5: /* 36 tokens of length 5 */
+        default:
+          goto unknown;
+      }
+
+    case 5: /* 38 tokens of length 5 */
       switch (name[0])
       {
         case 'B':
@@ -6646,8 +6799,10 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           }
 
         case 'b':
-          if (name[1] == 'l' &&
-              name[2] == 'e' &&
+          switch (name[1])
+          {
+            case 'l':
+              if (name[2] == 'e' &&
               name[3] == 's' &&
               name[4] == 's')
           {                                       /* bless      */
@@ -6656,6 +6811,20 @@ Perl_keyword (pTHX_ const char *name, I32 len)
 
           goto unknown;
 
+            case 'r':
+              if (name[2] == 'e' &&
+                  name[3] == 'a' &&
+                  name[4] == 'k')
+              {                                   /* break      */
+                return (FEATURE_IS_ENABLED("switch") ? -KEY_break : 0);
+              }
+
+              goto unknown;
+
+            default:
+              goto unknown;
+          }
+
         case 'c':
           switch (name[1])
           {
@@ -6769,6 +6938,17 @@ Perl_keyword (pTHX_ const char *name, I32 len)
               goto unknown;
           }
 
+        case 'g':
+          if (name[1] == 'i' &&
+              name[2] == 'v' &&
+              name[3] == 'e' &&
+              name[4] == 'n')
+          {                                       /* given      */
+            return (FEATURE_IS_ENABLED("switch") ? KEY_given : 0);
+          }
+
+          goto unknown;
+
         case 'i':
           switch (name[1])
           {
@@ -7505,7 +7685,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           goto unknown;
       }
 
-    case 7: /* 28 tokens of length 7 */
+    case 7: /* 29 tokens of length 7 */
       switch (name[0])
       {
         case 'D':
@@ -7576,9 +7756,22 @@ Perl_keyword (pTHX_ const char *name, I32 len)
               goto unknown;
 
             case 'e':
-              if (name[2] == 'f' &&
-                  name[3] == 'i' &&
-                  name[4] == 'n' &&
+              if (name[2] == 'f')
+              {
+                switch (name[3])
+                {
+                  case 'a':
+                    if (name[4] == 'u' &&
+                        name[5] == 'l' &&
+                        name[6] == 't')
+                    {                             /* default    */
+                      return (FEATURE_IS_ENABLED("switch") ? KEY_default : 0);
+                    }
+
+                    goto unknown;
+
+                  case 'i':
+                    if (name[4] == 'n' &&
                   name[5] == 'e' &&
                   name[6] == 'd')
               {                                   /* defined    */
@@ -7590,6 +7783,13 @@ Perl_keyword (pTHX_ const char *name, I32 len)
             default:
               goto unknown;
           }
+              }
+
+              goto unknown;
+
+            default:
+              goto unknown;
+          }
 
         case 'f':
           if (name[1] == 'o' &&
@@ -8996,7 +9196,7 @@ S_checkcomma(pTHX_ register char *s, const char *name, const char *what)
        while (s < PL_bufend && isSPACE(*s))
            s++;
        if (*s == ',') {
-           int kw;
+           I32 kw;
            *s = '\0'; /* XXX If we didn't do this, we could const a lot of toke.c */
            kw = keyword(w, s - w) || get_cv(w, FALSE) != 0;
            *s = ',';
@@ -9081,7 +9281,7 @@ S_new_constant(pTHX_ const char *s, STRLEN len, const char *key, SV *sv, SV *pv,
 
     /* Check the eval first */
     if (!PL_in_eval && SvTRUE(ERRSV)) {
-       sv_catpv(ERRSV, "Propagated");
+       sv_catpvs(ERRSV, "Propagated");
        yyerror(SvPV_nolen_const(ERRSV)); /* Duplicates the message inside eval */
        (void)POPs;
        res = SvREFCNT_inc(sv);
@@ -9351,7 +9551,7 @@ S_scan_pat(pTHX_ char *start, I32 type)
     if ((pm->op_pmflags & PMf_CONTINUE) && !(pm->op_pmflags & PMf_GLOBAL)
            && ckWARN(WARN_REGEXP))
     {
-        Perl_warner(aTHX_ packWARN(WARN_REGEXP), c_without_g);
+        Perl_warner(aTHX_ packWARN(WARN_REGEXP), "Use of /c modifier is meaningless without /g" );
     }
 
     pm->op_pmpermflags = pm->op_pmflags;
@@ -9403,10 +9603,8 @@ S_scan_subst(pTHX_ char *start)
            break;
     }
 
-    /* /c is not meaningful with s/// */
-    if ((pm->op_pmflags & PMf_CONTINUE) && ckWARN(WARN_REGEXP))
-    {
-        Perl_warner(aTHX_ packWARN(WARN_REGEXP), c_in_subst);
+    if ((pm->op_pmflags & PMf_CONTINUE) && ckWARN(WARN_REGEXP)) {
+        Perl_warner(aTHX_ packWARN(WARN_REGEXP), "Use of /c modifier is meaningless in s///" );
     }
 
     if (es) {
@@ -9415,12 +9613,12 @@ S_scan_subst(pTHX_ char *start)
        PL_sublex_info.super_bufend = PL_bufend;
        PL_multi_end = 0;
        pm->op_pmflags |= PMf_EVAL;
-       repl = newSVpvn("",0);
+       repl = newSVpvs("");
        while (es-- > 0)
            sv_catpv(repl, es ? "eval " : "do ");
-       sv_catpvn(repl, "{ ", 2);
+       sv_catpvs(repl, "{ ");
        sv_catsv(repl, PL_lex_repl);
-       sv_catpvn(repl, " };", 2);
+       sv_catpvs(repl, " }");
        SvEVALED_on(repl);
        SvREFCNT_dec(PL_lex_repl);
        PL_lex_repl = repl;
@@ -9498,7 +9696,6 @@ S_scan_heredoc(pTHX_ register char *s)
     I32 len;
     SV *tmpstr;
     char term;
-    const char newline[] = "\n";
     const char *found_newline;
     register char *d;
     register char *e;
@@ -9560,7 +9757,7 @@ S_scan_heredoc(pTHX_ register char *s)
        s = olds;
     }
 #endif
-    if ( outer || !(found_newline = ninstr(s,PL_bufend,newline,newline+1)) ) {
+    if ( outer || !(found_newline = memchr(s, '\n', PL_bufend - s)) ) {
         herewas = newSVpvn(s,PL_bufend-s);
     }
     else {
@@ -9664,7 +9861,7 @@ S_scan_heredoc(pTHX_ register char *s)
            sv_setsv(sv,PL_linestr);
             (void)SvIOK_on(sv);
             SvIV_set(sv, 0);
-           av_store(CopFILEAV(PL_curcop), (I32)CopLINE(PL_curcop),sv);
+           av_store(CopFILEAVx(PL_curcop), (I32)CopLINE(PL_curcop),sv);
        }
        if (*s == term && memEQ(s,PL_tokenbuf,len)) {
            STRLEN off = PL_bufend - 1 - SvPVX_const(PL_linestr);
@@ -9778,7 +9975,7 @@ S_scan_inputsymbol(pTHX_ char *start)
            Copy("ARGV",d,5,char);
 
        /* Check whether readline() is overriden */
-       if (((gv_readline = gv_fetchpv("readline", FALSE, SVt_PVCV))
+       if (((gv_readline = gv_fetchpv("readline", 0, SVt_PVCV))
                && GvCVu(gv_readline) && GvIMPORTED_CV(gv_readline))
                ||
                ((gvp = (GV**)hv_fetch(PL_globalstash, "readline", 8, FALSE))
@@ -9800,7 +9997,7 @@ S_scan_inputsymbol(pTHX_ char *start)
                    HV *stash = PAD_COMPNAME_OURSTASH(tmp);
                    HEK *stashname = HvNAME_HEK(stash);
                    SV *sym = sv_2mortal(newSVhek(stashname));
-                   sv_catpvn(sym, "::", 2);
+                   sv_catpvs(sym, "::");
                    sv_catpv(sym, d+1);
                    d = SvPVX(sym);
                    goto intro_sym;
@@ -9842,7 +10039,7 @@ intro_sym:
        /* If it's none of the above, it must be a literal filehandle
           (<Foo::BAR> or <FOO>) so build a simple readline OP */
        else {
-           GV *gv = gv_fetchpv(d,TRUE, SVt_PVIO);
+           GV *gv = gv_fetchpv(d, GV_ADD, SVt_PVIO);
            PL_lex_op = readline_overriden
                ? (OP*)newUNOP(OP_ENTERSUB, OPf_STACKED,
                        append_elem(OP_LIST,
@@ -10131,13 +10328,13 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
 
        /* update debugger info */
        if (PERLDB_LINE && PL_curstash != PL_debstash) {
-           SV *sv = NEWSV(88,0);
+           SV * const sv = NEWSV(88,0);
 
            sv_upgrade(sv, SVt_PVMG);
            sv_setsv(sv,PL_linestr);
             (void)SvIOK_on(sv);
             SvIV_set(sv, 0);
-           av_store(CopFILEAV(PL_curcop), (I32)CopLINE(PL_curcop), sv);
+           av_store(CopFILEAVx(PL_curcop), (I32)CopLINE(PL_curcop), sv);
        }
 
        /* having changed the buffer, we must update PL_bufend */
@@ -10205,7 +10402,7 @@ Perl_scan_num(pTHX_ const char *start, YYSTYPE* lvalp)
     NV nv;                             /* number read, as a double */
     SV *sv = Nullsv;                   /* place to put the converted number */
     bool floatit;                      /* boolean: int or float? */
-    const char *lastub = 0;            /* position of last underbar */
+    const char *lastub = NULL;         /* position of last underbar */
     static char const number_too_long[] = "Number too long";
 
     /* We use the first character to decide what type of number this is */
@@ -10582,7 +10779,7 @@ S_scan_formline(pTHX_ register char *s)
 {
     register char *eol;
     register char *t;
-    SV *stuff = newSVpvn("",0);
+    SV *stuff = newSVpvs("");
     bool needargs = FALSE;
     bool eofmt = FALSE;
 
@@ -10772,7 +10969,7 @@ Perl_yyerror(pTHX_ const char *s)
            where = "within string";
     }
     else {
-       SV *where_sv = sv_2mortal(newSVpvn("next char ", 10));
+       SV *where_sv = sv_2mortal(newSVpvs("next char "));
        if (yychar < 32)
            Perl_sv_catpvf(aTHX_ where_sv, "^%c", toCTRL(yychar));
        else if (isPRINT_LC(yychar))
@@ -10807,7 +11004,7 @@ Perl_yyerror(pTHX_ const char *s)
             OutCopFILE(PL_curcop));
     }
     PL_in_my = 0;
-    PL_in_my_stash = Nullhv;
+    PL_in_my_stash = NULL;
     return 0;
 }
 #ifdef __SC__
@@ -10916,7 +11113,7 @@ S_swallow_bom(pTHX_ U8 *s)
 static void
 restore_rsfp(pTHX_ void *f)
 {
-    PerlIO *fp = (PerlIO*)f;
+    PerlIO * const fp = (PerlIO*)f;
 
     if (PL_rsfp == PerlIO_stdin())
        PerlIO_clearerr(PL_rsfp);
@@ -11004,16 +11201,15 @@ Perl_scan_vstring(pTHX_ const char *s, SV *sv)
     }
 
     if (!isALPHA(*pos)) {
-       UV rev;
        U8 tmpbuf[UTF8_MAXBYTES+1];
-       U8 *tmpend;
 
        if (*s == 'v') s++;  /* get past 'v' */
 
        sv_setpvn(sv, "", 0);
 
        for (;;) {
-           rev = 0;
+           U8 *tmpend;
+           UV rev = 0;
            {
                /* this is atoi() that tolerates underscores */
                const char *end = pos;