/* 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.
#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 LEX_FORMLINE 1
#define LEX_KNOWNEXT 0
-#ifdef I_FCNTL
-#include <fcntl.h>
-#endif
-#ifdef I_SYS_FILE
-#include <sys/file.h>
-#endif
-
/* XXX If this causes problems, set i_unistd=undef in the hint file. */
#ifdef I_UNISTD
# include <unistd.h> /* Needed for execv() */
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);
}
#endif
+#if 0
STATIC I32
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;
}
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
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);
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;
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);
}
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)){
start = skipspace(start);
s = start;
- if (isIDFIRST_lazy(s) ||
+ if (isIDFIRST_lazy_if(s,UTF) ||
(allow_pack && *s == ':') ||
(allow_initial_tick && *s == '\'') )
{
}
}
+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.
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 */
+ }
}
}
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;
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;
}
/* 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
/* (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 */
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 */
/* \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",
- len,s,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;
++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{}");
*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)) {
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;
* 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
* =>
*/
*/
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 {
}
#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(AvARRAY(PL_comppad_name)[tmp]) & SVpad_OUR) {
+ if (SvFLAGS(namesv) & SVpad_OUR) {
/* build ops for a bareword */
- yylval.opval = (OP*)newSVOP(OP_CONST, 0, newSVpv(PL_tokenbuf+1, 0));
+ 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(PL_tokenbuf+1,
+ gv_fetchpv(SvPVX(sym),
(PL_in_eval
- ? (GV_ADDMULTI | GV_ADDINEVAL | GV_ADDOUR)
- : GV_ADDOUR
+ ? (GV_ADDMULTI | GV_ADDINEVAL)
+ : TRUE
),
((PL_tokenbuf[0] == '$') ? SVt_PV
: (PL_tokenbuf[0] == '@') ? SVt_PVAV
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:
}
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 */
{
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);
}
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) {
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) {
op_free(attrs);
OPERATOR(':');
}
+ got_attrs:
if (attrs) {
PL_nextval[PL_nexttoke].opval = attrs;
force_next(THING);
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'))
}
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))
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);
}
}
- 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);
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);
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))
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:
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++;
/* 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());
OPERATOR(REFGEN);
case 'v':
- if (isDIGIT(s[1]) && PL_expect == XTERM) {
+ if (isDIGIT(s[1]) && PL_expect != XOPERATOR) {
char *start = s;
start++;
start++;
- while (isDIGIT(*start))
+ while (isDIGIT(*start) || *start == '_')
start++;
if (*start == '.' && isDIGIT(start[1])) {
s = scan_num(s);
TERM(THING);
}
+ /* avoid v123abc() or $h{v1}, allow C<print v10;> */
+ else if (!isALPHA(*start) && (PL_expect == XTERM || PL_expect == XREF)) {
+ char c = *start;
+ GV *gv;
+ *start = '\0';
+ gv = gv_fetchpv(s, FALSE, SVt_PVCV);
+ *start = c;
+ if (!gv) {
+ s = scan_num(s);
+ TERM(THING);
+ }
+ }
}
goto keylookup;
case 'x':
case 'z': case 'Z':
keylookup: {
- STRLEN n_a;
gv = Nullgv;
gvp = 0;
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"))
/* 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);
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;
/* 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. */
/* 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) */
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;
s += 2;
d = s;
s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
- tmp = keyword(PL_tokenbuf, len);
+ if (!(tmp = keyword(PL_tokenbuf, len)))
+ Perl_croak(aTHX_ "CORE::%s is not a keyword", PL_tokenbuf);
if (tmp < 0)
tmp = -tmp;
goto reserved_word;
LOP(OP_BIND,XTERM);
case KEY_binmode:
- UNI(OP_BINMODE);
+ LOP(OP_BINMODE,XTERM);
case KEY_bless:
LOP(OP_BLESS,XTERM);
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);
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)))
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);
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);
TERM(sublex_start());
case KEY_map:
- LOP(OP_MAPSTART, *s == '(' ? XTERM : XREF);
+ LOP(OP_MAPSTART, XREF);
case KEY_mkdir:
LOP(OP_MKDIR,XTERM);
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;
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);
}
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;
}
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");
s = skipspace(s);
- if (isIDFIRST_lazy(s) || *s == '\'' ||
+ if (isIDFIRST_lazy_if(s,UTF) || *s == '\'' ||
(*s == ':' && s[1] == ':'))
{
PL_expect = XBLOCK;
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);
break;
case 'C':
if (strEQ(d,"CORE")) return -KEY_CORE;
+ if (strEQ(d,"CHECK")) return KEY_CHECK;
break;
case 'c':
switch (len) {
break;
}
break;
- case 'S':
- if (strEQ(d,"STOP")) return KEY_STOP;
- break;
case 's':
switch (d[1]) {
case 0: return KEY_s;
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++;
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 */
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 */
why2 = key;
sv = res;
goto report;
- }
+ }
- return res;
+ return res;
}
STATIC char *
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++;
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++;
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;
}
}
}
}
- 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);
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 == '$' && 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
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))
/* 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;
have found the terminator */
else if (*s == term)
break;
+ else if (!has_utf && (*s & 0x80) && UTF)
+ has_utf = TRUE;
*to = *s;
}
}
break;
else if (*s == PL_multi_open)
brackets++;
+ else if (!has_utf && (*s & 0x80) && UTF)
+ has_utf = TRUE;
*to = *s;
}
}
* 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) {
if (keep_delims)
sv_catpvn(sv, s, 1);
+ if (has_utf)
+ SvUTF8_on(sv);
PL_multi_end = CopLINE(PL_curcop);
s++;
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? */
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 */
/* make an sv from the string */
sv = NEWSV(92,0);
+ /* unfortunately this monster needs to be on one line or
+ makedepend will be confused. */
+#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);
/*
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) {
+ IV iv;
+ UV uv;
+ errno = 0;
+ if (*PL_tokenbuf == '-')
+ iv = Atol(PL_tokenbuf);
+ else
+ uv = Atoul(PL_tokenbuf);
+ if (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;
+ value = Atof(PL_tokenbuf);
+ if (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;
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);
}
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";
PL_multi_end = 0;
}
if (PL_in_eval & EVAL_WARNONLY)
- Perl_warn(aTHX_ "%_", msg);
+ Perl_warn(aTHX_ "%"SVf, msg);
else
qerror(msg);
if (PL_error_count >= 10)