File::Spec::VMS fixup for tmpdir from Craig Berry.
[p5sagit/p5-mst-13.2.git] / toke.c
diff --git a/toke.c b/toke.c
index 6f9f70c..98210a0 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -1,6 +1,6 @@
 /*    toke.c
  *
- *    Copyright (c) 1991-1999, Larry Wall
+ *    Copyright (c) 1991-2000, Larry Wall
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
 static char ident_too_long[] = "Identifier too long";
 
 static void restore_rsfp(pTHXo_ void *f);
+#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);
+#endif
 
 #define XFAKEBRACK 128
 #define XENUMMASK 127
 
+/*#define UTF (SvUTF8(PL_linestr) && !(PL_hints & HINT_BYTE))*/
 #define UTF (PL_hints & HINT_UTF8)
-/*
- * Note: we try to be careful never to call the isXXX_utf8() functions
- * unless we're pretty sure we've seen the beginning of a UTF-8 character
- * (that is, the two high bits are set).  Otherwise we risk loading in the
- * heavy-duty SWASHINIT and SWASHGET routines unnecessarily.
- */
-#define isIDFIRST_lazy(p) ((!UTF || (*((U8*)p) < 0xc0)) \
-                               ? isIDFIRST(*(p)) \
-                               : isIDFIRST_utf8((U8*)p))
-#define isALNUM_lazy(p) ((!UTF || (*((U8*)p) < 0xc0)) \
-                               ? isALNUM(*(p)) \
-                               : isALNUM_utf8((U8*)p))
 
 /* In variables name $^X, these are the legal values for X.  
  * 1999-02-27 mjd-perl-patch@plover.com */
 #define isCONTROLVAR(x) (isUPPER(x) || strchr("[\\]^_?", (x)))
 
+/* On MacOS, respect nonbreaking spaces */
+#ifdef MACOS_TRADITIONAL
+#define SPACE_OR_TAB(c) ((c)==' '||(c)=='\312'||(c)=='\t')
+#else
+#define SPACE_OR_TAB(c) ((c)==' '||(c)=='\t')
+#endif
+
 /* LEX_* are values for PL_lex_state, the state of the lexer.
  * They are arranged oddly so that the guard on the switch statement
  * can get by with a single comparison (if the compiler is smart enough).
@@ -69,13 +69,6 @@ static void restore_rsfp(pTHXo_ void *f);
 #define LEX_FORMLINE            1
 #define LEX_KNOWNEXT            0
 
-#ifdef I_FCNTL
-#include <fcntl.h>
-#endif
-#ifdef I_SYS_FILE
-#include <sys/file.h>
-#endif
-
 /* XXX If this causes problems, set i_unistd=undef in the hint file.  */
 #ifdef I_UNISTD
 #  include <unistd.h> /* Needed for execv() */
@@ -223,9 +216,9 @@ S_no_op(pTHX_ char *what, char *s)
     yywarn(Perl_form(aTHX_ "%s found where operator expected", what));
     if (is_first)
        Perl_warn(aTHX_ "\t(Missing semicolon on previous line?)\n");
-    else if (PL_oldoldbufptr && isIDFIRST_lazy(PL_oldoldbufptr)) {
+    else if (PL_oldoldbufptr && isIDFIRST_lazy_if(PL_oldoldbufptr,UTF)) {
        char *t;
-       for (t = PL_oldoldbufptr; *t && (isALNUM_lazy(t) || *t == ':'); t++) ;
+       for (t = PL_oldoldbufptr; *t && (isALNUM_lazy_if(t,UTF) || *t == ':'); t++) ;
        if (t < PL_bufptr && isSPACE(*t))
            Perl_warn(aTHX_ "\t(Do you need to predeclare %.*s?)\n",
                t - PL_oldoldbufptr, PL_oldoldbufptr);
@@ -337,36 +330,6 @@ S_cr_textfilter(pTHX_ int idx, SV *sv, int maxlen)
 }
 #endif
 
-STATIC I32
-S_utf16_textfilter(pTHX_ int idx, SV *sv, int maxlen)
-{
-    I32 count = FILTER_READ(idx+1, sv, maxlen);
-    if (count) {
-       U8* tmps;
-       U8* tend;
-       New(898, tmps, SvCUR(sv) * 3 / 2 + 1, U8);
-       tend = utf16_to_utf8((U16*)SvPVX(sv), tmps, SvCUR(sv));
-       sv_usepvn(sv, (char*)tmps, tend - tmps);
-    
-    }
-    return count;
-}
-
-STATIC I32
-S_utf16rev_textfilter(pTHX_ int idx, SV *sv, int maxlen)
-{
-    I32 count = FILTER_READ(idx+1, sv, maxlen);
-    if (count) {
-       U8* tmps;
-       U8* tend;
-       New(898, tmps, SvCUR(sv) * 3 / 2 + 1, U8);
-       tend = utf16_to_utf8_reversed((U16*)SvPVX(sv), tmps, SvCUR(sv));
-       sv_usepvn(sv, (char*)tmps, tend - tmps);
-    
-    }
-    return count;
-}
-
 /*
  * Perl_lex_start
  * Initialize variables.  Uses the Perl save_stack to save its state (for
@@ -387,6 +350,15 @@ Perl_lex_start(pTHX_ SV *line)
     SAVEI32(PL_lex_state);
     SAVEVPTR(PL_lex_inpat);
     SAVEI32(PL_lex_inwhat);
+    if (PL_lex_state == LEX_KNOWNEXT) {
+       I32 toke = PL_nexttoke;
+       while (--toke >= 0) {
+           SAVEI32(PL_nexttype[toke]);
+           SAVEVPTR(PL_nextval[toke]);
+       }
+       SAVEI32(PL_nexttoke);
+       PL_nexttoke = 0;
+    }
     SAVECOPLINE(PL_curcop);
     SAVEPPTR(PL_bufptr);
     SAVEPPTR(PL_bufend);
@@ -466,35 +438,52 @@ S_incline(pTHX_ char *s)
     dTHR;
     char *t;
     char *n;
+    char *e;
     char ch;
-    int sawline = 0;
 
     CopLINE_inc(PL_curcop);
     if (*s++ != '#')
        return;
-    while (*s == ' ' || *s == '\t') s++;
-    if (strnEQ(s, "line ", 5)) {
-       s += 5;
-       sawline = 1;
-    }
+    while (SPACE_OR_TAB(*s)) s++;
+    if (strnEQ(s, "line", 4))
+       s += 4;
+    else
+       return;
+    if (*s == ' ' || *s == '\t')
+       s++;
+    else 
+       return;
+    while (SPACE_OR_TAB(*s)) s++;
     if (!isDIGIT(*s))
        return;
     n = s;
     while (isDIGIT(*s))
        s++;
-    while (*s == ' ' || *s == '\t')
+    while (SPACE_OR_TAB(*s))
        s++;
-    if (*s == '"' && (t = strchr(s+1, '"')))
+    if (*s == '"' && (t = strchr(s+1, '"'))) {
        s++;
+       e = t + 1;
+    }
     else {
-       if (!sawline)
-           return;             /* false alarm */
        for (t = s; !isSPACE(*t); t++) ;
+       e = t;
     }
+    while (SPACE_OR_TAB(*e) || *e == '\r' || *e == '\f')
+       e++;
+    if (*e != '\n' && *e != '\0')
+       return;         /* false alarm */
+
     ch = *t;
     *t = '\0';
-    if (t - s > 0)
+    if (t - s > 0) {
+#ifdef USE_ITHREADS
+       Safefree(CopFILE(PL_curcop));
+#else
+       SvREFCNT_dec(CopFILEGV(PL_curcop));
+#endif
        CopFILE_set(PL_curcop, s);
+    }
     *t = ch;
     CopLINE_set(PL_curcop, atoi(n)-1);
 }
@@ -510,7 +499,7 @@ S_skipspace(pTHX_ register char *s)
 {
     dTHR;
     if (PL_lex_formbrack && PL_lex_brackets <= PL_lex_formbrack) {
-       while (s < PL_bufend && (*s == ' ' || *s == '\t'))
+       while (s < PL_bufend && SPACE_OR_TAB(*s))
            s++;
        return s;
     }
@@ -633,7 +622,7 @@ S_check_uni(pTHX)
        return;
     while (isSPACE(*PL_last_uni))
        PL_last_uni++;
-    for (s = PL_last_uni; isALNUM_lazy(s) || *s == '-'; s++) ;
+    for (s = PL_last_uni; isALNUM_lazy_if(s,UTF) || *s == '-'; s++) ;
     if ((t = strchr(s, '(')) && t < PL_bufptr)
        return;
     if (ckWARN_d(WARN_AMBIGUOUS)){
@@ -756,7 +745,7 @@ S_force_word(pTHX_ register char *start, int token, int check_keyword, int allow
     
     start = skipspace(start);
     s = start;
-    if (isIDFIRST_lazy(s) ||
+    if (isIDFIRST_lazy_if(s,UTF) ||
        (allow_pack && *s == ':') ||
        (allow_initial_tick && *s == '\'') )
     {
@@ -810,6 +799,31 @@ S_force_ident(pTHX_ register char *s, int kind)
     }
 }
 
+NV
+Perl_str_to_version(pTHX_ SV *sv)
+{
+    NV retval = 0.0;
+    NV nshift = 1.0;
+    STRLEN len;
+    char *start = SvPVx(sv,len);
+    bool utf = SvUTF8(sv) ? TRUE : FALSE;
+    char *end = start + len;
+    while (start < end) {
+       I32 skip;
+       UV n;
+       if (utf)
+           n = utf8_to_uv((U8*)start, &skip);
+       else {
+           n = *(U8*)start;
+           skip = 1;
+       }
+       retval += ((NV)n)/nshift;
+       start += skip;
+       nshift *= 1000;
+    }
+    return retval;
+}
+
 /* 
  * S_force_version
  * Forces the next token to be a version number.
@@ -819,18 +833,25 @@ STATIC char *
 S_force_version(pTHX_ char *s)
 {
     OP *version = Nullop;
+    char *d;
 
     s = skipspace(s);
 
-    if (isDIGIT(*s) || (*s == 'v' && isDIGIT(s[1]))) {
-        char *d = s;
-       if (*d == 'v')
-           d++;
+    d = s;
+    if (*d == 'v')
+       d++;
+    if (isDIGIT(*d)) {
         for (; isDIGIT(*d) || *d == '_' || *d == '.'; d++);
-        if ((*d == ';' || isSPACE(*d)) && *(skipspace(d)) != ',') {
+        if (*d == ';' || isSPACE(*d) || *d == '}' || !*d) {
+           SV *ver;
             s = scan_num(s);
-            /* real VERSION number -- GBARR */
             version = yylval.opval;
+           ver = cSVOPx(version)->op_sv;
+           if (SvPOK(ver) && !SvNIOK(ver)) {
+               (void)SvUPGRADE(ver, SVt_PVNV);
+               SvNVX(ver) = str_to_version(ver);
+               SvNOK_on(ver);          /* hint that it is a version */
+           }
         }
     }
 
@@ -862,7 +883,7 @@ S_tokeq(pTHX_ SV *sv)
        goto finish;
 
     s = SvPV_force(sv, len);
-    if (SvIVX(sv) == -1)
+    if (SvTYPE(sv) >= SVt_PVIV && SvIVX(sv) == -1)
        goto finish;
     send = s + len;
     while (s < send && *s != '\\')
@@ -940,6 +961,8 @@ S_sublex_start(pTHX)
 
            p = SvPV(sv, len);
            nsv = newSVpvn(p, len);
+           if (SvUTF8(sv))
+               SvUTF8_on(nsv);
            SvREFCNT_dec(sv);
            sv = nsv;
        } 
@@ -1159,7 +1182,11 @@ S_scan_const(pTHX_ char *start)
     register char *s = start;                  /* start of the constant */
     register char *d = SvPVX(sv);              /* destination for copies */
     bool dorange = FALSE;                      /* are we in a translit range? */
+    bool didrange = FALSE;                     /* did we just finish a range? */
+    bool has_utf = FALSE;                      /* embedded \x{} */
     I32 len;                                   /* ? */
+    UV uv;
+
     I32 utf = (PL_lex_inwhat == OP_TRANS && PL_sublex_info.sub_op)
        ? (PL_sublex_info.sub_op->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF))
        : UTF;
@@ -1189,6 +1216,12 @@ S_scan_const(pTHX_ char *start)
                min = (U8)*d;                   /* first char in range */
                max = (U8)d[1];                 /* last char in range  */
 
+                if (min > max) {
+                   Perl_croak(aTHX_
+                              "Invalid [] range \"%c-%c\" in transliteration operator",
+                              min, max);
+                }
+
 #ifndef ASCIIish
                if ((isLOWER(min) && isLOWER(max)) ||
                    (isUPPER(min) && isUPPER(max))) {
@@ -1209,11 +1242,15 @@ S_scan_const(pTHX_ char *start)
 
                /* mark the range as done, and continue */
                dorange = FALSE;
+               didrange = TRUE;
                continue;
-           }
+           } 
 
            /* range begins (ignore - as first or last char) */
            else if (*s == '-' && s+1 < send  && s != start) {
+               if (didrange) { 
+                   Perl_croak(aTHX_ "Ambiguous range in transliteration operator");
+               }
                if (utf) {
                    *d++ = (char)0xff;  /* use illegal utf8 byte--see pmtrans */
                    s++;
@@ -1222,6 +1259,9 @@ S_scan_const(pTHX_ char *start)
                dorange = TRUE;
                s++;
            }
+           else {
+               didrange = FALSE;
+           }
        }
 
        /* if we get here, we're not doing a transliteration */
@@ -1232,8 +1272,10 @@ S_scan_const(pTHX_ char *start)
            if (s[2] == '#') {
                while (s < send && *s != ')')
                    *d++ = *s++;
-           } else if (s[2] == '{'
-                      || s[2] == 'p' && s[3] == '{') { /* This should march regcomp.c */
+           }
+           else if (s[2] == '{' /* This should match regcomp.c */
+                    || ((s[2] == 'p' || s[2] == '?') && s[3] == '{'))
+           {
                I32 count = 1;
                char *regparse = s + (s[2] == '{' ? 3 : 4);
                char c;
@@ -1264,7 +1306,8 @@ S_scan_const(pTHX_ char *start)
        }
 
        /* check for embedded arrays (@foo, @:foo, @'foo, @{foo}, @$foo) */
-       else if (*s == '@' && s[1] && (isALNUM_lazy(s+1) || strchr(":'{$", s[1])))
+       else if (*s == '@' && s[1]
+                && (isALNUM_lazy_if(s+1,UTF) || strchr(":'{$", s[1])))
            break;
 
        /* check for embedded scalars.  only stop if we're sure it's a
@@ -1280,15 +1323,20 @@ S_scan_const(pTHX_ char *start)
        /* (now in tr/// code again) */
 
        if (*s & 0x80 && thisutf) {
-           dTHR;                       /* only for ckWARN */
-           if (ckWARN(WARN_UTF8)) {
-               (void)utf8_to_uv((U8*)s, &len); /* could cvt latin-1 to utf8 here... */
-               if (len) {
-                   while (len--)
-                       *d++ = *s++;
-                   continue;
-               }
-           }
+          (void)utf8_to_uv((U8*)s, &len);
+          if (len == 1) {
+              /* illegal UTF8, make it valid */
+              char *old_pvx = SvPVX(sv);
+              /* need space for one extra char (NOTE: SvCUR() not set here) */
+              d = SvGROW(sv, SvLEN(sv) + 1) + (d - old_pvx);
+              d = (char*)uv_to_utf8((U8*)d, (U8)*s++);
+          }
+          else {
+              while (len--)
+                  *d++ = *s++;
+          }
+          has_utf = TRUE;
+          continue;
        }
 
        /* backslashes */
@@ -1332,8 +1380,8 @@ S_scan_const(pTHX_ char *start)
            default:
                {
                    dTHR;
-                   if (ckWARN(WARN_UNSAFE) && isALPHA(*s))
-                       Perl_warner(aTHX_ WARN_UNSAFE, 
+                   if (ckWARN(WARN_MISC) && isALNUM(*s))
+                       Perl_warner(aTHX_ WARN_MISC, 
                               "Unrecognized escape \\%c passed through",
                               *s);
                    /* default action is to copy the quoted character */
@@ -1344,49 +1392,78 @@ S_scan_const(pTHX_ char *start)
            /* \132 indicates an octal constant */
            case '0': case '1': case '2': case '3':
            case '4': case '5': case '6': case '7':
-               *d++ = (char)scan_oct(s, 3, &len);
+               len = 0;        /* disallow underscores */
+               uv = (UV)scan_oct(s, 3, &len);
                s += len;
-               continue;
+               goto NUM_ESCAPE_INSERT;
 
            /* \x24 indicates a hex constant */
            case 'x':
                ++s;
                if (*s == '{') {
                    char* e = strchr(s, '}');
-
                    if (!e) {
                        yyerror("Missing right brace on \\x{}");
                        e = s;
                    }
-                   if (!utf) {
-                       dTHR;
-                       if (ckWARN(WARN_UTF8))
-                           Perl_warner(aTHX_ WARN_UTF8,
-                                  "Use of \\x{} without utf8 declaration");
-                   }
-                   /* note: utf always shorter than hex */
-                   d = (char*)uv_to_utf8((U8*)d,
-                                         (UV)scan_hex(s + 1, e - s - 1, &len));
-                   s = e + 1;
+                   len = 1;            /* allow underscores */
+                    uv = (UV)scan_hex(s + 1, e - s - 1, &len);
+                    s = e + 1;
                }
                else {
-                   UV uv = (UV)scan_hex(s, 2, &len);
-                   if (utf && PL_lex_inwhat == OP_TRANS &&
-                       utf != (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF))
-                   {
-                       d = (char*)uv_to_utf8((U8*)d, uv);      /* doing a CU or UC */
-                   }
-                   else {
-                       if (uv >= 127 && UTF) {
-                           dTHR;
-                           if (ckWARN(WARN_UTF8))
-                               Perl_warner(aTHX_ WARN_UTF8,
-                                   "\\x%.*s will produce malformed UTF-8 character; use \\x{%.*s} for that",
-                                   (int)len,s,(int)len,s);
+                   len = 0;            /* disallow underscores */
+                   uv = (UV)scan_hex(s, 2, &len);
+                   s += len;
+               }
+
+             NUM_ESCAPE_INSERT:
+               /* Insert oct or hex escaped character.
+                * There will always enough room in sv since such escapes will
+                * be longer than any utf8 sequence they can end up as
+                */
+               if (uv > 127) {
+                   if (!thisutf && !has_utf && uv > 255) {
+                       /* might need to recode whatever we have accumulated so far
+                        * if it contains any hibit chars
+                        */
+                       int hicount = 0;
+                       char *c;
+                       for (c = SvPVX(sv); c < d; c++) {
+                           if (*c & 0x80)
+                               hicount++;
                        }
-                       *d++ = (char)uv;
+                       if (hicount) {
+                           char *old_pvx = SvPVX(sv);
+                           char *src, *dst;
+                           d = SvGROW(sv, SvCUR(sv) + hicount + 1) + (d - old_pvx);
+
+                           src = d - 1;
+                           d += hicount;
+                           dst = d - 1;
+
+                           while (src < dst) {
+                               if (*src & 0x80) {
+                                   dst--;
+                                   uv_to_utf8((U8*)dst, (U8)*src--);
+                                   dst--;
+                               }
+                               else {
+                                   *dst-- = *src--;
+                               }
+                           }
+                        }
+                    }
+
+                    if (thisutf || uv > 255) {
+                       d = (char*)uv_to_utf8((U8*)d, uv);
+                       has_utf = TRUE;
+                    }
+                   else {
+                       *d++ = (char)uv;
                    }
-                   s += len;
+               }
+               else {
+                   *d++ = (char)uv;
                }
                continue;
 
@@ -1395,12 +1472,9 @@ S_scan_const(pTHX_ char *start)
                ++s;
                if (*s == '{') {
                    char* e = strchr(s, '}');
-                   HV *hv;
-                   SV **svp;
-                   SV *res, *cv;
+                   SV *res;
                    STRLEN len;
                    char *str;
-                   char *why = Nullch;
  
                    if (!e) {
                        yyerror("Missing right brace on \\N{}");
@@ -1411,6 +1485,14 @@ S_scan_const(pTHX_ char *start)
                    res = new_constant( Nullch, 0, "charnames", 
                                        res, Nullsv, "\\N{...}" );
                    str = SvPV(res,len);
+                   if (!has_utf && SvUTF8(res)) {
+                       char *ostart = SvPVX(sv);
+                       SvCUR_set(sv, d - ostart);
+                       SvPOK_on(sv);
+                       sv_utf8_upgrade(sv);
+                       d = SvPVX(sv) + SvCUR(sv);
+                       has_utf = TRUE;
+                   }
                    if (len > e - s + 4) {
                        char *odest = SvPVX(sv);
 
@@ -1434,7 +1516,8 @@ S_scan_const(pTHX_ char *start)
                *d = *s++;
                if (isLOWER(*d))
                   *d = toUPPER(*d);
-               *d++ = toCTRL(*d); 
+               *d = toCTRL(*d); 
+               d++;
 #else
                len = *s++;
                *d++ = toCTRL(len);
@@ -1485,6 +1568,8 @@ S_scan_const(pTHX_ char *start)
     *d = '\0';
     SvCUR_set(sv, d - SvPVX(sv));
     SvPOK_on(sv);
+    if (has_utf)
+       SvUTF8_on(sv);
 
     /* shrink the sv if we allocated more than we used */
     if (SvCUR(sv) + 5 < SvLEN(sv)) {
@@ -1593,7 +1678,7 @@ S_intuit_more(pTHX_ register char *s)
            case '&':
            case '$':
                weight -= seen[un_char] * 10;
-               if (isALNUM_lazy(s+1)) {
+               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))
                        weight -= 100;
@@ -1677,7 +1762,7 @@ S_intuit_more(pTHX_ register char *s)
  * Not a method if it's really "print foo $bar"
  * Method if it's really "foo package::" (interpreted as package->foo)
  * Not a method if bar is known to be a subroutne ("sub bar; foo bar")
- * Not a method if bar is a filehandle or package, but is quotd with
+ * Not a method if bar is a filehandle or package, but is quoted with
  *   =>
  */
 
@@ -1778,7 +1863,7 @@ S_incl_perldb(pTHX)
  * store private buffers and state information.
  *
  * The supplied datasv parameter is upgraded to a PVIO type
- * and the IoDIRP field is used to store the function pointer,
+ * and the IoDIRP/IoANY field is used to store the function pointer,
  * and IOf_FAKE_DIRP is enabled on datasv to mark this as such.
  * Note that IoTOP_NAME, IoFMT_NAME, IoBOTTOM_NAME, if set for
  * private use must be set using malloc'd pointers.
@@ -1796,7 +1881,7 @@ Perl_filter_add(pTHX_ filter_t funcp, SV *datasv)
        datasv = NEWSV(255,0);
     if (!SvUPGRADE(datasv, SVt_PVIO))
         Perl_die(aTHX_ "Can't upgrade filter_add data to SVt_PVIO");
-    IoDIRP(datasv) = (DIR*)funcp; /* stash funcp into spare field */
+    IoANY(datasv) = (void *)funcp; /* stash funcp into spare field */
     IoFLAGS(datasv) |= IOf_FAKE_DIRP;
     DEBUG_P(PerlIO_printf(Perl_debug_log, "filter_add func %p (%s)\n",
                          funcp, SvPV_nolen(datasv)));
@@ -1816,9 +1901,9 @@ Perl_filter_del(pTHX_ filter_t funcp)
        return;
     /* if filter is on top of stack (usual case) just pop it off */
     datasv = FILTER_DATA(AvFILLp(PL_rsfp_filters));
-    if (IoDIRP(datasv) == (DIR*)funcp) {
+    if (IoANY(datasv) == (void *)funcp) {
        IoFLAGS(datasv) &= ~IOf_FAKE_DIRP;
-       IoDIRP(datasv) = (DIR*)NULL;
+       IoANY(datasv) = (void *)NULL;
        sv_free(av_pop(PL_rsfp_filters));
 
         return;
@@ -1878,7 +1963,7 @@ Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen)
        return FILTER_READ(idx+1, buf_sv, maxlen); /* recurse */
     }
     /* Get function pointer hidden within datasv       */
-    funcp = (filter_t)IoDIRP(datasv);
+    funcp = (filter_t)IoANY(datasv);
     DEBUG_P(PerlIO_printf(Perl_debug_log,
                          "filter_read %d: via function %p (%s)\n",
                          idx, funcp, SvPV_nolen(datasv)));
@@ -1909,6 +1994,31 @@ S_filter_gets(pTHX_ register SV *sv, register PerlIO *fp, STRLEN append)
         return (sv_gets(sv, fp, append));
 }
 
+STATIC HV *
+S_find_in_my_stash(pTHX_ char *pkgname, I32 len)
+{
+    GV *gv;
+
+    if (len == 11 && *pkgname == '_' && strEQ(pkgname, "__PACKAGE__"))
+        return PL_curstash;
+
+    if (len > 2 &&
+        (pkgname[len - 2] == ':' && pkgname[len - 1] == ':') &&
+        (gv = gv_fetchpv(pkgname, FALSE, SVt_PVHV)))
+    {
+        return GvHV(gv);                       /* Foo:: */
+    }
+
+    /* use constant CLASS => 'MyClass' */
+    if ((gv = gv_fetchpv(pkgname, FALSE, SVt_PVCV))) {
+        SV *sv;
+        if (GvCV(gv) && (sv = cv_const_sv(GvCV(gv)))) {
+            pkgname = SvPV_nolen(sv);
+        }
+    }
+
+    return gv_stashpv(pkgname, FALSE);
+}
 
 #ifdef DEBUGGING
     static char* exp_name[] =
@@ -1942,6 +2052,9 @@ S_filter_gets(pTHX_ register SV *sv, register PerlIO *fp, STRLEN append)
       if we already built the token before, use it.
 */
 
+#ifdef __SC__
+#pragma segment Perl_yylex
+#endif
 int
 #ifdef USE_PURE_BISON
 Perl_yylex(pTHX_ YYSTYPE *lvalp, int *lcharp)
@@ -2067,9 +2180,14 @@ Perl_yylex(pTHX)
        */
        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)))
-               yyerror(Perl_form(aTHX_ "In string, %s now must be written as \\%s",
-                            PL_tokenbuf, PL_tokenbuf));
+           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 */
@@ -2285,7 +2403,7 @@ Perl_yylex(pTHX)
   retry:
     switch (*s) {
     default:
-       if (isIDFIRST_lazy(s))
+       if (isIDFIRST_lazy_if(s,UTF))
            goto keylookup;
        Perl_croak(aTHX_ "Unrecognized character \\x%02X", *s & 255);
     case 4:
@@ -2362,6 +2480,8 @@ Perl_yylex(pTHX)
            goto retry;
        }
        do {
+           bool bof;
+           bof = PL_rsfp && (PerlIO_tell(PL_rsfp) == 0); /* *Before* read! */
            if ((s = filter_gets(PL_linestr, PL_rsfp, 0)) == Nullch) {
              fake_eof:
                if (PL_rsfp) {
@@ -2397,7 +2517,9 @@ Perl_yylex(pTHX)
                    PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
                    PL_doextract = FALSE;
                }
-           }
+           } 
+           if (bof)
+               s = swallow_bom((U8*)s);
            incline(s);
        } while (PL_doextract);
        PL_oldoldbufptr = PL_oldbufptr = PL_bufptr = PL_linestart = s;
@@ -2497,6 +2619,7 @@ Perl_yylex(pTHX)
                        *s = '#';       /* Don't try to parse shebang line */
                }
 #endif /* ALTERNATE_SHEBANG */
+#ifndef MACOS_TRADITIONAL
                if (!d &&
                    *s == '#' &&
                    ipathend > ipath &&
@@ -2524,13 +2647,14 @@ Perl_yylex(pTHX)
                    PerlProc_execv(ipath, newargv);
                    Perl_croak(aTHX_ "Can't exec %s", ipath);
                }
+#endif
                if (d) {
                    U32 oldpdb = PL_perldb;
                    bool oldn = PL_minus_n;
                    bool oldp = PL_minus_p;
 
                    while (*d && !isSPACE(*d)) d++;
-                   while (*d == ' ' || *d == '\t') d++;
+                   while (SPACE_OR_TAB(*d)) d++;
 
                    if (*d++ == '-') {
                        do {
@@ -2542,8 +2666,8 @@ Perl_yylex(pTHX)
                            }
                            d = moreswitches(d);
                        } while (d);
-                       if (PERLDB_LINE && !oldpdb ||
-                           ( PL_minus_n || PL_minus_p ) && !(oldn || oldp) )
+                       if ((PERLDB_LINE && !oldpdb) ||
+                           ((PL_minus_n || PL_minus_p) && !(oldn || oldp)))
                              /* if we have already added "LINE: while (<>) {",
                                 we must not do it again */
                        {
@@ -2569,14 +2693,22 @@ Perl_yylex(pTHX)
 #ifdef PERL_STRICT_CR
        Perl_warn(aTHX_ "Illegal character \\%03o (carriage return)", '\r');
        Perl_croak(aTHX_ 
-      "(Maybe you didn't strip carriage returns after a network transfer?)\n");
+      "\t(Maybe you didn't strip carriage returns after a network transfer?)\n");
 #endif
     case ' ': case '\t': case '\f': case 013:
+#ifdef MACOS_TRADITIONAL
+    case '\312':
+#endif
        s++;
        goto retry;
     case '#':
     case '\n':
        if (PL_lex_state != LEX_NORMAL || (PL_in_eval && !PL_rsfp)) {
+           if (*s == '#' && s == PL_linestart && PL_in_eval && !PL_rsfp) {
+               /* handle eval qq[#line 1 "foo"\n ...] */
+               CopLINE_dec(PL_curcop);
+               incline(s);
+           }
            d = PL_bufend;
            while (s < d && *s != '\n')
                s++;
@@ -2600,7 +2732,7 @@ Perl_yylex(pTHX)
            PL_bufptr = s;
            tmp = *s++;
 
-           while (s < PL_bufend && (*s == ' ' || *s == '\t'))
+           while (s < PL_bufend && SPACE_OR_TAB(*s))
                s++;
 
            if (strnEQ(s,"=>",2)) {
@@ -2653,7 +2785,7 @@ Perl_yylex(pTHX)
        else if (*s == '>') {
            s++;
            s = skipspace(s);
-           if (isIDFIRST_lazy(s)) {
+           if (isIDFIRST_lazy_if(s,UTF)) {
                s = force_word(s,METHOD,FALSE,TRUE,FALSE);
                TOKEN(ARROW);
            }
@@ -2749,8 +2881,23 @@ Perl_yylex(pTHX)
         grabattrs:
            s = skipspace(s);
            attrs = Nullop;
-           while (isIDFIRST_lazy(s)) {
+           while (isIDFIRST_lazy_if(s,UTF)) {
                d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
+               if (isLOWER(*s) && (tmp = keyword(PL_tokenbuf, len))) {
+                   if (tmp < 0) tmp = -tmp;
+                   switch (tmp) {
+                   case KEY_or:
+                   case KEY_and:
+                   case KEY_for:
+                   case KEY_unless:
+                   case KEY_if:
+                   case KEY_while:
+                   case KEY_until:
+                       goto got_attrs;
+                   default:
+                       break;
+                   }
+               }
                if (*d == '(') {
                    d = scan_str(d,TRUE,TRUE);
                    if (!d) {
@@ -2782,11 +2929,13 @@ Perl_yylex(pTHX)
                                                newSVpvn(s, len)));
                }
                s = skipspace(d);
-               while (*s == ',')
+               if (*s == ':' && s[1] != ':')
                    s = skipspace(s+1);
+               else if (s == d)
+                   break;      /* require real whitespace or :'s */
            }
-           tmp = (PL_expect == XOPERATOR ? '=' : '{'); /*'}' for vi */
-           if (*s != ';' && *s != tmp) {
+           tmp = (PL_expect == XOPERATOR ? '=' : '{'); /*'}(' for vi */
+           if (*s != ';' && *s != tmp && (tmp != '=' || *s != ')')) {
                char q = ((*s == '\'') ? '"' : '\'');
                /* If here for an expression, and parsed no attrs, back off. */
                if (tmp == '=' && !attrs) {
@@ -2806,6 +2955,7 @@ Perl_yylex(pTHX)
                    op_free(attrs);
                OPERATOR(':');
            }
+       got_attrs:
            if (attrs) {
                PL_nextval[PL_nexttoke].opval = attrs;
                force_next(THING);
@@ -2821,8 +2971,7 @@ Perl_yylex(pTHX)
            PL_expect = XTERM;
        TOKEN('(');
     case ';':
-       if (CopLINE(PL_curcop) < PL_copline)
-           PL_copline = CopLINE(PL_curcop);
+       CLINE;
        tmp = *s++;
        OPERATOR(tmp);
     case ')':
@@ -2866,20 +3015,20 @@ Perl_yylex(pTHX)
                PL_lex_brackstack[PL_lex_brackets++] = XOPERATOR;
            OPERATOR(HASHBRACK);
        case XOPERATOR:
-           while (s < PL_bufend && (*s == ' ' || *s == '\t'))
+           while (s < PL_bufend && SPACE_OR_TAB(*s))
                s++;
            d = s;
            PL_tokenbuf[0] = '\0';
            if (d < PL_bufend && *d == '-') {
                PL_tokenbuf[0] = '-';
                d++;
-               while (d < PL_bufend && (*d == ' ' || *d == '\t'))
+               while (d < PL_bufend && SPACE_OR_TAB(*d))
                    d++;
            }
-           if (d < PL_bufend && isIDFIRST_lazy(d)) {
+           if (d < PL_bufend && isIDFIRST_lazy_if(d,UTF)) {
                d = scan_word(d, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1,
                              FALSE, &len);
-               while (d < PL_bufend && (*d == ' ' || *d == '\t'))
+               while (d < PL_bufend && SPACE_OR_TAB(*d))
                    d++;
                if (*d == '}') {
                    char minus = (PL_tokenbuf[0] == '-');
@@ -2967,9 +3116,9 @@ Perl_yylex(pTHX)
                    }
                    t++;
                }
-               else if (isALNUM_lazy(t)) {
+               else if (isALNUM_lazy_if(t,UTF)) {
                    t += UTF8SKIP(t);
-                   while (t < PL_bufend && isALNUM_lazy(t))
+                   while (t < PL_bufend && isALNUM_lazy_if(t,UTF))
                         t += UTF8SKIP(t);
                }
                while (t < PL_bufend && isSPACE(*t))
@@ -2999,7 +3148,7 @@ Perl_yylex(pTHX)
            yyerror("Unmatched right curly bracket");
        else
            PL_expect = (expectation)PL_lex_brackstack[--PL_lex_brackets];
-       if (PL_lex_brackets < PL_lex_formbrack)
+       if (PL_lex_brackets < PL_lex_formbrack && PL_lex_state != LEX_INTERPNORMAL)
            PL_lex_formbrack = 0;
        if (PL_lex_state == LEX_INTERPNORMAL) {
            if (PL_lex_brackets == 0) {
@@ -3029,7 +3178,9 @@ Perl_yylex(pTHX)
            AOPERATOR(ANDAND);
        s--;
        if (PL_expect == XOPERATOR) {
-           if (ckWARN(WARN_SEMICOLON) && isIDFIRST_lazy(s) && PL_bufptr == PL_linestart) {
+           if (ckWARN(WARN_SEMICOLON)
+               && isIDFIRST_lazy_if(s,UTF) && PL_bufptr == PL_linestart)
+           {
                CopLINE_dec(PL_curcop);
                Perl_warner(aTHX_ WARN_SEMICOLON, PL_warn_nosemi);
                CopLINE_inc(PL_curcop);
@@ -3094,9 +3245,9 @@ Perl_yylex(pTHX)
        if (PL_lex_brackets < PL_lex_formbrack) {
            char *t;
 #ifdef PERL_STRICT_CR
-           for (t = s; *t == ' ' || *t == '\t'; t++) ;
+           for (t = s; SPACE_OR_TAB(*t); t++) ;
 #else
-           for (t = s; *t == ' ' || *t == '\t' || *t == '\r'; t++) ;
+           for (t = s; SPACE_OR_TAB(*t) || *t == '\r'; t++) ;
 #endif
            if (*t == '\n' || *t == '#') {
                s--;
@@ -3159,7 +3310,7 @@ Perl_yylex(pTHX)
            }
        }
 
-       if (s[1] == '#' && (isIDFIRST_lazy(s+2) || strchr("{$:+-", s[2]))) {
+       if (s[1] == '#' && (isIDFIRST_lazy_if(s+2,UTF) || strchr("{$:+-", s[2]))) {
            PL_tokenbuf[0] = '@';
            s = scan_ident(s + 1, PL_bufend, PL_tokenbuf + 1,
                           sizeof PL_tokenbuf - 1, FALSE);
@@ -3186,7 +3337,7 @@ Perl_yylex(pTHX)
        /* This kludge not intended to be bulletproof. */
        if (PL_tokenbuf[1] == '[' && !PL_tokenbuf[2]) {
            yylval.opval = newSVOP(OP_CONST, 0,
-                                  newSViv((IV)PL_compiling.cop_arybase));
+                                  newSViv(PL_compiling.cop_arybase));
            yylval.opval->op_private = OPpCONST_ARYBASE;
            TERM(THING);
        }
@@ -3202,7 +3353,7 @@ Perl_yylex(pTHX)
                PL_tokenbuf[0] = '@';
                if (ckWARN(WARN_SYNTAX)) {
                    for(t = s + 1;
-                       isSPACE(*t) || isALNUM_lazy(t) || *t == '$';
+                       isSPACE(*t) || isALNUM_lazy_if(t,UTF) || *t == '$';
                        t++) ;
                    if (*t++ == ',') {
                        PL_bufptr = skipspace(PL_bufptr);
@@ -3222,7 +3373,7 @@ Perl_yylex(pTHX)
                    char tmpbuf[sizeof PL_tokenbuf];
                    STRLEN len;
                    for (t++; isSPACE(*t); t++) ;
-                   if (isIDFIRST_lazy(t)) {
+                   if (isIDFIRST_lazy_if(t,UTF)) {
                        t = scan_word(t, tmpbuf, sizeof tmpbuf, TRUE, &len);
                        for (; isSPACE(*t); t++) ;
                        if (*t == ';' && get_cv(tmpbuf, FALSE))
@@ -3240,12 +3391,12 @@ Perl_yylex(pTHX)
                PL_expect = XOPERATOR;
            else if (strchr("$@\"'`q", *s))
                PL_expect = XTERM;              /* e.g. print $fh "foo" */
-           else if (strchr("&*<%", *s) && isIDFIRST_lazy(s+1))
+           else if (strchr("&*<%", *s) && isIDFIRST_lazy_if(s+1,UTF))
                PL_expect = XTERM;              /* e.g. print $fh &sub */
-           else if (isIDFIRST_lazy(s)) {
+           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)) {
+               if ((tmp = keyword(tmpbuf, len))) {
                    /* binary operators exclude handle interpretations */
                    switch (tmp) {
                    case -KEY_x:
@@ -3300,7 +3451,7 @@ Perl_yylex(pTHX)
            if (ckWARN(WARN_SYNTAX)) {
                if (*s == '[' || *s == '{') {
                    char *t = s + 1;
-                   while (*t && (isALNUM_lazy(t) || strchr(" \t$#+-'\"", *t)))
+                   while (*t && (isALNUM_lazy_if(t,UTF) || strchr(" \t$#+-'\"", *t)))
                        t++;
                    if (*t == '}' || *t == ']') {
                        t++;
@@ -3321,7 +3472,8 @@ Perl_yylex(pTHX)
            /* Disable warning on "study /blah/" */
            if (PL_oldoldbufptr == PL_last_uni 
                && (*PL_last_uni != 's' || s - PL_last_uni < 5 
-                   || memNE(PL_last_uni, "study", 5) || isALNUM_lazy(PL_last_uni+5)))
+                   || memNE(PL_last_uni, "study", 5)
+                   || isALNUM_lazy_if(PL_last_uni+5,UTF)))
                check_uni();
            s = scan_pat(s,OP_MATCH);
            TERM(sublex_start());
@@ -3426,16 +3578,28 @@ Perl_yylex(pTHX)
        OPERATOR(REFGEN);
 
     case 'v':
-       if (isDIGIT(s[1]) && PL_expect == XTERM) {
+       if (isDIGIT(s[1]) && PL_expect != XOPERATOR) {
            char *start = s;
            start++;
            start++;
-           while (isDIGIT(*start))
+           while (isDIGIT(*start) || *start == '_')
                start++;
            if (*start == '.' && isDIGIT(start[1])) {
                s = scan_num(s);
                TERM(THING);
            }
+           /* avoid v123abc() or $h{v1}, allow C<print v10;> */
+           else if (!isALPHA(*start) && (PL_expect == XTERM || PL_expect == XREF)) {
+               char c = *start;
+               GV *gv;
+               *start = '\0';
+               gv = gv_fetchpv(s, FALSE, SVt_PVCV);
+               *start = c;
+               if (!gv) {
+                   s = scan_num(s);
+                   TERM(THING);
+               }
+           }
        }
        goto keylookup;
     case 'x':
@@ -3474,7 +3638,6 @@ Perl_yylex(pTHX)
     case 'z': case 'Z':
 
       keylookup: {
-       STRLEN n_a;
        gv = Nullgv;
        gvp = 0;
 
@@ -3482,10 +3645,10 @@ Perl_yylex(pTHX)
        s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
 
        /* Some keywords can be followed by any delimiter, including ':' */
-       tmp = (len == 1 && strchr("msyq", PL_tokenbuf[0]) ||
-              len == 2 && ((PL_tokenbuf[0] == 't' && PL_tokenbuf[1] == 'r') ||
-                           (PL_tokenbuf[0] == 'q' &&
-                            strchr("qwxr", PL_tokenbuf[1]))));
+       tmp = ((len == 1 && strchr("msyq", PL_tokenbuf[0])) ||
+              (len == 2 && ((PL_tokenbuf[0] == 't' && PL_tokenbuf[1] == 'r') ||
+                            (PL_tokenbuf[0] == 'q' &&
+                             strchr("qwxr", PL_tokenbuf[1])))));
 
        /* x::* is just a word, unless x is "CORE" */
        if (!tmp && *s == ':' && s[1] == ':' && strNE(PL_tokenbuf, "CORE"))
@@ -3508,7 +3671,7 @@ Perl_yylex(pTHX)
        tmp = keyword(PL_tokenbuf, len);
 
        /* Is this a word before a => operator? */
-       if (strnEQ(d,"=>",2)) {
+       if (*d == '=' && d[1] == '>') {
            CLINE;
            yylval.opval = (OP*)newSVOP(OP_CONST, 0, newSVpv(PL_tokenbuf,0));
            yylval.opval->op_private = OPpCONST_BARE;
@@ -3568,7 +3731,7 @@ Perl_yylex(pTHX)
 
                /* Get the rest if it looks like a package qualifier */
 
-               if (*s == '\'' || *s == ':' && s[1] == ':') {
+               if (*s == '\'' || (*s == ':' && s[1] == ':')) {
                    STRLEN morelen;
                    s = scan_word(s, PL_tokenbuf + len, sizeof PL_tokenbuf - len,
                                  TRUE, &morelen);
@@ -3595,8 +3758,8 @@ Perl_yylex(pTHX)
                if (len > 2 &&
                    PL_tokenbuf[len - 2] == ':' && PL_tokenbuf[len - 1] == ':')
                {
-                   if (ckWARN(WARN_UNSAFE) && ! gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVHV))
-                       Perl_warner(aTHX_ WARN_UNSAFE, 
+                   if (ckWARN(WARN_BAREWORD) && ! gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVHV))
+                       Perl_warner(aTHX_ WARN_BAREWORD, 
                            "Bareword \"%s\" refers to nonexistent package",
                             PL_tokenbuf);
                    len -= 2;
@@ -3647,7 +3810,7 @@ Perl_yylex(pTHX)
 
                    /* Two barewords in a row may indicate method call. */
 
-                   if ((isIDFIRST_lazy(s) || *s == '$') && (tmp=intuit_method(s,gv)))
+                   if ((isIDFIRST_lazy_if(s,UTF) || *s == '$') && (tmp=intuit_method(s,gv)))
                        return tmp;
 
                    /* If not a declared subroutine, it's an indirect object. */
@@ -3663,14 +3826,22 @@ Perl_yylex(pTHX)
                    }
                }
 
-               /* If followed by a paren, it's certainly a subroutine. */
 
                PL_expect = XOPERATOR;
                s = skipspace(s);
+
+               /* Is this a word before a => operator? */
+               if (*s == '=' && s[1] == '>') {
+                   CLINE;
+                   sv_setpv(((SVOP*)yylval.opval)->op_sv, PL_tokenbuf);
+                   TERM(WORD);
+               }
+
+               /* If followed by a paren, it's certainly a subroutine. */
                if (*s == '(') {
                    CLINE;
                    if (gv && GvCVu(gv)) {
-                       for (d = s + 1; *d == ' ' || *d == '\t'; d++) ;
+                       for (d = s + 1; SPACE_OR_TAB(*d); d++) ;
                        if (*d == ')' && (sv = cv_const_sv(GvCV(gv)))) {
                            s = d + 1;
                            goto its_constant;
@@ -3693,7 +3864,7 @@ Perl_yylex(pTHX)
 
                /* If followed by a bareword, see if it looks like indir obj. */
 
-               if ((isIDFIRST_lazy(s) || *s == '$') && (tmp = intuit_method(s,gv)))
+               if ((isIDFIRST_lazy_if(s,UTF) || *s == '$') && (tmp = intuit_method(s,gv)))
                    return tmp;
 
                /* Not a method, so call it a subroutine (if defined) */
@@ -3842,9 +4013,9 @@ Perl_yylex(pTHX)
        case KEY_AUTOLOAD:
        case KEY_DESTROY:
        case KEY_BEGIN:
-       case KEY_END:
-       case KEY_STOP:
+       case KEY_CHECK:
        case KEY_INIT:
+       case KEY_END:
            if (PL_expect == XSTATE) {
                s = PL_bufptr;
                goto really_sub;
@@ -3856,7 +4027,8 @@ Perl_yylex(pTHX)
                s += 2;
                d = s;
                s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
-               tmp = keyword(PL_tokenbuf, len);
+               if (!(tmp = keyword(PL_tokenbuf, len)))
+                   Perl_croak(aTHX_ "CORE::%s is not a keyword", PL_tokenbuf);
                if (tmp < 0)
                    tmp = -tmp;
                goto reserved_word;
@@ -3882,7 +4054,7 @@ Perl_yylex(pTHX)
            LOP(OP_BIND,XTERM);
 
        case KEY_binmode:
-           UNI(OP_BINMODE);
+           LOP(OP_BINMODE,XTERM);
 
        case KEY_bless:
            LOP(OP_BLESS,XTERM);
@@ -3919,11 +4091,11 @@ Perl_yylex(pTHX)
            LOP(OP_CRYPT,XTERM);
 
        case KEY_chmod:
-           if (ckWARN(WARN_OCTAL)) {
+           if (ckWARN(WARN_CHMOD)) {
                for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ;
                if (*d != '0' && isDIGIT(*d))
-                   Perl_warner(aTHX_ WARN_OCTAL,
-                               "chmod: mode argument is missing initial 0");
+                   Perl_warner(aTHX_ WARN_CHMOD,
+                               "chmod() mode argument is missing initial 0");
            }
            LOP(OP_CHMOD,XTERM);
 
@@ -4027,7 +4199,7 @@ Perl_yylex(pTHX)
        case KEY_foreach:
            yylval.ival = CopLINE(PL_curcop);
            s = skipspace(s);
-           if (PL_expect == XSTATE && isIDFIRST_lazy(s)) {
+           if (PL_expect == XSTATE && isIDFIRST_lazy_if(s,UTF)) {
                char *p = s;
                if ((PL_bufend - p) >= 3 &&
                    strnEQ(p, "my", 2) && isSPACE(*(p + 2)))
@@ -4036,7 +4208,7 @@ Perl_yylex(pTHX)
                    strnEQ(p, "our", 3) && isSPACE(*(p + 3)))
                    p += 3;
                p = skipspace(p);
-               if (isIDFIRST_lazy(p)) {
+               if (isIDFIRST_lazy_if(p,UTF)) {
                    p = scan_ident(p, PL_bufend,
                        PL_tokenbuf, sizeof PL_tokenbuf, TRUE);
                    p = skipspace(p);
@@ -4068,7 +4240,7 @@ Perl_yylex(pTHX)
            Rop(OP_SGE);
 
        case KEY_grep:
-           LOP(OP_GREPSTART, *s == '(' ? XTERM : XREF);
+           LOP(OP_GREPSTART, XREF);
 
        case KEY_goto:
            s = force_word(s,WORD,TRUE,FALSE,FALSE);
@@ -4230,7 +4402,7 @@ Perl_yylex(pTHX)
            TERM(sublex_start());
 
        case KEY_map:
-           LOP(OP_MAPSTART, *s == '(' ? XTERM : XREF);
+           LOP(OP_MAPSTART, XREF);
 
        case KEY_mkdir:
            LOP(OP_MKDIR,XTERM);
@@ -4251,11 +4423,11 @@ Perl_yylex(pTHX)
        case KEY_my:
            PL_in_my = tmp;
            s = skipspace(s);
-           if (isIDFIRST_lazy(s)) {
+           if (isIDFIRST_lazy_if(s,UTF)) {
                s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len);
                if (len == 3 && strnEQ(PL_tokenbuf, "sub", 3))
                    goto really_sub;
-               PL_in_my_stash = gv_stashpv(PL_tokenbuf, FALSE);
+               PL_in_my_stash = find_in_my_stash(PL_tokenbuf, len);
                if (!PL_in_my_stash) {
                    char tmpbuf[1024];
                    PL_bufptr = s;
@@ -4289,12 +4461,12 @@ Perl_yylex(pTHX)
 
        case KEY_open:
            s = skipspace(s);
-           if (isIDFIRST_lazy(s)) {
+           if (isIDFIRST_lazy_if(s,UTF)) {
                char *t;
-               for (d = s; isALNUM_lazy(d); d++) ;
+               for (d = s; isALNUM_lazy_if(d,UTF); d++) ;
                t = skipspace(d);
-               if (strchr("|&*+-=!?:.", *t) && ckWARN_d(WARN_AMBIGUOUS))
-                   Perl_warner(aTHX_ WARN_AMBIGUOUS,
+               if (strchr("|&*+-=!?:.", *t) && ckWARN_d(WARN_PRECEDENCE))
+                   Perl_warner(aTHX_ WARN_PRECEDENCE,
                           "Precedence problem: open %.*s should be open(%.*s)",
                            d-s,s, d-s,s);
            }
@@ -4366,15 +4538,15 @@ Perl_yylex(pTHX)
                    for (; isSPACE(*d) && len; --len, ++d) ;
                    if (len) {
                        char *b = d;
-                       if (!warned && ckWARN(WARN_SYNTAX)) {
+                       if (!warned && ckWARN(WARN_QW)) {
                            for (; !isSPACE(*d) && len; --len, ++d) {
                                if (*d == ',') {
-                                   Perl_warner(aTHX_ WARN_SYNTAX,
+                                   Perl_warner(aTHX_ WARN_QW,
                                        "Possible attempt to separate words with commas");
                                    ++warned;
                                }
                                else if (*d == '#') {
-                                   Perl_warner(aTHX_ WARN_SYNTAX,
+                                   Perl_warner(aTHX_ WARN_QW,
                                        "Possible attempt to put comments in qw() list");
                                    ++warned;
                                }
@@ -4384,7 +4556,7 @@ Perl_yylex(pTHX)
                            for (; !isSPACE(*d) && len; --len, ++d) ;
                        }
                        words = append_elem(OP_LIST, words,
-                                           newSVOP(OP_CONST, 0, newSVpvn(b, d-b)));
+                                           newSVOP(OP_CONST, 0, tokeq(newSVpvn(b, d-b))));
                    }
                }
                if (words) {
@@ -4430,7 +4602,7 @@ Perl_yylex(pTHX)
            else {
                *PL_tokenbuf = '\0';
                s = force_word(s,WORD,TRUE,TRUE,FALSE);
-               if (isIDFIRST_lazy(PL_tokenbuf))
+               if (isIDFIRST_lazy_if(PL_tokenbuf,UTF))
                    gv_stashpvn(PL_tokenbuf, strlen(PL_tokenbuf), TRUE);
                else if (*s == '<')
                    yyerror("<> should be quotes");
@@ -4621,7 +4793,7 @@ Perl_yylex(pTHX)
 
                s = skipspace(s);
 
-               if (isIDFIRST_lazy(s) || *s == '\'' ||
+               if (isIDFIRST_lazy_if(s,UTF) || *s == '\'' ||
                    (*s == ':' && s[1] == ':'))
                {
                    PL_expect = XBLOCK;
@@ -4781,10 +4953,10 @@ Perl_yylex(pTHX)
            LOP(OP_UTIME,XTERM);
 
        case KEY_umask:
-           if (ckWARN(WARN_OCTAL)) {
+           if (ckWARN(WARN_UMASK)) {
                for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ;
                if (*d != '0' && isDIGIT(*d)) 
-                   Perl_warner(aTHX_ WARN_OCTAL,
+                   Perl_warner(aTHX_ WARN_UMASK,
                                "umask: argument is missing initial 0");
            }
            UNI(OP_UMASK);
@@ -4863,6 +5035,9 @@ Perl_yylex(pTHX)
        }
     }}
 }
+#ifdef __SC__
+#pragma segment Main
+#endif
 
 I32
 Perl_keyword(pTHX_ register char *d, I32 len)
@@ -4905,6 +5080,7 @@ Perl_keyword(pTHX_ register char *d, I32 len)
        break;
     case 'C':
        if (strEQ(d,"CORE"))                    return -KEY_CORE;
+       if (strEQ(d,"CHECK"))                   return KEY_CHECK;
        break;
     case 'c':
        switch (len) {
@@ -5288,9 +5464,6 @@ Perl_keyword(pTHX_ register char *d, I32 len)
            break;
        }
        break;
-    case 'S':
-       if (strEQ(d,"STOP"))                    return KEY_STOP;
-       break;
     case 's':
        switch (d[1]) {
        case 0:                                 return KEY_s;
@@ -5513,9 +5686,9 @@ S_checkcomma(pTHX_ register char *s, char *name, char *what)
        s++;
     while (s < PL_bufend && isSPACE(*s))
        s++;
-    if (isIDFIRST_lazy(s)) {
+    if (isIDFIRST_lazy_if(s,UTF)) {
        w = s++;
-       while (isALNUM_lazy(s))
+       while (isALNUM_lazy_if(s,UTF))
            s++;
        while (s < PL_bufend && isSPACE(*s))
            s++;
@@ -5538,37 +5711,35 @@ S_checkcomma(pTHX_ register char *s, char *name, char *what)
 
 STATIC SV *
 S_new_constant(pTHX_ char *s, STRLEN len, const char *key, SV *sv, SV *pv,
-              const char *type) 
+              const char *type)
 {
     dSP;
     HV *table = GvHV(PL_hintgv);                /* ^H */
     SV *res;
     SV **cvp;
     SV *cv, *typesv;
-    const char *why, *why1, *why2;
+    const char *why1, *why2, *why3;
     
-    if (!(PL_hints & HINT_LOCALIZE_HH)) {
+    if (!table || !(PL_hints & HINT_LOCALIZE_HH)) {
        SV *msg;
        
-       why = "%^H is not localized";
-    report_short:
-       why1 = why2 = "";
+       why1 = "%^H is not consistent";
+       why2 = strEQ(key,"charnames")
+              ? " (missing \"use charnames ...\"?)"
+              : "";
+       why3 = "";
     report:
        msg = Perl_newSVpvf(aTHX_ "constant(%s): %s%s%s", 
-                           (type ? type: "undef"), why1, why2, why);
+                           (type ? type: "undef"), why1, why2, why3);
        yyerror(SvPVX(msg));
        SvREFCNT_dec(msg);
        return sv;
     }
-    if (!table) {
-       why = "%^H is not defined";
-       goto report_short;
-    }
     cvp = hv_fetch(table, key, strlen(key), FALSE);
     if (!cvp || !SvOK(*cvp)) {
-       why = "} is not defined";
        why1 = "$^H{";
        why2 = key;
+       why3 = "} is not defined";
        goto report;
     }
     sv_2mortal(sv);                    /* Parent created it permanently */
@@ -5598,8 +5769,7 @@ S_new_constant(pTHX_ char *s, STRLEN len, const char *key, SV *sv, SV *pv,
     SPAGAIN ;
     
     /* Check the eval first */
-    if (!PL_in_eval && SvTRUE(ERRSV))
-    {
+    if (!PL_in_eval && SvTRUE(ERRSV)) {
        STRLEN n_a;
        sv_catpv(ERRSV, "Propagated");
        yyerror(SvPV(ERRSV, n_a)); /* Duplicates the message inside eval */
@@ -5617,14 +5787,14 @@ S_new_constant(pTHX_ char *s, STRLEN len, const char *key, SV *sv, SV *pv,
     POPSTACK;
     
     if (!SvOK(res)) {
-       why = "}} did not return a defined value";
        why1 = "Call to &{$^H{";
        why2 = key;
+       why3 = "}} did not return a defined value";
        sv = res;
        goto report;
-     }
+    }
 
-     return res;
+    return res;
 }
   
 STATIC char *
@@ -5637,7 +5807,7 @@ S_scan_word(pTHX_ register char *s, char *dest, STRLEN destlen, int allow_packag
            Perl_croak(aTHX_ ident_too_long);
        if (isALNUM(*s))        /* UTF handled below */
            *d++ = *s++;
-       else if (*s == '\'' && allow_package && isIDFIRST_lazy(s+1)) {
+       else if (*s == '\'' && allow_package && isIDFIRST_lazy_if(s+1,UTF)) {
            *d++ = ':';
            *d++ = ':';
            s++;
@@ -5689,7 +5859,7 @@ S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN des
                Perl_croak(aTHX_ ident_too_long);
            if (isALNUM(*s))    /* UTF handled below */
                *d++ = *s++;
-           else if (*s == '\'' && isIDFIRST_lazy(s+1)) {
+           else if (*s == '\'' && isIDFIRST_lazy_if(s+1,UTF)) {
                *d++ = ':';
                *d++ = ':';
                s++;
@@ -5720,7 +5890,7 @@ S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN des
        return s;
     }
     if (*s == '$' && s[1] &&
-       (isALNUM_lazy(s+1) || strchr("${", s[1]) || strnEQ(s+1,"::",2)) )
+       (isALNUM_lazy_if(s+1,UTF) || strchr("${", s[1]) || strnEQ(s+1,"::",2)) )
     {
        return s;
     }
@@ -5741,17 +5911,17 @@ S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN des
        if (isSPACE(s[-1])) {
            while (s < send) {
                char ch = *s++;
-               if (ch != ' ' && ch != '\t') {
+               if (!SPACE_OR_TAB(ch)) {
                    *d = ch;
                    break;
                }
            }
        }
-       if (isIDFIRST_lazy(d)) {
+       if (isIDFIRST_lazy_if(d,UTF)) {
            d++;
            if (UTF) {
                e = s;
-               while (e < send && isALNUM_lazy(e) || *e == ':') {
+               while ((e < send && isALNUM_lazy_if(e,UTF)) || *e == ':') {
                    e += UTF8SKIP(e);
                    while (e < send && *e & 0x80 && is_utf8_mark((U8*)e))
                        e += UTF8SKIP(e);
@@ -5767,7 +5937,7 @@ S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN des
                    Perl_croak(aTHX_ ident_too_long);
            }
            *d = '\0';
-           while (s < send && (*s == ' ' || *s == '\t')) s++;
+           while (s < send && SPACE_OR_TAB(*s)) s++;
            if ((*s == '[' || (*s == '{' && strNE(dest, "sub")))) {
                dTHR;                   /* only for ckWARN */
                if (ckWARN(WARN_AMBIGUOUS) && keyword(dest, d - dest)) {
@@ -5977,45 +6147,20 @@ S_scan_trans(pTHX_ char *start)
        Perl_croak(aTHX_ "Transliteration replacement not terminated");
     }
 
-    if (UTF) {
-       o = newSVOP(OP_TRANS, 0, 0);
-       utf8 = OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF;
-    }
-    else {
-       New(803,tbl,256,short);
-       o = newPVOP(OP_TRANS, 0, (char*)tbl);
-       utf8 = 0;
-    }
+    New(803,tbl,256,short);
+    o = newPVOP(OP_TRANS, 0, (char*)tbl);
 
     complement = del = squash = 0;
-    while (strchr("cdsCU", *s)) {
+    while (strchr("cds", *s)) {
        if (*s == 'c')
            complement = OPpTRANS_COMPLEMENT;
        else if (*s == 'd')
            del = OPpTRANS_DELETE;
        else if (*s == 's')
            squash = OPpTRANS_SQUASH;
-       else {
-           switch (count++) {
-           case 0:
-               if (*s == 'C')
-                   utf8 &= ~OPpTRANS_FROM_UTF;
-               else
-                   utf8 |= OPpTRANS_FROM_UTF;
-               break;
-           case 1:
-               if (*s == 'C')
-                   utf8 &= ~OPpTRANS_TO_UTF;
-               else
-                   utf8 |= OPpTRANS_TO_UTF;
-               break;
-           default: 
-               Perl_croak(aTHX_ "Too many /C and /U options");
-           }
-       }
        s++;
     }
-    o->op_private = del|squash|complement|utf8;
+    o->op_private = del|squash|complement;
 
     PL_lex_op = o;
     yylval.ival = OP_TRANS;
@@ -6041,7 +6186,7 @@ S_scan_heredoc(pTHX_ register char *s)
     e = PL_tokenbuf + sizeof PL_tokenbuf - 1;
     if (!outer)
        *d++ = '\n';
-    for (peek = s; *peek == ' ' || *peek == '\t'; peek++) ;
+    for (peek = s; SPACE_OR_TAB(*peek); peek++) ;
     if (*peek && strchr("`'\"",*peek)) {
        s = peek;
        term = *s++;
@@ -6055,9 +6200,9 @@ S_scan_heredoc(pTHX_ register char *s)
            s++, term = '\'';
        else
            term = '"';
-       if (!isALNUM_lazy(s))
+       if (!isALNUM_lazy_if(s,UTF))
            deprecate("bare << to mean <<\"\"");
-       for (; isALNUM_lazy(s); s++) {
+       for (; isALNUM_lazy_if(s,UTF); s++) {
            if (d < e)
                *d++ = *s;
        }
@@ -6268,7 +6413,7 @@ S_scan_inputsymbol(pTHX_ char *start)
     if (*d == '$' && d[1]) d++;
 
     /* allow <Pkg'VALUE> or <Pkg::VALUE> */
-    while (*d && (isALNUM_lazy(d) || *d == '\'' || *d == ':'))
+    while (*d && (isALNUM_lazy_if(d,UTF) || *d == '\'' || *d == ':'))
        d++;
 
     /* If we've tried to read what we allow filehandles to look like, and
@@ -6384,6 +6529,7 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
     register char term;                        /* terminating character */
     register char *to;                 /* current position in the sv's data */
     I32 brackets = 1;                  /* bracket nesting level */
+    bool has_utf = FALSE;              /* is there any utf8 content? */
 
     /* skip space before the delimiter */
     if (isSPACE(*s))
@@ -6394,6 +6540,9 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
 
     /* after skipping whitespace, the next character is the terminator */
     term = *s;
+    if ((term & 0x80) && UTF)
+       has_utf = TRUE;
+
     /* mark where we are */
     PL_multi_start = CopLINE(PL_curcop);
     PL_multi_open = term;
@@ -6438,6 +6587,8 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
                   have found the terminator */
                else if (*s == term)
                    break;
+               else if (!has_utf && (*s & 0x80) && UTF)
+                   has_utf = TRUE;
                *to = *s;
            }
        }
@@ -6465,6 +6616,8 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
                    break;
                else if (*s == PL_multi_open)
                    brackets++;
+               else if (!has_utf && (*s & 0x80) && UTF)
+                   has_utf = TRUE;
                *to = *s;
            }
        }
@@ -6476,7 +6629,8 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
         * this next chunk reads more into the buffer if we're not done yet
         */
 
-       if (s < PL_bufend) break;       /* handle case where we are done yet :-) */
+       if (s < PL_bufend)
+           break;              /* handle case where we are done yet :-) */
 
 #ifndef PERL_STRICT_CR
        if (to - SvPVX(sv) >= 2) {
@@ -6523,6 +6677,8 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
 
     if (keep_delims)
        sv_catpvn(sv, s, 1);
+    if (has_utf)
+       SvUTF8_on(sv);
     PL_multi_end = CopLINE(PL_curcop);
     s++;
 
@@ -6571,8 +6727,7 @@ Perl_scan_num(pTHX_ char *start)
     register char *s = start;          /* current position in buffer */
     register char *d;                  /* destination in temp buffer */
     register char *e;                  /* end of temp buffer */
-    IV tryiv;                          /* used to see if it can be an IV */
-    NV value;                          /* number read, as a double */
+    NV nv;                             /* number read, as a double */
     SV *sv = Nullsv;                   /* place to put the converted number */
     bool floatit;                      /* boolean: int or float? */
     char *lastub = 0;                  /* position of last underbar */
@@ -6796,6 +6951,11 @@ Perl_scan_num(pTHX_ char *start)
                if (*s != '_')
                    *d++ = *s;
            }
+           if (*s == '.' && isDIGIT(s[1])) {
+               /* oops, it's really a v-string, but without the "v" */
+               s = start - 1;
+               goto vstring;
+           }
        }
 
        /* read exponent part, if present */
@@ -6824,73 +6984,149 @@ Perl_scan_num(pTHX_ char *start)
        /* make an sv from the string */
        sv = NEWSV(92,0);
 
-       value = Atof(PL_tokenbuf);
+#if defined(Strtol) && defined(Strtoul)
 
-       /* 
-          See if we can make do with an integer value without loss of
-          precision.  We use I_V to cast to an int, because some
-          compilers have issues.  Then we try casting it back and see
-          if it was the same.  We only do this if we know we
-          specifically read an integer.
+       /*
+          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.
+        */
 
-          Note: if floatit is true, then we don't need to do the
-          conversion at all.
-       */
-       tryiv = I_V(value);
-       if (!floatit && (NV)tryiv == value)
-           sv_setiv(sv, tryiv);
-       else
-           sv_setnv(sv, value);
+       if (!floatit) {
+           IV iv;
+           UV uv;
+           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)
+               sv_setiv(sv, uv); /* Prefer IVs over UVs. */
+           else
+               sv_setuv(sv, uv);
+       }
+       if (floatit) {
+           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, 
                              (floatit ? "float" : "integer"),
                              sv, Nullsv, NULL);
        break;
-    /* if it starts with a v, it could be a version number */
+
+    /* if it starts with a v, it could be a v-string */
     case 'v':
+vstring:
        {
            char *pos = s;
            pos++;
-           while (isDIGIT(*pos))
+           while (isDIGIT(*pos) || *pos == '_')
                pos++;
-           if (*pos == '.' && isDIGIT(pos[1])) {
+           if (!isALPHA(*pos)) {
                UV rev;
-               U8 tmpbuf[10];
+               U8 tmpbuf[UTF8_MAXLEN];
                U8 *tmpend;
-               NV nshift = 1.0;
+               bool utf8 = FALSE;
                s++;                            /* get past 'v' */
 
                sv = NEWSV(92,5);
-               SvUPGRADE(sv, SVt_PVNV);
                sv_setpvn(sv, "", 0);
 
-               do {
-                   rev = atoi(s);
-                   s = ++pos;
-                   while (isDIGIT(*pos))
-                       pos++;
-
+               for (;;) {
+                   if (*s == '0' && isDIGIT(s[1]))
+                       yyerror("Octal number in vector unsupported");
+                   rev = 0;
+                   {
+                       /* this is atoi() that tolerates underscores */
+                       char *end = pos;
+                       UV mult = 1;
+                       while (--end >= s) {
+                           UV orev;
+                           if (*end == '_')
+                               continue;
+                           orev = rev;
+                           rev += (*end - '0') * mult;
+                           mult *= 10;
+                           if (orev > rev && ckWARN_d(WARN_OVERFLOW))
+                               Perl_warner(aTHX_ WARN_OVERFLOW,
+                                           "Integer overflow in decimal number");
+                       }
+                   }
                    tmpend = uv_to_utf8(tmpbuf, rev);
-                   *tmpend = '\0';
+                   utf8 = utf8 || rev > 127;
                    sv_catpvn(sv, (const char*)tmpbuf, tmpend - tmpbuf);
-                   if (rev > 0)
-                       SvNVX(sv) += (NV)rev/nshift;
-                   nshift *= 1000;
-               } while (*pos == '.' && isDIGIT(pos[1]));
-
-               rev = atoi(s);
-               s = pos;
-               tmpend = uv_to_utf8(tmpbuf, rev);
-               *tmpend = '\0';
-               sv_catpvn(sv, (const char*)tmpbuf, tmpend - tmpbuf);
-               if (rev > 0)
-                   SvNVX(sv) += (NV)rev/nshift;
+                   if (*pos == '.' && isDIGIT(pos[1]))
+                       s = ++pos;
+                   else {
+                       s = pos;
+                       break;
+                   }
+                   while (isDIGIT(*pos) || *pos == '_')
+                       pos++;
+               }
 
                SvPOK_on(sv);
-               SvNOK_on(sv);
                SvREADONLY_on(sv);
-               SvUTF8_on(sv);
+               if (utf8) {
+                   SvUTF8_on(sv);
+                   sv_utf8_downgrade(sv, TRUE);
+               }
            }
        }
        break;
@@ -6916,12 +7152,12 @@ S_scan_formline(pTHX_ register char *s)
     bool needargs = FALSE;
 
     while (!needargs) {
-       if (*s == '.' || *s == '}') {
+       if (*s == '.' || *s == /*{*/'}') {
            /*SUPPRESS 530*/
 #ifdef PERL_STRICT_CR
-           for (t = s+1;*t == ' ' || *t == '\t'; t++) ;
+           for (t = s+1;SPACE_OR_TAB(*t); t++) ;
 #else
-           for (t = s+1;*t == ' ' || *t == '\t' || *t == '\r'; t++) ;
+           for (t = s+1;SPACE_OR_TAB(*t) || *t == '\r'; t++) ;
 #endif
            if (*t == '\n' || t == PL_bufend)
                break;
@@ -7011,8 +7247,7 @@ Perl_start_subparse(pTHX_ I32 is_format, U32 flags)
     SAVEI32(PL_subline);
     save_item(PL_subname);
     SAVEI32(PL_padix);
-    SAVEVPTR(PL_curpad);
-    SAVESPTR(PL_comppad);
+    SAVECOMPPAD();
     SAVESPTR(PL_comppad_name);
     SAVESPTR(PL_compcv);
     SAVEI32(PL_comppad_name_fill);
@@ -7091,7 +7326,12 @@ Perl_yyerror(pTHX_ char *s)
     }
     else if (yychar > 255)
        where = "next token ???";
+#ifdef USE_PURE_BISON
+/*  GNU Bison sets the value -2 */
+    else if (yychar == -2) {
+#else
     else if ((yychar & 127) == 127) {
+#endif
        if (PL_lex_state == LEX_NORMAL ||
           (PL_lex_state == LEX_KNOWNEXT && PL_lex_defer == LEX_NORMAL))
            where = "at end of line";
@@ -7127,13 +7367,73 @@ Perl_yyerror(pTHX_ char *s)
        Perl_warn(aTHX_ "%"SVf, msg);
     else
        qerror(msg);
-    if (PL_error_count >= 10)
-       Perl_croak(aTHX_ "%s has too many errors.\n", CopFILE(PL_curcop));
+    if (PL_error_count >= 10) {
+       if (PL_in_eval && SvCUR(ERRSV))
+           Perl_croak(aTHX_ "%_%s has too many errors.\n",
+                      ERRSV, CopFILE(PL_curcop));
+       else
+           Perl_croak(aTHX_ "%s has too many errors.\n",
+                      CopFILE(PL_curcop));
+    }
     PL_in_my = 0;
     PL_in_my_stash = Nullhv;
     return 0;
 }
 
+STATIC char*
+S_swallow_bom(pTHX_ U8 *s)
+{
+    STRLEN slen;
+    slen = SvCUR(PL_linestr);
+    switch (*s) {
+    case 0xFF:       
+       if (s[1] == 0xFE) { 
+           /* UTF-16 little-endian */
+#ifndef PERL_NO_UTF16_FILTER
+           U8 *news;
+#endif
+           if (s[2] == 0 && s[3] == 0)  /* UTF-32 little-endian */
+               Perl_croak(aTHX_ "Unsupported script encoding");
+#ifndef PERL_NO_UTF16_FILTER
+           s += 2;
+           filter_add(utf16rev_textfilter, NULL);
+           New(898, news, (PL_bufend - (char*)s) * 3 / 2 + 1, U8);
+           PL_bufend = (char*)utf16_to_utf8((U16*)s, news,
+                                            PL_bufend - (char*)s);
+           s = news;
+#else
+           Perl_croak(aTHX_ "Unsupported script encoding");
+#endif
+       }
+       break;
+    case 0xFE:
+       if (s[1] == 0xFF) {   /* UTF-16 big-endian */
+#ifndef PERL_NO_UTF16_FILTER
+           U8 *news;
+           filter_add(utf16_textfilter, NULL);
+           New(898, news, (PL_bufend - (char*)s) * 3 / 2 + 1, U8);
+           PL_bufend = (char*)utf16_to_utf8((U16*)s, news,
+                                            PL_bufend - (char*)s);
+           s = news;
+#else
+           Perl_croak(aTHX_ "Unsupported script encoding");
+#endif
+       }
+       break;
+    case 0xEF:
+       if (slen > 2 && s[1] == 0xBB && s[2] == 0xBF) {
+           s += 3;                      /* UTF-8 */
+       }
+       break;
+    case 0:
+       if (slen > 3 && s[1] == 0 &&  /* UTF-32 big-endian */
+           s[2] == 0xFE && s[3] == 0xFF)
+       {
+           Perl_croak(aTHX_ "Unsupported script encoding");
+       }
+    }
+    return (char*)s;
+}
 
 #ifdef PERL_OBJECT
 #include "XSUB.h"
@@ -7155,3 +7455,33 @@ restore_rsfp(pTHXo_ void *f)
        PerlIO_close(PL_rsfp);
     PL_rsfp = fp;
 }
+
+#ifndef PERL_NO_UTF16_FILTER
+static I32
+utf16_textfilter(pTHXo_ int idx, SV *sv, int maxlen)
+{
+    I32 count = FILTER_READ(idx+1, sv, maxlen);
+    if (count) {
+       U8* tmps;
+       U8* tend;
+       New(898, tmps, SvCUR(sv) * 3 / 2 + 1, U8);
+       tend = utf16_to_utf8((U16*)SvPVX(sv), tmps, SvCUR(sv));
+       sv_usepvn(sv, (char*)tmps, tend - tmps);
+    }
+    return count;
+}
+
+static I32
+utf16rev_textfilter(pTHXo_ int idx, SV *sv, int maxlen)
+{
+    I32 count = FILTER_READ(idx+1, sv, maxlen);
+    if (count) {
+       U8* tmps;
+       U8* tend;
+       New(898, tmps, SvCUR(sv) * 3 / 2 + 1, U8);
+       tend = utf16_to_utf8_reversed((U16*)SvPVX(sv), tmps, SvCUR(sv));
+       sv_usepvn(sv, (char*)tmps, tend - tmps);
+    }
+    return count;
+}
+#endif