X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/a72a1c8b669f627c80c2fa5d710eb7980a143476..26372e719d968db9587087a91713eb8747db7141:/toke.c diff --git a/toke.c b/toke.c index 93623f6..5a0a5b3 100644 --- a/toke.c +++ b/toke.c @@ -26,12 +26,7 @@ #define yychar (*PL_yycharp) #define yylval (*PL_yylvalp) -static const char ident_too_long[] = - "Identifier too long"; -static const char c_without_g[] = - "Use of /c modifier is meaningless without /g"; -static const char c_in_subst[] = - "Use of /c modifier is meaningless in s///"; +static const char ident_too_long[] = "Identifier too long"; static void restore_rsfp(pTHX_ void *f); #ifndef PERL_NO_UTF16_FILTER @@ -66,17 +61,22 @@ static I32 utf16rev_textfilter(pTHX_ int idx, SV *sv, int maxlen); /* #define LEX_NOTPARSING 11 is done in perl.h. */ -#define LEX_NORMAL 10 -#define LEX_INTERPNORMAL 9 -#define LEX_INTERPCASEMOD 8 -#define LEX_INTERPPUSH 7 -#define LEX_INTERPSTART 6 -#define LEX_INTERPEND 5 -#define LEX_INTERPENDMAYBE 4 -#define LEX_INTERPCONCAT 3 -#define LEX_INTERPCONST 2 -#define LEX_FORMLINE 1 -#define LEX_KNOWNEXT 0 +#define LEX_NORMAL 10 /* normal code (ie not within "...") */ +#define LEX_INTERPNORMAL 9 /* code within a string, eg "$foo[$x+1]" */ +#define LEX_INTERPCASEMOD 8 /* expecting a \U, \Q or \E etc */ +#define LEX_INTERPPUSH 7 /* starting a new sublex parse level */ +#define LEX_INTERPSTART 6 /* expecting the start of a $var */ + + /* at end of code, eg "$x" followed by: */ +#define LEX_INTERPEND 5 /* ... eg not one of [, { or -> */ +#define LEX_INTERPENDMAYBE 4 /* ... eg one of [, { or -> */ + +#define LEX_INTERPCONCAT 3 /* expecting anything, eg at start of + string or after \E, $foo, etc */ +#define LEX_INTERPCONST 2 /* NOT USED */ +#define LEX_FORMLINE 1 /* expecting a format line */ +#define LEX_KNOWNEXT 0 /* next token known; just return it */ + #ifdef DEBUGGING static const char* const lex_state_names[] = { @@ -136,7 +136,7 @@ static const char* const lex_state_names[] = { */ #ifdef DEBUGGING /* Serve -DT. */ -# define REPORT(retval) tokereport(s,(int)retval) +# define REPORT(retval) tokereport((I32)retval) #else # define REPORT(retval) (retval) #endif @@ -277,7 +277,7 @@ static struct debug_tokens { const int token, type; const char *name; } /* dump the returned token in rv, plus any optional arg in yylval */ STATIC int -S_tokereport(pTHX_ const char* s, I32 rv) +S_tokereport(pTHX_ I32 rv) { if (DEBUG_T_TEST) { const char *name = Nullch; @@ -315,25 +315,35 @@ S_tokereport(pTHX_ const char* s, I32 rv) Perl_sv_catpvf(aTHX_ report, "(pval=\"%s\")", yylval.pval); break; case TOKENTYPE_OPVAL: - if (yylval.opval) + if (yylval.opval) { Perl_sv_catpvf(aTHX_ report, "(opval=op_%s)", PL_op_name[yylval.opval->op_type]); + if (yylval.opval->op_type == OP_CONST) { + Perl_sv_catpvf(aTHX_ report, " %s", + SvPEEK(cSVOPx_sv(yylval.opval))); + } + + } else Perl_sv_catpv(aTHX_ report, "(opval=null)"); break; } - Perl_sv_catpvf(aTHX_ report, " at line %"IVdf" [", (IV)CopLINE(PL_curcop)); - if (s - PL_bufptr > 0) - sv_catpvn(report, PL_bufptr, s - PL_bufptr); - else { - if (PL_oldbufptr && *PL_oldbufptr) - sv_catpv(report, PL_tokenbuf); - } - PerlIO_printf(Perl_debug_log, "### %s]\n", SvPV_nolen_const(report)); + PerlIO_printf(Perl_debug_log, "### %s\n\n", SvPV_nolen_const(report)); }; return (int)rv; } + +/* print the buffer with suitable escapes */ + +STATIC void +S_printbuf(pTHX_ const char* fmt, const char* s) +{ + SV* const tmp = newSVpvn("", 0); + PerlIO_printf(Perl_debug_log, fmt, pv_display(tmp, s, strlen(s), 0, 60)); + SvREFCNT_dec(tmp); +} + #endif /* @@ -393,12 +403,12 @@ S_no_op(pTHX_ const char *what, char *s) if (t < PL_bufptr && isSPACE(*t)) Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "\t(Do you need to predeclare %.*s?)\n", - t - PL_oldoldbufptr, PL_oldoldbufptr); + (int)(t - PL_oldoldbufptr), PL_oldoldbufptr); } else { assert(s >= oldbp); Perl_warner(aTHX_ packWARN(WARN_SYNTAX), - "\t(Missing operator before %.*s?)\n", s - oldbp, oldbp); + "\t(Missing operator before %.*s?)\n", (int)(s - oldbp), oldbp); } } PL_bufptr = oldbp; @@ -431,7 +441,7 @@ S_missingterm(pTHX_ char *s) #endif ) { *tmpbuf = '^'; - tmpbuf[1] = toCTRL(PL_multi_close); + tmpbuf[1] = (char)toCTRL(PL_multi_close); tmpbuf[2] = '\0'; s = tmpbuf; } @@ -665,14 +675,14 @@ S_incline(pTHX_ char *s) *t = '\0'; if (t - s > 0) { #ifndef USE_ITHREADS - const char *cf = CopFILE(PL_curcop); - if (cf && strlen(cf) > 7 && strnEQ(cf, "(eval ", 6)) { + const char * const cf = CopFILE(PL_curcop); + STRLEN tmplen = cf ? strlen(cf) : 0; + if (tmplen > 7 && strnEQ(cf, "(eval ", 6)) { /* must copy *{"::_<(eval N)[oldfilename:L]"} * to *{"::_",2)) { s = force_word(PL_bufptr,WORD,FALSE,FALSE,FALSE); - DEBUG_T( { PerlIO_printf(Perl_debug_log, - "### Saw unary minus before =>, forcing word '%s'\n", s); + DEBUG_T( { S_printbuf(aTHX_ + "### Saw unary minus before =>, forcing word %s\n", s); } ); OPERATOR('-'); /* unary minus */ } @@ -3094,7 +3100,7 @@ Perl_yylex(pTHX) if (ftst) { PL_last_lop_op = (OPCODE)ftst; DEBUG_T( { PerlIO_printf(Perl_debug_log, - "### Saw file test %c\n", (int)ftst); + "### Saw file test %c\n", (int)tmp); } ); FTST(ftst); } @@ -3307,11 +3313,9 @@ Perl_yylex(pTHX) 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)); + yyerror( *s + ? Perl_form(aTHX_ "Invalid separator character %c%c%c in attribute list", q, *s, q) + : "Unterminated attribute list" ); if (attrs) op_free(attrs); OPERATOR(':'); @@ -3927,18 +3931,14 @@ Perl_yylex(pTHX) case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': s = scan_num(s, &yylval); - DEBUG_T( { PerlIO_printf(Perl_debug_log, - "### Saw number in '%s'\n", s); - } ); + DEBUG_T( { S_printbuf(aTHX_ "### Saw number in %s\n", s); } ); if (PL_expect == XOPERATOR) no_op("Number",s); TERM(THING); case '\'': s = scan_str(s,FALSE,FALSE); - DEBUG_T( { PerlIO_printf(Perl_debug_log, - "### Saw string before '%s'\n", s); - } ); + DEBUG_T( { S_printbuf(aTHX_ "### Saw string before %s\n", s); } ); if (PL_expect == XOPERATOR) { if (PL_lex_formbrack && PL_lex_brackets == PL_lex_formbrack) { PL_expect = XTERM; @@ -3955,9 +3955,7 @@ Perl_yylex(pTHX) case '"': s = scan_str(s,FALSE,FALSE); - DEBUG_T( { PerlIO_printf(Perl_debug_log, - "### Saw string before '%s'\n", s); - } ); + DEBUG_T( { S_printbuf(aTHX_ "### Saw string before %s\n", s); } ); if (PL_expect == XOPERATOR) { if (PL_lex_formbrack && PL_lex_brackets == PL_lex_formbrack) { PL_expect = XTERM; @@ -3982,9 +3980,7 @@ Perl_yylex(pTHX) case '`': s = scan_str(s,FALSE,FALSE); - DEBUG_T( { PerlIO_printf(Perl_debug_log, - "### Saw backtick string before '%s'\n", s); - } ); + DEBUG_T( { S_printbuf(aTHX_ "### Saw backtick string before %s\n", s); } ); if (PL_expect == XOPERATOR) no_op("Backticks",s); if (!s) @@ -4268,11 +4264,16 @@ Perl_yylex(pTHX) /* If not a declared subroutine, it's an indirect object. */ /* (But it's an indir obj regardless for sort.) */ + /* Also, if "_" follows a filetest operator, it's a bareword */ - if ( !immediate_paren && (PL_last_lop_op == OP_SORT || + if ( + ( !immediate_paren && (PL_last_lop_op == OP_SORT || ((!gv || !GvCVu(gv)) && (PL_last_lop_op != OP_MAPSTART && PL_last_lop_op != OP_GREPSTART)))) + || (PL_tokenbuf[0] == '_' && PL_tokenbuf[1] == '\0' + && ((PL_opargs[PL_last_lop_op] & OA_CLASS_MASK) == OA_FILESTATOP)) + ) { PL_expect = (PL_last_lop == PL_oldoldbufptr) ? XTERM : XOPERATOR; goto bareword; @@ -4520,9 +4521,9 @@ Perl_yylex(pTHX) Perl_croak(aTHX_ "CORE::%s is not a keyword", PL_tokenbuf); if (tmp < 0) tmp = -tmp; - else if (tmp == KEY_require) + else if (tmp == KEY_require || tmp == KEY_do) /* that's a way to remember we saw "CORE::" */ - orig_keyword = KEY_require; + orig_keyword = tmp; goto reserved_word; } goto just_a_word; @@ -4606,6 +4607,12 @@ Perl_yylex(pTHX) PRETERMBLOCK(DO); if (*s != '\'') s = force_word(s,WORD,TRUE,TRUE,FALSE); + if (orig_keyword == KEY_do) { + orig_keyword = 0; + yylval.ival = 1; + } + else + yylval.ival = 0; OPERATOR(DO); case KEY_die: @@ -4954,9 +4961,10 @@ Perl_yylex(pTHX) /* [perl #16184] */ && !(t[0] == '=' && t[1] == '>') ) { + int len = (int)(d-s); Perl_warner(aTHX_ packWARN(WARN_PRECEDENCE), "Precedence problem: open %.*s should be open(%.*s)", - d - s, s, d - s, s); + len, s, len, s); } } LOP(OP_OPEN,XTERM); @@ -5547,7 +5555,7 @@ S_pending_ident(pTHX) PL_pending_ident = 0; DEBUG_T({ PerlIO_printf(Perl_debug_log, - "### Tokener saw identifier '%s'\n", PL_tokenbuf); }); + "### Pending identifier '%s'\n", PL_tokenbuf); }); /* if we're in a my(), we can't allow dynamics here. $foo'bar has already been turned into $foo::bar, so @@ -9351,7 +9359,7 @@ S_scan_pat(pTHX_ char *start, I32 type) if ((pm->op_pmflags & PMf_CONTINUE) && !(pm->op_pmflags & PMf_GLOBAL) && ckWARN(WARN_REGEXP)) { - Perl_warner(aTHX_ packWARN(WARN_REGEXP), c_without_g); + Perl_warner(aTHX_ packWARN(WARN_REGEXP), "Use of /c modifier is meaningless without /g" ); } pm->op_pmpermflags = pm->op_pmflags; @@ -9403,10 +9411,8 @@ S_scan_subst(pTHX_ char *start) break; } - /* /c is not meaningful with s/// */ - if ((pm->op_pmflags & PMf_CONTINUE) && ckWARN(WARN_REGEXP)) - { - Perl_warner(aTHX_ packWARN(WARN_REGEXP), c_in_subst); + if ((pm->op_pmflags & PMf_CONTINUE) && ckWARN(WARN_REGEXP)) { + Perl_warner(aTHX_ packWARN(WARN_REGEXP), "Use of /c modifier is meaningless in s///" ); } if (es) { @@ -10916,7 +10922,7 @@ S_swallow_bom(pTHX_ U8 *s) static void restore_rsfp(pTHX_ void *f) { - PerlIO *fp = (PerlIO*)f; + PerlIO * const fp = (PerlIO*)f; if (PL_rsfp == PerlIO_stdin()) PerlIO_clearerr(PL_rsfp); @@ -11004,16 +11010,15 @@ Perl_scan_vstring(pTHX_ const char *s, SV *sv) } if (!isALPHA(*pos)) { - UV rev; U8 tmpbuf[UTF8_MAXBYTES+1]; - U8 *tmpend; if (*s == 'v') s++; /* get past 'v' */ sv_setpvn(sv, "", 0); for (;;) { - rev = 0; + U8 *tmpend; + UV rev = 0; { /* this is atoi() that tolerates underscores */ const char *end = pos;