X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=toke.c;h=322e194c54c291b5dfb27931c0aeb3f50833f17e;hb=155aba94f677ac771761a1f510964fe5b21524ed;hp=f2e01d61eef8fa397277e29ee5cfd5cb8f02f78f;hpb=894356b32151f778d4d2915c6db38e5d049b115a;p=p5sagit%2Fp5-mst-13.2.git diff --git a/toke.c b/toke.c index f2e01d6..322e194 100644 --- 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. @@ -32,19 +32,8 @@ 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 */ @@ -69,13 +58,6 @@ static void restore_rsfp(pTHXo_ void *f); #define LEX_FORMLINE 1 #define LEX_KNOWNEXT 0 -#ifdef I_FCNTL -#include -#endif -#ifdef I_SYS_FILE -#include -#endif - /* XXX If this causes problems, set i_unistd=undef in the hint file. */ #ifdef I_UNISTD # include /* Needed for execv() */ @@ -223,9 +205,9 @@ S_no_op(pTHX_ char *what, char *s) yywarn(Perl_form(aTHX_ "%s found where operator expected", what)); if (is_first) Perl_warn(aTHX_ "\t(Missing semicolon on previous line?)\n"); - else if (PL_oldoldbufptr && isIDFIRST_lazy(PL_oldoldbufptr)) { + else if (PL_oldoldbufptr && isIDFIRST_lazy_if(PL_oldoldbufptr,UTF)) { char *t; - for (t = PL_oldoldbufptr; *t && (isALNUM_lazy(t) || *t == ':'); t++) ; + for (t = PL_oldoldbufptr; *t && (isALNUM_lazy_if(t,UTF) || *t == ':'); t++) ; if (t < PL_bufptr && isSPACE(*t)) Perl_warn(aTHX_ "\t(Do you need to predeclare %.*s?)\n", t - PL_oldoldbufptr, PL_oldoldbufptr); @@ -337,6 +319,7 @@ S_cr_textfilter(pTHX_ int idx, SV *sv, int maxlen) } #endif +#if 0 STATIC I32 S_utf16_textfilter(pTHX_ int idx, SV *sv, int maxlen) { @@ -347,7 +330,6 @@ S_utf16_textfilter(pTHX_ int idx, SV *sv, int maxlen) New(898, tmps, SvCUR(sv) * 3 / 2 + 1, U8); tend = utf16_to_utf8((U16*)SvPVX(sv), tmps, SvCUR(sv)); sv_usepvn(sv, (char*)tmps, tend - tmps); - } return count; } @@ -362,10 +344,10 @@ S_utf16rev_textfilter(pTHX_ int idx, SV *sv, int maxlen) New(898, tmps, SvCUR(sv) * 3 / 2 + 1, U8); tend = utf16_to_utf8_reversed((U16*)SvPVX(sv), tmps, SvCUR(sv)); sv_usepvn(sv, (char*)tmps, tend - tmps); - } return count; } +#endif /* * Perl_lex_start @@ -387,6 +369,15 @@ Perl_lex_start(pTHX_ SV *line) SAVEI32(PL_lex_state); SAVEVPTR(PL_lex_inpat); SAVEI32(PL_lex_inwhat); + if (PL_lex_state == LEX_KNOWNEXT) { + I32 toke = PL_nexttoke; + while (--toke >= 0) { + SAVEI32(PL_nexttype[toke]); + SAVEVPTR(PL_nextval[toke]); + } + SAVEI32(PL_nexttoke); + PL_nexttoke = 0; + } SAVECOPLINE(PL_curcop); SAVEPPTR(PL_bufptr); SAVEPPTR(PL_bufend); @@ -466,17 +457,22 @@ S_incline(pTHX_ char *s) dTHR; char *t; char *n; + char *e; char ch; - int sawline = 0; CopLINE_inc(PL_curcop); if (*s++ != '#') return; while (*s == ' ' || *s == '\t') s++; - if (strnEQ(s, "line ", 5)) { - s += 5; - sawline = 1; - } + if (strnEQ(s, "line", 4)) + s += 4; + else + return; + if (*s == ' ' || *s == '\t') + s++; + else + return; + while (*s == ' ' || *s == '\t') s++; if (!isDIGIT(*s)) return; n = s; @@ -484,19 +480,23 @@ S_incline(pTHX_ char *s) s++; while (*s == ' ' || *s == '\t') s++; - if (*s == '"' && (t = strchr(s+1, '"'))) + if (*s == '"' && (t = strchr(s+1, '"'))) { s++; + e = t + 1; + } else { - if (!sawline) - return; /* false alarm */ for (t = s; !isSPACE(*t); t++) ; + e = t; } + while (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\f') + e++; + if (*e != '\n' && *e != '\0') + return; /* false alarm */ + ch = *t; *t = '\0'; if (t - s > 0) CopFILE_set(PL_curcop, s); - else - CopFILE_set(PL_curcop, PL_origfilename); *t = ch; CopLINE_set(PL_curcop, atoi(n)-1); } @@ -635,7 +635,7 @@ S_check_uni(pTHX) return; while (isSPACE(*PL_last_uni)) PL_last_uni++; - for (s = PL_last_uni; isALNUM_lazy(s) || *s == '-'; s++) ; + for (s = PL_last_uni; isALNUM_lazy_if(s,UTF) || *s == '-'; s++) ; if ((t = strchr(s, '(')) && t < PL_bufptr) return; if (ckWARN_d(WARN_AMBIGUOUS)){ @@ -758,7 +758,7 @@ S_force_word(pTHX_ register char *start, int token, int check_keyword, int allow start = skipspace(start); s = start; - if (isIDFIRST_lazy(s) || + if (isIDFIRST_lazy_if(s,UTF) || (allow_pack && *s == ':') || (allow_initial_tick && *s == '\'') ) { @@ -812,6 +812,31 @@ S_force_ident(pTHX_ register char *s, int kind) } } +NV +Perl_str_to_version(pTHX_ SV *sv) +{ + NV retval = 0.0; + NV nshift = 1.0; + STRLEN len; + char *start = SvPVx(sv,len); + bool utf = SvUTF8(sv); + char *end = start + len; + while (start < end) { + I32 skip; + UV n; + if (utf) + n = utf8_to_uv((U8*)start, &skip); + else { + n = *(U8*)start; + skip = 1; + } + retval += ((NV)n)/nshift; + start += skip; + nshift *= 1000; + } + return retval; +} + /* * S_force_version * Forces the next token to be a version number. @@ -821,18 +846,25 @@ STATIC char * S_force_version(pTHX_ char *s) { OP *version = Nullop; + char *d; s = skipspace(s); - if (isDIGIT(*s) || (*s == 'v' && isDIGIT(s[1]))) { - char *d = s; - if (*d == 'v') - d++; + d = s; + if (*d == 'v') + d++; + if (isDIGIT(*d)) { for (; isDIGIT(*d) || *d == '_' || *d == '.'; d++); - if ((*d == ';' || isSPACE(*d)) && *(skipspace(d)) != ',') { + if (*d == ';' || isSPACE(*d) || *d == '}' || !*d) { + SV *ver; s = scan_num(s); - /* real VERSION number -- GBARR */ version = yylval.opval; + ver = cSVOPx(version)->op_sv; + if (SvPOK(ver) && !SvNIOK(ver)) { + (void)SvUPGRADE(ver, SVt_PVNV); + SvNVX(ver) = str_to_version(ver); + SvNOK_on(ver); /* hint that it is a version */ + } } } @@ -1161,7 +1193,10 @@ S_scan_const(pTHX_ char *start) register char *s = start; /* start of the constant */ register char *d = SvPVX(sv); /* destination for copies */ bool dorange = FALSE; /* are we in a translit range? */ + bool has_utf = FALSE; /* embedded \x{} */ I32 len; /* ? */ + UV uv; + I32 utf = (PL_lex_inwhat == OP_TRANS && PL_sublex_info.sub_op) ? (PL_sublex_info.sub_op->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)) : UTF; @@ -1234,8 +1269,10 @@ S_scan_const(pTHX_ char *start) if (s[2] == '#') { while (s < send && *s != ')') *d++ = *s++; - } else if (s[2] == '{' - || s[2] == 'p' && s[3] == '{') { /* This should march regcomp.c */ + } + else if (s[2] == '{' /* This should match regcomp.c */ + || ((s[2] == 'p' || s[2] == '?') && s[3] == '{')) + { I32 count = 1; char *regparse = s + (s[2] == '{' ? 3 : 4); char c; @@ -1266,7 +1303,8 @@ S_scan_const(pTHX_ char *start) } /* check for embedded arrays (@foo, @:foo, @'foo, @{foo}, @$foo) */ - else if (*s == '@' && s[1] && (isALNUM_lazy(s+1) || strchr(":'{$", s[1]))) + else if (*s == '@' && s[1] + && (isALNUM_lazy_if(s+1,UTF) || strchr(":'{$", s[1]))) break; /* check for embedded scalars. only stop if we're sure it's a @@ -1282,15 +1320,20 @@ S_scan_const(pTHX_ char *start) /* (now in tr/// code again) */ if (*s & 0x80 && thisutf) { - dTHR; /* only for ckWARN */ - if (ckWARN(WARN_UTF8)) { - (void)utf8_to_uv((U8*)s, &len); /* could cvt latin-1 to utf8 here... */ - if (len) { - while (len--) - *d++ = *s++; - continue; - } - } + (void)utf8_to_uv((U8*)s, &len); + if (len == 1) { + /* illegal UTF8, make it valid */ + char *old_pvx = SvPVX(sv); + /* need space for one extra char (NOTE: SvCUR() not set here) */ + d = SvGROW(sv, SvLEN(sv) + 1) + (d - old_pvx); + d = (char*)uv_to_utf8((U8*)d, (U8)*s++); + } + else { + while (len--) + *d++ = *s++; + } + has_utf = TRUE; + continue; } /* backslashes */ @@ -1334,8 +1377,8 @@ S_scan_const(pTHX_ char *start) default: { dTHR; - if (ckWARN(WARN_UNSAFE) && isALPHA(*s)) - Perl_warner(aTHX_ WARN_UNSAFE, + if (ckWARN(WARN_MISC) && isALPHA(*s)) + Perl_warner(aTHX_ WARN_MISC, "Unrecognized escape \\%c passed through", *s); /* default action is to copy the quoted character */ @@ -1346,49 +1389,75 @@ S_scan_const(pTHX_ char *start) /* \132 indicates an octal constant */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - *d++ = (char)scan_oct(s, 3, &len); + uv = (UV)scan_oct(s, 3, &len); s += len; - continue; + goto NUM_ESCAPE_INSERT; /* \x24 indicates a hex constant */ case 'x': ++s; if (*s == '{') { char* e = strchr(s, '}'); - if (!e) { yyerror("Missing right brace on \\x{}"); e = s; } - if (!utf) { - dTHR; - if (ckWARN(WARN_UTF8)) - Perl_warner(aTHX_ WARN_UTF8, - "Use of \\x{} without utf8 declaration"); - } - /* note: utf always shorter than hex */ - d = (char*)uv_to_utf8((U8*)d, - (UV)scan_hex(s + 1, e - s - 1, &len)); - s = e + 1; + uv = (UV)scan_hex(s + 1, e - s - 1, &len); + s = e + 1; } else { - UV uv = (UV)scan_hex(s, 2, &len); - if (utf && PL_lex_inwhat == OP_TRANS && - utf != (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)) - { - d = (char*)uv_to_utf8((U8*)d, uv); /* doing a CU or UC */ - } - else { - if (uv >= 127 && UTF) { - dTHR; - if (ckWARN(WARN_UTF8)) - Perl_warner(aTHX_ WARN_UTF8, - "\\x%.*s will produce malformed UTF-8 character; use \\x{%.*s} for that", - (int)len,s,(int)len,s); + uv = (UV)scan_hex(s, 2, &len); + s += len; + } + + NUM_ESCAPE_INSERT: + /* Insert oct or hex escaped character. + * There will always enough room in sv since such escapes will + * be longer than any utf8 sequence they can end up as + */ + if (uv > 127) { + if (!thisutf && !has_utf && uv > 255) { + /* might need to recode whatever we have accumulated so far + * if it contains any hibit chars + */ + int hicount = 0; + char *c; + for (c = SvPVX(sv); c < d; c++) { + if (*c & 0x80) + hicount++; } - *d++ = (char)uv; + if (hicount) { + char *old_pvx = SvPVX(sv); + char *src, *dst; + d = SvGROW(sv, SvCUR(sv) + hicount + 1) + (d - old_pvx); + + src = d - 1; + d += hicount; + dst = d - 1; + + while (src < dst) { + if (*src & 0x80) { + dst--; + uv_to_utf8((U8*)dst, (U8)*src--); + dst--; + } + else { + *dst-- = *src--; + } + } + } + } + + if (thisutf || uv > 255) { + d = (char*)uv_to_utf8((U8*)d, uv); + has_utf = TRUE; + } + else { + *d++ = (char)uv; } - s += len; + } + else { + *d++ = (char)uv; } continue; @@ -1397,12 +1466,9 @@ S_scan_const(pTHX_ char *start) ++s; if (*s == '{') { char* e = strchr(s, '}'); - HV *hv; - SV **svp; - SV *res, *cv; + SV *res; STRLEN len; char *str; - char *why = Nullch; if (!e) { yyerror("Missing right brace on \\N{}"); @@ -1487,6 +1553,8 @@ S_scan_const(pTHX_ char *start) *d = '\0'; SvCUR_set(sv, d - SvPVX(sv)); SvPOK_on(sv); + if (has_utf) + SvUTF8_on(sv); /* shrink the sv if we allocated more than we used */ if (SvCUR(sv) + 5 < SvLEN(sv)) { @@ -1595,7 +1663,7 @@ S_intuit_more(pTHX_ register char *s) case '&': case '$': weight -= seen[un_char] * 10; - if (isALNUM_lazy(s+1)) { + if (isALNUM_lazy_if(s+1,UTF)) { scan_ident(s, send, tmpbuf, sizeof tmpbuf, FALSE); if ((int)strlen(tmpbuf) > 1 && gv_fetchpv(tmpbuf,FALSE, SVt_PV)) weight -= 100; @@ -1679,7 +1747,7 @@ S_intuit_more(pTHX_ register char *s) * Not a method if it's really "print foo $bar" * Method if it's really "foo package::" (interpreted as package->foo) * Not a method if bar is known to be a subroutne ("sub bar; foo bar") - * Not a method if bar is a filehandle or package, but is quotd with + * Not a method if bar is a filehandle or package, but is quoted with * => */ @@ -1978,6 +2046,10 @@ Perl_yylex(pTHX) */ if (PL_in_my) { if (PL_in_my == KEY_our) { /* "our" is merely analogous to "my" */ + if (strchr(PL_tokenbuf,':')) + yyerror(Perl_form(aTHX_ "No package name allowed for " + "variable %s in \"our\"", + PL_tokenbuf)); tmp = pad_allocmy(PL_tokenbuf); } else { @@ -2283,7 +2355,7 @@ Perl_yylex(pTHX) retry: switch (*s) { default: - if (isIDFIRST_lazy(s)) + if (isIDFIRST_lazy_if(s,UTF)) goto keylookup; Perl_croak(aTHX_ "Unrecognized character \\x%02X", *s & 255); case 4: @@ -2540,8 +2612,8 @@ Perl_yylex(pTHX) } d = moreswitches(d); } while (d); - if (PERLDB_LINE && !oldpdb || - ( PL_minus_n || PL_minus_p ) && !(oldn || oldp) ) + if ((PERLDB_LINE && !oldpdb) || + ((PL_minus_n || PL_minus_p) && !(oldn || oldp))) /* if we have already added "LINE: while (<>) {", we must not do it again */ { @@ -2651,7 +2723,7 @@ Perl_yylex(pTHX) else if (*s == '>') { s++; s = skipspace(s); - if (isIDFIRST_lazy(s)) { + if (isIDFIRST_lazy_if(s,UTF)) { s = force_word(s,METHOD,FALSE,TRUE,FALSE); TOKEN(ARROW); } @@ -2747,8 +2819,23 @@ Perl_yylex(pTHX) grabattrs: s = skipspace(s); attrs = Nullop; - while (isIDFIRST_lazy(s)) { + while (isIDFIRST_lazy_if(s,UTF)) { d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); + if (isLOWER(*s) && (tmp = keyword(PL_tokenbuf, len))) { + if (tmp < 0) tmp = -tmp; + switch (tmp) { + case KEY_or: + case KEY_and: + case KEY_for: + case KEY_unless: + case KEY_if: + case KEY_while: + case KEY_until: + goto got_attrs; + default: + break; + } + } if (*d == '(') { d = scan_str(d,TRUE,TRUE); if (!d) { @@ -2780,11 +2867,13 @@ Perl_yylex(pTHX) newSVpvn(s, len))); } s = skipspace(d); - while (*s == ',') + if (*s == ':' && s[1] != ':') s = skipspace(s+1); + else if (s == d) + break; /* require real whitespace or :'s */ } - tmp = (PL_expect == XOPERATOR ? '=' : '{'); /*'}' for vi */ - if (*s != ';' && *s != tmp) { + tmp = (PL_expect == XOPERATOR ? '=' : '{'); /*'}(' for vi */ + if (*s != ';' && *s != tmp && (tmp != '=' || *s != ')')) { char q = ((*s == '\'') ? '"' : '\''); /* If here for an expression, and parsed no attrs, back off. */ if (tmp == '=' && !attrs) { @@ -2804,6 +2893,7 @@ Perl_yylex(pTHX) op_free(attrs); OPERATOR(':'); } + got_attrs: if (attrs) { PL_nextval[PL_nexttoke].opval = attrs; force_next(THING); @@ -2874,7 +2964,7 @@ Perl_yylex(pTHX) 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')) @@ -2965,9 +3055,9 @@ Perl_yylex(pTHX) } t++; } - else if (isALNUM_lazy(t)) { + else if (isALNUM_lazy_if(t,UTF)) { t += UTF8SKIP(t); - while (t < PL_bufend && isALNUM_lazy(t)) + while (t < PL_bufend && isALNUM_lazy_if(t,UTF)) t += UTF8SKIP(t); } while (t < PL_bufend && isSPACE(*t)) @@ -3027,7 +3117,9 @@ Perl_yylex(pTHX) AOPERATOR(ANDAND); s--; if (PL_expect == XOPERATOR) { - if (ckWARN(WARN_SEMICOLON) && isIDFIRST_lazy(s) && PL_bufptr == PL_linestart) { + if (ckWARN(WARN_SEMICOLON) + && isIDFIRST_lazy_if(s,UTF) && PL_bufptr == PL_linestart) + { CopLINE_dec(PL_curcop); Perl_warner(aTHX_ WARN_SEMICOLON, PL_warn_nosemi); CopLINE_inc(PL_curcop); @@ -3157,7 +3249,7 @@ Perl_yylex(pTHX) } } - if (s[1] == '#' && (isIDFIRST_lazy(s+2) || strchr("{$:+-", s[2]))) { + if (s[1] == '#' && (isIDFIRST_lazy_if(s+2,UTF) || strchr("{$:+-", s[2]))) { PL_tokenbuf[0] = '@'; s = scan_ident(s + 1, PL_bufend, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1, FALSE); @@ -3200,7 +3292,7 @@ Perl_yylex(pTHX) PL_tokenbuf[0] = '@'; if (ckWARN(WARN_SYNTAX)) { for(t = s + 1; - isSPACE(*t) || isALNUM_lazy(t) || *t == '$'; + isSPACE(*t) || isALNUM_lazy_if(t,UTF) || *t == '$'; t++) ; if (*t++ == ',') { PL_bufptr = skipspace(PL_bufptr); @@ -3220,7 +3312,7 @@ Perl_yylex(pTHX) char tmpbuf[sizeof PL_tokenbuf]; STRLEN len; for (t++; isSPACE(*t); t++) ; - if (isIDFIRST_lazy(t)) { + if (isIDFIRST_lazy_if(t,UTF)) { t = scan_word(t, tmpbuf, sizeof tmpbuf, TRUE, &len); for (; isSPACE(*t); t++) ; if (*t == ';' && get_cv(tmpbuf, FALSE)) @@ -3238,12 +3330,12 @@ Perl_yylex(pTHX) PL_expect = XOPERATOR; else if (strchr("$@\"'`q", *s)) PL_expect = XTERM; /* e.g. print $fh "foo" */ - else if (strchr("&*<%", *s) && isIDFIRST_lazy(s+1)) + else if (strchr("&*<%", *s) && isIDFIRST_lazy_if(s+1,UTF)) PL_expect = XTERM; /* e.g. print $fh &sub */ - else if (isIDFIRST_lazy(s)) { + else if (isIDFIRST_lazy_if(s,UTF)) { char tmpbuf[sizeof PL_tokenbuf]; scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len); - if (tmp = keyword(tmpbuf, len)) { + if ((tmp = keyword(tmpbuf, len))) { /* binary operators exclude handle interpretations */ switch (tmp) { case -KEY_x: @@ -3298,7 +3390,7 @@ Perl_yylex(pTHX) if (ckWARN(WARN_SYNTAX)) { if (*s == '[' || *s == '{') { char *t = s + 1; - while (*t && (isALNUM_lazy(t) || strchr(" \t$#+-'\"", *t))) + while (*t && (isALNUM_lazy_if(t,UTF) || strchr(" \t$#+-'\"", *t))) t++; if (*t == '}' || *t == ']') { t++; @@ -3319,7 +3411,8 @@ Perl_yylex(pTHX) /* Disable warning on "study /blah/" */ if (PL_oldoldbufptr == PL_last_uni && (*PL_last_uni != 's' || s - PL_last_uni < 5 - || memNE(PL_last_uni, "study", 5) || isALNUM_lazy(PL_last_uni+5))) + || memNE(PL_last_uni, "study", 5) + || isALNUM_lazy_if(PL_last_uni+5,UTF))) check_uni(); s = scan_pat(s,OP_MATCH); TERM(sublex_start()); @@ -3424,16 +3517,28 @@ Perl_yylex(pTHX) OPERATOR(REFGEN); case 'v': - if (isDIGIT(s[1]) && PL_expect == XTERM) { + if (isDIGIT(s[1]) && PL_expect != XOPERATOR) { char *start = s; start++; start++; - while (isDIGIT(*start)) + while (isDIGIT(*start) || *start == '_') start++; if (*start == '.' && isDIGIT(start[1])) { s = scan_num(s); TERM(THING); } + /* avoid v123abc() or $h{v1}, allow C */ + else if (!isALPHA(*start) && (PL_expect == XTERM || PL_expect == XREF)) { + char c = *start; + GV *gv; + *start = '\0'; + gv = gv_fetchpv(s, FALSE, SVt_PVCV); + *start = c; + if (!gv) { + s = scan_num(s); + TERM(THING); + } + } } goto keylookup; case 'x': @@ -3472,7 +3577,6 @@ Perl_yylex(pTHX) case 'z': case 'Z': keylookup: { - STRLEN n_a; gv = Nullgv; gvp = 0; @@ -3480,10 +3584,10 @@ Perl_yylex(pTHX) s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len); /* Some keywords can be followed by any delimiter, including ':' */ - tmp = (len == 1 && strchr("msyq", PL_tokenbuf[0]) || - len == 2 && ((PL_tokenbuf[0] == 't' && PL_tokenbuf[1] == 'r') || - (PL_tokenbuf[0] == 'q' && - strchr("qwxr", PL_tokenbuf[1])))); + tmp = ((len == 1 && strchr("msyq", PL_tokenbuf[0])) || + (len == 2 && ((PL_tokenbuf[0] == 't' && PL_tokenbuf[1] == 'r') || + (PL_tokenbuf[0] == 'q' && + strchr("qwxr", PL_tokenbuf[1]))))); /* x::* is just a word, unless x is "CORE" */ if (!tmp && *s == ':' && s[1] == ':' && strNE(PL_tokenbuf, "CORE")) @@ -3566,7 +3670,7 @@ Perl_yylex(pTHX) /* Get the rest if it looks like a package qualifier */ - if (*s == '\'' || *s == ':' && s[1] == ':') { + if (*s == '\'' || (*s == ':' && s[1] == ':')) { STRLEN morelen; s = scan_word(s, PL_tokenbuf + len, sizeof PL_tokenbuf - len, TRUE, &morelen); @@ -3593,8 +3697,8 @@ Perl_yylex(pTHX) if (len > 2 && PL_tokenbuf[len - 2] == ':' && PL_tokenbuf[len - 1] == ':') { - if (ckWARN(WARN_UNSAFE) && ! gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVHV)) - Perl_warner(aTHX_ WARN_UNSAFE, + if (ckWARN(WARN_BAREWORD) && ! gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVHV)) + Perl_warner(aTHX_ WARN_BAREWORD, "Bareword \"%s\" refers to nonexistent package", PL_tokenbuf); len -= 2; @@ -3645,7 +3749,7 @@ Perl_yylex(pTHX) /* Two barewords in a row may indicate method call. */ - if ((isIDFIRST_lazy(s) || *s == '$') && (tmp=intuit_method(s,gv))) + if ((isIDFIRST_lazy_if(s,UTF) || *s == '$') && (tmp=intuit_method(s,gv))) return tmp; /* If not a declared subroutine, it's an indirect object. */ @@ -3691,7 +3795,7 @@ Perl_yylex(pTHX) /* If followed by a bareword, see if it looks like indir obj. */ - if ((isIDFIRST_lazy(s) || *s == '$') && (tmp = intuit_method(s,gv))) + if ((isIDFIRST_lazy_if(s,UTF) || *s == '$') && (tmp = intuit_method(s,gv))) return tmp; /* Not a method, so call it a subroutine (if defined) */ @@ -3840,9 +3944,9 @@ Perl_yylex(pTHX) case KEY_AUTOLOAD: case KEY_DESTROY: case KEY_BEGIN: - case KEY_END: - case KEY_STOP: + case KEY_CHECK: case KEY_INIT: + case KEY_END: if (PL_expect == XSTATE) { s = PL_bufptr; goto really_sub; @@ -3917,11 +4021,11 @@ Perl_yylex(pTHX) LOP(OP_CRYPT,XTERM); case KEY_chmod: - if (ckWARN(WARN_OCTAL)) { + if (ckWARN(WARN_CHMOD)) { for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ; if (*d != '0' && isDIGIT(*d)) - Perl_warner(aTHX_ WARN_OCTAL, - "chmod: mode argument is missing initial 0"); + Perl_warner(aTHX_ WARN_CHMOD, + "chmod() mode argument is missing initial 0"); } LOP(OP_CHMOD,XTERM); @@ -4025,7 +4129,7 @@ Perl_yylex(pTHX) case KEY_foreach: yylval.ival = CopLINE(PL_curcop); s = skipspace(s); - if (PL_expect == XSTATE && isIDFIRST_lazy(s)) { + if (PL_expect == XSTATE && isIDFIRST_lazy_if(s,UTF)) { char *p = s; if ((PL_bufend - p) >= 3 && strnEQ(p, "my", 2) && isSPACE(*(p + 2))) @@ -4034,7 +4138,7 @@ Perl_yylex(pTHX) strnEQ(p, "our", 3) && isSPACE(*(p + 3))) p += 3; p = skipspace(p); - if (isIDFIRST_lazy(p)) { + if (isIDFIRST_lazy_if(p,UTF)) { p = scan_ident(p, PL_bufend, PL_tokenbuf, sizeof PL_tokenbuf, TRUE); p = skipspace(p); @@ -4066,7 +4170,7 @@ Perl_yylex(pTHX) Rop(OP_SGE); case KEY_grep: - LOP(OP_GREPSTART, *s == '(' ? XTERM : XREF); + LOP(OP_GREPSTART, XREF); case KEY_goto: s = force_word(s,WORD,TRUE,FALSE,FALSE); @@ -4228,7 +4332,7 @@ Perl_yylex(pTHX) TERM(sublex_start()); case KEY_map: - LOP(OP_MAPSTART, *s == '(' ? XTERM : XREF); + LOP(OP_MAPSTART, XREF); case KEY_mkdir: LOP(OP_MKDIR,XTERM); @@ -4249,7 +4353,7 @@ Perl_yylex(pTHX) case KEY_my: PL_in_my = tmp; s = skipspace(s); - if (isIDFIRST_lazy(s)) { + if (isIDFIRST_lazy_if(s,UTF)) { s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, TRUE, &len); if (len == 3 && strnEQ(PL_tokenbuf, "sub", 3)) goto really_sub; @@ -4287,12 +4391,12 @@ Perl_yylex(pTHX) case KEY_open: s = skipspace(s); - if (isIDFIRST_lazy(s)) { + if (isIDFIRST_lazy_if(s,UTF)) { char *t; - for (d = s; isALNUM_lazy(d); d++) ; + for (d = s; isALNUM_lazy_if(d,UTF); d++) ; t = skipspace(d); - if (strchr("|&*+-=!?:.", *t) && ckWARN_d(WARN_AMBIGUOUS)) - Perl_warner(aTHX_ WARN_AMBIGUOUS, + if (strchr("|&*+-=!?:.", *t) && ckWARN_d(WARN_PRECEDENCE)) + Perl_warner(aTHX_ WARN_PRECEDENCE, "Precedence problem: open %.*s should be open(%.*s)", d-s,s, d-s,s); } @@ -4364,15 +4468,15 @@ Perl_yylex(pTHX) for (; isSPACE(*d) && len; --len, ++d) ; if (len) { char *b = d; - if (!warned && ckWARN(WARN_SYNTAX)) { + if (!warned && ckWARN(WARN_QW)) { for (; !isSPACE(*d) && len; --len, ++d) { if (*d == ',') { - Perl_warner(aTHX_ WARN_SYNTAX, + Perl_warner(aTHX_ WARN_QW, "Possible attempt to separate words with commas"); ++warned; } else if (*d == '#') { - Perl_warner(aTHX_ WARN_SYNTAX, + Perl_warner(aTHX_ WARN_QW, "Possible attempt to put comments in qw() list"); ++warned; } @@ -4428,7 +4532,7 @@ Perl_yylex(pTHX) else { *PL_tokenbuf = '\0'; s = force_word(s,WORD,TRUE,TRUE,FALSE); - if (isIDFIRST_lazy(PL_tokenbuf)) + if (isIDFIRST_lazy_if(PL_tokenbuf,UTF)) gv_stashpvn(PL_tokenbuf, strlen(PL_tokenbuf), TRUE); else if (*s == '<') yyerror("<> should be quotes"); @@ -4619,7 +4723,7 @@ Perl_yylex(pTHX) s = skipspace(s); - if (isIDFIRST_lazy(s) || *s == '\'' || + if (isIDFIRST_lazy_if(s,UTF) || *s == '\'' || (*s == ':' && s[1] == ':')) { PL_expect = XBLOCK; @@ -4779,10 +4883,10 @@ Perl_yylex(pTHX) LOP(OP_UTIME,XTERM); case KEY_umask: - if (ckWARN(WARN_OCTAL)) { + if (ckWARN(WARN_UMASK)) { for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ; if (*d != '0' && isDIGIT(*d)) - Perl_warner(aTHX_ WARN_OCTAL, + Perl_warner(aTHX_ WARN_UMASK, "umask: argument is missing initial 0"); } UNI(OP_UMASK); @@ -4903,6 +5007,7 @@ Perl_keyword(pTHX_ register char *d, I32 len) break; case 'C': if (strEQ(d,"CORE")) return -KEY_CORE; + if (strEQ(d,"CHECK")) return KEY_CHECK; break; case 'c': switch (len) { @@ -5286,9 +5391,6 @@ Perl_keyword(pTHX_ register char *d, I32 len) break; } break; - case 'S': - if (strEQ(d,"STOP")) return KEY_STOP; - break; case 's': switch (d[1]) { case 0: return KEY_s; @@ -5511,9 +5613,9 @@ S_checkcomma(pTHX_ register char *s, char *name, char *what) s++; while (s < PL_bufend && isSPACE(*s)) s++; - if (isIDFIRST_lazy(s)) { + if (isIDFIRST_lazy_if(s,UTF)) { w = s++; - while (isALNUM_lazy(s)) + while (isALNUM_lazy_if(s,UTF)) s++; while (s < PL_bufend && isSPACE(*s)) s++; @@ -5536,7 +5638,7 @@ S_checkcomma(pTHX_ register char *s, char *name, char *what) STATIC SV * S_new_constant(pTHX_ char *s, STRLEN len, const char *key, SV *sv, SV *pv, - const char *type) + const char *type) { dSP; HV *table = GvHV(PL_hintgv); /* ^H */ @@ -5596,8 +5698,7 @@ S_new_constant(pTHX_ char *s, STRLEN len, const char *key, SV *sv, SV *pv, SPAGAIN ; /* Check the eval first */ - if (!PL_in_eval && SvTRUE(ERRSV)) - { + if (!PL_in_eval && SvTRUE(ERRSV)) { STRLEN n_a; sv_catpv(ERRSV, "Propagated"); yyerror(SvPV(ERRSV, n_a)); /* Duplicates the message inside eval */ @@ -5620,9 +5721,9 @@ S_new_constant(pTHX_ char *s, STRLEN len, const char *key, SV *sv, SV *pv, why2 = key; sv = res; goto report; - } + } - return res; + return res; } STATIC char * @@ -5635,7 +5736,7 @@ S_scan_word(pTHX_ register char *s, char *dest, STRLEN destlen, int allow_packag Perl_croak(aTHX_ ident_too_long); if (isALNUM(*s)) /* UTF handled below */ *d++ = *s++; - else if (*s == '\'' && allow_package && isIDFIRST_lazy(s+1)) { + else if (*s == '\'' && allow_package && isIDFIRST_lazy_if(s+1,UTF)) { *d++ = ':'; *d++ = ':'; s++; @@ -5687,7 +5788,7 @@ S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN des Perl_croak(aTHX_ ident_too_long); if (isALNUM(*s)) /* UTF handled below */ *d++ = *s++; - else if (*s == '\'' && isIDFIRST_lazy(s+1)) { + else if (*s == '\'' && isIDFIRST_lazy_if(s+1,UTF)) { *d++ = ':'; *d++ = ':'; s++; @@ -5718,7 +5819,7 @@ S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN des return s; } if (*s == '$' && s[1] && - (isALNUM_lazy(s+1) || strchr("${", s[1]) || strnEQ(s+1,"::",2)) ) + (isALNUM_lazy_if(s+1,UTF) || strchr("${", s[1]) || strnEQ(s+1,"::",2)) ) { return s; } @@ -5745,11 +5846,11 @@ S_scan_ident(pTHX_ register char *s, register char *send, char *dest, STRLEN des } } } - 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); @@ -6053,9 +6154,9 @@ S_scan_heredoc(pTHX_ register char *s) s++, term = '\''; else term = '"'; - if (!isALNUM_lazy(s)) + if (!isALNUM_lazy_if(s,UTF)) deprecate("bare << to mean <<\"\""); - for (; isALNUM_lazy(s); s++) { + for (; isALNUM_lazy_if(s,UTF); s++) { if (d < e) *d++ = *s; } @@ -6266,7 +6367,7 @@ S_scan_inputsymbol(pTHX_ char *start) if (*d == '$' && d[1]) d++; /* allow or */ - 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 @@ -6382,6 +6483,7 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims) register char term; /* terminating character */ register char *to; /* current position in the sv's data */ I32 brackets = 1; /* bracket nesting level */ + bool has_utf = FALSE; /* is there any utf8 content? */ /* skip space before the delimiter */ if (isSPACE(*s)) @@ -6392,6 +6494,9 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims) /* after skipping whitespace, the next character is the terminator */ term = *s; + if ((term & 0x80) && UTF) + has_utf = TRUE; + /* mark where we are */ PL_multi_start = CopLINE(PL_curcop); PL_multi_open = term; @@ -6436,6 +6541,8 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims) have found the terminator */ else if (*s == term) break; + else if (!has_utf && (*s & 0x80) && UTF) + has_utf = TRUE; *to = *s; } } @@ -6463,6 +6570,8 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims) break; else if (*s == PL_multi_open) brackets++; + else if (!has_utf && (*s & 0x80) && UTF) + has_utf = TRUE; *to = *s; } } @@ -6474,7 +6583,8 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims) * this next chunk reads more into the buffer if we're not done yet */ - if (s < PL_bufend) break; /* handle case where we are done yet :-) */ + if (s < PL_bufend) + break; /* handle case where we are done yet :-) */ #ifndef PERL_STRICT_CR if (to - SvPVX(sv) >= 2) { @@ -6521,6 +6631,8 @@ S_scan_str(pTHX_ char *start, int keep_quoted, int keep_delims) if (keep_delims) sv_catpvn(sv, s, 1); + if (has_utf) + SvUTF8_on(sv); PL_multi_end = CopLINE(PL_curcop); s++; @@ -6569,7 +6681,6 @@ Perl_scan_num(pTHX_ char *start) register char *s = start; /* current position in buffer */ register char *d; /* destination in temp buffer */ register char *e; /* end of temp buffer */ - IV tryiv; /* used to see if it can be an IV */ NV value; /* number read, as a double */ SV *sv = Nullsv; /* place to put the converted number */ bool floatit; /* boolean: int or float? */ @@ -6794,6 +6905,11 @@ Perl_scan_num(pTHX_ char *start) if (*s != '_') *d++ = *s; } + if (*s == '.' && isDIGIT(s[1])) { + /* oops, it's really a v-string, but without the "v" */ + s = start - 1; + goto vstring; + } } /* read exponent part, if present */ @@ -6822,6 +6938,16 @@ Perl_scan_num(pTHX_ char *start) /* make an sv from the string */ sv = NEWSV(92,0); +#if ( defined(USE_64_BIT_INT) && \ + (!defined(HAS_STRTOLL)|| !defined(HAS_STRTOULL))) || \ + (!defined(USE_64_BIT_INT) && \ + (!defined(HAS_STRTOL) || !defined(HAS_STRTOUL))) + + /* + No working strto[u]l[l]. Since atoi() doesn't do range checks, + we need to do this the hard way. + */ + value = Atof(PL_tokenbuf); /* @@ -6834,61 +6960,125 @@ Perl_scan_num(pTHX_ char *start) Note: if floatit is true, then we don't need to do the conversion at all. */ - tryiv = I_V(value); - if (!floatit && (NV)tryiv == value) - sv_setiv(sv, tryiv); - else - sv_setnv(sv, value); + { + UV tryuv = U_V(value); + if (!floatit && (NV)tryuv == value) { + if (tryuv <= IV_MAX) + sv_setiv(sv, (IV)tryuv); + else + sv_setuv(sv, tryuv); + } + else + sv_setnv(sv, value); + } +#else + /* + strtol/strtoll sets errno to ERANGE if the number is too big + for an integer. We try to do an integer conversion first + if no characters indicating "float" have been found. + */ + + if (!floatit) { + char *tp; + IV iv; + UV uv; + errno = 0; +#ifdef USE_64_BIT_INT + if (*PL_tokenbuf == '-') + iv = strtoll(PL_tokenbuf,&tp,10); + else + uv = strtoull(PL_tokenbuf,&tp,10); +#else + if (*PL_tokenbuf == '-') + iv = strtol(PL_tokenbuf,&tp,10); + else + uv = strtoul(PL_tokenbuf,&tp,10); +#endif + if (*tp || errno) + floatit = TRUE; /* probably just too large */ + else if (*PL_tokenbuf == '-') + sv_setiv(sv, iv); + else + sv_setuv(sv, uv); + } + if (floatit) { + char *tp; + errno = 0; +#ifdef USE_LONG_DOUBLE + value = strtold(PL_tokenbuf,&tp); +#else + value = strtod(PL_tokenbuf,&tp); +#endif + if (*tp || errno) + Perl_die(aTHX_ "unparseable float"); + else + sv_setnv(sv, value); + } +#endif if ( floatit ? (PL_hints & HINT_NEW_FLOAT) : (PL_hints & HINT_NEW_INTEGER) ) sv = new_constant(PL_tokenbuf, d - PL_tokenbuf, (floatit ? "float" : "integer"), sv, Nullsv, NULL); break; - /* if it starts with a v, it could be a version number */ + + /* if it starts with a v, it could be a v-string */ case 'v': +vstring: { char *pos = s; pos++; - while (isDIGIT(*pos)) + while (isDIGIT(*pos) || *pos == '_') pos++; - if (*pos == '.' && isDIGIT(pos[1])) { + if (!isALPHA(*pos)) { UV rev; - U8 tmpbuf[10]; + U8 tmpbuf[UTF8_MAXLEN]; U8 *tmpend; - NV nshift = 1.0; + bool utf8 = FALSE; s++; /* get past 'v' */ sv = NEWSV(92,5); - SvUPGRADE(sv, SVt_PVNV); sv_setpvn(sv, "", 0); - do { - rev = atoi(s); - s = ++pos; - while (isDIGIT(*pos)) - pos++; - + for (;;) { + if (*s == '0' && isDIGIT(s[1])) + yyerror("Octal number in vector unsupported"); + rev = 0; + { + /* this is atoi() that tolerates underscores */ + char *end = pos; + UV mult = 1; + while (--end >= s) { + UV orev; + if (*end == '_') + continue; + orev = rev; + rev += (*end - '0') * mult; + mult *= 10; + if (orev > rev && ckWARN_d(WARN_OVERFLOW)) + Perl_warner(aTHX_ WARN_OVERFLOW, + "Integer overflow in decimal number"); + } + } tmpend = uv_to_utf8(tmpbuf, rev); - *tmpend = '\0'; + utf8 = utf8 || rev > 127; sv_catpvn(sv, (const char*)tmpbuf, tmpend - tmpbuf); - if (rev > 0) - SvNVX(sv) += (NV)rev/nshift; - nshift *= 1000; - } while (*pos == '.' && isDIGIT(pos[1])); - - rev = atoi(s); - s = pos; - tmpend = uv_to_utf8(tmpbuf, rev); - *tmpend = '\0'; - sv_catpvn(sv, (const char*)tmpbuf, tmpend - tmpbuf); - if (rev > 0) - SvNVX(sv) += (NV)rev/nshift; + if (*pos == '.' && isDIGIT(pos[1])) + s = ++pos; + else { + s = pos; + break; + } + while (isDIGIT(*pos) || *pos == '_') + pos++; + } SvPOK_on(sv); - SvNOK_on(sv); SvREADONLY_on(sv); - SvUTF8_on(sv); + if (utf8) { + SvUTF8_on(sv); + sv_utf8_downgrade(sv, TRUE); + } } } break; @@ -7009,8 +7199,7 @@ Perl_start_subparse(pTHX_ I32 is_format, U32 flags) SAVEI32(PL_subline); save_item(PL_subname); SAVEI32(PL_padix); - SAVEVPTR(PL_curpad); - SAVESPTR(PL_comppad); + SAVECOMPPAD(); SAVESPTR(PL_comppad_name); SAVESPTR(PL_compcv); SAVEI32(PL_comppad_name_fill); @@ -7089,7 +7278,12 @@ Perl_yyerror(pTHX_ char *s) } else if (yychar > 255) where = "next token ???"; +#ifdef USE_PURE_BISON +/* GNU Bison sets the value -2 */ + else if (yychar == -2) { +#else else if ((yychar & 127) == 127) { +#endif if (PL_lex_state == LEX_NORMAL || (PL_lex_state == LEX_KNOWNEXT && PL_lex_defer == LEX_NORMAL)) where = "at end of line";