This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: [ID 20010920.007] q and qq does not work after do
[perl5.git] / toke.c
diff --git a/toke.c b/toke.c
index 3ae0f27..af117bc 100644 (file)
--- a/toke.c
+++ b/toke.c
 
 static char ident_too_long[] = "Identifier too long";
 
 
 static char ident_too_long[] = "Identifier too long";
 
-static void restore_rsfp(pTHXo_ void *f);
+static void restore_rsfp(pTHX_ void *f);
 #ifndef PERL_NO_UTF16_FILTER
 #ifndef PERL_NO_UTF16_FILTER
-static I32 utf16_textfilter(pTHXo_ int idx, SV *sv, int maxlen);
-static I32 utf16rev_textfilter(pTHXo_ int idx, SV *sv, int maxlen);
+static I32 utf16_textfilter(pTHX_ int idx, SV *sv, int maxlen);
+static I32 utf16rev_textfilter(pTHX_ int idx, SV *sv, int maxlen);
 #endif
 
 #define XFAKEBRACK 128
 #define XENUMMASK 127
 
 #endif
 
 #define XFAKEBRACK 128
 #define XENUMMASK 127
 
-#ifdef EBCDIC
-/* For now 'use utf8' does not affect tokenizer on EBCDIC */
-#define UTF (PL_linestr && DO_UTF8(PL_linestr))
+#ifdef USE_UTF8_SCRIPTS
+#   define UTF (!IN_BYTES)
 #else
 #else
-#define UTF ((PL_linestr && DO_UTF8(PL_linestr)) || (PL_hints & HINT_UTF8))
+#   ifdef EBCDIC /* For now 'use utf8' does not affect tokenizer on EBCDIC */
+#       define UTF (PL_linestr && DO_UTF8(PL_linestr))
+#   else
+#       define UTF ((PL_linestr && DO_UTF8(PL_linestr)) || (PL_hints & HINT_UTF8))
+#   endif
 #endif
 
 /* In variables named $^X, these are the legal values for X.
 #endif
 
 /* In variables named $^X, these are the legal values for X.
@@ -442,8 +445,6 @@ Perl_lex_start(pTHX_ SV *line)
     PL_oldoldbufptr = PL_oldbufptr = PL_bufptr = PL_linestart = SvPVX(PL_linestr);
     PL_bufend = PL_bufptr + SvCUR(PL_linestr);
     PL_last_lop = PL_last_uni = Nullch;
     PL_oldoldbufptr = PL_oldbufptr = PL_bufptr = PL_linestart = SvPVX(PL_linestr);
     PL_bufend = PL_bufptr + SvCUR(PL_linestr);
     PL_last_lop = PL_last_uni = Nullch;
-    SvREFCNT_dec(PL_rs);
-    PL_rs = newSVpvn("\n", 1);
     PL_rsfp = 0;
 }
 
     PL_rsfp = 0;
 }
 
@@ -861,10 +862,13 @@ Perl_str_to_version(pTHX_ SV *sv)
 /*
  * S_force_version
  * Forces the next token to be a version number.
 /*
  * S_force_version
  * Forces the next token to be a version number.
+ * If the next token appears to be an invalid version number, (e.g. "v2b"),
+ * and if "guessing" is TRUE, then no new token is created (and the caller
+ * must use an alternative parsing method).
  */
 
 STATIC char *
  */
 
 STATIC char *
-S_force_version(pTHX_ char *s)
+S_force_version(pTHX_ char *s, int guessing)
 {
     OP *version = Nullop;
     char *d;
 {
     OP *version = Nullop;
     char *d;
@@ -875,7 +879,8 @@ S_force_version(pTHX_ char *s)
     if (*d == 'v')
        d++;
     if (isDIGIT(*d)) {
     if (*d == 'v')
        d++;
     if (isDIGIT(*d)) {
-        for (; isDIGIT(*d) || *d == '_' || *d == '.'; d++);
+       while (isDIGIT(*d) || *d == '_' || *d == '.')
+           d++;
         if (*d == ';' || isSPACE(*d) || *d == '}' || !*d) {
            SV *ver;
             s = scan_num(s, &yylval);
         if (*d == ';' || isSPACE(*d) || *d == '}' || !*d) {
            SV *ver;
             s = scan_num(s, &yylval);
@@ -887,13 +892,15 @@ S_force_version(pTHX_ char *s)
                SvNOK_on(ver);          /* hint that it is a version */
            }
         }
                SvNOK_on(ver);          /* hint that it is a version */
            }
         }
+       else if (guessing)
+           return s;
     }
 
     /* NOTE: The parser sees the package name and the VERSION swapped */
     PL_nextval[PL_nexttoke].opval = version;
     force_next(WORD);
 
     }
 
     /* NOTE: The parser sees the package name and the VERSION swapped */
     PL_nextval[PL_nexttoke].opval = version;
     force_next(WORD);
 
-    return (s);
+    return s;
 }
 
 /*
 }
 
 /*
@@ -1431,8 +1438,9 @@ S_scan_const(pTHX_ char *start)
            case '0': case '1': case '2': case '3':
            case '4': case '5': case '6': case '7':
                {
            case '0': case '1': case '2': case '3':
            case '4': case '5': case '6': case '7':
                {
-                   STRLEN len = 0;     /* disallow underscores */
-                   uv = (UV)scan_oct(s, 3, &len);
+                    I32 flags = 0;
+                    STRLEN len = 3;
+                   uv = grok_oct(s, &len, &flags, NULL);
                    s += len;
                }
                goto NUM_ESCAPE_INSERT;
                    s += len;
                }
                goto NUM_ESCAPE_INSERT;
@@ -1442,20 +1450,24 @@ S_scan_const(pTHX_ char *start)
                ++s;
                if (*s == '{') {
                    char* e = strchr(s, '}');
                ++s;
                if (*s == '{') {
                    char* e = strchr(s, '}');
-                   STRLEN len = 1;             /* allow underscores */
+                    I32 flags = PERL_SCAN_ALLOW_UNDERSCORES |
+                      PERL_SCAN_DISALLOW_PREFIX;
+                   STRLEN len;
 
 
+                    ++s;
                    if (!e) {
                        yyerror("Missing right brace on \\x{}");
                    if (!e) {
                        yyerror("Missing right brace on \\x{}");
-                       ++s;
                        continue;
                    }
                        continue;
                    }
-                   uv = (UV)scan_hex(s + 1, e - s - 1, &len);
+                    len = e - s;
+                   uv = grok_hex(s, &len, &flags, NULL);
                    s = e + 1;
                }
                else {
                    {
                    s = e + 1;
                }
                else {
                    {
-                       STRLEN len = 0;         /* disallow underscores */
-                       uv = (UV)scan_hex(s, 2, &len);
+                       STRLEN len = 2;
+                        I32 flags = PERL_SCAN_DISALLOW_PREFIX;
+                       uv = grok_hex(s, &len, &flags, NULL);
                        s += len;
                    }
                }
                        s += len;
                    }
                }
@@ -2048,7 +2060,7 @@ Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen)
     /* Call function. The function is expected to      */
     /* call "FILTER_READ(idx+1, buf_sv)" first.                */
     /* Return: <0:error, =0:eof, >0:not eof            */
     /* Call function. The function is expected to      */
     /* call "FILTER_READ(idx+1, buf_sv)" first.                */
     /* Return: <0:error, =0:eof, >0:not eof            */
-    return (*funcp)(aTHXo_ idx, buf_sv, maxlen);
+    return (*funcp)(aTHX_ idx, buf_sv, maxlen);
 }
 
 STATIC char *
 }
 
 STATIC char *
@@ -2166,132 +2178,8 @@ Perl_yylex(pTHX)
     bool bof = FALSE;
 
     /* check if there's an identifier for us to look at */
     bool bof = FALSE;
 
     /* check if there's an identifier for us to look at */
-    if (PL_pending_ident) {
-        /* pit holds the identifier we read and pending_ident is reset */
-       char pit = PL_pending_ident;
-       PL_pending_ident = 0;
-
-       DEBUG_T({ PerlIO_printf(Perl_debug_log,
-              "### Tokener saw 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
-          just check for colons.
-
-          if it's a legal name, the OP is a PADANY.
-       */
-       if (PL_in_my) {
-           if (PL_in_my == KEY_our) {  /* "our" is merely analogous to "my" */
-               if (strchr(PL_tokenbuf,':'))
-                   yyerror(Perl_form(aTHX_ "No package name allowed for "
-                                     "variable %s in \"our\"",
-                                     PL_tokenbuf));
-               tmp = pad_allocmy(PL_tokenbuf);
-           }
-           else {
-               if (strchr(PL_tokenbuf,':'))
-                   yyerror(Perl_form(aTHX_ PL_no_myglob,PL_tokenbuf));
-
-               yylval.opval = newOP(OP_PADANY, 0);
-               yylval.opval->op_targ = pad_allocmy(PL_tokenbuf);
-               return PRIVATEREF;
-           }
-       }
-
-       /*
-          build the ops for accesses to a my() variable.
-
-          Deny my($a) or my($b) in a sort block, *if* $a or $b is
-          then used in a comparison.  This catches most, but not
-          all cases.  For instance, it catches
-              sort { my($a); $a <=> $b }
-          but not
-              sort { my($a); $a < $b ? -1 : $a == $b ? 0 : 1; }
-          (although why you'd do that is anyone's guess).
-       */
-
-       if (!strchr(PL_tokenbuf,':')) {
-#ifdef USE_THREADS
-           /* Check for single character per-thread SVs */
-           if (PL_tokenbuf[0] == '$' && PL_tokenbuf[2] == '\0'
-               && !isALPHA(PL_tokenbuf[1]) /* Rule out obvious non-threadsvs */
-               && (tmp = find_threadsv(&PL_tokenbuf[1])) != NOT_IN_PAD)
-           {
-               yylval.opval = newOP(OP_THREADSV, 0);
-               yylval.opval->op_targ = tmp;
-               return PRIVATEREF;
-           }
-#endif /* USE_THREADS */
-           if ((tmp = pad_findmy(PL_tokenbuf)) != NOT_IN_PAD) {
-               SV *namesv = AvARRAY(PL_comppad_name)[tmp];
-               /* might be an "our" variable" */
-               if (SvFLAGS(namesv) & SVpad_OUR) {
-                   /* build ops for a bareword */
-                   SV *sym = newSVpv(HvNAME(GvSTASH(namesv)),0);
-                   sv_catpvn(sym, "::", 2);
-                   sv_catpv(sym, PL_tokenbuf+1);
-                   yylval.opval = (OP*)newSVOP(OP_CONST, 0, sym);
-                   yylval.opval->op_private = OPpCONST_ENTERED;
-                   gv_fetchpv(SvPVX(sym),
-                       (PL_in_eval
-                           ? (GV_ADDMULTI | GV_ADDINEVAL)
-                           : TRUE
-                       ),
-                       ((PL_tokenbuf[0] == '$') ? SVt_PV
-                        : (PL_tokenbuf[0] == '@') ? SVt_PVAV
-                        : SVt_PVHV));
-                   return WORD;
-               }
-
-               /* if it's a sort block and they're naming $a or $b */
-               if (PL_last_lop_op == OP_SORT &&
-                   PL_tokenbuf[0] == '$' &&
-                   (PL_tokenbuf[1] == 'a' || PL_tokenbuf[1] == 'b')
-                   && !PL_tokenbuf[2])
-               {
-                   for (d = PL_in_eval ? PL_oldoldbufptr : PL_linestart;
-                        d < PL_bufend && *d != '\n';
-                        d++)
-                   {
-                       if (strnEQ(d,"<=>",3) || strnEQ(d,"cmp",3)) {
-                           Perl_croak(aTHX_ "Can't use \"my %s\" in sort comparison",
-                                 PL_tokenbuf);
-                       }
-                   }
-               }
-
-               yylval.opval = newOP(OP_PADANY, 0);
-               yylval.opval->op_targ = tmp;
-               return PRIVATEREF;
-           }
-       }
-
-       /*
-          Whine if they've said @foo in a doublequoted string,
-          and @foo isn't a variable we can find in the symbol
-          table.
-       */
-       if (pit == '@' && PL_lex_state != LEX_NORMAL && !PL_lex_brackets) {
-           GV *gv = gv_fetchpv(PL_tokenbuf+1, FALSE, SVt_PVAV);
-           if ((!gv || ((PL_tokenbuf[0] == '@') ? !GvAV(gv) : !GvHV(gv)))
-                && ckWARN(WARN_AMBIGUOUS))
-           {
-                /* Downgraded from fatal to warning 20000522 mjd */
-               Perl_warner(aTHX_ WARN_AMBIGUOUS,
-                           "Possible unintended interpolation of %s in string",
-                            PL_tokenbuf);
-           }
-       }
-
-       /* 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));
-       return WORD;
-    }
+    if (PL_pending_ident) 
+        return S_pending_ident(aTHX);
 
     /* no identifier pending identification */
 
 
     /* no identifier pending identification */
 
@@ -2406,13 +2294,13 @@ Perl_yylex(pTHX)
        if (PL_lex_dojoin) {
            PL_nextval[PL_nexttoke].ival = 0;
            force_next(',');
        if (PL_lex_dojoin) {
            PL_nextval[PL_nexttoke].ival = 0;
            force_next(',');
-#ifdef USE_THREADS
+#ifdef USE_5005THREADS
            PL_nextval[PL_nexttoke].opval = newOP(OP_THREADSV, 0);
            PL_nextval[PL_nexttoke].opval->op_targ = find_threadsv("\"");
            force_next(PRIVATEREF);
 #else
            force_ident("\"", '$');
            PL_nextval[PL_nexttoke].opval = newOP(OP_THREADSV, 0);
            PL_nextval[PL_nexttoke].opval->op_targ = find_threadsv("\"");
            force_next(PRIVATEREF);
 #else
            force_ident("\"", '$');
-#endif /* USE_THREADS */
+#endif /* USE_5005THREADS */
            PL_nextval[PL_nexttoke].ival = 0;
            force_next('$');
            PL_nextval[PL_nexttoke].ival = 0;
            PL_nextval[PL_nexttoke].ival = 0;
            force_next('$');
            PL_nextval[PL_nexttoke].ival = 0;
@@ -4117,7 +4005,7 @@ Perl_yylex(pTHX)
                    if (ckWARN(WARN_RESERVED)) {
                        if (lastchar != '-') {
                            for (d = PL_tokenbuf; *d && isLOWER(*d); d++) ;
                    if (ckWARN(WARN_RESERVED)) {
                        if (lastchar != '-') {
                            for (d = PL_tokenbuf; *d && isLOWER(*d); d++) ;
-                           if (!*d)
+                           if (!*d && strNE(PL_tokenbuf,"main"))
                                Perl_warner(aTHX_ WARN_RESERVED, PL_warn_reserved,
                                       PL_tokenbuf);
                        }
                                Perl_warner(aTHX_ WARN_RESERVED, PL_warn_reserved,
                                       PL_tokenbuf);
                        }
@@ -4299,12 +4187,6 @@ Perl_yylex(pTHX)
            LOP(OP_CRYPT,XTERM);
 
        case KEY_chmod:
            LOP(OP_CRYPT,XTERM);
 
        case KEY_chmod:
-           if (ckWARN(WARN_CHMOD)) {
-               for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ;
-               if (*d != '0' && isDIGIT(*d))
-                   Perl_warner(aTHX_ WARN_CHMOD,
-                               "chmod() mode argument is missing initial 0");
-           }
            LOP(OP_CHMOD,XTERM);
 
        case KEY_chown:
            LOP(OP_CHMOD,XTERM);
 
        case KEY_chown:
@@ -4327,7 +4209,7 @@ Perl_yylex(pTHX)
            if (*s == '{')
                PRETERMBLOCK(DO);
            if (*s != '\'')
            if (*s == '{')
                PRETERMBLOCK(DO);
            if (*s != '\'')
-               s = force_word(s,WORD,FALSE,TRUE,FALSE);
+               s = force_word(s,WORD,TRUE,TRUE,FALSE);
            OPERATOR(DO);
 
        case KEY_die:
            OPERATOR(DO);
 
        case KEY_die:
@@ -4657,7 +4539,7 @@ Perl_yylex(pTHX)
            if (PL_expect != XSTATE)
                yyerror("\"no\" not allowed in expression");
            s = force_word(s,WORD,FALSE,TRUE,FALSE);
            if (PL_expect != XSTATE)
                yyerror("\"no\" not allowed in expression");
            s = force_word(s,WORD,FALSE,TRUE,FALSE);
-           s = force_version(s);
+           s = force_version(s, FALSE);
            yylval.ival = 0;
            OPERATOR(USE);
 
            yylval.ival = 0;
            OPERATOR(USE);
 
@@ -4809,10 +4691,12 @@ Perl_yylex(pTHX)
 
        case KEY_require:
            s = skipspace(s);
 
        case KEY_require:
            s = skipspace(s);
-           if (isDIGIT(*s) || (*s == 'v' && isDIGIT(s[1]))) {
-               s = force_version(s);
+           if (isDIGIT(*s)) {
+               s = force_version(s, FALSE);
            }
            }
-           else {
+           else if (*s != 'v' || !isDIGIT(s[1])
+                   || (s = force_version(s, TRUE), *s == 'v'))
+           {
                *PL_tokenbuf = '\0';
                s = force_word(s,WORD,TRUE,TRUE,FALSE);
                if (isIDFIRST_lazy_if(PL_tokenbuf,UTF))
                *PL_tokenbuf = '\0';
                s = force_word(s,WORD,TRUE,TRUE,FALSE);
                if (isIDFIRST_lazy_if(PL_tokenbuf,UTF))
@@ -5162,12 +5046,6 @@ Perl_yylex(pTHX)
            LOP(OP_UTIME,XTERM);
 
        case KEY_umask:
            LOP(OP_UTIME,XTERM);
 
        case KEY_umask:
-           if (ckWARN(WARN_UMASK)) {
-               for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ;
-               if (*d != '0' && isDIGIT(*d))
-                   Perl_warner(aTHX_ WARN_UMASK,
-                               "umask: argument is missing initial 0");
-           }
            UNI(OP_UMASK);
 
        case KEY_unshift:
            UNI(OP_UMASK);
 
        case KEY_unshift:
@@ -5178,15 +5056,19 @@ Perl_yylex(pTHX)
                yyerror("\"use\" not allowed in expression");
            s = skipspace(s);
            if (isDIGIT(*s) || (*s == 'v' && isDIGIT(s[1]))) {
                yyerror("\"use\" not allowed in expression");
            s = skipspace(s);
            if (isDIGIT(*s) || (*s == 'v' && isDIGIT(s[1]))) {
-               s = force_version(s);
+               s = force_version(s, TRUE);
                if (*s == ';' || (s = skipspace(s), *s == ';')) {
                    PL_nextval[PL_nexttoke].opval = Nullop;
                    force_next(WORD);
                }
                if (*s == ';' || (s = skipspace(s), *s == ';')) {
                    PL_nextval[PL_nexttoke].opval = Nullop;
                    force_next(WORD);
                }
+               else if (*s == 'v') {
+                   s = force_word(s,WORD,FALSE,TRUE,FALSE);
+                   s = force_version(s, FALSE);
+               }
            }
            else {
                s = force_word(s,WORD,FALSE,TRUE,FALSE);
            }
            else {
                s = force_word(s,WORD,FALSE,TRUE,FALSE);
-               s = force_version(s);
+               s = force_version(s, FALSE);
            }
            yylval.ival = 1;
            OPERATOR(USE);
            }
            yylval.ival = 1;
            OPERATOR(USE);
@@ -5248,6 +5130,137 @@ Perl_yylex(pTHX)
 #pragma segment Main
 #endif
 
 #pragma segment Main
 #endif
 
+static int
+S_pending_ident(pTHX)
+{
+    register char *d;
+    register I32 tmp;
+    /* pit holds the identifier we read and pending_ident is reset */
+    char pit = PL_pending_ident;
+    PL_pending_ident = 0;
+
+    DEBUG_T({ PerlIO_printf(Perl_debug_log,
+          "### Tokener saw 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
+       just check for colons.
+
+       if it's a legal name, the OP is a PADANY.
+    */
+    if (PL_in_my) {
+        if (PL_in_my == KEY_our) {     /* "our" is merely analogous to "my" */
+            if (strchr(PL_tokenbuf,':'))
+                yyerror(Perl_form(aTHX_ "No package name allowed for "
+                                  "variable %s in \"our\"",
+                                  PL_tokenbuf));
+            tmp = pad_allocmy(PL_tokenbuf);
+        }
+        else {
+            if (strchr(PL_tokenbuf,':'))
+                yyerror(Perl_form(aTHX_ PL_no_myglob,PL_tokenbuf));
+
+            yylval.opval = newOP(OP_PADANY, 0);
+            yylval.opval->op_targ = pad_allocmy(PL_tokenbuf);
+            return PRIVATEREF;
+        }
+    }
+
+    /*
+       build the ops for accesses to a my() variable.
+
+       Deny my($a) or my($b) in a sort block, *if* $a or $b is
+       then used in a comparison.  This catches most, but not
+       all cases.  For instance, it catches
+           sort { my($a); $a <=> $b }
+       but not
+           sort { my($a); $a < $b ? -1 : $a == $b ? 0 : 1; }
+       (although why you'd do that is anyone's guess).
+    */
+
+    if (!strchr(PL_tokenbuf,':')) {
+#ifdef USE_5005THREADS
+        /* Check for single character per-thread SVs */
+        if (PL_tokenbuf[0] == '$' && PL_tokenbuf[2] == '\0'
+            && !isALPHA(PL_tokenbuf[1]) /* Rule out obvious non-threadsvs */
+            && (tmp = find_threadsv(&PL_tokenbuf[1])) != NOT_IN_PAD)
+        {
+            yylval.opval = newOP(OP_THREADSV, 0);
+            yylval.opval->op_targ = tmp;
+            return PRIVATEREF;
+        }
+#endif /* USE_5005THREADS */
+        if ((tmp = pad_findmy(PL_tokenbuf)) != NOT_IN_PAD) {
+            SV *namesv = AvARRAY(PL_comppad_name)[tmp];
+            /* might be an "our" variable" */
+            if (SvFLAGS(namesv) & SVpad_OUR) {
+                /* build ops for a bareword */
+                SV *sym = newSVpv(HvNAME(GvSTASH(namesv)),0);
+                sv_catpvn(sym, "::", 2);
+                sv_catpv(sym, PL_tokenbuf+1);
+                yylval.opval = (OP*)newSVOP(OP_CONST, 0, sym);
+                yylval.opval->op_private = OPpCONST_ENTERED;
+                gv_fetchpv(SvPVX(sym),
+                    (PL_in_eval
+                        ? (GV_ADDMULTI | GV_ADDINEVAL)
+                        : TRUE
+                    ),
+                    ((PL_tokenbuf[0] == '$') ? SVt_PV
+                     : (PL_tokenbuf[0] == '@') ? SVt_PVAV
+                     : SVt_PVHV));
+                return WORD;
+            }
+
+            /* if it's a sort block and they're naming $a or $b */
+            if (PL_last_lop_op == OP_SORT &&
+                PL_tokenbuf[0] == '$' &&
+                (PL_tokenbuf[1] == 'a' || PL_tokenbuf[1] == 'b')
+                && !PL_tokenbuf[2])
+            {
+                for (d = PL_in_eval ? PL_oldoldbufptr : PL_linestart;
+                     d < PL_bufend && *d != '\n';
+                     d++)
+                {
+                    if (strnEQ(d,"<=>",3) || strnEQ(d,"cmp",3)) {
+                        Perl_croak(aTHX_ "Can't use \"my %s\" in sort comparison",
+                              PL_tokenbuf);
+                    }
+                }
+            }
+
+            yylval.opval = newOP(OP_PADANY, 0);
+            yylval.opval->op_targ = tmp;
+            return PRIVATEREF;
+        }
+    }
+
+    /*
+       Whine if they've said @foo in a doublequoted string,
+       and @foo isn't a variable we can find in the symbol
+       table.
+    */
+    if (pit == '@' && PL_lex_state != LEX_NORMAL && !PL_lex_brackets) {
+        GV *gv = gv_fetchpv(PL_tokenbuf+1, FALSE, SVt_PVAV);
+        if ((!gv || ((PL_tokenbuf[0] == '@') ? !GvAV(gv) : !GvHV(gv)))
+             && ckWARN(WARN_AMBIGUOUS))
+        {
+            /* Downgraded from fatal to warning 20000522 mjd */
+            Perl_warner(aTHX_ WARN_AMBIGUOUS,
+                        "Possible unintended interpolation of %s in string",
+                         PL_tokenbuf);
+        }
+    }
+
+    /* 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));
+    return WORD;
+}
+
 I32
 Perl_keyword(pTHX_ register char *d, I32 len)
 {
 I32
 Perl_keyword(pTHX_ register char *d, I32 len)
 {
@@ -7221,91 +7234,39 @@ Perl_scan_num(pTHX_ char *start, YYSTYPE* lvalp)
            }
        }
 
            }
        }
 
-       /* terminate the string */
-       *d = '\0';
 
        /* make an sv from the string */
        sv = NEWSV(92,0);
 
 
        /* make an sv from the string */
        sv = NEWSV(92,0);
 
-#if defined(Strtol) && defined(Strtoul)
-
        /*
        /*
-          strtol/strtoll sets errno to ERANGE if the number is too big
-          for an integer. We try to do an integer conversion first
-          if no characters indicating "float" have been found.
+           We try to do an integer conversion first if no characters
+           indicating "float" have been found.
         */
 
        if (!floatit) {
         */
 
        if (!floatit) {
-           IV iv = 0;
-           UV uv = 0;
-           errno = 0;
-           if (*PL_tokenbuf == '-')
-               iv = Strtol(PL_tokenbuf, (char**)NULL, 10);
-           else
-               uv = Strtoul(PL_tokenbuf, (char**)NULL, 10);
-           if (errno)
-               floatit = TRUE; /* Probably just too large. */
-           else if (*PL_tokenbuf == '-')
-               sv_setiv(sv, iv);
-           else if (uv <= IV_MAX)
+           UV uv;
+            int flags = grok_number (PL_tokenbuf, d - PL_tokenbuf, &uv);
+
+            if (flags == IS_NUMBER_IN_UV) {
+              if (uv <= IV_MAX)
                sv_setiv(sv, uv); /* Prefer IVs over UVs. */
                sv_setiv(sv, uv); /* Prefer IVs over UVs. */
-           else
+              else
                sv_setuv(sv, uv);
                sv_setuv(sv, uv);
-       }
+            } else if (flags == (IS_NUMBER_IN_UV | IS_NUMBER_NEG)) {
+              if (uv <= (UV) IV_MIN)
+                sv_setiv(sv, -(IV)uv);
+              else
+               floatit = TRUE;
+            } else
+              floatit = TRUE;
+        }
        if (floatit) {
        if (floatit) {
+           /* terminate the string */
+           *d = '\0';
            nv = Atof(PL_tokenbuf);
            sv_setnv(sv, nv);
        }
            nv = Atof(PL_tokenbuf);
            sv_setnv(sv, nv);
        }
-#else
-       /*
-          No working strtou?ll?.
-
-          Unfortunately atol() doesn't do range checks (returning
-          LONG_MIN/LONG_MAX, and setting errno to ERANGE on overflows)
-          everywhere [1], so we cannot use use atol() (or atoll()).
-          If we could, they would be used, as Atol(), very much like
-          Strtol() and Strtoul() are used above.
 
 
-          [1] XXX Configure test needed to check for atol()
-                  (and atoll()) overflow behaviour XXX
-
-          --jhi
-
-          We need to do this the hard way.  */
-
-       nv = Atof(PL_tokenbuf);
-
-       /* See if we can make do with an integer value without loss of
-          precision.  We use U_V to cast to a UV, because some
-          compilers have issues.  Then we try casting it back and see
-          if it was the same [1].  We only do this if we know we
-          specifically read an integer.  If floatit is true, then we
-          don't need to do the conversion at all.
-
-          [1] Note that this is lossy if our NVs cannot preserve our
-          UVs.  There are metaconfig defines NV_PRESERVES_UV (a boolean)
-          and NV_PRESERVES_UV_BITS (a number), but in general we really
-          do hope all such potentially lossy platforms have strtou?ll?
-          to do a lossless IV/UV conversion.
-
-          Maybe could do some tricks with DBL_DIG, LDBL_DIG and
-          DBL_MANT_DIG and LDBL_MANT_DIG (these are already available
-          as NV_DIG and NV_MANT_DIG)?
-       
-          --jhi
-          */
-       {
-           UV uv = U_V(nv);
-           if (!floatit && (NV)uv == nv) {
-               if (uv <= IV_MAX)
-                   sv_setiv(sv, uv); /* Prefer IVs over UVs. */
-               else
-                   sv_setuv(sv, uv);
-           }
-           else
-               sv_setnv(sv, nv);
-       }
-#endif
        if ( floatit ? (PL_hints & HINT_NEW_FLOAT) :
                       (PL_hints & HINT_NEW_INTEGER) )
            sv = new_constant(PL_tokenbuf, d - PL_tokenbuf,
        if ( floatit ? (PL_hints & HINT_NEW_FLOAT) :
                       (PL_hints & HINT_NEW_INTEGER) )
            sv = new_constant(PL_tokenbuf, d - PL_tokenbuf,
@@ -7416,15 +7377,19 @@ S_scan_formline(pTHX_ register char *s)
                if (*t == '@' || *t == '^')
                    needargs = TRUE;
            }
                if (*t == '@' || *t == '^')
                    needargs = TRUE;
            }
-           sv_catpvn(stuff, s, eol-s);
+           if (eol > s) {
+               sv_catpvn(stuff, s, eol-s);
 #ifndef PERL_STRICT_CR
 #ifndef PERL_STRICT_CR
-           if (eol-s > 1 && eol[-2] == '\r' && eol[-1] == '\n') {
-               char *end = SvPVX(stuff) + SvCUR(stuff);
-               end[-2] = '\n';
-               end[-1] = '\0';
-               SvCUR(stuff)--;
-           }
+               if (eol-s > 1 && eol[-2] == '\r' && eol[-1] == '\n') {
+                   char *end = SvPVX(stuff) + SvCUR(stuff);
+                   end[-2] = '\n';
+                   end[-1] = '\0';
+                   SvCUR(stuff)--;
+               }
 #endif
 #endif
+           }
+           else
+             break;
        }
        s = eol;
        if (PL_rsfp) {
        }
        s = eol;
        if (PL_rsfp) {
@@ -7505,11 +7470,11 @@ Perl_start_subparse(pTHX_ I32 is_format, U32 flags)
     PL_min_intro_pending = 0;
     PL_padix = 0;
     PL_subline = CopLINE(PL_curcop);
     PL_min_intro_pending = 0;
     PL_padix = 0;
     PL_subline = CopLINE(PL_curcop);
-#ifdef USE_THREADS
+#ifdef USE_5005THREADS
     av_store(PL_comppad_name, 0, newSVpvn("@_", 2));
     PL_curpad[0] = (SV*)newAV();
     SvPADMY_on(PL_curpad[0]);  /* XXX Needed? */
     av_store(PL_comppad_name, 0, newSVpvn("@_", 2));
     PL_curpad[0] = (SV*)newAV();
     SvPADMY_on(PL_curpad[0]);  /* XXX Needed? */
-#endif /* USE_THREADS */
+#endif /* USE_5005THREADS */
 
     comppadlist = newAV();
     AvREAL_off(comppadlist);
 
     comppadlist = newAV();
     AvREAL_off(comppadlist);
@@ -7518,11 +7483,11 @@ Perl_start_subparse(pTHX_ I32 is_format, U32 flags)
 
     CvPADLIST(PL_compcv) = comppadlist;
     CvOUTSIDE(PL_compcv) = (CV*)SvREFCNT_inc(outsidecv);
 
     CvPADLIST(PL_compcv) = comppadlist;
     CvOUTSIDE(PL_compcv) = (CV*)SvREFCNT_inc(outsidecv);
-#ifdef USE_THREADS
+#ifdef USE_5005THREADS
     CvOWNER(PL_compcv) = 0;
     New(666, CvMUTEXP(PL_compcv), 1, perl_mutex);
     MUTEX_INIT(CvMUTEXP(PL_compcv));
     CvOWNER(PL_compcv) = 0;
     New(666, CvMUTEXP(PL_compcv), 1, perl_mutex);
     MUTEX_INIT(CvMUTEXP(PL_compcv));
-#endif /* USE_THREADS */
+#endif /* USE_5005THREADS */
 
     return oldsavestack_ix;
 }
 
     return oldsavestack_ix;
 }
@@ -7697,17 +7662,13 @@ S_swallow_bom(pTHX_ U8 *s)
     return (char*)s;
 }
 
     return (char*)s;
 }
 
-#ifdef PERL_OBJECT
-#include "XSUB.h"
-#endif
-
 /*
  * restore_rsfp
  * Restore a source filter.
  */
 
 static void
 /*
  * restore_rsfp
  * Restore a source filter.
  */
 
 static void
-restore_rsfp(pTHXo_ void *f)
+restore_rsfp(pTHX_ void *f)
 {
     PerlIO *fp = (PerlIO*)f;
 
 {
     PerlIO *fp = (PerlIO*)f;
 
@@ -7720,7 +7681,7 @@ restore_rsfp(pTHXo_ void *f)
 
 #ifndef PERL_NO_UTF16_FILTER
 static I32
 
 #ifndef PERL_NO_UTF16_FILTER
 static I32
-utf16_textfilter(pTHXo_ int idx, SV *sv, int maxlen)
+utf16_textfilter(pTHX_ int idx, SV *sv, int maxlen)
 {
     I32 count = FILTER_READ(idx+1, sv, maxlen);
     if (count) {
 {
     I32 count = FILTER_READ(idx+1, sv, maxlen);
     if (count) {
@@ -7739,7 +7700,7 @@ utf16_textfilter(pTHXo_ int idx, SV *sv, int maxlen)
 }
 
 static I32
 }
 
 static I32
-utf16rev_textfilter(pTHXo_ int idx, SV *sv, int maxlen)
+utf16rev_textfilter(pTHX_ int idx, SV *sv, int maxlen)
 {
     I32 count = FILTER_READ(idx+1, sv, maxlen);
     if (count) {
 {
     I32 count = FILTER_READ(idx+1, sv, maxlen);
     if (count) {