document unimplemented status of forking pipe open() on windows
[p5sagit/p5-mst-13.2.git] / toke.c
diff --git a/toke.c b/toke.c
index 8308604..e7e2174 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -28,8 +28,9 @@
 static char ident_too_long[] = "Identifier too long";
 
 static void restore_rsfp(pTHXo_ void *f);
-static void restore_expect(pTHXo_ void *e);
-static void restore_lex_expect(pTHXo_ void *e);
+
+#define XFAKEBRACK 128
+#define XENUMMASK 127
 
 #define UTF (PL_hints & HINT_UTF8)
 /*
@@ -104,7 +105,7 @@ int* yychar_pointer = NULL;
 #ifdef CLINE
 #undef CLINE
 #endif
-#define CLINE (PL_copline = (PL_curcop->cop_line < PL_copline ? PL_curcop->cop_line : PL_copline))
+#define CLINE (PL_copline = (CopLINE(PL_curcop) < PL_copline ? CopLINE(PL_curcop) : PL_copline))
 
 /*
  * Convenience functions to return different tokens and prime the
@@ -120,7 +121,7 @@ int* yychar_pointer = NULL;
  * LOOPX        : loop exiting command (goto, last, dump, etc)
  * FTST         : file test operator
  * FUN0         : zero-argument function
- * FUN1         : not used
+ * FUN1         : not used, except for not, which isn't a UNIOP
  * BOop         : bitwise or or xor
  * BAop         : bitwise and
  * SHop         : shift operator
@@ -213,8 +214,12 @@ S_no_op(pTHX_ char *what, char *s)
     char *oldbp = PL_bufptr;
     bool is_first = (PL_oldbufptr == PL_linestart);
 
-    assert(s >= oldbp);
-    PL_bufptr = s;
+    if (!s)
+       s = oldbp;
+    else {
+       assert(s >= oldbp);
+       PL_bufptr = s;
+    }
     yywarn(Perl_form(aTHX_ "%s found where operator expected", what));
     if (is_first)
        Perl_warn(aTHX_ "\t(Missing semicolon on previous line?)\n");
@@ -299,15 +304,36 @@ S_depcom(pTHX)
  * utf16-to-utf8-reversed.
  */
 
-#ifdef WIN32
+#ifdef PERL_CR_FILTER
+static void
+strip_return(SV *sv)
+{
+    register char *s = SvPVX(sv);
+    register char *e = s + SvCUR(sv);
+    /* outer loop optimized to do nothing if there are no CR-LFs */
+    while (s < e) {
+       if (*s++ == '\r' && *s == '\n') {
+           /* hit a CR-LF, need to copy the rest */
+           register char *d = s - 1;
+           *d++ = *s++;
+           while (s < e) {
+               if (*s == '\r' && s[1] == '\n')
+                   s++;
+               *d++ = *s++;
+           }
+           SvCUR(sv) -= s - d;
+           return;
+       }
+    }
+}
 
 STATIC I32
-S_win32_textfilter(pTHX_ int idx, SV *sv, int maxlen)
+S_cr_textfilter(pTHX_ int idx, SV *sv, int maxlen)
 {
- I32 count = FILTER_READ(idx+1, sv, maxlen);
- if (count > 0 && !maxlen)
-  win32_strip_return(sv);
- return count;
+    I32 count = FILTER_READ(idx+1, sv, maxlen);
+    if (count > 0 && !maxlen)
+       strip_return(sv);
+    return count;
 }
 #endif
 
@@ -356,13 +382,12 @@ Perl_lex_start(pTHX_ SV *line)
 
     SAVEI32(PL_lex_dojoin);
     SAVEI32(PL_lex_brackets);
-    SAVEI32(PL_lex_fakebrack);
     SAVEI32(PL_lex_casemods);
     SAVEI32(PL_lex_starts);
     SAVEI32(PL_lex_state);
-    SAVESPTR(PL_lex_inpat);
+    SAVEVPTR(PL_lex_inpat);
     SAVEI32(PL_lex_inwhat);
-    SAVEI16(PL_curcop->cop_line);
+    SAVECOPLINE(PL_curcop);
     SAVEPPTR(PL_bufptr);
     SAVEPPTR(PL_bufend);
     SAVEPPTR(PL_oldbufptr);
@@ -371,18 +396,18 @@ Perl_lex_start(pTHX_ SV *line)
     SAVESPTR(PL_linestr);
     SAVEPPTR(PL_lex_brackstack);
     SAVEPPTR(PL_lex_casestack);
-    SAVEDESTRUCTOR(restore_rsfp, PL_rsfp);
+    SAVEDESTRUCTOR_X(restore_rsfp, PL_rsfp);
     SAVESPTR(PL_lex_stuff);
     SAVEI32(PL_lex_defer);
+    SAVEI32(PL_sublex_info.sub_inwhat);
     SAVESPTR(PL_lex_repl);
-    SAVEDESTRUCTOR(restore_expect, PL_tokenbuf + PL_expect); /* encode as pointer */
-    SAVEDESTRUCTOR(restore_lex_expect, PL_tokenbuf + PL_expect);
+    SAVEINT(PL_expect);
+    SAVEINT(PL_lex_expect);
 
     PL_lex_state = LEX_NORMAL;
     PL_lex_defer = 0;
     PL_expect = XSTATE;
     PL_lex_brackets = 0;
-    PL_lex_fakebrack = 0;
     New(899, PL_lex_brackstack, 120, char);
     New(899, PL_lex_casestack, 12, char);
     SAVEFREEPV(PL_lex_brackstack);
@@ -395,6 +420,7 @@ Perl_lex_start(pTHX_ SV *line)
     PL_lex_repl = Nullsv;
     PL_lex_inpat = 0;
     PL_lex_inwhat = 0;
+    PL_sublex_info.sub_inwhat = 0;
     PL_linestr = line;
     if (SvREADONLY(PL_linestr))
        PL_linestr = sv_2mortal(newSVsv(PL_linestr));
@@ -428,7 +454,7 @@ Perl_lex_end(pTHX)
  * S_incline
  * This subroutine has nothing to do with tilting, whether at windmills
  * or pinball tables.  Its name is short for "increment line".  It
- * increments the current line number in PL_curcop->cop_line and checks
+ * increments the current line number in CopLINE(PL_curcop) and checks
  * to see whether the line starts with a comment of the form
  *    # line 500 "foo.pm"
  * If so, it sets the current line number and file to the values in the comment.
@@ -443,7 +469,7 @@ S_incline(pTHX_ char *s)
     char ch;
     int sawline = 0;
 
-    PL_curcop->cop_line++;
+    CopLINE_inc(PL_curcop);
     if (*s++ != '#')
        return;
     while (*s == ' ' || *s == '\t') s++;
@@ -468,11 +494,9 @@ S_incline(pTHX_ char *s)
     ch = *t;
     *t = '\0';
     if (t - s > 0)
-       PL_curcop->cop_filegv = gv_fetchfile(s);
-    else
-       PL_curcop->cop_filegv = gv_fetchfile(PL_origfilename);
+       CopFILE_set(PL_curcop, s);
     *t = ch;
-    PL_curcop->cop_line = atoi(n)-1;
+    CopLINE_set(PL_curcop, atoi(n)-1);
 }
 
 /*
@@ -492,6 +516,8 @@ S_skipspace(pTHX_ register char *s)
     }
     for (;;) {
        STRLEN prevlen;
+       SSize_t oldprevlen, oldoldprevlen;
+       SSize_t oldloplen, oldunilen;
        while (s < PL_bufend && isSPACE(*s)) {
            if (*s++ == '\n' && PL_in_eval && !PL_rsfp)
                incline(s);
@@ -514,7 +540,8 @@ S_skipspace(pTHX_ register char *s)
         * of the buffer, we're not reading from a source filter, and
         * we're in normal lexing mode
         */
-       if (s < PL_bufend || !PL_rsfp || PL_lex_state != LEX_NORMAL)
+       if (s < PL_bufend || !PL_rsfp || PL_sublex_info.sub_inwhat ||
+               PL_lex_state == LEX_FORMLINE)
            return s;
 
        /* try to recharge the buffer */
@@ -555,9 +582,22 @@ S_skipspace(pTHX_ register char *s)
        }
 
        /* not at end of file, so we only read another line */
+       /* make corresponding updates to old pointers, for yyerror() */
+       oldprevlen = PL_oldbufptr - PL_bufend;
+       oldoldprevlen = PL_oldoldbufptr - PL_bufend;
+       if (PL_last_uni)
+           oldunilen = PL_last_uni - PL_bufend;
+       if (PL_last_lop)
+           oldloplen = PL_last_lop - PL_bufend;
        PL_linestart = PL_bufptr = s + prevlen;
        PL_bufend = s + SvCUR(PL_linestr);
        s = PL_bufptr;
+       PL_oldbufptr = s + oldprevlen;
+       PL_oldoldbufptr = s + oldoldprevlen;
+       if (PL_last_uni)
+           PL_last_uni = s + oldunilen;
+       if (PL_last_lop)
+           PL_last_lop = s + oldloplen;
        incline(s);
 
        /* debugger active and we're not compiling the debugger code,
@@ -568,7 +608,7 @@ S_skipspace(pTHX_ register char *s)
 
            sv_upgrade(sv, SVt_PVMG);
            sv_setpvn(sv,PL_bufptr,PL_bufend-PL_bufptr);
-           av_store(GvAV(PL_curcop->cop_filegv),(I32)PL_curcop->cop_line,sv);
+           av_store(CopFILEAV(PL_curcop),(I32)CopLINE(PL_curcop),sv);
        }
     }
 }
@@ -651,7 +691,7 @@ S_uni(pTHX_ I32 f, char *s)
  */
 
 STATIC I32
-S_lop(pTHX_ I32 f, expectation x, char *s)
+S_lop(pTHX_ I32 f, int x, char *s)
 {
     dTHR;
     yylval.ival = f;
@@ -699,7 +739,7 @@ S_force_next(pTHX_ I32 type)
  * it calls S_force_word to stick the next word into the PL_next lookahead.
  *
  * Arguments:
- *   char *start : start of the buffer
+ *   char *start : buffer position (must be within PL_linestr)
  *   int token   : PL_next will be this type of bare word (e.g., METHOD,WORD)
  *   int check_keyword : if true, Perl checks to make sure the word isn't
  *       a keyword (do this if the word is a label, e.g. goto FOO)
@@ -782,13 +822,12 @@ S_force_version(pTHX_ char *s)
 
     s = skipspace(s);
 
-    /* default VERSION number -- GBARR */
-
-    if(isDIGIT(*s)) {
-        char *d;
-        int c;
-        for( d=s, c = 1; isDIGIT(*d) || *d == '_' || (*d == '.' && c--); d++);
-        if((*d == ';' || isSPACE(*d)) && *(skipspace(d)) != ',') {
+    if (isDIGIT(*s) || (*s == 'v' && isDIGIT(s[1]))) {
+        char *d = s;
+       if (*d == 'v')
+           d++;
+        for (; isDIGIT(*d) || *d == '_' || *d == '.'; d++);
+        if ((*d == ';' || isSPACE(*d)) && *(skipspace(d)) != ',') {
             s = scan_num(s);
             /* real VERSION number -- GBARR */
             version = yylval.opval;
@@ -941,13 +980,12 @@ S_sublex_push(pTHX)
     PL_lex_state = PL_sublex_info.super_state;
     SAVEI32(PL_lex_dojoin);
     SAVEI32(PL_lex_brackets);
-    SAVEI32(PL_lex_fakebrack);
     SAVEI32(PL_lex_casemods);
     SAVEI32(PL_lex_starts);
     SAVEI32(PL_lex_state);
-    SAVESPTR(PL_lex_inpat);
+    SAVEVPTR(PL_lex_inpat);
     SAVEI32(PL_lex_inwhat);
-    SAVEI16(PL_curcop->cop_line);
+    SAVECOPLINE(PL_curcop);
     SAVEPPTR(PL_bufptr);
     SAVEPPTR(PL_oldbufptr);
     SAVEPPTR(PL_oldoldbufptr);
@@ -966,7 +1004,6 @@ S_sublex_push(pTHX)
 
     PL_lex_dojoin = FALSE;
     PL_lex_brackets = 0;
-    PL_lex_fakebrack = 0;
     New(899, PL_lex_brackstack, 120, char);
     New(899, PL_lex_casestack, 12, char);
     SAVEFREEPV(PL_lex_brackstack);
@@ -975,7 +1012,7 @@ S_sublex_push(pTHX)
     *PL_lex_casestack = '\0';
     PL_lex_starts = 0;
     PL_lex_state = LEX_INTERPCONCAT;
-    PL_curcop->cop_line = PL_multi_start;
+    CopLINE_set(PL_curcop, PL_multi_start);
 
     PL_lex_inwhat = PL_sublex_info.sub_inwhat;
     if (PL_lex_inwhat == OP_MATCH || PL_lex_inwhat == OP_QR || PL_lex_inwhat == OP_SUBST)
@@ -1014,7 +1051,6 @@ S_sublex_done(pTHX)
        SAVEFREESV(PL_linestr);
        PL_lex_dojoin = FALSE;
        PL_lex_brackets = 0;
-       PL_lex_fakebrack = 0;
        PL_lex_casemods = 0;
        *PL_lex_casestack = '\0';
        PL_lex_starts = 0;
@@ -1037,6 +1073,7 @@ S_sublex_done(pTHX)
        PL_bufend = SvPVX(PL_linestr);
        PL_bufend += SvCUR(PL_linestr);
        PL_expect = XOPERATOR;
+       PL_sublex_info.sub_inwhat = 0;
        return ')';
     }
 }
@@ -1130,9 +1167,9 @@ S_scan_const(pTHX_ char *start)
        ? (PL_sublex_info.sub_op->op_private & (PL_lex_repl ?
                                                OPpTRANS_FROM_UTF : OPpTRANS_TO_UTF))
        : UTF;
-    char *leaveit =                    /* set of acceptably-backslashed characters */
+    const char *leaveit =      /* set of acceptably-backslashed characters */
        PL_lex_inpat
-           ? "\\.^$@AGZdDwWsSbBpPXO+*?|()-nrtfeaxcz0123456789[{]} \t\n\r\f\v#"
+           ? "\\.^$@AGZdDwWsSbBpPXC+*?|()-nrtfeaxcz0123456789[{]} \t\n\r\f\v#"
            : "";
 
     while (s < send || dorange) {
@@ -1307,7 +1344,7 @@ 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++ = scan_oct(s, 3, &len);
+               *d++ = (char)scan_oct(s, 3, &len);
                s += len;
                continue;
 
@@ -1329,7 +1366,7 @@ S_scan_const(pTHX_ char *start)
                    }
                    /* note: utf always shorter than hex */
                    d = (char*)uv_to_utf8((U8*)d,
-                                         scan_hex(s + 1, e - s - 1, &len));
+                                         (UV)scan_hex(s + 1, e - s - 1, &len));
                    s = e + 1;
                }
                else {
@@ -1345,7 +1382,7 @@ S_scan_const(pTHX_ char *start)
                            if (ckWARN(WARN_UTF8))
                                Perl_warner(aTHX_ WARN_UTF8,
                                    "\\x%.*s will produce malformed UTF-8 character; use \\x{%.*s} for that",
-                                   len,s,len,s);
+                                   (int)len,s,(int)len,s);
                        }
                        *d++ = (char)uv;
                    }
@@ -1353,8 +1390,8 @@ S_scan_const(pTHX_ char *start)
                }
                continue;
 
-           /* \C{latin small letter a} is a named character */
-           case 'C':
+           /* \N{latin small letter a} is a named character */
+           case 'N':
                ++s;
                if (*s == '{') {
                    char* e = strchr(s, '}');
@@ -1366,13 +1403,13 @@ S_scan_const(pTHX_ char *start)
                    char *why = Nullch;
  
                    if (!e) {
-                       yyerror("Missing right brace on \\C{}");
+                       yyerror("Missing right brace on \\N{}");
                        e = s - 1;
                        goto cont_scan;
                    }
                    res = newSVpvn(s + 1, e - s - 1);
                    res = new_constant( Nullch, 0, "charnames", 
-                                       res, Nullsv, "\\C{...}" );
+                                       res, Nullsv, "\\N{...}" );
                    str = SvPV(res,len);
                    if (len > e - s + 4) {
                        char *odest = SvPVX(sv);
@@ -1387,7 +1424,7 @@ S_scan_const(pTHX_ char *start)
                    s = e + 1;
                }
                else
-                   yyerror("Missing braces on \\C{}");
+                   yyerror("Missing braces on \\N{}");
                continue;
 
            /* \c is a control character */
@@ -1741,7 +1778,8 @@ 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 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.
  */
@@ -1749,10 +1787,9 @@ S_incl_perldb(pTHX)
 SV *
 Perl_filter_add(pTHX_ filter_t funcp, SV *datasv)
 {
-    if (!funcp){ /* temporary handy debugging hack to be deleted */
-       PL_filter_debug = atoi((char*)datasv);
-       return NULL;
-    }
+    if (!funcp)
+       return Nullsv;
+
     if (!PL_rsfp_filters)
        PL_rsfp_filters = newAV();
     if (!datasv)
@@ -1760,12 +1797,9 @@ Perl_filter_add(pTHX_ filter_t funcp, SV *datasv)
     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 */
-#ifdef DEBUGGING
-    if (PL_filter_debug) {
-       STRLEN n_a;
-       Perl_warn(aTHX_ "filter_add func %p (%s)", funcp, SvPV(datasv, n_a));
-    }
-#endif /* DEBUGGING */
+    IoFLAGS(datasv) |= IOf_FAKE_DIRP;
+    DEBUG_P(PerlIO_printf(Perl_debug_log, "filter_add func %p (%s)\n",
+                         funcp, SvPV_nolen(datasv)));
     av_unshift(PL_rsfp_filters, 1);
     av_store(PL_rsfp_filters, 0, datasv) ;
     return(datasv);
@@ -1776,15 +1810,15 @@ Perl_filter_add(pTHX_ filter_t funcp, SV *datasv)
 void
 Perl_filter_del(pTHX_ filter_t funcp)
 {
-#ifdef DEBUGGING
-    if (PL_filter_debug)
-       Perl_warn(aTHX_ "filter_del func %p", funcp);
-#endif /* DEBUGGING */
+    SV *datasv;
+    DEBUG_P(PerlIO_printf(Perl_debug_log, "filter_del func %p", funcp));
     if (!PL_rsfp_filters || AvFILLp(PL_rsfp_filters)<0)
        return;
     /* if filter is on top of stack (usual case) just pop it off */
-    if (IoDIRP(FILTER_DATA(AvFILLp(PL_rsfp_filters))) == (DIR*)funcp){
-       IoDIRP(FILTER_DATA(AvFILLp(PL_rsfp_filters))) = NULL;
+    datasv = FILTER_DATA(AvFILLp(PL_rsfp_filters));
+    if (IoDIRP(datasv) == (DIR*)funcp) {
+       IoFLAGS(datasv) &= ~IOf_FAKE_DIRP;
+       IoDIRP(datasv) = (DIR*)NULL;
        sv_free(av_pop(PL_rsfp_filters));
 
         return;
@@ -1809,10 +1843,8 @@ Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen)
     if (idx > AvFILLp(PL_rsfp_filters)){       /* Any more filters?    */
        /* Provide a default input filter to make life easy.    */
        /* Note that we append to the line. This is handy.      */
-#ifdef DEBUGGING
-       if (PL_filter_debug)
-           Perl_warn(aTHX_ "filter_read %d: from rsfp\n", idx);
-#endif /* DEBUGGING */
+       DEBUG_P(PerlIO_printf(Perl_debug_log,
+                             "filter_read %d: from rsfp\n", idx));
        if (maxlen) { 
            /* Want a block */
            int len ;
@@ -1840,21 +1872,16 @@ Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen)
     }
     /* Skip this filter slot if filter has been deleted        */
     if ( (datasv = FILTER_DATA(idx)) == &PL_sv_undef){
-#ifdef DEBUGGING
-       if (PL_filter_debug)
-           Perl_warn(aTHX_ "filter_read %d: skipped (filter deleted)\n", idx);
-#endif /* DEBUGGING */
+       DEBUG_P(PerlIO_printf(Perl_debug_log,
+                             "filter_read %d: skipped (filter deleted)\n",
+                             idx));
        return FILTER_READ(idx+1, buf_sv, maxlen); /* recurse */
     }
     /* Get function pointer hidden within datasv       */
     funcp = (filter_t)IoDIRP(datasv);
-#ifdef DEBUGGING
-    if (PL_filter_debug) {
-       STRLEN n_a;
-       Perl_warn(aTHX_ "filter_read %d: via function %p (%s)\n",
-               idx, funcp, SvPV(datasv,n_a));
-    }
-#endif /* DEBUGGING */
+    DEBUG_P(PerlIO_printf(Perl_debug_log,
+                         "filter_read %d: via function %p (%s)\n",
+                         idx, funcp, SvPV_nolen(datasv)));
     /* Call function. The function is expected to      */
     /* call "FILTER_READ(idx+1, buf_sv)" first.                */
     /* Return: <0:error, =0:eof, >0:not eof            */
@@ -1864,9 +1891,9 @@ Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen)
 STATIC char *
 S_filter_gets(pTHX_ register SV *sv, register PerlIO *fp, STRLEN append)
 {
-#ifdef WIN32FILTER
+#ifdef PERL_CR_FILTER
     if (!PL_rsfp_filters) {
-       filter_add(win32_textfilter,NULL);
+       filter_add(S_cr_textfilter,NULL);
     }
 #endif
     if (PL_rsfp_filters) {
@@ -1885,7 +1912,9 @@ S_filter_gets(pTHX_ register SV *sv, register PerlIO *fp, STRLEN append)
 
 #ifdef DEBUGGING
     static char* exp_name[] =
-       { "OPERATOR", "TERM", "REF", "STATE", "BLOCK", "TERMBLOCK" };
+       { "OPERATOR", "TERM", "REF", "STATE", "BLOCK", "ATTRBLOCK",
+         "ATTRTERM", "TERMBLOCK"
+       };
 #endif
 
 /*
@@ -1946,12 +1975,21 @@ Perl_yylex(pTHX)
           if it's a legal name, the OP is a PADANY.
        */
        if (PL_in_my) {
-           if (strchr(PL_tokenbuf,':'))
-               yyerror(Perl_form(aTHX_ PL_no_myglob,PL_tokenbuf));
+           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;
+               yylval.opval = newOP(OP_PADANY, 0);
+               yylval.opval->op_targ = pad_allocmy(PL_tokenbuf);
+               return PRIVATEREF;
+           }
        }
 
        /* 
@@ -1979,6 +2017,26 @@ Perl_yylex(pTHX)
            }
 #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] == '$' &&
@@ -2033,7 +2091,7 @@ Perl_yylex(pTHX)
        break;
 #endif
 
-    /* when we're already built the next token, just pull it out the queue */
+    /* when we've already built the next token, just pull it out of the queue */
     case LEX_KNOWNEXT:
        PL_nexttoke--;
        yylval = PL_nextval[PL_nexttoke];
@@ -2220,7 +2278,8 @@ Perl_yylex(pTHX)
     PL_oldoldbufptr = PL_oldbufptr;
     PL_oldbufptr = s;
     DEBUG_p( {
-       PerlIO_printf(PerlIO_stderr(), "### Tokener expecting %s at %s\n", exp_name[PL_expect], s);
+       PerlIO_printf(Perl_debug_log, "### Tokener expecting %s at %s\n",
+                     exp_name[PL_expect], s);
     } )
 
   retry:
@@ -2298,7 +2357,7 @@ Perl_yylex(pTHX)
 
                sv_upgrade(sv, SVt_PVMG);
                sv_setsv(sv,PL_linestr);
-               av_store(GvAV(PL_curcop->cop_filegv),(I32)PL_curcop->cop_line,sv);
+               av_store(CopFILEAV(PL_curcop),(I32)CopLINE(PL_curcop),sv);
            }
            goto retry;
        }
@@ -2347,10 +2406,10 @@ Perl_yylex(pTHX)
 
            sv_upgrade(sv, SVt_PVMG);
            sv_setsv(sv,PL_linestr);
-           av_store(GvAV(PL_curcop->cop_filegv),(I32)PL_curcop->cop_line,sv);
+           av_store(CopFILEAV(PL_curcop),(I32)CopLINE(PL_curcop),sv);
        }
        PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
-       if (PL_curcop->cop_line == 1) {
+       if (CopLINE(PL_curcop) == 1) {
            while (s < PL_bufend && isSPACE(*s))
                s++;
            if (*s == ':' && s[1] != ':') /* for csh execing sh scripts */
@@ -2388,7 +2447,7 @@ Perl_yylex(pTHX)
                     */
                    SV *x = GvSV(gv_fetchpv("\030", TRUE, SVt_PV));
                    assert(SvPOK(x) || SvGMAGICAL(x));
-                   if (sv_eq(x, GvSV(PL_curcop->cop_filegv))) {
+                   if (sv_eq(x, CopFILESV(PL_curcop))) {
                        sv_setpvn(x, ipath, ipathend - ipath);
                        SvSETMAGIC(x);
                    }
@@ -2400,8 +2459,24 @@ Perl_yylex(pTHX)
                 * Look for options.
                 */
                d = instr(s,"perl -");
-               if (!d)
+               if (!d) {
                    d = instr(s,"perl");
+#if defined(DOSISH)
+                   /* avoid getting into infinite loops when shebang
+                    * line contains "Perl" rather than "perl" */
+                   if (!d) {
+                       for (d = ipathend-4; d >= ipath; --d) {
+                           if ((*d == 'p' || *d == 'P')
+                               && !ibcmp(d, "perl", 4))
+                           {
+                               break;
+                           }
+                       }
+                       if (d < ipath)
+                           d = Nullch;
+                   }
+#endif
+               }
 #ifdef ALTERNATE_SHEBANG
                /*
                 * If the ALTERNATE_SHEBANG on this system starts with a
@@ -2659,6 +2734,102 @@ Perl_yylex(pTHX)
            goto just_a_word;
        }
        s++;
+       switch (PL_expect) {
+           OP *attrs;
+       case XOPERATOR:
+           if (!PL_in_my || PL_lex_state != LEX_NORMAL)
+               break;
+           PL_bufptr = s;      /* update in case we back off */
+           goto grabattrs;
+       case XATTRBLOCK:
+           PL_expect = XBLOCK;
+           goto grabattrs;
+       case XATTRTERM:
+           PL_expect = XTERMBLOCK;
+        grabattrs:
+           s = skipspace(s);
+           attrs = Nullop;
+           while (isIDFIRST_lazy(s)) {
+               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) {
+                       if (PL_lex_stuff) {
+                           SvREFCNT_dec(PL_lex_stuff);
+                           PL_lex_stuff = Nullsv;
+                       }
+                       /* MUST advance bufptr here to avoid bogus
+                          "at end of line" context messages from yyerror().
+                        */
+                       PL_bufptr = s + len;
+                       yyerror("Unterminated attribute parameter in attribute list");
+                       if (attrs)
+                           op_free(attrs);
+                       return 0;       /* EOF indicator */
+                   }
+               }
+               if (PL_lex_stuff) {
+                   SV *sv = newSVpvn(s, len);
+                   sv_catsv(sv, PL_lex_stuff);
+                   attrs = append_elem(OP_LIST, attrs,
+                                       newSVOP(OP_CONST, 0, sv));
+                   SvREFCNT_dec(PL_lex_stuff);
+                   PL_lex_stuff = Nullsv;
+               }
+               else {
+                   attrs = append_elem(OP_LIST, attrs,
+                                       newSVOP(OP_CONST, 0,
+                                               newSVpvn(s, len)));
+               }
+               s = skipspace(d);
+               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 != '=' || *s != ')')) {
+               char q = ((*s == '\'') ? '"' : '\'');
+               /* If here for an expression, and parsed no attrs, back off. */
+               if (tmp == '=' && !attrs) {
+                   s = PL_bufptr;
+                   break;
+               }
+               /* MUST advance bufptr here to avoid bogus "at end of line"
+                  context messages from yyerror().
+                */
+               PL_bufptr = s;
+               if (!*s)
+                   yyerror("Unterminated attribute list");
+               else
+                   yyerror(Perl_form(aTHX_ "Invalid separator character %c%c%c in attribute list",
+                                     q, *s, q));
+               if (attrs)
+                   op_free(attrs);
+               OPERATOR(':');
+           }
+       got_attrs:
+           if (attrs) {
+               PL_nextval[PL_nexttoke].opval = attrs;
+               force_next(THING);
+           }
+           TOKEN(COLONATTR);
+       }
        OPERATOR(':');
     case '(':
        s++;
@@ -2668,8 +2839,8 @@ Perl_yylex(pTHX)
            PL_expect = XTERM;
        TOKEN('(');
     case ';':
-       if (PL_curcop->cop_line < PL_copline)
-           PL_copline = PL_curcop->cop_line;
+       if (CopLINE(PL_curcop) < PL_copline)
+           PL_copline = CopLINE(PL_curcop);
        tmp = *s++;
        OPERATOR(tmp);
     case ')':
@@ -2736,10 +2907,12 @@ Perl_yylex(pTHX)
                }
            }
            /* FALL THROUGH */
+       case XATTRBLOCK:
        case XBLOCK:
            PL_lex_brackstack[PL_lex_brackets++] = XSTATE;
            PL_expect = XSTATE;
            break;
+       case XATTRTERM:
        case XTERMBLOCK:
            PL_lex_brackstack[PL_lex_brackets++] = XOPERATOR;
            PL_expect = XSTATE;
@@ -2780,7 +2953,8 @@ Perl_yylex(pTHX)
                    if (++t < PL_bufend
                        && (!isALNUM(*t)
                            || ((*t == 'q' || *t == 'x') && ++t < PL_bufend
-                               && !isALNUM(*t)))) {
+                               && !isALNUM(*t))))
+                   {
                        char *tmps;
                        char open, close, term;
                        I32 brackets = 1;
@@ -2811,8 +2985,10 @@ Perl_yylex(pTHX)
                    }
                    t++;
                }
-               else if (isIDFIRST_lazy(s)) {
-                   for (t++; t < PL_bufend && isALNUM_lazy(t); t++) ;
+               else if (isALNUM_lazy(t)) {
+                   t += UTF8SKIP(t);
+                   while (t < PL_bufend && isALNUM_lazy(t))
+                        t += UTF8SKIP(t);
                }
                while (t < PL_bufend && isSPACE(*t))
                    t++;
@@ -2830,7 +3006,7 @@ Perl_yylex(pTHX)
            }
            break;
        }
-       yylval.ival = PL_curcop->cop_line;
+       yylval.ival = CopLINE(PL_curcop);
        if (isSPACE(*s) || *s == '#')
            PL_copline = NOLINE;   /* invalidate current command line number */
        TOKEN('{');
@@ -2845,7 +3021,8 @@ Perl_yylex(pTHX)
            PL_lex_formbrack = 0;
        if (PL_lex_state == LEX_INTERPNORMAL) {
            if (PL_lex_brackets == 0) {
-               if (PL_lex_fakebrack) {
+               if (PL_expect & XFAKEBRACK) {
+                   PL_expect &= XENUMMASK;
                    PL_lex_state = LEX_INTERPEND;
                    PL_bufptr = s;
                    return yylex();     /* ignore fake brackets */
@@ -2856,9 +3033,9 @@ Perl_yylex(pTHX)
                    PL_lex_state = LEX_INTERPEND;
            }
        }
-       if (PL_lex_brackets < PL_lex_fakebrack) {
+       if (PL_expect & XFAKEBRACK) {
+           PL_expect &= XENUMMASK;
            PL_bufptr = s;
-           PL_lex_fakebrack = 0;
            return yylex();             /* ignore fake brackets */
        }
        force_next('}');
@@ -2871,9 +3048,9 @@ Perl_yylex(pTHX)
        s--;
        if (PL_expect == XOPERATOR) {
            if (ckWARN(WARN_SEMICOLON) && isIDFIRST_lazy(s) && PL_bufptr == PL_linestart) {
-               PL_curcop->cop_line--;
+               CopLINE_dec(PL_curcop);
                Perl_warner(aTHX_ WARN_SEMICOLON, PL_warn_nosemi);
-               PL_curcop->cop_line++;
+               CopLINE_inc(PL_curcop);
            }
            BAop(OP_BIT_AND);
        }
@@ -3210,7 +3387,7 @@ Perl_yylex(pTHX)
        TERM(THING);
 
     case '\'':
-       s = scan_str(s);
+       s = scan_str(s,FALSE,FALSE);
        if (PL_expect == XOPERATOR) {
            if (PL_lex_formbrack && PL_lex_brackets == PL_lex_formbrack) {
                PL_expect = XTERM;
@@ -3226,7 +3403,7 @@ Perl_yylex(pTHX)
        TERM(sublex_start());
 
     case '"':
-       s = scan_str(s);
+       s = scan_str(s,FALSE,FALSE);
        if (PL_expect == XOPERATOR) {
            if (PL_lex_formbrack && PL_lex_brackets == PL_lex_formbrack) {
                PL_expect = XTERM;
@@ -3248,7 +3425,7 @@ Perl_yylex(pTHX)
        TERM(sublex_start());
 
     case '`':
-       s = scan_str(s);
+       s = scan_str(s,FALSE,FALSE);
        if (PL_expect == XOPERATOR)
            no_op("Backticks",s);
        if (!s)
@@ -3266,6 +3443,19 @@ Perl_yylex(pTHX)
            no_op("Backslash",s);
        OPERATOR(REFGEN);
 
+    case 'v':
+       if (isDIGIT(s[1]) && PL_expect == XTERM) {
+           char *start = s;
+           start++;
+           start++;
+           while (isDIGIT(*start))
+               start++;
+           if (*start == '.' && isDIGIT(start[1])) {
+               s = scan_num(s);
+               TERM(THING);
+           }
+       }
+       goto keylookup;
     case 'x':
        if (isDIGIT(s[1]) && PL_expect == XOPERATOR) {
            s++;
@@ -3295,7 +3485,7 @@ Perl_yylex(pTHX)
     case 's': case 'S':
     case 't': case 'T':
     case 'u': case 'U':
-    case 'v': case 'V':
+             case 'V':
     case 'w': case 'W':
              case 'X':
     case 'y': case 'Y':
@@ -3369,6 +3559,7 @@ Perl_yylex(pTHX)
            }
            else if (gv && !gvp
                     && -tmp==KEY_lock  /* XXX generalizable kludge */
+                    && GvCVu(gv)
                     && !hv_fetch(GvHVn(PL_incgv), "Thread.pm", 9, FALSE))
            {
                tmp = 0;                /* any sub overrides "weak" keyword */
@@ -3407,9 +3598,9 @@ Perl_yylex(pTHX)
 
                if (PL_expect == XOPERATOR) {
                    if (PL_bufptr == PL_linestart) {
-                       PL_curcop->cop_line--;
+                       CopLINE_dec(PL_curcop);
                        Perl_warner(aTHX_ WARN_SEMICOLON, PL_warn_nosemi);
-                       PL_curcop->cop_line++;
+                       CopLINE_inc(PL_curcop);
                    }
                    else
                        no_op("Bareword",s);
@@ -3461,7 +3652,8 @@ Perl_yylex(pTHX)
 
                if (PL_oldoldbufptr &&
                    PL_oldoldbufptr < PL_bufptr &&
-                   (PL_oldoldbufptr == PL_last_lop || PL_oldoldbufptr == PL_last_uni) &&
+                   (PL_oldoldbufptr == PL_last_lop
+                    || PL_oldoldbufptr == PL_last_uni) &&
                    /* NO SKIPSPACE BEFORE HERE! */
                    (PL_expect == XREF ||
                     ((PL_opargs[PL_last_lop_op] >> OASHIFT)& 7) == OA_FILEREF))
@@ -3595,17 +3787,12 @@ Perl_yylex(pTHX)
 
        case KEY___FILE__:
            yylval.opval = (OP*)newSVOP(OP_CONST, 0,
-                                       newSVsv(GvSV(PL_curcop->cop_filegv)));
+                                       newSVpv(CopFILE(PL_curcop),0));
            TERM(THING);
 
        case KEY___LINE__:
-#ifdef IV_IS_QUAD
             yylval.opval = (OP*)newSVOP(OP_CONST, 0,
-                                    Perl_newSVpvf(aTHX_ "%" PERL_PRId64, (IV)PL_curcop->cop_line));
-#else
-            yylval.opval = (OP*)newSVOP(OP_CONST, 0,
-                                    Perl_newSVpvf(aTHX_ "%ld", (long)PL_curcop->cop_line));
-#endif
+                                    Perl_newSVpvf(aTHX_ "%"IVdf, (IV)CopLINE(PL_curcop)));
            TERM(THING);
 
        case KEY___PACKAGE__:
@@ -3643,6 +3830,28 @@ Perl_yylex(pTHX)
                    IoTYPE(GvIOp(gv)) = '-';
                else
                    IoTYPE(GvIOp(gv)) = '<';
+#if defined(WIN32) && !defined(PERL_TEXTMODE_SCRIPTS)
+               /* if the script was opened in binmode, we need to revert
+                * it to text mode for compatibility; but only iff it has CRs
+                * XXX this is a questionable hack at best. */
+               if (PL_bufend-PL_bufptr > 2
+                   && PL_bufend[-1] == '\n' && PL_bufend[-2] == '\r')
+               {
+                   Off_t loc = 0;
+                   if (IoTYPE(GvIOp(gv)) == '<') {
+                       loc = PerlIO_tell(PL_rsfp);
+                       (void)PerlIO_seek(PL_rsfp, 0L, 0);
+                   }
+                   if (PerlLIO_setmode(PerlIO_fileno(PL_rsfp), O_TEXT) != -1) {
+#if defined(__BORLANDC__)
+                       /* XXX see note in do_binmode() */
+                       ((FILE*)PL_rsfp)->flags |= _F_BIN;
+#endif
+                       if (loc > 0)
+                           PerlIO_seek(PL_rsfp, loc, 0);
+                   }
+               }
+#endif
                PL_rsfp = Nullfp;
            }
            goto fake_eof;
@@ -3651,8 +3860,9 @@ Perl_yylex(pTHX)
        case KEY_AUTOLOAD:
        case KEY_DESTROY:
        case KEY_BEGIN:
-       case KEY_END:
+       case KEY_CHECK:
        case KEY_INIT:
+       case KEY_END:
            if (PL_expect == XSTATE) {
                s = PL_bufptr;
                goto really_sub;
@@ -3719,8 +3929,10 @@ Perl_yylex(pTHX)
 
        case KEY_crypt:
 #ifdef FCRYPT
-           if (!PL_cryptseen++)
+           if (!PL_cryptseen) {
+               PL_cryptseen = TRUE;
                init_des();
+           }
 #endif
            LOP(OP_CRYPT,XTERM);
 
@@ -3781,7 +3993,7 @@ Perl_yylex(pTHX)
            PREBLOCK(ELSE);
 
        case KEY_elsif:
-           yylval.ival = PL_curcop->cop_line;
+           yylval.ival = CopLINE(PL_curcop);
            OPERATOR(ELSIF);
 
        case KEY_eq:
@@ -3831,15 +4043,23 @@ Perl_yylex(pTHX)
 
        case KEY_for:
        case KEY_foreach:
-           yylval.ival = PL_curcop->cop_line;
+           yylval.ival = CopLINE(PL_curcop);
            s = skipspace(s);
            if (PL_expect == XSTATE && isIDFIRST_lazy(s)) {
                char *p = s;
                if ((PL_bufend - p) >= 3 &&
                    strnEQ(p, "my", 2) && isSPACE(*(p + 2)))
                    p += 2;
+               else if ((PL_bufend - p) >= 4 &&
+                   strnEQ(p, "our", 3) && isSPACE(*(p + 3)))
+                   p += 3;
                p = skipspace(p);
-               if (isIDFIRST_lazy(p))
+               if (isIDFIRST_lazy(p)) {
+                   p = scan_ident(p, PL_bufend,
+                       PL_tokenbuf, sizeof PL_tokenbuf, TRUE);
+                   p = skipspace(p);
+               }
+               if (*p != '$')
                    Perl_croak(aTHX_ "Missing $ on loop variable");
            }
            OPERATOR(FOR);
@@ -3866,7 +4086,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);
@@ -3961,7 +4181,7 @@ Perl_yylex(pTHX)
            UNI(OP_HEX);
 
        case KEY_if:
-           yylval.ival = PL_curcop->cop_line;
+           yylval.ival = CopLINE(PL_curcop);
            OPERATOR(IF);
 
        case KEY_index:
@@ -3993,6 +4213,7 @@ Perl_yylex(pTHX)
            UNI(OP_LCFIRST);
 
        case KEY_local:
+           yylval.ival = 0;
            OPERATOR(LOCAL);
 
        case KEY_length:
@@ -4027,7 +4248,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);
@@ -4044,11 +4265,14 @@ Perl_yylex(pTHX)
        case KEY_msgsnd:
            LOP(OP_MSGSND,XTERM);
 
+       case KEY_our:
        case KEY_my:
-           PL_in_my = TRUE;
+           PL_in_my = tmp;
            s = skipspace(s);
            if (isIDFIRST_lazy(s)) {
                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);
                if (!PL_in_my_stash) {
                    char tmpbuf[1024];
@@ -4057,6 +4281,7 @@ Perl_yylex(pTHX)
                    yyerror(tmpbuf);
                }
            }
+           yylval.ival = 1;
            OPERATOR(MY);
 
        case KEY_next:
@@ -4075,7 +4300,10 @@ Perl_yylex(pTHX)
            OPERATOR(USE);
 
        case KEY_not:
-           OPERATOR(NOTOP);
+           if (*s == '(' || (s = skipspace(s), *s == '('))
+               FUN1(OP_NOT);
+           else
+               OPERATOR(NOTOP);
 
        case KEY_open:
            s = skipspace(s);
@@ -4134,7 +4362,7 @@ Perl_yylex(pTHX)
            LOP(OP_PIPE_OP,XTERM);
 
        case KEY_q:
-           s = scan_str(s);
+           s = scan_str(s,FALSE,FALSE);
            if (!s)
                missingterm((char*)0);
            yylval.ival = OP_CONST;
@@ -4144,7 +4372,7 @@ Perl_yylex(pTHX)
            UNI(OP_QUOTEMETA);
 
        case KEY_qw:
-           s = scan_str(s);
+           s = scan_str(s,FALSE,FALSE);
            if (!s)
                missingterm((char*)0);
            force_next(')');
@@ -4189,7 +4417,7 @@ Perl_yylex(pTHX)
            TOKEN('(');
 
        case KEY_qq:
-           s = scan_str(s);
+           s = scan_str(s,FALSE,FALSE);
            if (!s)
                missingterm((char*)0);
            yylval.ival = OP_STRINGIFY;
@@ -4202,7 +4430,7 @@ Perl_yylex(pTHX)
            TERM(sublex_start());
 
        case KEY_qx:
-           s = scan_str(s);
+           s = scan_str(s,FALSE,FALSE);
            if (!s)
                missingterm((char*)0);
            yylval.ival = OP_BACKTICK;
@@ -4213,12 +4441,18 @@ Perl_yylex(pTHX)
            OLDLOP(OP_RETURN);
 
        case KEY_require:
-           *PL_tokenbuf = '\0';
-           s = force_word(s,WORD,TRUE,TRUE,FALSE);
-           if (isIDFIRST_lazy(PL_tokenbuf))
-               gv_stashpvn(PL_tokenbuf, strlen(PL_tokenbuf), TRUE);
-           else if (*s == '<')
-               yyerror("<> should be quotes");
+           s = skipspace(s);
+           if (isDIGIT(*s) || (*s == 'v' && isDIGIT(s[1]))) {
+               s = force_version(s);
+           }
+           else {
+               *PL_tokenbuf = '\0';
+               s = force_word(s,WORD,TRUE,TRUE,FALSE);
+               if (isIDFIRST_lazy(PL_tokenbuf))
+                   gv_stashpvn(PL_tokenbuf, strlen(PL_tokenbuf), TRUE);
+               else if (*s == '<')
+                   yyerror("<> should be quotes");
+           }
            UNI(OP_REQUIRE);
 
        case KEY_reset:
@@ -4388,7 +4622,6 @@ Perl_yylex(pTHX)
            UNI(OP_STAT);
 
        case KEY_study:
-           PL_sawstudy++;
            UNI(OP_STUDY);
 
        case KEY_substr:
@@ -4397,73 +4630,97 @@ Perl_yylex(pTHX)
        case KEY_format:
        case KEY_sub:
          really_sub:
-           s = skipspace(s);
-
-           if (isIDFIRST_lazy(s) || *s == '\'' || *s == ':') {
+           {
                char tmpbuf[sizeof PL_tokenbuf];
-               PL_expect = XBLOCK;
-               d = scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len);
-               if (strchr(tmpbuf, ':'))
-                   sv_setpv(PL_subname, tmpbuf);
+               SSize_t tboffset;
+               expectation attrful;
+               bool have_name, have_proto;
+               int key = tmp;
+
+               s = skipspace(s);
+
+               if (isIDFIRST_lazy(s) || *s == '\'' ||
+                   (*s == ':' && s[1] == ':'))
+               {
+                   PL_expect = XBLOCK;
+                   attrful = XATTRBLOCK;
+                   /* remember buffer pos'n for later force_word */
+                   tboffset = s - PL_oldbufptr;
+                   d = scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len);
+                   if (strchr(tmpbuf, ':'))
+                       sv_setpv(PL_subname, tmpbuf);
+                   else {
+                       sv_setsv(PL_subname,PL_curstname);
+                       sv_catpvn(PL_subname,"::",2);
+                       sv_catpvn(PL_subname,tmpbuf,len);
+                   }
+                   s = skipspace(d);
+                   have_name = TRUE;
+               }
                else {
-                   sv_setsv(PL_subname,PL_curstname);
-                   sv_catpvn(PL_subname,"::",2);
-                   sv_catpvn(PL_subname,tmpbuf,len);
+                   if (key == KEY_my)
+                       Perl_croak(aTHX_ "Missing name in \"my sub\"");
+                   PL_expect = XTERMBLOCK;
+                   attrful = XATTRTERM;
+                   sv_setpv(PL_subname,"?");
+                   have_name = FALSE;
                }
-               s = force_word(s,WORD,FALSE,TRUE,TRUE);
-               s = skipspace(s);
-           }
-           else {
-               PL_expect = XTERMBLOCK;
-               sv_setpv(PL_subname,"?");
-           }
 
-           if (tmp == KEY_format) {
-               s = skipspace(s);
-               if (*s == '=')
-                   PL_lex_formbrack = PL_lex_brackets + 1;
-               OPERATOR(FORMAT);
-           }
+               if (key == KEY_format) {
+                   if (*s == '=')
+                       PL_lex_formbrack = PL_lex_brackets + 1;
+                   if (have_name)
+                       (void) force_word(PL_oldbufptr + tboffset, WORD,
+                                         FALSE, TRUE, TRUE);
+                   OPERATOR(FORMAT);
+               }
 
-           /* Look for a prototype */
-           if (*s == '(') {
-               char *p;
+               /* Look for a prototype */
+               if (*s == '(') {
+                   char *p;
+
+                   s = scan_str(s,FALSE,FALSE);
+                   if (!s) {
+                       if (PL_lex_stuff)
+                           SvREFCNT_dec(PL_lex_stuff);
+                       PL_lex_stuff = Nullsv;
+                       Perl_croak(aTHX_ "Prototype not terminated");
+                   }
+                   /* strip spaces */
+                   d = SvPVX(PL_lex_stuff);
+                   tmp = 0;
+                   for (p = d; *p; ++p) {
+                       if (!isSPACE(*p))
+                           d[tmp++] = *p;
+                   }
+                   d[tmp] = '\0';
+                   SvCUR(PL_lex_stuff) = tmp;
+                   have_proto = TRUE;
 
-               s = scan_str(s);
-               if (!s) {
-                   if (PL_lex_stuff)
-                       SvREFCNT_dec(PL_lex_stuff);
-                   PL_lex_stuff = Nullsv;
-                   Perl_croak(aTHX_ "Prototype not terminated");
+                   s = skipspace(s);
                }
-               /* strip spaces */
-               d = SvPVX(PL_lex_stuff);
-               tmp = 0;
-               for (p = d; *p; ++p) {
-                   if (!isSPACE(*p))
-                       d[tmp++] = *p;
+               else
+                   have_proto = FALSE;
+
+               if (*s == ':' && s[1] != ':')
+                   PL_expect = attrful;
+
+               if (have_proto) {
+                   PL_nextval[PL_nexttoke].opval =
+                       (OP*)newSVOP(OP_CONST, 0, PL_lex_stuff);
+                   PL_lex_stuff = Nullsv;
+                   force_next(THING);
                }
-               d[tmp] = '\0';
-               SvCUR(PL_lex_stuff) = tmp;
-
-               PL_nexttoke++;
-               PL_nextval[1] = PL_nextval[0];
-               PL_nexttype[1] = PL_nexttype[0];
-               PL_nextval[0].opval = (OP*)newSVOP(OP_CONST, 0, PL_lex_stuff);
-               PL_nexttype[0] = THING;
-               if (PL_nexttoke == 1) {
-                   PL_lex_defer = PL_lex_state;
-                   PL_lex_expect = PL_expect;
-                   PL_lex_state = LEX_KNOWNEXT;
+               if (!have_name) {
+                   sv_setpv(PL_subname,"__ANON__");
+                   TOKEN(ANONSUB);
                }
-               PL_lex_stuff = Nullsv;
-           }
-
-           if (*SvPV(PL_subname,n_a) == '?') {
-               sv_setpv(PL_subname,"__ANON__");
-               TOKEN(ANONSUB);
+               (void) force_word(PL_oldbufptr + tboffset, WORD,
+                                 FALSE, TRUE, TRUE);
+               if (key == KEY_my)
+                   TOKEN(MYSUB);
+               TOKEN(SUB);
            }
-           PREBLOCK(SUB);
 
        case KEY_system:
            set_csh();
@@ -4522,11 +4779,11 @@ Perl_yylex(pTHX)
            UNI(OP_UNTIE);
 
        case KEY_until:
-           yylval.ival = PL_curcop->cop_line;
+           yylval.ival = CopLINE(PL_curcop);
            OPERATOR(UNTIL);
 
        case KEY_unless:
-           yylval.ival = PL_curcop->cop_line;
+           yylval.ival = CopLINE(PL_curcop);
            OPERATOR(UNLESS);
 
        case KEY_unlink:
@@ -4557,9 +4814,9 @@ Perl_yylex(pTHX)
            if (PL_expect != XSTATE)
                yyerror("\"use\" not allowed in expression");
            s = skipspace(s);
-           if(isDIGIT(*s)) {
+           if (isDIGIT(*s) || (*s == 'v' && isDIGIT(s[1]))) {
                s = force_version(s);
-               if(*s == ';' || (s = skipspace(s), *s == ';')) {
+               if (*s == ';' || (s = skipspace(s), *s == ';')) {
                    PL_nextval[PL_nexttoke].opval = Nullop;
                    force_next(WORD);
                }
@@ -4575,11 +4832,10 @@ Perl_yylex(pTHX)
            UNI(OP_VALUES);
 
        case KEY_vec:
-           PL_sawvec = TRUE;
            LOP(OP_VEC,XTERM);
 
        case KEY_while:
-           yylval.ival = PL_curcop->cop_line;
+           yylval.ival = CopLINE(PL_curcop);
            OPERATOR(WHILE);
 
        case KEY_warn:
@@ -4667,6 +4923,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) {
@@ -4971,8 +5228,7 @@ Perl_keyword(pTHX_ register char *d, I32 len)
        case 3:
            if (strEQ(d,"ord"))                 return -KEY_ord;
            if (strEQ(d,"oct"))                 return -KEY_oct;
-           if (strEQ(d,"our")) { deprecate("reserved word \"our\"");
-                                               return 0;}
+           if (strEQ(d,"our"))                 return KEY_our;
            break;
        case 4:
            if (strEQ(d,"open"))                return -KEY_open;
@@ -5263,7 +5519,8 @@ S_checkcomma(pTHX_ register char *s, char *name, char *what)
            if (*w)
                for (; *w && isSPACE(*w); w++) ;
            if (!*w || !strchr(";|})]oaiuw!=", *w))     /* an advisory hack only... */
-               Perl_warner(aTHX_ WARN_SYNTAX, "%s (...) interpreted as function",name);
+               Perl_warner(aTHX_ WARN_SYNTAX,
+                           "%s (...) interpreted as function",name);
        }
     }
     while (s < PL_bufend && isSPACE(*s))
@@ -5296,14 +5553,15 @@ S_checkcomma(pTHX_ register char *s, char *name, char *what)
    and type is used with error messages only. */
 
 STATIC SV *
-S_new_constant(pTHX_ char *s, STRLEN len, char *key, SV *sv, SV *pv, char *type) 
+S_new_constant(pTHX_ char *s, STRLEN len, const char *key, SV *sv, SV *pv,
+              const char *type) 
 {
     dSP;
     HV *table = GvHV(PL_hintgv);                /* ^H */
     SV *res;
     SV **cvp;
     SV *cv, *typesv;
-    char *why, *why1, *why2;
+    const char *why, *why1, *why2;
     
     if (!(PL_hints & HINT_LOCALIZE_HH)) {
        SV *msg;
@@ -5361,12 +5619,12 @@ S_new_constant(pTHX_ char *s, STRLEN len, char *key, SV *sv, SV *pv, char *type)
        STRLEN n_a;
        sv_catpv(ERRSV, "Propagated");
        yyerror(SvPV(ERRSV, n_a)); /* Duplicates the message inside eval */
-       POPs ;
+       (void)POPs;
        res = SvREFCNT_inc(sv);
     }
     else {
        res = POPs;
-       SvREFCNT_inc(res);
+       (void)SvREFCNT_inc(res);
     }
     
     PUTBACK ;
@@ -5430,8 +5688,6 @@ S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN des
     char *bracket = 0;
     char funny = *s++;
 
-    if (PL_lex_brackets == 0)
-       PL_lex_fakebrack = 0;
     if (isSPACE(*s))
        s = skipspace(s);
     d = dest;
@@ -5531,14 +5787,13 @@ S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN des
            if ((*s == '[' || (*s == '{' && strNE(dest, "sub")))) {
                dTHR;                   /* only for ckWARN */
                if (ckWARN(WARN_AMBIGUOUS) && keyword(dest, d - dest)) {
-                   char *brack = *s == '[' ? "[...]" : "{...}";
+                   const char *brack = *s == '[' ? "[...]" : "{...}";
                    Perl_warner(aTHX_ WARN_AMBIGUOUS,
                        "Ambiguous use of %c{%s%s} resolved to %c%s%s",
                        funny, dest, brack, funny, dest, brack);
                }
-               PL_lex_fakebrack = PL_lex_brackets+1;
                bracket++;
-               PL_lex_brackstack[PL_lex_brackets++] = XOPERATOR;
+               PL_lex_brackstack[PL_lex_brackets++] = (char)(XOPERATOR | XFAKEBRACK);
                return s;
            }
        } 
@@ -5607,7 +5862,7 @@ S_scan_pat(pTHX_ char *start, I32 type)
     PMOP *pm;
     char *s;
 
-    s = scan_str(start);
+    s = scan_str(start,FALSE,FALSE);
     if (!s) {
        if (PL_lex_stuff)
            SvREFCNT_dec(PL_lex_stuff);
@@ -5643,7 +5898,7 @@ S_scan_subst(pTHX_ char *start)
 
     yylval.ival = OP_NULL;
 
-    s = scan_str(start);
+    s = scan_str(start,FALSE,FALSE);
 
     if (!s) {
        if (PL_lex_stuff)
@@ -5656,7 +5911,7 @@ S_scan_subst(pTHX_ char *start)
        s--;
 
     first_start = PL_multi_start;
-    s = scan_str(s);
+    s = scan_str(s,FALSE,FALSE);
     if (!s) {
        if (PL_lex_stuff)
            SvREFCNT_dec(PL_lex_stuff);
@@ -5717,7 +5972,7 @@ S_scan_trans(pTHX_ char *start)
 
     yylval.ival = OP_NULL;
 
-    s = scan_str(start);
+    s = scan_str(start,FALSE,FALSE);
     if (!s) {
        if (PL_lex_stuff)
            SvREFCNT_dec(PL_lex_stuff);
@@ -5727,7 +5982,7 @@ S_scan_trans(pTHX_ char *start)
     if (s[-1] == PL_multi_open)
        s--;
 
-    s = scan_str(s);
+    s = scan_str(s,FALSE,FALSE);
     if (!s) {
        if (PL_lex_stuff)
            SvREFCNT_dec(PL_lex_stuff);
@@ -5871,7 +6126,7 @@ S_scan_heredoc(pTHX_ register char *s)
     }
 
     CLINE;
-    PL_multi_start = PL_curcop->cop_line;
+    PL_multi_start = CopLINE(PL_curcop);
     PL_multi_open = PL_multi_close = '<';
     term = *PL_tokenbuf;
     if (PL_lex_inwhat == OP_SUBST && PL_in_eval && !PL_rsfp) {
@@ -5885,10 +6140,10 @@ S_scan_heredoc(pTHX_ register char *s)
        while (s < bufend &&
          (*s != term || memNE(s,PL_tokenbuf,len)) ) {
            if (*s++ == '\n')
-               PL_curcop->cop_line++;
+               CopLINE_inc(PL_curcop);
        }
        if (s >= bufend) {
-           PL_curcop->cop_line = PL_multi_start;
+           CopLINE_set(PL_curcop, PL_multi_start);
            missingterm(PL_tokenbuf);
        }
        sv_setpvn(herewas,bufptr,d-bufptr+1);
@@ -5905,15 +6160,15 @@ S_scan_heredoc(pTHX_ register char *s)
        while (s < PL_bufend &&
          (*s != term || memNE(s,PL_tokenbuf,len)) ) {
            if (*s++ == '\n')
-               PL_curcop->cop_line++;
+               CopLINE_inc(PL_curcop);
        }
        if (s >= PL_bufend) {
-           PL_curcop->cop_line = PL_multi_start;
+           CopLINE_set(PL_curcop, PL_multi_start);
            missingterm(PL_tokenbuf);
        }
        sv_setpvn(tmpstr,d+1,s-d);
        s += len - 1;
-       PL_curcop->cop_line++;  /* the preceding stmt passes a newline */
+       CopLINE_inc(PL_curcop); /* the preceding stmt passes a newline */
 
        sv_catpvn(herewas,s,PL_bufend-s);
        sv_setsv(PL_linestr,herewas);
@@ -5925,10 +6180,10 @@ S_scan_heredoc(pTHX_ register char *s)
     while (s >= PL_bufend) {   /* multiple line string? */
        if (!outer ||
         !(PL_oldoldbufptr = PL_oldbufptr = s = PL_linestart = filter_gets(PL_linestr, PL_rsfp, 0))) {
-           PL_curcop->cop_line = PL_multi_start;
+           CopLINE_set(PL_curcop, PL_multi_start);
            missingterm(PL_tokenbuf);
        }
-       PL_curcop->cop_line++;
+       CopLINE_inc(PL_curcop);
        PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
 #ifndef PERL_STRICT_CR
        if (PL_bufend - PL_linestart >= 2) {
@@ -5950,8 +6205,7 @@ S_scan_heredoc(pTHX_ register char *s)
 
            sv_upgrade(sv, SVt_PVMG);
            sv_setsv(sv,PL_linestr);
-           av_store(GvAV(PL_curcop->cop_filegv),
-             (I32)PL_curcop->cop_line,sv);
+           av_store(CopFILEAV(PL_curcop), (I32)CopLINE(PL_curcop),sv);
        }
        if (*s == term && memEQ(s,PL_tokenbuf,len)) {
            s = PL_bufend - 1;
@@ -5966,7 +6220,7 @@ S_scan_heredoc(pTHX_ register char *s)
     }
     s++;
 retval:
-    PL_multi_end = PL_curcop->cop_line;
+    PL_multi_end = CopLINE(PL_curcop);
     if (SvCUR(tmpstr) + 5 < SvLEN(tmpstr)) {
        SvLEN_set(tmpstr, SvCUR(tmpstr) + 1);
        Renew(SvPVX(tmpstr), SvLEN(tmpstr), char);
@@ -6042,7 +6296,7 @@ S_scan_inputsymbol(pTHX_ char *start)
     if (d - PL_tokenbuf != len) {
        yylval.ival = OP_GLOB;
        set_csh();
-       s = scan_str(start);
+       s = scan_str(start,FALSE,FALSE);
        if (!s)
           Perl_croak(aTHX_ "Glob not terminated");
        return s;
@@ -6095,6 +6349,8 @@ S_scan_inputsymbol(pTHX_ char *start)
 
 /* scan_str
    takes: start position in buffer
+         keep_quoted preserve \ on the embedded delimiter(s)
+         keep_delims preserve the delimiters around the string
    returns: position to continue reading from buffer
    side-effects: multi_start, multi_close, lex_repl or lex_stuff, and
        updates the read buffer.
@@ -6112,6 +6368,7 @@ S_scan_inputsymbol(pTHX_ char *start)
        tr///           string transliterate    tr/this/that/
        y///            string transliterate    y/this/that/
        ($*@)           sub prototypes          sub foo ($)
+       (stuff)         sub attr parameters     sub foo : attr(stuff)
        <>              readline or globs       <FOO>, <>, <$fh>, or <*.c>
        
    In most of these cases (all but <>, patterns and transliterate)
@@ -6134,7 +6391,7 @@ S_scan_inputsymbol(pTHX_ char *start)
 */
 
 STATIC char *
-S_scan_str(pTHX_ char *start)
+S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
 {
     dTHR;
     SV *sv;                            /* scalar value: string */
@@ -6154,7 +6411,7 @@ S_scan_str(pTHX_ char *start)
     /* after skipping whitespace, the next character is the terminator */
     term = *s;
     /* mark where we are */
-    PL_multi_start = PL_curcop->cop_line;
+    PL_multi_start = CopLINE(PL_curcop);
     PL_multi_open = term;
 
     /* find corresponding closing delimiter */
@@ -6170,22 +6427,24 @@ S_scan_str(pTHX_ char *start)
     (void)SvPOK_only(sv);              /* validate pointer */
 
     /* move past delimiter and try to read a complete string */
+    if (keep_delims)
+       sv_catpvn(sv, s, 1);
     s++;
     for (;;) {
        /* extend sv if need be */
        SvGROW(sv, SvCUR(sv) + (PL_bufend - s) + 1);
        /* set 'to' to the next character in the sv's string */
        to = SvPVX(sv)+SvCUR(sv);
-       
+
        /* if open delimiter is the close delimiter read unbridle */
        if (PL_multi_open == PL_multi_close) {
            for (; s < PL_bufend; s++,to++) {
                /* embedded newlines increment the current line number */
                if (*s == '\n' && !PL_rsfp)
-                   PL_curcop->cop_line++;
+                   CopLINE_inc(PL_curcop);
                /* handle quoted delimiters */
                if (*s == '\\' && s+1 < PL_bufend && term != '\\') {
-                   if (s[1] == term)
+                   if (!keep_quoted && s[1] == term)
                        s++;
                /* any other quotes are simply copied straight through */
                    else
@@ -6208,10 +6467,11 @@ S_scan_str(pTHX_ char *start)
            for (; s < PL_bufend; s++,to++) {
                /* embedded newlines increment the line count */
                if (*s == '\n' && !PL_rsfp)
-                   PL_curcop->cop_line++;
+                   CopLINE_inc(PL_curcop);
                /* backslashes can escape the open or closing characters */
                if (*s == '\\' && s+1 < PL_bufend) {
-                   if ((s[1] == PL_multi_open) || (s[1] == PL_multi_close))
+                   if (!keep_quoted &&
+                       ((s[1] == PL_multi_open) || (s[1] == PL_multi_close)))
                        s++;
                    else
                        *to++ = *s++;
@@ -6256,11 +6516,11 @@ S_scan_str(pTHX_ char *start)
        if (!PL_rsfp ||
         !(PL_oldoldbufptr = PL_oldbufptr = s = PL_linestart = filter_gets(PL_linestr, PL_rsfp, 0))) {
            sv_free(sv);
-           PL_curcop->cop_line = PL_multi_start;
+           CopLINE_set(PL_curcop, PL_multi_start);
            return Nullch;
        }
        /* we read a line, so increment our line counter */
-       PL_curcop->cop_line++;
+       CopLINE_inc(PL_curcop);
 
        /* update debugger info */
        if (PERLDB_LINE && PL_curstash != PL_debstash) {
@@ -6268,8 +6528,7 @@ S_scan_str(pTHX_ char *start)
 
            sv_upgrade(sv, SVt_PVMG);
            sv_setsv(sv,PL_linestr);
-           av_store(GvAV(PL_curcop->cop_filegv),
-             (I32)PL_curcop->cop_line, sv);
+           av_store(CopFILEAV(PL_curcop), (I32)CopLINE(PL_curcop), sv);
        }
 
        /* having changed the buffer, we must update PL_bufend */
@@ -6278,7 +6537,9 @@ S_scan_str(pTHX_ char *start)
     
     /* at this point, we have successfully read the delimited string */
 
-    PL_multi_end = PL_curcop->cop_line;
+    if (keep_delims)
+       sv_catpvn(sv, s, 1);
+    PL_multi_end = CopLINE(PL_curcop);
     s++;
 
     /* if we allocated too much space, give some back */
@@ -6328,7 +6589,7 @@ Perl_scan_num(pTHX_ char *start)
     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 */
-    SV *sv;                            /* place to put the converted number */
+    SV *sv = Nullsv;                   /* place to put the converted number */
     bool floatit;                      /* boolean: int or float? */
     char *lastub = 0;                  /* position of last underbar */
     static char number_too_long[] = "Number too long";
@@ -6340,8 +6601,7 @@ Perl_scan_num(pTHX_ char *start)
       Perl_croak(aTHX_ "panic: scan_num");
       
     /* if it starts with a 0, it could be an octal number, a decimal in
-       0.13 disguise, or a hexadecimal number, or a binary number.
-    */
+       0.13 disguise, or a hexadecimal number, or a binary number. */
     case '0':
        {
          /* variables:
@@ -6380,7 +6640,7 @@ Perl_scan_num(pTHX_ char *start)
                s += 2;
            }
            /* check for a decimal in disguise */
-           else if (s[1] == '.')
+           else if (s[1] == '.' || s[1] == 'e' || s[1] == 'E')
                goto decimal;
            /* so it must be octal */
            else
@@ -6411,9 +6671,6 @@ Perl_scan_num(pTHX_ char *start)
                case '8': case '9':
                    if (shift == 3)
                        yyerror(Perl_form(aTHX_ "Illegal octal digit '%c'", *s));
-                   else
-                       if (shift == 1)
-                           yyerror(Perl_form(aTHX_ "Illegal binary digit '%c'", *s));
                    /* FALL THROUGH */
 
                /* octal digits */
@@ -6448,9 +6705,8 @@ Perl_scan_num(pTHX_ char *start)
                            dTHR;
                            overflowed = TRUE;
                            n = (NV) u;
-                           if (ckWARN_d(WARN_UNSAFE))
-                               Perl_warner(aTHX_ ((shift == 3) ?
-                                                  WARN_OCTAL : WARN_UNSAFE),
+                           if (ckWARN_d(WARN_OVERFLOW))
+                               Perl_warner(aTHX_ WARN_OVERFLOW,
                                            "Integer overflow in %s number",
                                            base);
                        } else
@@ -6479,17 +6735,17 @@ Perl_scan_num(pTHX_ char *start)
            sv = NEWSV(92,0);
            if (overflowed) {
                dTHR;
-               if (ckWARN(WARN_UNSAFE) && n > 4294967295.0)
-                   Perl_warner(aTHX_ WARN_UNSAFE,
+               if (ckWARN(WARN_PORTABLE) && n > 4294967295.0)
+                   Perl_warner(aTHX_ WARN_PORTABLE,
                                "%s number > %s non-portable",
                                Base, max);
                sv_setnv(sv, n);
            }
            else {
-#if UV_SIZEOF > 4
+#if UVSIZE > 4
                dTHR;
-               if (ckWARN(WARN_UNSAFE) && u > 0xffffffff)
-                   Perl_warner(aTHX_ WARN_UNSAFE,
+               if (ckWARN(WARN_PORTABLE) && u > 0xffffffff)
+                   Perl_warner(aTHX_ WARN_PORTABLE,
                                "%s number > %s non-portable",
                                Base, max);
 #endif
@@ -6607,11 +6863,61 @@ Perl_scan_num(pTHX_ char *start)
                              (floatit ? "float" : "integer"),
                              sv, Nullsv, NULL);
        break;
+    /* if it starts with a v, it could be a version number */
+    case 'v':
+       {
+           char *pos = s;
+           pos++;
+           while (isDIGIT(*pos))
+               pos++;
+           if (*pos == '.' && isDIGIT(pos[1])) {
+               UV rev;
+               U8 tmpbuf[10];
+               U8 *tmpend;
+               NV nshift = 1.0;
+               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++;
+
+                   tmpend = uv_to_utf8(tmpbuf, rev);
+                   *tmpend = '\0';
+                   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;
+
+               SvPOK_on(sv);
+               SvNOK_on(sv);
+               SvREADONLY_on(sv);
+               SvUTF8_on(sv);
+           }
+       }
+       break;
     }
 
     /* make the op for the constant and return */
 
-    yylval.opval = newSVOP(OP_CONST, 0, sv);
+    if (sv)
+       yylval.opval = newSVOP(OP_CONST, 0, sv);
+    else
+       yylval.opval = Nullop;
 
     return s;
 }
@@ -6653,6 +6959,14 @@ S_scan_formline(pTHX_ register char *s)
                    needargs = TRUE;
            }
            sv_catpvn(stuff, s, eol-s);
+#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)--;
+           }
+#endif
        }
        s = eol;
        if (PL_rsfp) {
@@ -6710,10 +7024,10 @@ Perl_start_subparse(pTHX_ I32 is_format, U32 flags)
     if (PL_compcv) {
        assert(SvTYPE(PL_compcv) == SVt_PVCV);
     }
-    save_I32(&PL_subline);
+    SAVEI32(PL_subline);
     save_item(PL_subname);
     SAVEI32(PL_padix);
-    SAVESPTR(PL_curpad);
+    SAVEVPTR(PL_curpad);
     SAVESPTR(PL_comppad);
     SAVESPTR(PL_comppad_name);
     SAVESPTR(PL_compcv);
@@ -6733,7 +7047,7 @@ Perl_start_subparse(pTHX_ I32 is_format, U32 flags)
     PL_comppad_name_fill = 0;
     PL_min_intro_pending = 0;
     PL_padix = 0;
-    PL_subline = PL_curcop->cop_line;
+    PL_subline = CopLINE(PL_curcop);
 #ifdef USE_THREADS
     av_store(PL_comppad_name, 0, newSVpvn("@_", 2));
     PL_curpad[0] = (SV*)newAV();
@@ -6760,7 +7074,6 @@ int
 Perl_yywarn(pTHX_ char *s)
 {
     dTHR;
-    --PL_error_count;
     PL_in_eval |= EVAL_WARNONLY;
     yyerror(s);
     PL_in_eval &= ~EVAL_WARNONLY;
@@ -6814,38 +7127,24 @@ Perl_yyerror(pTHX_ char *s)
        where = SvPVX(where_sv);
     }
     msg = sv_2mortal(newSVpv(s, 0));
-#ifdef IV_IS_QUAD
-    Perl_sv_catpvf(aTHX_ msg, " at %_ line %" PERL_PRId64 ", ",
-              GvSV(PL_curcop->cop_filegv), (IV)PL_curcop->cop_line);
-#else
-    Perl_sv_catpvf(aTHX_ msg, " at %_ line %ld, ",
-              GvSV(PL_curcop->cop_filegv), (long)PL_curcop->cop_line);
-#endif
+    Perl_sv_catpvf(aTHX_ msg, " at %s line %"IVdf", ",
+                  CopFILE(PL_curcop), (IV)CopLINE(PL_curcop));
     if (context)
        Perl_sv_catpvf(aTHX_ msg, "near \"%.*s\"\n", contlen, context);
     else
        Perl_sv_catpvf(aTHX_ msg, "%s\n", where);
-    if (PL_multi_start < PL_multi_end && (U32)(PL_curcop->cop_line - PL_multi_end) <= 1) {
-#ifdef IV_IS_QUAD
+    if (PL_multi_start < PL_multi_end && (U32)(CopLINE(PL_curcop) - PL_multi_end) <= 1) {
         Perl_sv_catpvf(aTHX_ msg,
-        "  (Might be a runaway multi-line %c%c string starting on line %" PERL_\
-PRId64 ")\n",
+        "  (Might be a runaway multi-line %c%c string starting on line %"IVdf")\n",
                 (int)PL_multi_open,(int)PL_multi_close,(IV)PL_multi_start);
-#else
-        Perl_sv_catpvf(aTHX_ msg,
-        "  (Might be a runaway multi-line %c%c string starting on line %ld)\n",
-                (int)PL_multi_open,(int)PL_multi_close,(long)PL_multi_start);
-#endif
         PL_multi_end = 0;
     }
     if (PL_in_eval & EVAL_WARNONLY)
-       Perl_warn(aTHX_ "%_", msg);
-    else if (PL_in_eval)
-       sv_catsv(ERRSV, msg);
+       Perl_warn(aTHX_ "%"SVf, msg);
     else
-       PerlIO_write(PerlIO_stderr(), SvPVX(msg), SvCUR(msg));
-    if (++PL_error_count >= 10)
-       Perl_croak(aTHX_ "%_ has too many errors.\n", GvSV(PL_curcop->cop_filegv));
+       qerror(msg);
+    if (PL_error_count >= 10)
+       Perl_croak(aTHX_ "%s has too many errors.\n", CopFILE(PL_curcop));
     PL_in_my = 0;
     PL_in_my_stash = Nullhv;
     return 0;
@@ -6853,7 +7152,6 @@ PRId64 ")\n",
 
 
 #ifdef PERL_OBJECT
-#define NO_XSLOCKS
 #include "XSUB.h"
 #endif
 
@@ -6873,29 +7171,3 @@ restore_rsfp(pTHXo_ void *f)
        PerlIO_close(PL_rsfp);
     PL_rsfp = fp;
 }
-
-/*
- * restore_expect
- * Restores the state of PL_expect when the lexing that begun with a
- * start_lex() call has ended.
- */ 
-
-static void
-restore_expect(pTHXo_ void *e)
-{
-    /* a safe way to store a small integer in a pointer */
-    PL_expect = (expectation)((char *)e - PL_tokenbuf);
-}
-
-/*
- * restore_lex_expect
- * Restores the state of PL_lex_expect when the lexing that begun with a
- * start_lex() call has ended.
- */ 
-
-static void
-restore_lex_expect(pTHXo_ void *e)
-{
-    /* a safe way to store a small integer in a pointer */
-    PL_lex_expect = (expectation)((char *)e - PL_tokenbuf);
-}