This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
longstanding bug in parsing "require VERSION", could reallocate
[perl5.git] / toke.c
diff --git a/toke.c b/toke.c
index e9234f6..44b3023 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.
  *   "It all comes from here, the stench and the peril."  --Frodo
  */
 
+/*
+ * This file is the lexer for Perl.  It's closely linked to the
+ * parser, perly.y.  
+ *
+ * The main routine is yylex(), which returns the next token.
+ */
+
 #include "EXTERN.h"
+#define PERL_IN_TOKE_C
 #include "perl.h"
 
 #define yychar PL_yychar
 #define yylval PL_yylval
 
-#ifndef PERL_OBJECT
-static void check_uni _((void));
-static void  force_next _((I32 type));
-static char *force_version _((char *start));
-static char *force_word _((char *start, int token, int check_keyword, int allow_pack, int allow_tick));
-static SV *tokeq _((SV *sv));
-static char *scan_const _((char *start));
-static char *scan_formline _((char *s));
-static char *scan_heredoc _((char *s));
-static char *scan_ident _((char *s, char *send, char *dest, STRLEN destlen,
-                          I32 ck_uni));
-static char *scan_inputsymbol _((char *start));
-static char *scan_pat _((char *start, I32 type));
-static char *scan_str _((char *start));
-static char *scan_subst _((char *start));
-static char *scan_trans _((char *start));
-static char *scan_word _((char *s, char *dest, STRLEN destlen,
-                         int allow_package, STRLEN *slp));
-static char *skipspace _((char *s));
-static void checkcomma _((char *s, char *name, char *what));
-static void force_ident _((char *s, int kind));
-static void incline _((char *s));
-static int intuit_method _((char *s, GV *gv));
-static int intuit_more _((char *s));
-static I32 lop _((I32 f, expectation x, char *s));
-static void missingterm _((char *s));
-static void no_op _((char *what, char *s));
-static void set_csh _((void));
-static I32 sublex_done _((void));
-static I32 sublex_push _((void));
-static I32 sublex_start _((void));
-#ifdef CRIPPLED_CC
-static int uni _((I32 f, char *s));
-#endif
-static char * filter_gets _((SV *sv, PerlIO *fp, STRLEN append));
-static void restore_rsfp _((void *f));
-static SV *new_constant _((char *s, STRLEN len, char *key, SV *sv, SV *pv, char *type));
-static void restore_expect _((void *e));
-static void restore_lex_expect _((void *e));
-#endif /* PERL_OBJECT */
-
 static char ident_too_long[] = "Identifier too long";
 
+static void restore_rsfp(pTHXo_ void *f);
+
+#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)))
 
-/* The following are arranged oddly so that the guard on the switch statement
+/* 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).
  */
 
@@ -121,16 +83,46 @@ int* yychar_pointer = NULL;
 #  define yylval (*yylval_pointer)
 #  define yychar (*yychar_pointer)
 #  define PERL_YYLEX_PARAM yylval_pointer,yychar_pointer
-#else
-#  define PERL_YYLEX_PARAM
+#  undef yylex
+#  define yylex()      Perl_yylex(aTHX_ yylval_pointer, yychar_pointer)
 #endif
 
 #include "keywords.h"
 
+/* CLINE is a macro that ensures PL_copline has a sane value */
+
 #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
+ * lexer for the next token.  They all take an argument.
+ *
+ * TOKEN        : generic token (used for '(', DOLSHARP, etc)
+ * OPERATOR     : generic operator
+ * AOPERATOR    : assignment operator
+ * PREBLOCK     : beginning the block after an if, while, foreach, ...
+ * PRETERMBLOCK : beginning a non-code-defining {} block (eg, hash ref)
+ * PREREF       : *EXPR where EXPR is not a simple identifier
+ * TERM         : expression term
+ * LOOPX        : loop exiting command (goto, last, dump, etc)
+ * FTST         : file test operator
+ * FUN0         : zero-argument function
+ * FUN1         : not used, except for not, which isn't a UNIOP
+ * BOop         : bitwise or or xor
+ * BAop         : bitwise and
+ * SHop         : shift operator
+ * PWop         : power operator
+ * PMop         : pattern-matching operator
+ * Aop          : addition-level operator
+ * Mop          : multiplication-level operator
+ * Eop          : equality-testing operator
+ * Rop        : relational operator <= != gt
+ *
+ * Also see LOP and lop() below.
+ */
 
 #define TOKEN(retval) return (PL_bufptr = s,(int)retval)
 #define OPERATOR(retval) return (PL_expect = XTERM,PL_bufptr = s,(int)retval)
@@ -171,8 +163,15 @@ int* yychar_pointer = NULL;
 /* grandfather return to old style */
 #define OLDLOP(f) return(yylval.ival=f,PL_expect = XTERM,PL_bufptr = s,(int)LSTOP)
 
+/*
+ * S_ao
+ *
+ * This subroutine detects &&= and ||= and turns an ANDAND or OROR
+ * into an OP_ANDASSIGN or OP_ORASSIGN
+ */
+
 STATIC int
-ao(int toketype)
+S_ao(pTHX_ int toketype)
 {
     if (*PL_bufptr == '=') {
        PL_bufptr++;
@@ -185,33 +184,57 @@ ao(int toketype)
     return toketype;
 }
 
+/*
+ * S_no_op
+ * When Perl expects an operator and finds something else, no_op
+ * prints the warning.  It always prints "<something> found where
+ * operator expected.  It prints "Missing semicolon on previous line?"
+ * if the surprise occurs at the start of the line.  "do you need to
+ * predeclare ..." is printed out for code like "sub bar; foo bar $x"
+ * where the compiler doesn't know if foo is a method call or a function.
+ * It prints "Missing operator before end of line" if there's nothing
+ * after the missing operator, or "... before <...>" if there is something
+ * after the missing operator.
+ */
+
 STATIC void
-no_op(char *what, char *s)
+S_no_op(pTHX_ char *what, char *s)
 {
     char *oldbp = PL_bufptr;
     bool is_first = (PL_oldbufptr == PL_linestart);
 
-    PL_bufptr = s;
-    yywarn(form("%s found where operator expected", what));
+    if (!s)
+       s = oldbp;
+    else {
+       assert(s >= oldbp);
+       PL_bufptr = s;
+    }
+    yywarn(Perl_form(aTHX_ "%s found where operator expected", what));
     if (is_first)
-       warn("\t(Missing semicolon on previous line?)\n");
-    else if (PL_oldoldbufptr && isIDFIRST_lazy(PL_oldoldbufptr)) {
+       Perl_warn(aTHX_ "\t(Missing semicolon on previous line?)\n");
+    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))
-           warn("\t(Do you need to predeclare %.*s?)\n",
+           Perl_warn(aTHX_ "\t(Do you need to predeclare %.*s?)\n",
                t - PL_oldoldbufptr, PL_oldoldbufptr);
-
     }
-    else if (s <= oldbp)
-       warn("\t(Missing operator before end of line?)\n");
     else
-       warn("\t(Missing operator before %.*s?)\n", s - oldbp, oldbp);
+       Perl_warn(aTHX_ "\t(Missing operator before %.*s?)\n", s - oldbp, oldbp);
     PL_bufptr = oldbp;
 }
 
+/*
+ * S_missingterm
+ * Complain about missing quote/regexp/heredoc terminator.
+ * If it's called with (char *)NULL then it cauterizes the line buffer.
+ * If we're in a delimited string and the delimiter is a control
+ * character, it's reformatted into a two-char sequence like ^C.
+ * This is fatal.
+ */
+
 STATIC void
-missingterm(char *s)
+S_missingterm(pTHX_ char *s)
 {
     char tmpbuf[3];
     char q;
@@ -239,39 +262,72 @@ missingterm(char *s)
        s = tmpbuf;
     }
     q = strchr(s,'"') ? '\'' : '"';
-    croak("Can't find string terminator %c%s%c anywhere before EOF",q,s,q);
+    Perl_croak(aTHX_ "Can't find string terminator %c%s%c anywhere before EOF",q,s,q);
 }
 
+/*
+ * Perl_deprecate
+ */
+
 void
-deprecate(char *s)
+Perl_deprecate(pTHX_ char *s)
 {
     dTHR;
     if (ckWARN(WARN_DEPRECATED))
-       warner(WARN_DEPRECATED, "Use of %s is deprecated", s);
+       Perl_warner(aTHX_ WARN_DEPRECATED, "Use of %s is deprecated", s);
 }
 
+/*
+ * depcom
+ * Deprecate a comma-less variable list.
+ */
+
 STATIC void
-depcom(void)
+S_depcom(pTHX)
 {
     deprecate("comma-less variable list");
 }
 
-#ifdef WIN32
+/*
+ * experimental text filters for win32 carriage-returns, utf16-to-utf8 and
+ * utf16-to-utf8-reversed.
+ */
+
+#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
-win32_textfilter(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
 
-#ifndef PERL_OBJECT
-
 STATIC I32
-utf16_textfilter(int idx, SV *sv, int maxlen)
+S_utf16_textfilter(pTHX_ int idx, SV *sv, int maxlen)
 {
     I32 count = FILTER_READ(idx+1, sv, maxlen);
     if (count) {
@@ -286,7 +342,7 @@ utf16_textfilter(int idx, SV *sv, int maxlen)
 }
 
 STATIC I32
-utf16rev_textfilter(int idx, SV *sv, int maxlen)
+S_utf16rev_textfilter(pTHX_ int idx, SV *sv, int maxlen)
 {
     I32 count = FILTER_READ(idx+1, sv, maxlen);
     if (count) {
@@ -300,10 +356,14 @@ utf16rev_textfilter(int idx, SV *sv, int maxlen)
     return count;
 }
 
-#endif
+/*
+ * Perl_lex_start
+ * Initialize variables.  Uses the Perl save_stack to save its state (for
+ * recursive calls to the parser).
+ */
 
 void
-lex_start(SV *line)
+Perl_lex_start(pTHX_ SV *line)
 {
     dTHR;
     char *s;
@@ -311,13 +371,21 @@ lex_start(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);
+    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);
     SAVEPPTR(PL_oldbufptr);
@@ -326,18 +394,18 @@ lex_start(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);
@@ -350,6 +418,7 @@ lex_start(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));
@@ -367,40 +436,30 @@ lex_start(SV *line)
     PL_rsfp = 0;
 }
 
+/*
+ * Perl_lex_end
+ * Finalizer for lexing operations.  Must be called when the parser is
+ * done with the lexer.
+ */
+
 void
-lex_end(void)
+Perl_lex_end(pTHX)
 {
     PL_doextract = FALSE;
 }
 
-STATIC void
-restore_rsfp(void *f)
-{
-    PerlIO *fp = (PerlIO*)f;
-
-    if (PL_rsfp == PerlIO_stdin())
-       PerlIO_clearerr(PL_rsfp);
-    else if (PL_rsfp && (PL_rsfp != fp))
-       PerlIO_close(PL_rsfp);
-    PL_rsfp = fp;
-}
-
-STATIC void
-restore_expect(void *e)
-{
-    /* a safe way to store a small integer in a pointer */
-    PL_expect = (expectation)((char *)e - PL_tokenbuf);
-}
-
-STATIC void
-restore_lex_expect(void *e)
-{
-    /* a safe way to store a small integer in a pointer */
-    PL_lex_expect = (expectation)((char *)e - PL_tokenbuf);
-}
+/*
+ * 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 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.
+ */
 
 STATIC void
-incline(char *s)
+S_incline(pTHX_ char *s)
 {
     dTHR;
     char *t;
@@ -408,7 +467,7 @@ incline(char *s)
     char ch;
     int sawline = 0;
 
-    PL_curcop->cop_line++;
+    CopLINE_inc(PL_curcop);
     if (*s++ != '#')
        return;
     while (*s == ' ' || *s == '\t') s++;
@@ -433,15 +492,19 @@ incline(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);
 }
 
+/*
+ * S_skipspace
+ * Called to gobble the appropriate amount and type of whitespace.
+ * Skips comments as well.
+ */
+
 STATIC char *
-skipspace(register char *s)
+S_skipspace(pTHX_ register char *s)
 {
     dTHR;
     if (PL_lex_formbrack && PL_lex_brackets <= PL_lex_formbrack) {
@@ -451,10 +514,14 @@ skipspace(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);
        }
+
+       /* comment */
        if (s < PL_bufend && *s == '#') {
            while (s < PL_bufend && *s != '\n')
                s++;
@@ -466,9 +533,20 @@ skipspace(register char *s)
                }
            }
        }
-       if (s < PL_bufend || !PL_rsfp || PL_lex_state != LEX_NORMAL)
+
+       /* only continue to recharge the buffer if we're at the end
+        * 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_sublex_info.sub_inwhat ||
+               PL_lex_state == LEX_FORMLINE)
            return s;
-       if ((s = filter_gets(PL_linestr, PL_rsfp, (prevlen = SvCUR(PL_linestr)))) == Nullch) {
+
+       /* try to recharge the buffer */
+       if ((s = filter_gets(PL_linestr, PL_rsfp,
+                            (prevlen = SvCUR(PL_linestr)))) == Nullch)
+       {
+           /* end of file.  Add on the -p or -n magic */
            if (PL_minus_n || PL_minus_p) {
                sv_setpv(PL_linestr,PL_minus_p ?
                         ";}continue{print or die qq(-p destination: $!\\n)" :
@@ -478,8 +556,19 @@ skipspace(register char *s)
            }
            else
                sv_setpv(PL_linestr,";");
-           PL_oldoldbufptr = PL_oldbufptr = PL_bufptr = s = PL_linestart = SvPVX(PL_linestr);
+
+           /* reset variables for next time we lex */
+           PL_oldoldbufptr = PL_oldbufptr = PL_bufptr = s = PL_linestart
+               = SvPVX(PL_linestr);
            PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
+
+           /* Close the filehandle.  Could be from -P preprocessor,
+            * STDIN, or a regular file.  If we were reading code from
+            * STDIN (because the commandline held no -e or filename)
+            * then we don't close it, we reset it so the code can
+            * read from STDIN too.
+            */
+
            if (PL_preprocess && !PL_in_eval)
                (void)PerlProc_pclose(PL_rsfp);
            else if ((PerlIO*)PL_rsfp == PerlIO_stdin())
@@ -489,46 +578,84 @@ skipspace(register char *s)
            PL_rsfp = Nullfp;
            return 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,
+        * so store the line into the debugger's array of lines
+        */
        if (PERLDB_LINE && PL_curstash != PL_debstash) {
            SV *sv = NEWSV(85,0);
 
            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);
        }
     }
 }
 
+/*
+ * S_check_uni
+ * Check the unary operators to ensure there's no ambiguity in how they're
+ * used.  An ambiguous piece of code would be:
+ *     rand + 5
+ * This doesn't mean rand() + 5.  Because rand() is a unary operator,
+ * the +5 is its argument.
+ */
+
 STATIC void
-check_uni(void) {
+S_check_uni(pTHX)
+{
     char *s;
-    char ch;
     char *t;
+    dTHR;
 
     if (PL_oldoldbufptr != PL_last_uni)
        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;
-    ch = *s;
-    *s = '\0';
-    warn("Warning: Use of \"%s\" without parens is ambiguous", PL_last_uni);
-    *s = ch;
+    if (ckWARN_d(WARN_AMBIGUOUS)){
+        char ch = *s;
+        *s = '\0';
+        Perl_warner(aTHX_ WARN_AMBIGUOUS, 
+                  "Warning: Use of \"%s\" without parens is ambiguous", 
+                  PL_last_uni);
+        *s = ch;
+    }
 }
 
+/* workaround to replace the UNI() macro with a function.  Only the
+ * hints/uts.sh file mentions this.  Other comments elsewhere in the
+ * source indicate Microport Unix might need it too.
+ */
+
 #ifdef CRIPPLED_CC
 
 #undef UNI
 #define UNI(f) return uni(f,s)
 
 STATIC int
-uni(I32 f, char *s)
+S_uni(pTHX_ I32 f, char *s)
 {
     yylval.ival = f;
     PL_expect = XTERM;
@@ -546,10 +673,23 @@ uni(I32 f, char *s)
 
 #endif /* CRIPPLED_CC */
 
+/*
+ * LOP : macro to build a list operator.  Its behaviour has been replaced
+ * with a subroutine, S_lop() for which LOP is just another name.
+ */
+
 #define LOP(f,x) return lop(f,x,s)
 
+/*
+ * S_lop
+ * Build a list operator (or something that might be one).  The rules:
+ *  - if we have a next token, then it's a list operator [why?]
+ *  - if the next thing is an opening paren, then it's a function
+ *  - else it's a list operator
+ */
+
 STATIC I32
-lop(I32 f, expectation x, char *s)
+S_lop(pTHX_ I32 f, int x, char *s)
 {
     dTHR;
     yylval.ival = f;
@@ -569,8 +709,17 @@ lop(I32 f, expectation x, char *s)
        return LSTOP;
 }
 
+/*
+ * S_force_next
+ * When the lexer realizes it knows the next token (for instance,
+ * it is reordering tokens for the parser) then it can call S_force_next
+ * to know what token to return the next time the lexer is called.  Caller
+ * will need to set PL_nextval[], and possibly PL_expect to ensure the lexer
+ * handles the token correctly.
+ */
+
 STATIC void 
-force_next(I32 type)
+S_force_next(pTHX_ I32 type)
 {
     PL_nexttype[PL_nexttoke] = type;
     PL_nexttoke++;
@@ -581,15 +730,31 @@ force_next(I32 type)
     }
 }
 
+/*
+ * S_force_word
+ * When the lexer knows the next thing is a word (for instance, it has
+ * just seen -> and it knows that the next char is a word char, then
+ * it calls S_force_word to stick the next word into the PL_next lookahead.
+ *
+ * Arguments:
+ *   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)
+ *   int allow_pack : if true, : characters will also be allowed (require,
+ *       use, etc. do this)
+ *   int allow_initial_tick : used by the "sub" lexer only.
+ */
+
 STATIC char *
-force_word(register char *start, int token, int check_keyword, int allow_pack, int allow_initial_tick)
+S_force_word(pTHX_ register char *start, int token, int check_keyword, int allow_pack, int allow_initial_tick)
 {
     register char *s;
     STRLEN len;
     
     start = skipspace(start);
     s = start;
-    if (isIDFIRST_lazy(s) ||
+    if (isIDFIRST_lazy_if(s,UTF) ||
        (allow_pack && *s == ':') ||
        (allow_initial_tick && *s == '\'') )
     {
@@ -611,8 +776,17 @@ force_word(register char *start, int token, int check_keyword, int allow_pack, i
     return s;
 }
 
+/*
+ * S_force_ident
+ * Called when the lexer wants $foo *foo &foo etc, but the program
+ * text only contains the "foo" portion.  The first argument is a pointer
+ * to the "foo", and the second argument is the type symbol to prefix.
+ * Forces the next token to be a "WORD".
+ * Creates the symbol if it didn't already exist (via gv_fetchpv()).
+ */
+
 STATIC void
-force_ident(register char *s, int kind)
+S_force_ident(pTHX_ register char *s, int kind)
 {
     if (s && *s) {
        OP* o = (OP*)newSVOP(OP_CONST, 0, newSVpv(s,0));
@@ -634,20 +808,24 @@ force_ident(register char *s, int kind)
     }
 }
 
+/* 
+ * S_force_version
+ * Forces the next token to be a version number.
+ */
+
 STATIC char *
-force_version(char *s)
+S_force_version(pTHX_ char *s)
 {
     OP *version = Nullop;
 
     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) || *d == '}' || !*d) {
             s = scan_num(s);
             /* real VERSION number -- GBARR */
             version = yylval.opval;
@@ -661,8 +839,16 @@ force_version(char *s)
     return (s);
 }
 
+/*
+ * S_tokeq
+ * Tokenize a quoted string passed in as an SV.  It finds the next
+ * chunk, up to end of string or a backslash.  It may make a new
+ * SV containing that chunk (if HINT_NEW_STRING is on).  It also
+ * turns \\ into \.
+ */
+
 STATIC SV *
-tokeq(SV *sv)
+S_tokeq(pTHX_ SV *sv)
 {
     register char *s;
     register char *send;
@@ -699,8 +885,40 @@ tokeq(SV *sv)
     return sv;
 }
 
+/*
+ * Now come three functions related to double-quote context,
+ * S_sublex_start, S_sublex_push, and S_sublex_done.  They're used when
+ * converting things like "\u\Lgnat" into ucfirst(lc("gnat")).  They
+ * interact with PL_lex_state, and create fake ( ... ) argument lists
+ * to handle functions and concatenation.
+ * They assume that whoever calls them will be setting up a fake
+ * join call, because each subthing puts a ',' after it.  This lets
+ *   "lower \luPpEr"
+ * become
+ *  join($, , 'lower ', lcfirst( 'uPpEr', ) ,)
+ *
+ * (I'm not sure whether the spurious commas at the end of lcfirst's
+ * arguments and join's arguments are created or not).
+ */
+
+/*
+ * S_sublex_start
+ * Assumes that yylval.ival is the op we're creating (e.g. OP_LCFIRST).
+ *
+ * Pattern matching will set PL_lex_op to the pattern-matching op to
+ * make (we return THING if yylval.ival is OP_NULL, PMFUNC otherwise).
+ *
+ * OP_CONST and OP_READLINE are easy--just make the new op and return.
+ *
+ * Everything else becomes a FUNC.
+ *
+ * Sets PL_lex_state to LEX_INTERPPUSH unless (ival was OP_NULL or we
+ * had an OP_CONST or OP_READLINE).  This just sets us up for a
+ * call to S_sublex_push().
+ */
+
 STATIC I32
-sublex_start(void)
+S_sublex_start(pTHX)
 {
     register I32 op_type = yylval.ival;
 
@@ -743,8 +961,16 @@ sublex_start(void)
        return FUNC;
 }
 
+/*
+ * S_sublex_push
+ * Create a new scope to save the lexing state.  The scope will be
+ * ended in S_sublex_done.  Returns a '(', starting the function arguments
+ * to the uc, lc, etc. found before.
+ * Sets PL_lex_state to LEX_INTERPCONCAT.
+ */
+
 STATIC I32
-sublex_push(void)
+S_sublex_push(pTHX)
 {
     dTHR;
     ENTER;
@@ -752,13 +978,12 @@ sublex_push(void)
     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);
@@ -770,13 +995,13 @@ sublex_push(void)
     PL_linestr = PL_lex_stuff;
     PL_lex_stuff = Nullsv;
 
-    PL_bufend = PL_bufptr = PL_oldbufptr = PL_oldoldbufptr = PL_linestart = SvPVX(PL_linestr);
+    PL_bufend = PL_bufptr = PL_oldbufptr = PL_oldoldbufptr = PL_linestart
+       = SvPVX(PL_linestr);
     PL_bufend += SvCUR(PL_linestr);
     SAVEFREESV(PL_linestr);
 
     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);
@@ -785,7 +1010,7 @@ sublex_push(void)
     *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)
@@ -796,8 +1021,13 @@ sublex_push(void)
     return '(';
 }
 
+/*
+ * S_sublex_done
+ * Restores lexer state after a S_sublex_push.
+ */
+
 STATIC I32
-sublex_done(void)
+S_sublex_done(pTHX)
 {
     if (!PL_lex_starts++) {
        PL_expect = XOPERATOR;
@@ -807,10 +1037,10 @@ sublex_done(void)
 
     if (PL_lex_casemods) {             /* oops, we've got some unbalanced parens */
        PL_lex_state = LEX_INTERPCASEMOD;
-       return yylex(PERL_YYLEX_PARAM);
+       return yylex();
     }
 
-    /* Is there a right-hand side to take care of? */
+    /* Is there a right-hand side to take care of? (s//RHS/ or tr//RHS/) */
     if (PL_lex_repl && (PL_lex_inwhat == OP_SUBST || PL_lex_inwhat == OP_TRANS)) {
        PL_linestr = PL_lex_repl;
        PL_lex_inpat = 0;
@@ -819,7 +1049,6 @@ sublex_done(void)
        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;
@@ -842,6 +1071,7 @@ sublex_done(void)
        PL_bufend = SvPVX(PL_linestr);
        PL_bufend += SvCUR(PL_linestr);
        PL_expect = XOPERATOR;
+       PL_sublex_info.sub_inwhat = 0;
        return ')';
     }
 }
@@ -920,23 +1150,23 @@ sublex_done(void)
 */
 
 STATIC char *
-scan_const(char *start)
+S_scan_const(pTHX_ char *start)
 {
     register char *send = PL_bufend;           /* end of the constant */
     SV *sv = NEWSV(93, send - start);          /* sv for the constant */
     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 has_utf = FALSE;                      /* embedded \x{} */
     I32 len;                                   /* ? */
     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;
     I32 thisutf = (PL_lex_inwhat == OP_TRANS && PL_sublex_info.sub_op)
-       ? (PL_sublex_info.sub_op->op_private & (PL_lex_repl ? OPpTRANS_FROM_UTF : OPpTRANS_TO_UTF))
+       ? (PL_sublex_info.sub_op->op_private & (PL_lex_repl ?
+                                               OPpTRANS_FROM_UTF : OPpTRANS_TO_UTF))
        : UTF;
-
-    /* leaveit is the set of acceptably-backslashed characters */
-    char *leaveit =
+    const char *leaveit =      /* set of acceptably-backslashed characters */
        PL_lex_inpat
            ? "\\.^$@AGZdDwWsSbBpPXC+*?|()-nrtfeaxcz0123456789[{]} \t\n\r\f\v#"
            : "";
@@ -951,8 +1181,8 @@ scan_const(char *start)
                I32 max;                        /* last character in range */
 
                i = d - SvPVX(sv);              /* remember current offset */
-               SvGROW(sv, SvLEN(sv) + 256);    /* expand the sv -- there'll never be more'n 256 chars in a range for it to grow by */
-               d = SvPVX(sv) + i;              /* restore d after the grow potentially has changed the ptr */
+               SvGROW(sv, SvLEN(sv) + 256);    /* never more than 256 chars in a range */
+               d = SvPVX(sv) + i;              /* refresh d after realloc */
                d -= 2;                         /* eat the first char and the - */
 
                min = (U8)*d;                   /* first char in range */
@@ -1033,7 +1263,8 @@ scan_const(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
@@ -1053,11 +1284,14 @@ scan_const(char *start)
            if (ckWARN(WARN_UTF8)) {
                (void)utf8_to_uv((U8*)s, &len); /* could cvt latin-1 to utf8 here... */
                if (len) {
+                   has_utf = TRUE;
                    while (len--)
                        *d++ = *s++;
                    continue;
                }
            }
+           else
+               has_utf = TRUE;         /* assume valid utf8 */
        }
 
        /* backslashes */
@@ -1077,7 +1311,7 @@ scan_const(char *start)
            {
                dTHR;                   /* only for ckWARN */
                if (ckWARN(WARN_SYNTAX))
-                   warner(WARN_SYNTAX, "\\%c better written as $%c", *s, *s);
+                   Perl_warner(aTHX_ WARN_SYNTAX, "\\%c better written as $%c", *s, *s);
                *--s = '$';
                break;
            }
@@ -1102,7 +1336,7 @@ scan_const(char *start)
                {
                    dTHR;
                    if (ckWARN(WARN_UNSAFE) && isALPHA(*s))
-                       warner(WARN_UNSAFE, 
+                       Perl_warner(aTHX_ WARN_UNSAFE, 
                               "Unrecognized escape \\%c passed through",
                               *s);
                    /* default action is to copy the quoted character */
@@ -1113,7 +1347,7 @@ scan_const(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;
 
@@ -1122,37 +1356,38 @@ scan_const(char *start)
                ++s;
                if (*s == '{') {
                    char* e = strchr(s, '}');
+                   UV uv;
 
                    if (!e) {
                        yyerror("Missing right brace on \\x{}");
                        e = s;
                    }
-                   if (!utf) {
-                       dTHR;
-                       if (ckWARN(WARN_UTF8))
-                           warner(WARN_UTF8,
-                                  "Use of \\x{} without utf8 declaration");
-                   }
                    /* note: utf always shorter than hex */
-                   d = (char*)uv_to_utf8((U8*)d,
-                                         scan_hex(s + 1, e - s - 1, &len));
+                   uv = (UV)scan_hex(s + 1, e - s - 1, &len);
+                   if (uv > 127) {
+                       d = (char*)uv_to_utf8((U8*)d, uv);
+                       has_utf = TRUE;
+                   }
+                   else
+                       *d++ = (char)uv;
                    s = e + 1;
-                       
                }
                else {
+                   /* XXX collapse this branch into the one above */
                    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 */
+                       has_utf = TRUE;
                    }
                    else {
                        if (uv >= 127 && UTF) {
                            dTHR;
                            if (ckWARN(WARN_UTF8))
-                               warner(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;
                    }
@@ -1160,6 +1395,43 @@ scan_const(char *start)
                }
                continue;
 
+           /* \N{latin small letter a} is a named character */
+           case 'N':
+               ++s;
+               if (*s == '{') {
+                   char* e = strchr(s, '}');
+                   HV *hv;
+                   SV **svp;
+                   SV *res, *cv;
+                   STRLEN len;
+                   char *str;
+                   char *why = Nullch;
+                   if (!e) {
+                       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, "\\N{...}" );
+                   str = SvPV(res,len);
+                   if (len > e - s + 4) {
+                       char *odest = SvPVX(sv);
+
+                       SvGROW(sv, (SvCUR(sv) + len - (e - s + 4)));
+                       d = SvPVX(sv) + (d - odest);
+                   }
+                   Copy(str, d, len, char);
+                   d += len;
+                   SvREFCNT_dec(res);
+                 cont_scan:
+                   s = e + 1;
+               }
+               else
+                   yyerror("Missing braces on \\N{}");
+               continue;
+
            /* \c is a control character */
            case 'c':
                s++;
@@ -1190,12 +1462,21 @@ scan_const(char *start)
            case 't':
                *d++ = '\t';
                break;
+#ifdef EBCDIC
+           case 'e':
+               *d++ = '\047';  /* CP 1047 */
+               break;
+           case 'a':
+               *d++ = '\057';  /* CP 1047 */
+               break;
+#else
            case 'e':
                *d++ = '\033';
                break;
            case 'a':
                *d++ = '\007';
                break;
+#endif
            } /* end switch */
 
            s++;
@@ -1209,6 +1490,8 @@ scan_const(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)) {
@@ -1232,9 +1515,29 @@ scan_const(char *start)
     return s;
 }
 
+/* S_intuit_more
+ * Returns TRUE if there's more to the expression (e.g., a subscript),
+ * FALSE otherwise.
+ *
+ * It deals with "$foo[3]" and /$foo[3]/ and /$foo[0123456789$]+/
+ *
+ * ->[ and ->{ return TRUE
+ * { and [ outside a pattern are always subscripts, so return TRUE
+ * if we're outside a pattern and it's not { or [, then return FALSE
+ * if we're in a pattern and the first char is a {
+ *   {4,5} (any digits around the comma) returns FALSE
+ * if we're in a pattern and the first char is a [
+ *   [] returns FALSE
+ *   [SOMETHING] has a funky algorithm to decide whether it's a
+ *      character class or not.  It has to deal with things like
+ *      /$foo[-3]/ and /$foo[$bar]/ as well as /$foo[$\d]+/
+ * anything else returns TRUE
+ */
+
 /* This is the one truly awful dwimmer necessary to conflate C and sed. */
+
 STATIC int
-intuit_more(register char *s)
+S_intuit_more(pTHX_ register char *s)
 {
     if (PL_lex_brackets)
        return TRUE;
@@ -1268,6 +1571,7 @@ intuit_more(register char *s)
     if (*s == ']' || *s == '^')
        return FALSE;
     else {
+        /* this is terrifying, and it works */
        int weight = 2;         /* let's weigh the evidence */
        char seen[256];
        unsigned char un_char = 255, last_un_char;
@@ -1296,7 +1600,7 @@ intuit_more(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;
@@ -1363,8 +1667,29 @@ intuit_more(register char *s)
     return TRUE;
 }
 
+/*
+ * S_intuit_method
+ *
+ * Does all the checking to disambiguate
+ *   foo bar
+ * between foo(bar) and bar->foo.  Returns 0 if not a method, otherwise
+ * FUNCMETH (bar->foo(args)) or METHOD (bar->foo args).
+ *
+ * First argument is the stuff after the first token, e.g. "bar".
+ *
+ * Not a method if bar is a filehandle.
+ * Not a method if foo is a subroutine prototyped to take a filehandle.
+ * Not a method if it's really "Foo $bar"
+ * Method if it's "foo $bar"
+ * 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 quoted with
+ *   =>
+ */
+
 STATIC int
-intuit_method(char *start, GV *gv)
+S_intuit_method(pTHX_ char *start, GV *gv)
 {
     char *s = start + (*start == '$');
     char tmpbuf[sizeof PL_tokenbuf];
@@ -1387,6 +1712,11 @@ intuit_method(char *start, GV *gv)
            gv = 0;
     }
     s = scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len);
+    /* start is the beginning of the possible filehandle/object,
+     * and s is the end of it
+     * tmpbuf is a copy of it
+     */
+
     if (*start == '$') {
        if (gv || PL_last_lop_op == OP_PRINT || isUPPER(*PL_tokenbuf))
            return 0;
@@ -1422,8 +1752,15 @@ intuit_method(char *start, GV *gv)
     return 0;
 }
 
+/*
+ * S_incl_perldb
+ * Return a string of Perl code to load the debugger.  If PERL5DB
+ * is set, it will return the contents of that, otherwise a
+ * compile-time require of perl5db.pl.
+ */
+
 STATIC char*
-incl_perldb(void)
+S_incl_perldb(pTHX)
 {
     if (PL_perldb) {
        char *pdb = PerlEnv_getenv("PERL5DB");
@@ -1448,29 +1785,28 @@ incl_perldb(void)
  * 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.
  */
 
 SV *
-filter_add(filter_t funcp, SV *datasv)
+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)
        datasv = NEWSV(255,0);
     if (!SvUPGRADE(datasv, SVt_PVIO))
-        die("Can't upgrade filter_add data to SVt_PVIO");
+        Perl_die(aTHX_ "Can't upgrade filter_add data to SVt_PVIO");
     IoDIRP(datasv) = (DIR*)funcp; /* stash funcp into spare field */
-    if (PL_filter_debug) {
-       STRLEN n_a;
-       warn("filter_add func %p (%s)", funcp, SvPV(datasv, n_a));
-    }
+    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);
@@ -1479,26 +1815,29 @@ filter_add(filter_t funcp, SV *datasv)
 
 /* Delete most recently added instance of this filter function.        */
 void
-filter_del(filter_t funcp)
+Perl_filter_del(pTHX_ filter_t funcp)
 {
-    if (PL_filter_debug)
-       warn("filter_del func %p", funcp);
+    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){
+    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;
     }
     /* we need to search for the correct entry and clear it    */
-    die("filter_del can only delete in reverse order (currently)");
+    Perl_die(aTHX_ "filter_del can only delete in reverse order (currently)");
 }
 
 
 /* Invoke the n'th filter function for the current rsfp.        */
 I32
-filter_read(int idx, SV *buf_sv, int maxlen)
+Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen)
             
                
                                /* 0 = read one text line */
@@ -1511,8 +1850,8 @@ filter_read(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.      */
-       if (PL_filter_debug)
-           warn("filter_read %d: from rsfp\n", idx);
+       DEBUG_P(PerlIO_printf(Perl_debug_log,
+                             "filter_read %d: from rsfp\n", idx));
        if (maxlen) { 
            /* Want a block */
            int len ;
@@ -1540,29 +1879,28 @@ filter_read(int idx, SV *buf_sv, int maxlen)
     }
     /* Skip this filter slot if filter has been deleted        */
     if ( (datasv = FILTER_DATA(idx)) == &PL_sv_undef){
-       if (PL_filter_debug)
-           warn("filter_read %d: skipped (filter deleted)\n", idx);
+       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);
-    if (PL_filter_debug) {
-       STRLEN n_a;
-       warn("filter_read %d: via function %p (%s)\n",
-               idx, funcp, SvPV(datasv,n_a));
-    }
+    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            */
-    return (*funcp)(PERL_OBJECT_THIS_ idx, buf_sv, maxlen);
+    return (*funcp)(aTHXo_ idx, buf_sv, maxlen);
 }
 
 STATIC char *
-filter_gets(register SV *sv, register PerlIO *fp, STRLEN append)
+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) {
@@ -1581,7 +1919,9 @@ filter_gets(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
 
 /*
@@ -1609,7 +1949,12 @@ filter_gets(register SV *sv, register PerlIO *fp, STRLEN append)
       if we already built the token before, use it.
 */
 
-int yylex(PERL_YYLEX_PARAM_DECL)
+int
+#ifdef USE_PURE_BISON
+Perl_yylex(pTHX_ YYSTYPE *lvalp, int *lcharp)
+#else
+Perl_yylex(pTHX)
+#endif
 {
     dTHR;
     register char *s;
@@ -1637,12 +1982,21 @@ int yylex(PERL_YYLEX_PARAM_DECL)
           if it's a legal name, the OP is a PADANY.
        */
        if (PL_in_my) {
-           if (strchr(PL_tokenbuf,':'))
-               yyerror(form(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;
+           }
        }
 
        /* 
@@ -1670,6 +2024,26 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            }
 #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] == '$' &&
@@ -1681,7 +2055,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                         d++)
                    {
                        if (strnEQ(d,"<=>",3) || strnEQ(d,"cmp",3)) {
-                           croak("Can't use \"my %s\" in sort comparison",
+                           Perl_croak(aTHX_ "Can't use \"my %s\" in sort comparison",
                                  PL_tokenbuf);
                        }
                    }
@@ -1701,7 +2075,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        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(form("In string, %s now must be written as \\%s",
+               yyerror(Perl_form(aTHX_ "In string, %s now must be written as \\%s",
                             PL_tokenbuf, PL_tokenbuf));
        }
 
@@ -1724,7 +2098,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        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];
@@ -1741,7 +2115,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
     case LEX_INTERPCASEMOD:
 #ifdef DEBUGGING
        if (PL_bufptr != PL_bufend && *PL_bufptr != '\\')
-           croak("panic: INTERPCASEMOD");
+           Perl_croak(aTHX_ "panic: INTERPCASEMOD");
 #endif
        /* handle \E or end of string */
                if (PL_bufptr == PL_bufend || PL_bufptr[1] == 'E') {
@@ -1761,7 +2135,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            if (PL_bufptr != PL_bufend)
                PL_bufptr += 2;
            PL_lex_state = LEX_INTERPCONCAT;
-           return yylex(PERL_YYLEX_PARAM);
+           return yylex();
        }
        else {
            s = PL_bufptr + 1;
@@ -1796,7 +2170,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            else if (*s == 'Q')
                PL_nextval[PL_nexttoke].ival = OP_QUOTEMETA;
            else
-               croak("panic: yylex");
+               Perl_croak(aTHX_ "panic: yylex");
            PL_bufptr = s + 1;
            force_next(FUNC);
            if (PL_lex_starts) {
@@ -1805,7 +2179,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                Aop(OP_CONCAT);
            }
            else
-               return yylex(PERL_YYLEX_PARAM);
+               return yylex();
        }
 
     case LEX_INTERPPUSH:
@@ -1838,7 +2212,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            s = PL_bufptr;
            Aop(OP_CONCAT);
        }
-       return yylex(PERL_YYLEX_PARAM);
+       return yylex();
 
     case LEX_INTERPENDMAYBE:
        if (intuit_more(PL_bufptr)) {
@@ -1857,14 +2231,14 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            && SvEVALED(PL_lex_repl))
        {
            if (PL_bufptr != PL_bufend)
-               croak("Bad evalled substitution pattern");
+               Perl_croak(aTHX_ "Bad evalled substitution pattern");
            PL_lex_repl = Nullsv;
        }
        /* FALLTHROUGH */
     case LEX_INTERPCONCAT:
 #ifdef DEBUGGING
        if (PL_lex_brackets)
-           croak("panic: INTERPCONCAT");
+           Perl_croak(aTHX_ "panic: INTERPCONCAT");
 #endif
        if (PL_bufptr == PL_bufend)
            return sublex_done();
@@ -1894,11 +2268,11 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                Aop(OP_CONCAT);
            else {
                PL_bufptr = s;
-               return yylex(PERL_YYLEX_PARAM);
+               return yylex();
            }
        }
 
-       return yylex(PERL_YYLEX_PARAM);
+       return yylex();
     case LEX_FORMLINE:
        PL_lex_state = LEX_NORMAL;
        s = scan_formline(PL_bufptr);
@@ -1911,15 +2285,16 @@ int yylex(PERL_YYLEX_PARAM_DECL)
     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:
     switch (*s) {
     default:
-       if (isIDFIRST_lazy(s))
+       if (isIDFIRST_lazy_if(s,UTF))
            goto keylookup;
-       croak("Unrecognized character \\x%02X", *s & 255);
+       Perl_croak(aTHX_ "Unrecognized character \\x%02X", *s & 255);
     case 4:
     case 26:
        goto fake_eof;                  /* emulate EOF on ^D or ^Z */
@@ -1961,20 +2336,20 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    if (PL_minus_F) {
                        if (strchr("/'\"", *PL_splitstr)
                              && strchr(PL_splitstr + 1, *PL_splitstr))
-                           sv_catpvf(PL_linestr, "@F=split(%s);", PL_splitstr);
+                           Perl_sv_catpvf(aTHX_ PL_linestr, "@F=split(%s);", PL_splitstr);
                        else {
                            char delim;
                            s = "'~#\200\1'"; /* surely one char is unused...*/
                            while (s[1] && strchr(PL_splitstr, *s))  s++;
                            delim = *s;
-                           sv_catpvf(PL_linestr, "@F=split(%s%c",
+                           Perl_sv_catpvf(aTHX_ PL_linestr, "@F=split(%s%c",
                                      "q" + (delim == '\''), delim);
                            for (s = PL_splitstr; *s; s++) {
                                if (*s == '\\')
                                    sv_catpvn(PL_linestr, "\\", 1);
                                sv_catpvn(PL_linestr, s, 1);
                            }
-                           sv_catpvf(PL_linestr, "%c);", delim);
+                           Perl_sv_catpvf(aTHX_ PL_linestr, "%c);", delim);
                        }
                    }
                    else
@@ -1989,7 +2364,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 
                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;
        }
@@ -2038,10 +2413,10 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 
            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 */
@@ -2079,7 +2454,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                     */
                    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);
                    }
@@ -2091,8 +2466,24 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                 * 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
@@ -2138,7 +2529,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                        newargv = PL_origargv;
                    newargv[0] = ipath;
                    PerlProc_execv(ipath, newargv);
-                   croak("Can't exec %s", ipath);
+                   Perl_croak(aTHX_ "Can't exec %s", ipath);
                }
                if (d) {
                    U32 oldpdb = PL_perldb;
@@ -2153,7 +2544,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                            if (*d == 'M' || *d == 'm') {
                                char *m = d;
                                while (*d && !isSPACE(*d)) d++;
-                               croak("Too late for \"-%.*s\" option",
+                               Perl_croak(aTHX_ "Too late for \"-%.*s\" option",
                                      (int)(d - m), m);
                            }
                            d = moreswitches(d);
@@ -2178,13 +2569,13 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        if (PL_lex_formbrack && PL_lex_brackets <= PL_lex_formbrack) {
            PL_bufptr = s;
            PL_lex_state = LEX_FORMLINE;
-           return yylex(PERL_YYLEX_PARAM);
+           return yylex();
        }
        goto retry;
     case '\r':
 #ifdef PERL_STRICT_CR
-       warn("Illegal character \\%03o (carriage return)", '\r');
-       croak(
+       Perl_warn(aTHX_ "Illegal character \\%03o (carriage return)", '\r');
+       Perl_croak(aTHX_ 
       "(Maybe you didn't strip carriage returns after a network transfer?)\n");
 #endif
     case ' ': case '\t': case '\f': case 013:
@@ -2202,7 +2593,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            if (PL_lex_formbrack && PL_lex_brackets <= PL_lex_formbrack) {
                PL_bufptr = s;
                PL_lex_state = LEX_FORMLINE;
-               return yylex(PERL_YYLEX_PARAM);
+               return yylex();
            }
        }
        else {
@@ -2254,7 +2645,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            case 'A': gv_fetchpv("\024",TRUE, SVt_PV); FTST(OP_FTATIME);
            case 'C': gv_fetchpv("\024",TRUE, SVt_PV); FTST(OP_FTCTIME);
            default:
-               croak("Unrecognized file test: -%c", (int)tmp);
+               Perl_croak(aTHX_ "Unrecognized file test: -%c", (int)tmp);
                break;
            }
        }
@@ -2269,7 +2660,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        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);
            }
@@ -2350,6 +2741,102 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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_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) {
+                       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++;
@@ -2359,8 +2846,8 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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 ')':
@@ -2414,7 +2901,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                while (d < PL_bufend && (*d == ' ' || *d == '\t'))
                    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'))
@@ -2427,10 +2914,12 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                }
            }
            /* 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;
@@ -2471,7 +2960,8 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    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;
@@ -2502,8 +2992,10 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    }
                    t++;
                }
-               else if (isIDFIRST_lazy(s)) {
-                   for (t++; t < PL_bufend && isALNUM_lazy(t); t++) ;
+               else if (isALNUM_lazy_if(t,UTF)) {
+                   t += UTF8SKIP(t);
+                   while (t < PL_bufend && isALNUM_lazy_if(t,UTF))
+                        t += UTF8SKIP(t);
                }
                while (t < PL_bufend && isSPACE(*t))
                    t++;
@@ -2513,7 +3005,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                                   || (*t == '=' && t[1] == '>')))
                    OPERATOR(HASHBRACK);
                if (PL_expect == XREF)
-                   PL_expect = XSTATE; /* was XTERM, trying XSTATE */
+                   PL_expect = XTERM;
                else {
                    PL_lex_brackstack[PL_lex_brackets-1] = XSTATE;
                    PL_expect = XSTATE;
@@ -2521,7 +3013,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            }
            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('{');
@@ -2536,10 +3028,11 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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(PERL_YYLEX_PARAM);     /* ignore fake brackets */
+                   return yylex();     /* ignore fake brackets */
                }
                if (*s == '-' && s[1] == '>')
                    PL_lex_state = LEX_INTERPENDMAYBE;
@@ -2547,10 +3040,10 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    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(PERL_YYLEX_PARAM);             /* ignore fake brackets */
+           return yylex();             /* ignore fake brackets */
        }
        force_next('}');
        TOKEN(';');
@@ -2561,10 +3054,12 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            AOPERATOR(ANDAND);
        s--;
        if (PL_expect == XOPERATOR) {
-           if (ckWARN(WARN_SEMICOLON) && isIDFIRST_lazy(s) && PL_bufptr == PL_linestart) {
-               PL_curcop->cop_line--;
-               warner(WARN_SEMICOLON, PL_warn_nosemi);
-               PL_curcop->cop_line++;
+           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);
            }
            BAop(OP_BIT_AND);
        }
@@ -2596,7 +3091,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        if (tmp == '~')
            PMop(OP_MATCH);
        if (ckWARN(WARN_SYNTAX) && tmp && isSPACE(*s) && strchr("+-*/%.^&|<",tmp))
-           warner(WARN_SYNTAX, "Reversed %c= operator",(int)tmp);
+           Perl_warner(aTHX_ WARN_SYNTAX, "Reversed %c= operator",(int)tmp);
        s--;
        if (PL_expect == XSTATE && isALPHA(tmp) &&
                (s == PL_linestart+1 || s[-2] == '\n') )
@@ -2691,12 +3186,12 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            }
        }
 
-       if (s[1] == '#' && (isIDFIRST_lazy(s+2) || strchr("{$:+-", s[2]))) {
-           if (PL_expect == XOPERATOR)
-               no_op("Array length", PL_bufptr);
+       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);
+           s = scan_ident(s + 1, PL_bufend, PL_tokenbuf + 1,
+                          sizeof PL_tokenbuf - 1, FALSE);
+           if (PL_expect == XOPERATOR)
+               no_op("Array length", s);
            if (!PL_tokenbuf[1])
                PREREF(DOLSHARP);
            PL_expect = XOPERATOR;
@@ -2704,10 +3199,11 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            TOKEN(DOLSHARP);
        }
 
-       if (PL_expect == XOPERATOR)
-           no_op("Scalar", PL_bufptr);
        PL_tokenbuf[0] = '$';
-       s = scan_ident(s, PL_bufend, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, FALSE);
+       s = scan_ident(s, PL_bufend, PL_tokenbuf + 1,
+                      sizeof PL_tokenbuf - 1, FALSE);
+       if (PL_expect == XOPERATOR)
+           no_op("Scalar", s);
        if (!PL_tokenbuf[1]) {
            if (s == PL_bufend)
                yyerror("Final $ should be \\$ or $name");
@@ -2733,13 +3229,13 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                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);
                        while (t < PL_bufend && *t != ']')
                            t++;
-                       warner(WARN_SYNTAX,
+                       Perl_warner(aTHX_ WARN_SYNTAX,
                                "Multidimensional syntax %.*s not supported",
                                (t - PL_bufptr) + 1, PL_bufptr);
                    }
@@ -2753,11 +3249,11 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    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 == ';' && perl_get_cv(tmpbuf, FALSE))
-                           warner(WARN_SYNTAX,
+                       if (*t == ';' && get_cv(tmpbuf, FALSE))
+                           Perl_warner(aTHX_ WARN_SYNTAX,
                                "You need to quote \"%s\"", tmpbuf);
                    }
                }
@@ -2771,9 +3267,9 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                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)) {
@@ -2831,12 +3327,12 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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++;
                        PL_bufptr = skipspace(PL_bufptr);
-                       warner(WARN_SYNTAX,
+                       Perl_warner(aTHX_ WARN_SYNTAX,
                            "Scalar value %.*s better written as $%.*s",
                            t-PL_bufptr, PL_bufptr, t-PL_bufptr-1, PL_bufptr+1);
                    }
@@ -2852,7 +3348,8 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            /* 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());
@@ -2900,7 +3397,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        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;
@@ -2916,7 +3413,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        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;
@@ -2938,7 +3435,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        TERM(sublex_start());
 
     case '`':
-       s = scan_str(s);
+       s = scan_str(s,FALSE,FALSE);
        if (PL_expect == XOPERATOR)
            no_op("Backticks",s);
        if (!s)
@@ -2950,12 +3447,25 @@ int yylex(PERL_YYLEX_PARAM_DECL)
     case '\\':
        s++;
        if (ckWARN(WARN_SYNTAX) && PL_lex_inwhat && isDIGIT(*s))
-           warner(WARN_SYNTAX,"Can't use \\%c to mean $%c in expression",
+           Perl_warner(aTHX_ WARN_SYNTAX,"Can't use \\%c to mean $%c in expression",
                        *s, *s);
        if (PL_expect == XOPERATOR)
            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++;
@@ -2985,7 +3495,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
     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':
@@ -3059,6 +3569,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            }
            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 */
@@ -3069,7 +3580,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                gvp = 0;
                if (ckWARN(WARN_AMBIGUOUS) && hgv
                    && tmp != KEY_x && tmp != KEY_CORE) /* never ambiguous */
-                   warner(WARN_AMBIGUOUS,
+                   Perl_warner(aTHX_ WARN_AMBIGUOUS,
                        "Ambiguous call resolved as CORE::%s(), %s",
                         GvENAME(hgv), "qualify as such or use &");
            }
@@ -3090,16 +3601,16 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    s = scan_word(s, PL_tokenbuf + len, sizeof PL_tokenbuf - len,
                                  TRUE, &morelen);
                    if (!morelen)
-                       croak("Bad name after %s%s", PL_tokenbuf,
+                       Perl_croak(aTHX_ "Bad name after %s%s", PL_tokenbuf,
                                *s == '\'' ? "'" : "::");
                    len += morelen;
                }
 
                if (PL_expect == XOPERATOR) {
                    if (PL_bufptr == PL_linestart) {
-                       PL_curcop->cop_line--;
-                       warner(WARN_SEMICOLON, PL_warn_nosemi);
-                       PL_curcop->cop_line++;
+                       CopLINE_dec(PL_curcop);
+                       Perl_warner(aTHX_ WARN_SEMICOLON, PL_warn_nosemi);
+                       CopLINE_inc(PL_curcop);
                    }
                    else
                        no_op("Bareword",s);
@@ -3113,7 +3624,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    PL_tokenbuf[len - 2] == ':' && PL_tokenbuf[len - 1] == ':')
                {
                    if (ckWARN(WARN_UNSAFE) && ! gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVHV))
-                       warner(WARN_UNSAFE, 
+                       Perl_warner(aTHX_ WARN_UNSAFE, 
                            "Bareword \"%s\" refers to nonexistent package",
                             PL_tokenbuf);
                    len -= 2;
@@ -3151,13 +3662,11 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 
                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
-                    || (PL_last_lop_op == OP_ENTERSUB 
-                        && PL_last_proto 
-                        && PL_last_proto[PL_last_proto[0] == ';' ? 1 : 0] == '*')) )
+                   (PL_expect == XREF ||
+                    ((PL_opargs[PL_last_lop_op] >> OASHIFT)& 7) == OA_FILEREF))
                {
                    bool immediate_paren = *s == '(';
 
@@ -3166,15 +3675,17 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 
                    /* 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. */
                    /* (But it's an indir obj regardless for sort.) */
 
                    if ((PL_last_lop_op == OP_SORT ||
-                         (!immediate_paren && (!gv || !GvCVu(gv))) ) &&
-                        (PL_last_lop_op != OP_MAPSTART && PL_last_lop_op != OP_GREPSTART)){
+                         (!immediate_paren && (!gv || !GvCVu(gv)))) &&
+                        (PL_last_lop_op != OP_MAPSTART &&
+                        PL_last_lop_op != OP_GREPSTART))
+                   {
                        PL_expect = (PL_last_lop == PL_oldoldbufptr) ? XTERM : XOPERATOR;
                        goto bareword;
                    }
@@ -3187,11 +3698,8 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                if (*s == '(') {
                    CLINE;
                    if (gv && GvCVu(gv)) {
-                       CV *cv;
-                       if ((cv = GvCV(gv)) && SvPOK(cv))
-                           PL_last_proto = SvPV((SV*)cv, n_a);
                        for (d = s + 1; *d == ' ' || *d == '\t'; d++) ;
-                       if (*d == ')' && (sv = cv_const_sv(cv))) {
+                       if (*d == ')' && (sv = cv_const_sv(GvCV(gv)))) {
                            s = d + 1;
                            goto its_constant;
                        }
@@ -3200,7 +3708,6 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    PL_expect = XOPERATOR;
                    force_next(WORD);
                    yylval.ival = 0;
-                   PL_last_lop_op = OP_ENTERSUB;
                    TOKEN('&');
                }
 
@@ -3214,18 +3721,17 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 
                /* 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) */
 
                if (gv && GvCVu(gv)) {
                    CV* cv;
-                   if (lastchar == '-')
-                       warn("Ambiguous use of -%s resolved as -&%s()",
+                   if (lastchar == '-' && ckWARN_d(WARN_AMBIGUOUS))
+                       Perl_warner(aTHX_ WARN_AMBIGUOUS,
+                               "Ambiguous use of -%s resolved as -&%s()",
                                PL_tokenbuf, PL_tokenbuf);
-                   PL_last_lop = PL_oldbufptr;
-                   PL_last_lop_op = OP_ENTERSUB;
                    /* Check for a constant sub */
                    cv = GvCV(gv);
                    if ((sv = cv_const_sv(cv))) {
@@ -3239,60 +3745,51 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    /* Resolve to GV now. */
                    op_free(yylval.opval);
                    yylval.opval = newCVREF(0, newGVOP(OP_GV, 0, gv));
+                   yylval.opval->op_private |= OPpENTERSUB_NOPAREN;
+                   PL_last_lop = PL_oldbufptr;
                    PL_last_lop_op = OP_ENTERSUB;
                    /* Is there a prototype? */
                    if (SvPOK(cv)) {
                        STRLEN len;
-                       PL_last_proto = SvPV((SV*)cv, len);
+                       char *proto = SvPV((SV*)cv, len);
                        if (!len)
                            TERM(FUNC0SUB);
-                       if (strEQ(PL_last_proto, "$"))
+                       if (strEQ(proto, "$"))
                            OPERATOR(UNIOPSUB);
-                       if (*PL_last_proto == '&' && *s == '{') {
+                       if (*proto == '&' && *s == '{') {
                            sv_setpv(PL_subname,"__ANON__");
                            PREBLOCK(LSTOPSUB);
                        }
-                   } else
-                       PL_last_proto = NULL;
+                   }
                    PL_nextval[PL_nexttoke].opval = yylval.opval;
                    PL_expect = XTERM;
                    force_next(WORD);
                    TOKEN(NOAMP);
                }
 
-               if (PL_hints & HINT_STRICT_SUBS &&
-                   lastchar != '-' &&
-                   strnNE(s,"->",2) &&
-                   PL_last_lop_op != OP_TRUNCATE &&  /* S/F prototype in opcode.pl */
-                   PL_last_lop_op != OP_ACCEPT &&
-                   PL_last_lop_op != OP_PIPE_OP &&
-                   PL_last_lop_op != OP_SOCKPAIR &&
-                   !(PL_last_lop_op == OP_ENTERSUB 
-                        && PL_last_proto 
-                        && PL_last_proto[PL_last_proto[0] == ';' ? 1 : 0] == '*'))
-               {
-                   warn(
-                    "Bareword \"%s\" not allowed while \"strict subs\" in use",
-                       PL_tokenbuf);
-                   ++PL_error_count;
-               }
-
                /* Call it a bare word */
 
-           bareword:
-               if (ckWARN(WARN_RESERVED)) {
-                   if (lastchar != '-') {
-                       for (d = PL_tokenbuf; *d && isLOWER(*d); d++) ;
-                       if (!*d)
-                           warner(WARN_RESERVED, PL_warn_reserved, PL_tokenbuf);
+               if (PL_hints & HINT_STRICT_SUBS)
+                   yylval.opval->op_private |= OPpCONST_STRICT;
+               else {
+               bareword:
+                   if (ckWARN(WARN_RESERVED)) {
+                       if (lastchar != '-') {
+                           for (d = PL_tokenbuf; *d && isLOWER(*d); d++) ;
+                           if (!*d)
+                               Perl_warner(aTHX_ WARN_RESERVED, PL_warn_reserved,
+                                      PL_tokenbuf);
+                       }
                    }
                }
 
            safe_bareword:
-               if (lastchar && strchr("*%&", lastchar)) {
-                   warn("Operator or semicolon missing before %c%s",
+               if (lastchar && strchr("*%&", lastchar) && ckWARN_d(WARN_AMBIGUOUS)) {
+                   Perl_warner(aTHX_ WARN_AMBIGUOUS,
+                       "Operator or semicolon missing before %c%s",
                        lastchar, PL_tokenbuf);
-                   warn("Ambiguous use of %c resolved as operator %c",
+                   Perl_warner(aTHX_ WARN_AMBIGUOUS,
+                       "Ambiguous use of %c resolved as operator %c",
                        lastchar, lastchar);
                }
                TOKEN(WORD);
@@ -3300,12 +3797,12 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 
        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__:
-           yylval.opval = (OP*)newSVOP(OP_CONST, 0,
-                                   newSVpvf("%ld", (long)PL_curcop->cop_line));
+            yylval.opval = (OP*)newSVOP(OP_CONST, 0,
+                                    Perl_newSVpvf(aTHX_ "%"IVdf, (IV)CopLINE(PL_curcop)));
            TERM(THING);
 
        case KEY___PACKAGE__:
@@ -3324,7 +3821,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                char *pname = "main";
                if (PL_tokenbuf[2] == 'D')
                    pname = HvNAME(PL_curstash ? PL_curstash : PL_defstash);
-               gv = gv_fetchpv(form("%s::DATA", pname), TRUE, SVt_PVIO);
+               gv = gv_fetchpv(Perl_form(aTHX_ "%s::DATA", pname), TRUE, SVt_PVIO);
                GvMULTI_on(gv);
                if (!GvIO(gv))
                    GvIOp(gv) = newIO();
@@ -3343,6 +3840,28 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    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;
@@ -3351,8 +3870,9 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        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;
@@ -3419,8 +3939,10 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 
        case KEY_crypt:
 #ifdef FCRYPT
-           if (!PL_cryptseen++)
+           if (!PL_cryptseen) {
+               PL_cryptseen = TRUE;
                init_des();
+           }
 #endif
            LOP(OP_CRYPT,XTERM);
 
@@ -3428,7 +3950,8 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            if (ckWARN(WARN_OCTAL)) {
                for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ;
                if (*d != '0' && isDIGIT(*d))
-                   yywarn("chmod: mode argument is missing initial 0");
+                   Perl_warner(aTHX_ WARN_OCTAL,
+                               "chmod: mode argument is missing initial 0");
            }
            LOP(OP_CHMOD,XTERM);
 
@@ -3480,7 +4003,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            PREBLOCK(ELSE);
 
        case KEY_elsif:
-           yylval.ival = PL_curcop->cop_line;
+           yylval.ival = CopLINE(PL_curcop);
            OPERATOR(ELSIF);
 
        case KEY_eq:
@@ -3530,16 +4053,24 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 
        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)) {
+           if (PL_expect == XSTATE && isIDFIRST_lazy_if(s,UTF)) {
                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))
-                   croak("Missing $ on loop variable");
+               if (isIDFIRST_lazy_if(p,UTF)) {
+                   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);
 
@@ -3565,7 +4096,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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);
@@ -3660,7 +4191,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            UNI(OP_HEX);
 
        case KEY_if:
-           yylval.ival = PL_curcop->cop_line;
+           yylval.ival = CopLINE(PL_curcop);
            OPERATOR(IF);
 
        case KEY_index:
@@ -3692,6 +4223,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            UNI(OP_LCFIRST);
 
        case KEY_local:
+           yylval.ival = 0;
            OPERATOR(LOCAL);
 
        case KEY_length:
@@ -3727,7 +4259,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 
        case KEY_map:
            LOP(OP_MAPSTART, XREF);
-           
+
        case KEY_mkdir:
            LOP(OP_MKDIR,XTERM);
 
@@ -3743,11 +4275,14 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        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)) {
+           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);
                if (!PL_in_my_stash) {
                    char tmpbuf[1024];
@@ -3756,6 +4291,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                    yyerror(tmpbuf);
                }
            }
+           yylval.ival = 1;
            OPERATOR(MY);
 
        case KEY_next:
@@ -3774,17 +4310,21 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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);
-           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))
-                   warn("Precedence problem: open %.*s should be open(%.*s)",
-                       d-s,s, d-s,s);
+               if (strchr("|&*+-=!?:.", *t) && ckWARN_d(WARN_AMBIGUOUS))
+                   Perl_warner(aTHX_ WARN_AMBIGUOUS,
+                          "Precedence problem: open %.*s should be open(%.*s)",
+                           d-s,s, d-s,s);
            }
            LOP(OP_OPEN,XTERM);
 
@@ -3832,7 +4372,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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;
@@ -3842,7 +4382,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            UNI(OP_QUOTEMETA);
 
        case KEY_qw:
-           s = scan_str(s);
+           s = scan_str(s,FALSE,FALSE);
            if (!s)
                missingterm((char*)0);
            force_next(')');
@@ -3857,12 +4397,12 @@ int yylex(PERL_YYLEX_PARAM_DECL)
                        if (!warned && ckWARN(WARN_SYNTAX)) {
                            for (; !isSPACE(*d) && len; --len, ++d) {
                                if (*d == ',') {
-                                   warner(WARN_SYNTAX,
+                                   Perl_warner(aTHX_ WARN_SYNTAX,
                                        "Possible attempt to separate words with commas");
                                    ++warned;
                                }
                                else if (*d == '#') {
-                                   warner(WARN_SYNTAX,
+                                   Perl_warner(aTHX_ WARN_SYNTAX,
                                        "Possible attempt to put comments in qw() list");
                                    ++warned;
                                }
@@ -3887,7 +4427,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            TOKEN('(');
 
        case KEY_qq:
-           s = scan_str(s);
+           s = scan_str(s,FALSE,FALSE);
            if (!s)
                missingterm((char*)0);
            yylval.ival = OP_STRINGIFY;
@@ -3900,7 +4440,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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;
@@ -3911,12 +4451,18 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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_if(PL_tokenbuf,UTF))
+                   gv_stashpvn(PL_tokenbuf, strlen(PL_tokenbuf), TRUE);
+               else if (*s == '<')
+                   yyerror("<> should be quotes");
+           }
            UNI(OP_REQUIRE);
 
        case KEY_reset:
@@ -4062,7 +4608,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            checkcomma(s,PL_tokenbuf,"subroutine name");
            s = skipspace(s);
            if (*s == ';' || *s == ')')         /* probably a close */
-               croak("sort is now a reserved word");
+               Perl_croak(aTHX_ "sort is now a reserved word");
            PL_expect = XTERM;
            s = force_word(s,WORD,TRUE,TRUE,FALSE);
            LOP(OP_SORT,XREF);
@@ -4086,7 +4632,6 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            UNI(OP_STAT);
 
        case KEY_study:
-           PL_sawstudy++;
            UNI(OP_STUDY);
 
        case KEY_substr:
@@ -4095,74 +4640,98 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        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_if(s,UTF) || *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;
+
+                   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 = skipspace(s);
+               }
+               else
+                   have_proto = FALSE;
 
-           /* Look for a prototype */
-           if (*s == '(') {
-               char *p;
+               if (*s == ':' && s[1] != ':')
+                   PL_expect = attrful;
 
-               s = scan_str(s);
-               if (!s) {
-                   if (PL_lex_stuff)
-                       SvREFCNT_dec(PL_lex_stuff);
+               if (have_proto) {
+                   PL_nextval[PL_nexttoke].opval =
+                       (OP*)newSVOP(OP_CONST, 0, PL_lex_stuff);
                    PL_lex_stuff = Nullsv;
-                   croak("Prototype not terminated");
-               }
-               /* strip spaces */
-               d = SvPVX(PL_lex_stuff);
-               tmp = 0;
-               for (p = d; *p; ++p) {
-                   if (!isSPACE(*p))
-                       d[tmp++] = *p;
+                   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;
+               (void) force_word(PL_oldbufptr + tboffset, WORD,
+                                 FALSE, TRUE, TRUE);
+               if (key == KEY_my)
+                   TOKEN(MYSUB);
+               TOKEN(SUB);
            }
 
-           if (*SvPV(PL_subname,n_a) == '?') {
-               sv_setpv(PL_subname,"__ANON__");
-               TOKEN(ANONSUB);
-           }
-           PREBLOCK(SUB);
-
        case KEY_system:
            set_csh();
            LOP(OP_SYSTEM,XREF);
@@ -4220,11 +4789,11 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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:
@@ -4242,8 +4811,9 @@ int yylex(PERL_YYLEX_PARAM_DECL)
        case KEY_umask:
            if (ckWARN(WARN_OCTAL)) {
                for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ;
-               if (*d != '0' && isDIGIT(*d))
-                   yywarn("umask: argument is missing initial 0");
+               if (*d != '0' && isDIGIT(*d)) 
+                   Perl_warner(aTHX_ WARN_OCTAL,
+                               "umask: argument is missing initial 0");
            }
            UNI(OP_UMASK);
 
@@ -4254,9 +4824,9 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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);
                }
@@ -4272,11 +4842,10 @@ int yylex(PERL_YYLEX_PARAM_DECL)
            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:
@@ -4324,7 +4893,7 @@ int yylex(PERL_YYLEX_PARAM_DECL)
 }
 
 I32
-keyword(register char *d, I32 len)
+Perl_keyword(pTHX_ register char *d, I32 len)
 {
     switch (*d) {
     case '_':
@@ -4364,6 +4933,7 @@ keyword(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) {
@@ -4447,7 +5017,7 @@ keyword(register char *d, I32 len)
            break;
        case 6:
            if (strEQ(d,"exists"))              return KEY_exists;
-           if (strEQ(d,"elseif")) warn("elseif should be elsif");
+           if (strEQ(d,"elseif")) Perl_warn(aTHX_ "elseif should be elsif");
            break;
        case 8:
            if (strEQ(d,"endgrent"))            return -KEY_endgrent;
@@ -4668,8 +5238,7 @@ keyword(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;
@@ -4943,7 +5512,7 @@ keyword(register char *d, I32 len)
 }
 
 STATIC void
-checkcomma(register char *s, char *name, char *what)
+S_checkcomma(pTHX_ register char *s, char *name, char *what)
 {
     char *w;
 
@@ -4960,7 +5529,8 @@ checkcomma(register char *s, char *name, char *what)
            if (*w)
                for (; *w && isSPACE(*w); w++) ;
            if (!*w || !strchr(";|})]oaiuw!=", *w))     /* an advisory hack only... */
-               warner(WARN_SYNTAX, "%s (...) interpreted as function",name);
+               Perl_warner(aTHX_ WARN_SYNTAX,
+                           "%s (...) interpreted as function",name);
        }
     }
     while (s < PL_bufend && isSPACE(*s))
@@ -4969,105 +5539,131 @@ checkcomma(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++;
        if (*s == ',') {
            int kw;
            *s = '\0';
-           kw = keyword(w, s - w) || perl_get_cv(w, FALSE) != 0;
+           kw = keyword(w, s - w) || get_cv(w, FALSE) != 0;
            *s = ',';
            if (kw)
                return;
-           croak("No comma allowed after %s", what);
+           Perl_croak(aTHX_ "No comma allowed after %s", what);
        }
     }
 }
 
+/* Either returns sv, or mortalizes sv and returns a new SV*.
+   Best used as sv=new_constant(..., sv, ...).
+   If s, pv are NULL, calls subroutine with one argument,
+   and type is used with error messages only. */
+
 STATIC SV *
-new_constant(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 */
-    BINOP myop;
     SV *res;
-    bool oldcatch = CATCH_GET;
     SV **cvp;
     SV *cv, *typesv;
-           
+    const char *why, *why1, *why2;
+    
+    if (!(PL_hints & HINT_LOCALIZE_HH)) {
+       SV *msg;
+       
+       why = "%^H is not localized";
+    report_short:
+       why1 = why2 = "";
+    report:
+       msg = Perl_newSVpvf(aTHX_ "constant(%s): %s%s%s", 
+                           (type ? type: "undef"), why1, why2, why);
+       yyerror(SvPVX(msg));
+       SvREFCNT_dec(msg);
+       return sv;
+    }
     if (!table) {
-       yyerror("%^H is not defined");
-       return sv;
+       why = "%^H is not defined";
+       goto report_short;
     }
     cvp = hv_fetch(table, key, strlen(key), FALSE);
     if (!cvp || !SvOK(*cvp)) {
-       char buf[128];
-       sprintf(buf,"$^H{%s} is not defined", key);
-       yyerror(buf);
-       return sv;
+       why = "} is not defined";
+       why1 = "$^H{";
+       why2 = key;
+       goto report;
     }
     sv_2mortal(sv);                    /* Parent created it permanently */
     cv = *cvp;
-    if (!pv)
-       pv = sv_2mortal(newSVpvn(s, len));
-    if (type)
-       typesv = sv_2mortal(newSVpv(type, 0));
+    if (!pv && s)
+       pv = sv_2mortal(newSVpvn(s, len));
+    if (type && pv)
+       typesv = sv_2mortal(newSVpv(type, 0));
     else
-       typesv = &PL_sv_undef;
-    CATCH_SET(TRUE);
-    Zero(&myop, 1, BINOP);
-    myop.op_last = (OP *) &myop;
-    myop.op_next = Nullop;
-    myop.op_flags = OPf_WANT_SCALAR | OPf_STACKED;
-
+       typesv = &PL_sv_undef;
+    
     PUSHSTACKi(PERLSI_OVERLOAD);
-    ENTER;
-    SAVEOP();
-    PL_op = (OP *) &myop;
-    if (PERLDB_SUB && PL_curstash != PL_debstash)
-       PL_op->op_private |= OPpENTERSUB_DB;
-    PUTBACK;
-    pp_pushmark(ARGS);
-
+    ENTER ;
+    SAVETMPS;
+    
+    PUSHMARK(SP) ;
     EXTEND(sp, 4);
-    PUSHs(pv);
+    if (pv)
+       PUSHs(pv);
     PUSHs(sv);
-    PUSHs(typesv);
+    if (pv)
+       PUSHs(typesv);
     PUSHs(cv);
     PUTBACK;
-
-    if (PL_op = pp_entersub(ARGS))
-      CALLRUNOPS();
-    LEAVE;
-    SPAGAIN;
-
-    res = POPs;
-    PUTBACK;
-    CATCH_SET(oldcatch);
+    call_sv(cv, G_SCALAR | ( PL_in_eval ? 0 : G_EVAL));
+    
+    SPAGAIN ;
+    
+    /* Check the eval first */
+    if (!PL_in_eval && SvTRUE(ERRSV))
+    {
+       STRLEN n_a;
+       sv_catpv(ERRSV, "Propagated");
+       yyerror(SvPV(ERRSV, n_a)); /* Duplicates the message inside eval */
+       (void)POPs;
+       res = SvREFCNT_inc(sv);
+    }
+    else {
+       res = POPs;
+       (void)SvREFCNT_inc(res);
+    }
+    
+    PUTBACK ;
+    FREETMPS ;
+    LEAVE ;
     POPSTACK;
-
+    
     if (!SvOK(res)) {
-       char buf[128];
-       sprintf(buf,"Call to &{$^H{%s}} did not return a defined value", key);
-       yyerror(buf);
-    }
-    return SvREFCNT_inc(res);
+       why = "}} did not return a defined value";
+       why1 = "Call to &{$^H{";
+       why2 = key;
+       sv = res;
+       goto report;
+     }
+
+     return res;
 }
-
+  
 STATIC char *
-scan_word(register char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp)
+S_scan_word(pTHX_ register char *s, char *dest, STRLEN destlen, int allow_package, STRLEN *slp)
 {
     register char *d = dest;
     register char *e = d + destlen - 3;  /* two-character token, ending NUL */
     for (;;) {
        if (d >= e)
-           croak(ident_too_long);
+           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++;
@@ -5081,7 +5677,7 @@ scan_word(register char *s, char *dest, STRLEN destlen, int allow_package, STRLE
            while (*t & 0x80 && is_utf8_mark((U8*)t))
                t += UTF8SKIP(t);
            if (d + (t - s) > e)
-               croak(ident_too_long);
+               Perl_croak(aTHX_ ident_too_long);
            Copy(s, d, t - s, char);
            d += t - s;
            s = t;
@@ -5095,15 +5691,13 @@ scan_word(register char *s, char *dest, STRLEN destlen, int allow_package, STRLE
 }
 
 STATIC char *
-scan_ident(register char *s, register char *send, char *dest, STRLEN destlen, I32 ck_uni)
+S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN destlen, I32 ck_uni)
 {
     register char *d;
     register char *e;
     char *bracket = 0;
     char funny = *s++;
 
-    if (PL_lex_brackets == 0)
-       PL_lex_fakebrack = 0;
     if (isSPACE(*s))
        s = skipspace(s);
     d = dest;
@@ -5111,17 +5705,17 @@ scan_ident(register char *s, register char *send, char *dest, STRLEN destlen, I3
     if (isDIGIT(*s)) {
        while (isDIGIT(*s)) {
            if (d >= e)
-               croak(ident_too_long);
+               Perl_croak(aTHX_ ident_too_long);
            *d++ = *s++;
        }
     }
     else {
        for (;;) {
            if (d >= e)
-               croak(ident_too_long);
+               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++;
@@ -5135,7 +5729,7 @@ scan_ident(register char *s, register char *send, char *dest, STRLEN destlen, I3
                while (*t & 0x80 && is_utf8_mark((U8*)t))
                    t += UTF8SKIP(t);
                if (d + (t - s) > e)
-                   croak(ident_too_long);
+                   Perl_croak(aTHX_ ident_too_long);
                Copy(s, d, t - s, char);
                d += t - s;
                s = t;
@@ -5152,7 +5746,7 @@ scan_ident(register char *s, register char *send, char *dest, STRLEN destlen, I3
        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;
     }
@@ -5179,11 +5773,11 @@ scan_ident(register char *s, register char *send, char *dest, STRLEN destlen, I3
                }
            }
        }
-       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);
@@ -5196,21 +5790,20 @@ scan_ident(register char *s, register char *send, char *dest, STRLEN destlen, I3
                while ((isALNUM(*s) || *s == ':') && d < e)
                    *d++ = *s++;
                if (d >= e)
-                   croak(ident_too_long);
+                   Perl_croak(aTHX_ ident_too_long);
            }
            *d = '\0';
            while (s < send && (*s == ' ' || *s == '\t')) s++;
            if ((*s == '[' || (*s == '{' && strNE(dest, "sub")))) {
                dTHR;                   /* only for ckWARN */
                if (ckWARN(WARN_AMBIGUOUS) && keyword(dest, d - dest)) {
-                   char *brack = *s == '[' ? "[...]" : "{...}";
-                   warner(WARN_AMBIGUOUS,
+                   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;
            }
        } 
@@ -5224,7 +5817,7 @@ scan_ident(register char *s, register char *send, char *dest, STRLEN destlen, I3
                *d++ = *s++;
            }
            if (d >= e)
-               croak(ident_too_long);
+               Perl_croak(aTHX_ ident_too_long);
            *d = '\0';
        }
        if (*s == '}') {
@@ -5236,9 +5829,9 @@ scan_ident(register char *s, register char *send, char *dest, STRLEN destlen, I3
            if (PL_lex_state == LEX_NORMAL) {
                dTHR;                   /* only for ckWARN */
                if (ckWARN(WARN_AMBIGUOUS) &&
-                   (keyword(dest, d - dest) || perl_get_cv(dest, FALSE)))
+                   (keyword(dest, d - dest) || get_cv(dest, FALSE)))
                {
-                   warner(WARN_AMBIGUOUS,
+                   Perl_warner(aTHX_ WARN_AMBIGUOUS,
                        "Ambiguous use of %c{%s} resolved to %c%s",
                        funny, dest, funny, dest);
                }
@@ -5254,7 +5847,8 @@ scan_ident(register char *s, register char *send, char *dest, STRLEN destlen, I3
     return s;
 }
 
-void pmflag(U16 *pmfl, int ch)
+void
+Perl_pmflag(pTHX_ U16 *pmfl, int ch)
 {
     if (ch == 'i')
        *pmfl |= PMf_FOLD;
@@ -5273,17 +5867,17 @@ void pmflag(U16 *pmfl, int ch)
 }
 
 STATIC char *
-scan_pat(char *start, I32 type)
+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);
        PL_lex_stuff = Nullsv;
-       croak("Search pattern not terminated");
+       Perl_croak(aTHX_ "Search pattern not terminated");
     }
 
     pm = (PMOP*)newPMOP(type, 0);
@@ -5305,7 +5899,7 @@ scan_pat(char *start, I32 type)
 }
 
 STATIC char *
-scan_subst(char *start)
+S_scan_subst(pTHX_ char *start)
 {
     register char *s;
     register PMOP *pm;
@@ -5314,20 +5908,20 @@ scan_subst(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);
        PL_lex_stuff = Nullsv;
-       croak("Substitution pattern not terminated");
+       Perl_croak(aTHX_ "Substitution pattern not terminated");
     }
 
     if (s[-1] == PL_multi_open)
        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);
@@ -5335,7 +5929,7 @@ scan_subst(char *start)
        if (PL_lex_repl)
            SvREFCNT_dec(PL_lex_repl);
        PL_lex_repl = Nullsv;
-       croak("Substitution replacement not terminated");
+       Perl_croak(aTHX_ "Substitution replacement not terminated");
     }
     PL_multi_start = first_start;      /* so whole substitution is taken together */
 
@@ -5375,7 +5969,7 @@ scan_subst(char *start)
 }
 
 STATIC char *
-scan_trans(char *start)
+S_scan_trans(pTHX_ char *start)
 {
     register char* s;
     OP *o;
@@ -5388,17 +5982,17 @@ scan_trans(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);
        PL_lex_stuff = Nullsv;
-       croak("Transliteration pattern not terminated");
+       Perl_croak(aTHX_ "Transliteration pattern not terminated");
     }
     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);
@@ -5406,7 +6000,7 @@ scan_trans(char *start)
        if (PL_lex_repl)
            SvREFCNT_dec(PL_lex_repl);
        PL_lex_repl = Nullsv;
-       croak("Transliteration replacement not terminated");
+       Perl_croak(aTHX_ "Transliteration replacement not terminated");
     }
 
     if (UTF) {
@@ -5442,7 +6036,7 @@ scan_trans(char *start)
                    utf8 |= OPpTRANS_TO_UTF;
                break;
            default: 
-               croak("Too many /C and /U options");
+               Perl_croak(aTHX_ "Too many /C and /U options");
            }
        }
        s++;
@@ -5455,7 +6049,7 @@ scan_trans(char *start)
 }
 
 STATIC char *
-scan_heredoc(register char *s)
+S_scan_heredoc(pTHX_ register char *s)
 {
     dTHR;
     SV *herewas;
@@ -5487,15 +6081,15 @@ scan_heredoc(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;
        }
     }
     if (d >= PL_tokenbuf + sizeof PL_tokenbuf - 1)
-       croak("Delimiter for here document is too long");
+       Perl_croak(aTHX_ "Delimiter for here document is too long");
     *d++ = '\n';
     *d = '\0';
     len = d - PL_tokenbuf;
@@ -5542,7 +6136,7 @@ scan_heredoc(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) {
@@ -5556,10 +6150,10 @@ scan_heredoc(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);
@@ -5576,15 +6170,15 @@ scan_heredoc(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);
@@ -5596,10 +6190,10 @@ scan_heredoc(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) {
@@ -5621,8 +6215,7 @@ scan_heredoc(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;
@@ -5637,7 +6230,7 @@ scan_heredoc(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);
@@ -5665,7 +6258,7 @@ retval:
 */
 
 STATIC char *
-scan_inputsymbol(char *start)
+S_scan_inputsymbol(pTHX_ char *start)
 {
     register char *s = start;          /* current position in buffer */
     register char *d;
@@ -5685,9 +6278,9 @@ scan_inputsymbol(char *start)
     */
 
     if (len >= sizeof PL_tokenbuf)
-       croak("Excessively long <> operator");
+       Perl_croak(aTHX_ "Excessively long <> operator");
     if (s >= end)
-       croak("Unterminated <> operator");
+       Perl_croak(aTHX_ "Unterminated <> operator");
 
     s++;
 
@@ -5701,7 +6294,7 @@ scan_inputsymbol(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
@@ -5713,9 +6306,9 @@ scan_inputsymbol(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)
-          croak("Glob not terminated");
+          Perl_croak(aTHX_ "Glob not terminated");
        return s;
     }
     else {
@@ -5766,6 +6359,8 @@ scan_inputsymbol(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.
@@ -5783,6 +6378,7 @@ scan_inputsymbol(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)
@@ -5805,7 +6401,7 @@ scan_inputsymbol(char *start)
 */
 
 STATIC char *
-scan_str(char *start)
+S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims)
 {
     dTHR;
     SV *sv;                            /* scalar value: string */
@@ -5814,6 +6410,7 @@ scan_str(char *start)
     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))
@@ -5824,8 +6421,11 @@ scan_str(char *start)
 
     /* 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 = PL_curcop->cop_line;
+    PL_multi_start = CopLINE(PL_curcop);
     PL_multi_open = term;
 
     /* find corresponding closing delimiter */
@@ -5841,22 +6441,24 @@ scan_str(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
@@ -5866,6 +6468,8 @@ scan_str(char *start)
                   have found the terminator */
                else if (*s == term)
                    break;
+               else if (!has_utf && (*s & 0x80) && UTF)
+                   has_utf = TRUE;
                *to = *s;
            }
        }
@@ -5879,10 +6483,11 @@ scan_str(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++;
@@ -5892,6 +6497,8 @@ scan_str(char *start)
                    break;
                else if (*s == PL_multi_open)
                    brackets++;
+               else if (!has_utf && (*s & 0x80) && UTF)
+                   has_utf = TRUE;
                *to = *s;
            }
        }
@@ -5903,7 +6510,8 @@ scan_str(char *start)
         * 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) {
@@ -5927,11 +6535,11 @@ scan_str(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) {
@@ -5939,8 +6547,7 @@ scan_str(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 */
@@ -5949,7 +6556,11 @@ scan_str(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);
+    if (has_utf)
+       SvUTF8_on(sv);
+    PL_multi_end = CopLINE(PL_curcop);
     s++;
 
     /* if we allocated too much space, give some back */
@@ -5992,15 +6603,15 @@ scan_str(char *start)
 */
   
 char *
-scan_num(char *start)
+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 */
-    I32 tryiv;                         /* used to see if it can be an int */
-    double value;                      /* number read, as a double */
-    SV *sv;                            /* place to put the converted number */
-    I32 floatit;                       /* boolean: int or float? */
+    IV tryiv;                          /* used to see if it can be an IV */
+    NV value;                          /* 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 */
     static char number_too_long[] = "Number too long";
 
@@ -6008,11 +6619,10 @@ scan_num(char *start)
 
     switch (*s) {
     default:
-      croak("panic: scan_num");
+      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:
@@ -6025,9 +6635,22 @@ scan_num(char *start)
             we in octal/hex/binary?" indicator to disallow hex characters
             when in octal mode.
           */
-           UV u;
+           dTHR;
+           NV n = 0.0;
+           UV u = 0;
            I32 shift;
            bool overflowed = FALSE;
+           static NV nvshift[5] = { 1.0, 2.0, 4.0, 8.0, 16.0 };
+           static char* bases[5] = { "", "binary", "", "octal",
+                                     "hexadecimal" };
+           static char* Bases[5] = { "", "Binary", "", "Octal",
+                                     "Hexadecimal" };
+           static char *maxima[5] = { "",
+                                      "0b11111111111111111111111111111111",
+                                      "",
+                                      "037777777777",
+                                      "0xffffffff" };
+           char *base, *Base, *max;
 
            /* check for hex */
            if (s[1] == 'x') {
@@ -6038,16 +6661,21 @@ scan_num(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
                shift = 3;
-           u = 0;
+
+           base = bases[shift];
+           Base = Bases[shift];
+           max  = maxima[shift];
 
            /* read the rest of the number */
            for (;;) {
-               UV n, b;        /* n is used in the overflow test, b is the digit we're adding on */
+               /* x is used in the overflow test,
+                  b is the digit we're adding on. */
+               UV x, b;
 
                switch (*s) {
 
@@ -6063,17 +6691,14 @@ scan_num(char *start)
                /* 8 and 9 are not octal */
                case '8': case '9':
                    if (shift == 3)
-                       yyerror(form("Illegal octal digit '%c'", *s));
-                   else
-                       if (shift == 1)
-                           yyerror(form("Illegal binary digit '%c'", *s));
+                       yyerror(Perl_form(aTHX_ "Illegal octal digit '%c'", *s));
                    /* FALL THROUGH */
 
                /* octal digits */
                case '2': case '3': case '4':
                case '5': case '6': case '7':
                    if (shift == 1)
-                       yyerror(form("Illegal binary digit '%c'", *s));
+                       yyerror(Perl_form(aTHX_ "Illegal binary digit '%c'", *s));
                    /* FALL THROUGH */
 
                case '0': case '1':
@@ -6093,15 +6718,33 @@ scan_num(char *start)
                    */
 
                  digit:
-                   n = u << shift;     /* make room for the digit */
-                   if (!overflowed && (n >> shift) != u
-                       && !(PL_hints & HINT_NEW_BINARY)) {
-                       warn("Integer overflow in %s number",
-                            (shift == 4) ? "hex"
-                            : ((shift == 3) ? "octal" : "binary"));
-                       overflowed = TRUE;
+                   if (!overflowed) {
+                       x = u << shift; /* make room for the digit */
+
+                       if ((x >> shift) != u
+                           && !(PL_hints & HINT_NEW_BINARY)) {
+                           dTHR;
+                           overflowed = TRUE;
+                           n = (NV) u;
+                           if (ckWARN_d(WARN_OVERFLOW))
+                               Perl_warner(aTHX_ WARN_OVERFLOW,
+                                           "Integer overflow in %s number",
+                                           base);
+                       } else
+                           u = x | b;          /* add the digit to the end */
+                   }
+                   if (overflowed) {
+                       n *= nvshift[shift];
+                       /* If an NV has not enough bits in its
+                        * mantissa to represent an UV this summing of
+                        * small low-order numbers is a waste of time
+                        * (because the NV cannot preserve the
+                        * low-order bits anyway): we could just
+                        * remember when did we overflow and in the
+                        * end just multiply n by the right
+                        * amount. */
+                       n += (NV) b;
                    }
-                   u = n | b;          /* add the digit to the end */
                    break;
                }
            }
@@ -6111,8 +6754,25 @@ scan_num(char *start)
          */
          out:
            sv = NEWSV(92,0);
-           sv_setuv(sv, u);
-           if ( PL_hints & HINT_NEW_BINARY)
+           if (overflowed) {
+               dTHR;
+               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 UVSIZE > 4
+               dTHR;
+               if (ckWARN(WARN_PORTABLE) && u > 0xffffffff)
+                   Perl_warner(aTHX_ WARN_PORTABLE,
+                               "%s number > %s non-portable",
+                               Base, max);
+#endif
+               sv_setuv(sv, u);
+           }
+           if (PL_hints & HINT_NEW_BINARY)
                sv = new_constant(start, s - start, "binary", sv, Nullsv, NULL);
        }
        break;
@@ -6136,13 +6796,13 @@ scan_num(char *start)
            if (*s == '_') {
                dTHR;                   /* only for ckWARN */
                if (ckWARN(WARN_SYNTAX) && lastub && s - lastub != 3)
-                   warner(WARN_SYNTAX, "Misplaced _ in number");
+                   Perl_warner(aTHX_ WARN_SYNTAX, "Misplaced _ in number");
                lastub = ++s;
            }
            else {
                /* check for end of fixed-length buffer */
                if (d >= e)
-                   croak(number_too_long);
+                   Perl_croak(aTHX_ number_too_long);
                /* if we're ok, copy the character */
                *d++ = *s++;
            }
@@ -6152,7 +6812,7 @@ scan_num(char *start)
        if (lastub && s - lastub != 3) {
            dTHR;
            if (ckWARN(WARN_SYNTAX))
-               warner(WARN_SYNTAX, "Misplaced _ in number");
+               Perl_warner(aTHX_ WARN_SYNTAX, "Misplaced _ in number");
        }
 
        /* read a decimal portion if there is one.  avoid
@@ -6169,7 +6829,7 @@ scan_num(char *start)
            for (; isDIGIT(*s) || *s == '_'; s++) {
                /* fixed length buffer check */
                if (d >= e)
-                   croak(number_too_long);
+                   Perl_croak(aTHX_ number_too_long);
                if (*s != '_')
                    *d++ = *s;
            }
@@ -6190,7 +6850,7 @@ scan_num(char *start)
            /* read digits of exponent (no underbars :-) */
            while (isDIGIT(*s)) {
                if (d >= e)
-                   croak(number_too_long);
+                   Perl_croak(aTHX_ number_too_long);
                *d++ = *s++;
            }
        }
@@ -6200,9 +6860,8 @@ scan_num(char *start)
 
        /* make an sv from the string */
        sv = NEWSV(92,0);
-       /* reset numeric locale in case we were earlier left in Swaziland */
-       SET_NUMERIC_STANDARD();
-       value = atof(PL_tokenbuf);
+
+       value = Atof(PL_tokenbuf);
 
        /* 
           See if we can make do with an integer value without loss of
@@ -6215,25 +6874,91 @@ scan_num(char *start)
           conversion at all.
        */
        tryiv = I_V(value);
-       if (!floatit && (double)tryiv == value)
+       if (!floatit && (NV)tryiv == value)
            sv_setiv(sv, tryiv);
        else
            sv_setnv(sv, value);
-       if ( floatit ? (PL_hints & HINT_NEW_FLOAT) : (PL_hints & HINT_NEW_INTEGER) )
+       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);
+                             (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;
+               bool utf8 = FALSE;
+               s++;                            /* get past 'v' */
+
+               sv = NEWSV(92,5);
+               SvUPGRADE(sv, SVt_PVNV);
+               sv_setpvn(sv, "", 0);
+
+               do {
+                   if (*s == '0' && isDIGIT(s[1]))
+                       yyerror("Octal number in vector unsupported");
+                   rev = atoi(s);
+                   s = ++pos;
+                   while (isDIGIT(*pos))
+                       pos++;
+
+                   if (rev > 127) {
+                       tmpend = uv_to_utf8(tmpbuf, rev);
+                       utf8 = TRUE;
+                   }
+                   else {
+                       tmpbuf[0] = (U8)rev;
+                       tmpend = &tmpbuf[1];
+                   }
+                   *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]));
+
+               if (*s == '0' && isDIGIT(s[1]))
+                   yyerror("Octal number in vector unsupported");
+               rev = atoi(s);
+               s = pos;
+               tmpend = uv_to_utf8(tmpbuf, rev);
+               utf8 = utf8 || rev > 127;
+               *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);
+               if (utf8)
+                   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;
 }
 
 STATIC char *
-scan_formline(register char *s)
+S_scan_formline(pTHX_ register char *s)
 {
     dTHR;
     register char *eol;
@@ -6269,6 +6994,14 @@ scan_formline(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) {
@@ -6307,7 +7040,7 @@ scan_formline(register char *s)
 }
 
 STATIC void
-set_csh(void)
+S_set_csh(pTHX)
 {
 #ifdef CSH
     if (!PL_cshlen)
@@ -6316,7 +7049,7 @@ set_csh(void)
 }
 
 I32
-start_subparse(I32 is_format, U32 flags)
+Perl_start_subparse(pTHX_ I32 is_format, U32 flags)
 {
     dTHR;
     I32 oldsavestack_ix = PL_savestack_ix;
@@ -6326,11 +7059,10 @@ start_subparse(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);
-    SAVESPTR(PL_comppad);
+    SAVECOMPPAD();
     SAVESPTR(PL_comppad_name);
     SAVESPTR(PL_compcv);
     SAVEI32(PL_comppad_name_fill);
@@ -6349,7 +7081,7 @@ start_subparse(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();
@@ -6373,18 +7105,17 @@ start_subparse(I32 is_format, U32 flags)
 }
 
 int
-yywarn(char *s)
+Perl_yywarn(pTHX_ char *s)
 {
     dTHR;
-    --PL_error_count;
-    PL_in_eval |= 2;
+    PL_in_eval |= EVAL_WARNONLY;
     yyerror(s);
-    PL_in_eval &= ~2;
+    PL_in_eval &= ~EVAL_WARNONLY;
     return 0;
 }
 
 int
-yyerror(char *s)
+Perl_yyerror(pTHX_ char *s)
 {
     dTHR;
     char *where = NULL;
@@ -6422,37 +7153,55 @@ yyerror(char *s)
     else {
        SV *where_sv = sv_2mortal(newSVpvn("next char ", 10));
        if (yychar < 32)
-           sv_catpvf(where_sv, "^%c", toCTRL(yychar));
+           Perl_sv_catpvf(aTHX_ where_sv, "^%c", toCTRL(yychar));
        else if (isPRINT_LC(yychar))
-           sv_catpvf(where_sv, "%c", yychar);
+           Perl_sv_catpvf(aTHX_ where_sv, "%c", yychar);
        else
-           sv_catpvf(where_sv, "\\%03o", yychar & 255);
+           Perl_sv_catpvf(aTHX_ where_sv, "\\%03o", yychar & 255);
        where = SvPVX(where_sv);
     }
     msg = sv_2mortal(newSVpv(s, 0));
-    sv_catpvf(msg, " at %_ line %ld, ",
-             GvSV(PL_curcop->cop_filegv), (long)PL_curcop->cop_line);
+    Perl_sv_catpvf(aTHX_ msg, " at %s line %"IVdf", ",
+                  CopFILE(PL_curcop), (IV)CopLINE(PL_curcop));
     if (context)
-       sv_catpvf(msg, "near \"%.*s\"\n", contlen, context);
+       Perl_sv_catpvf(aTHX_ msg, "near \"%.*s\"\n", contlen, context);
     else
-       sv_catpvf(msg, "%s\n", where);
-    if (PL_multi_start < PL_multi_end && (U32)(PL_curcop->cop_line - PL_multi_end) <= 1) {
-       sv_catpvf(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);
+       Perl_sv_catpvf(aTHX_ msg, "%s\n", where);
+    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 %"IVdf")\n",
+                (int)PL_multi_open,(int)PL_multi_close,(IV)PL_multi_start);
         PL_multi_end = 0;
     }
-    if (PL_in_eval & 2)
-       warn("%_", msg);
-    else if (PL_in_eval)
-       sv_catsv(ERRSV, msg);
+    if (PL_in_eval & EVAL_WARNONLY)
+       Perl_warn(aTHX_ "%"SVf, msg);
     else
-       PerlIO_write(PerlIO_stderr(), SvPVX(msg), SvCUR(msg));
-    if (++PL_error_count >= 10)
-       croak("%_ 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;
 }
 
 
+#ifdef PERL_OBJECT
+#include "XSUB.h"
+#endif
+
+/*
+ * restore_rsfp
+ * Restore a source filter.
+ */
+
+static void
+restore_rsfp(pTHXo_ void *f)
+{
+    PerlIO *fp = (PerlIO*)f;
+
+    if (PL_rsfp == PerlIO_stdin())
+       PerlIO_clearerr(PL_rsfp);
+    else if (PL_rsfp && (PL_rsfp != fp))
+       PerlIO_close(PL_rsfp);
+    PL_rsfp = fp;
+}