#ifdef CRIPPLED_CC
static int uni _((I32 f, char *s));
#endif
+static char * filter_gets _((SV *sv, FILE *fp));
+static void restore_rsfp _((void *f));
/* The following are arranged oddly so that the guard on the switch statement
* can get by with a single comparison (if the compiler is smart enough).
/* grandfather return to old style */
#define OLDLOP(f) return(yylval.ival=f,expect = XTERM,bufptr = s,(int)LSTOP)
-static cryptswitch_t cryptswitch_fp = NULL;
-
static int
ao(toketype)
int toketype;
char *s;
{
char tmpbuf[128];
- char *oldbufptr = bufptr;
+ char *oldbp = bufptr;
+ bool is_first = (oldbufptr == SvPVX(linestr));
bufptr = s;
sprintf(tmpbuf, "%s found where operator expected", what);
yywarn(tmpbuf);
- if (oldbufptr == SvPVX(linestr))
+ if (is_first)
warn("\t(Missing semicolon on previous line?)\n");
- bufptr = oldbufptr;
+ else if (oldoldbufptr && isIDFIRST(*oldoldbufptr)) {
+ char *t;
+ for (t = oldoldbufptr; *t && (isALNUM(*t) || *t == ':'); t++) ;
+ if (t < bufptr && isSPACE(*t))
+ warn("\t(Do you need to predeclare %.*s?)\n",
+ t - oldoldbufptr, oldoldbufptr);
+
+ }
+ else
+ warn("\t(Missing operator before %.*s?)\n", s - oldbp, oldbp);
+ bufptr = oldbp;
}
static void
SAVESPTR(linestr);
SAVEPPTR(lex_brackstack);
SAVEPPTR(lex_casestack);
- SAVESPTR(rsfp);
+ SAVEDESTRUCTOR(restore_rsfp, rsfp);
lex_state = LEX_NORMAL;
lex_defer = 0;
SvTEMP_off(linestr);
oldoldbufptr = oldbufptr = bufptr = SvPVX(linestr);
bufend = bufptr + SvCUR(linestr);
- rs = "\n";
- rslen = 1;
- rschar = '\n';
- rspara = 0;
+ SvREFCNT_dec(rs);
+ rs = newSVpv("\n", 1);
rsfp = 0;
}
}
static void
+restore_rsfp(f)
+void *f;
+{
+ FILE *fp = (FILE*)f;
+
+ if (rsfp == stdin)
+ clearerr(rsfp);
+ else if (rsfp && (rsfp != fp))
+ fclose(rsfp);
+ rsfp = fp;
+}
+
+static void
incline(s)
char *s;
{
}
if (s < bufend || !rsfp || lex_state != LEX_NORMAL)
return s;
- if ((s = sv_gets(linestr, rsfp, 0)) == Nullch) {
+ if ((s = filter_gets(linestr, rsfp)) == Nullch) {
if (minus_n || minus_p) {
sv_setpv(linestr,minus_p ? ";}continue{print" : "");
sv_catpv(linestr,";}");
int kind;
{
if (s && *s) {
- nextval[nexttoke].opval = (OP*)newSVOP(OP_CONST, 0, newSVpv(s,0));
+ OP* op = (OP*)newSVOP(OP_CONST, 0, newSVpv(s,0));
+ nextval[nexttoke].opval = op;
force_next(WORD);
- if (kind)
+ if (kind) {
+ op->op_private = OPpCONST_ENTERED;
gv_fetchpv(s, TRUE,
kind == '$' ? SVt_PV :
kind == '@' ? SVt_PVAV :
kind == '%' ? SVt_PVHV :
SVt_PVGV
);
+ }
}
}
return sv;
s = SvPV_force(sv, len);
+ if (SvIVX(sv) == -1)
+ return sv;
send = s + len;
while (s < send && *s != '\\')
s++;
SV *sv = NEWSV(93, send - start);
register char *s = start;
register char *d = SvPVX(sv);
- char delim = SvIVX(linestr);
bool dorange = FALSE;
I32 len;
char *leave =
lex_inpat
- ? "\\.^$@AGZdDwWsSbB+*?|()-nrtfeaxc0123456789[{]}"
+ ? "\\.^$@AGZdDwWsSbB+*?|()-nrtfeaxc0123456789[{]} \t\n\r\f\v#"
: (lex_inwhat & OP_TRANS)
? ""
: "";
SvGROW(sv, SvLEN(sv) + 256);
d = SvPVX(sv) + i;
d -= 2;
- max = d[1] & 0377;
- for (i = (*d & 0377); i <= max; i++)
+ max = (U8)d[1];
+ for (i = (U8)*d; i <= max; i++)
*d++ = i;
dorange = FALSE;
continue;
s++;
}
}
+ else if (*s == '(' && lex_inpat && s[1] == '?' && s[2] == '#') {
+ while (s < send && *s != ')')
+ *d++ = *s++;
+ }
+ else if (*s == '#' && lex_inpat &&
+ ((PMOP*)lex_inpat)->op_pmflags & PMf_EXTENDED) {
+ while (s+1 < send && *s != '\n')
+ *d++ = *s++;
+ }
else if (*s == '@' && s[1] && (isALNUM(s[1]) || strchr(":'{$", s[1])))
break;
else if (*s == '$') {
}
if (*s == '\\' && s+1 < send) {
s++;
-#ifdef NOTDEF
- if (*s == delim) {
- *d++ = *s++;
- continue;
- }
-#endif
if (*s && strchr(leave, *s)) {
*d++ = '\\';
*d++ = *s++;
}
-/* Encrypted script support: cryptswitch_add() may be called to */
-/* define a function which may manipulate the input stream */
-/* (via popen() etc) to decode the input if required. */
-/* At the moment we only allow one cryptswitch function. */
+/* Encoded script support. filter_add() effectively inserts a
+ * 'pre-processing' function into the current source input stream.
+ * Note that the filter function only applies to the current source file
+ * (e.g., it will not affect files 'require'd or 'use'd by this one).
+ *
+ * The datasv parameter (which may be NULL) can be used to pass
+ * private data to this instance of the filter. The filter function
+ * can recover the SV using the FILTER_DATA macro and use it to
+ * 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.
+ * Note that IoTOP_NAME, IoFMT_NAME, IoBOTTOM_NAME, if set for
+ * private use must be set using malloc'd pointers.
+ */
+static int filter_debug = 0;
+
+SV *
+filter_add(funcp, datasv)
+ filter_t funcp;
+ SV *datasv;
+{
+ if (!funcp){ /* temporary handy debugging hack to be deleted */
+ filter_debug = atoi((char*)datasv);
+ return NULL;
+ }
+ if (!rsfp_filters)
+ rsfp_filters = newAV();
+ if (!datasv)
+ datasv = newSV(0);
+ if (!SvUPGRADE(datasv, SVt_PVIO))
+ die("Can't upgrade filter_add data to SVt_PVIO");
+ IoDIRP(datasv) = (DIR*)funcp; /* stash funcp into spare field */
+ if (filter_debug)
+ warn("filter_add func %lx (%s)", funcp, SvPV(datasv,na));
+ av_unshift(rsfp_filters, 1);
+ av_store(rsfp_filters, 0, datasv) ;
+ return(datasv);
+}
+
+
+/* Delete most recently added instance of this filter function. */
void
-cryptswitch_add(funcp)
- cryptswitch_t funcp;
+filter_del(funcp)
+ filter_t funcp;
+{
+ if (filter_debug)
+ warn("filter_del func %lx", funcp);
+ if (!rsfp_filters || AvFILL(rsfp_filters)<0)
+ return;
+ /* if filter is on top of stack (usual case) just pop it off */
+ if (IoDIRP(FILTER_DATA(0)) == (void*)funcp){
+ /* sv_free(av_pop(rsfp_filters)); */
+ sv_free(av_shift(rsfp_filters));
+
+ return;
+ }
+ /* we need to search for the correct entry and clear it */
+ die("filter_del can only delete in reverse order (currently)");
+}
+
+
+/* Invoke the n'th filter function for the current rsfp. */
+I32
+filter_read(idx, buf_sv, maxlen)
+ int idx;
+ SV *buf_sv;
+ int maxlen; /* 0 = read one text line */
+{
+ filter_t funcp;
+ SV *datasv = NULL;
+
+ if (!rsfp_filters)
+ return -1;
+ if (idx > AvFILL(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 (filter_debug)
+ warn("filter_read %d: from rsfp\n", idx);
+ if (maxlen) {
+ /* Want a block */
+ int len ;
+ int old_len = SvCUR(buf_sv) ;
+
+ /* ensure buf_sv is large enough */
+ SvGROW(buf_sv, old_len + maxlen) ;
+ if ((len = fread(SvPVX(buf_sv) + old_len, 1, maxlen, rsfp)) <= 0){
+ if (ferror(rsfp))
+ return -1; /* error */
+ else
+ return 0 ; /* end of file */
+ }
+ SvCUR_set(buf_sv, old_len + len) ;
+ } else {
+ /* Want a line */
+ if (sv_gets(buf_sv, rsfp, SvCUR(buf_sv)) == NULL) {
+ if (ferror(rsfp))
+ return -1; /* error */
+ else
+ return 0 ; /* end of file */
+ }
+ }
+ return SvCUR(buf_sv);
+ }
+ /* Skip this filter slot if filter has been deleted */
+ if ( (datasv = FILTER_DATA(idx)) == &sv_undef){
+ if (filter_debug)
+ warn("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 (filter_debug)
+ warn("filter_read %d: via function %lx (%s)\n",
+ idx, funcp, SvPV(datasv,na));
+ /* 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)(idx, buf_sv, maxlen);
+}
+
+static char *
+filter_gets(sv,fp)
+register SV *sv;
+register FILE *fp;
{
- cryptswitch_fp = funcp;
+ if (rsfp_filters) {
+
+ SvCUR_set(sv, 0); /* start with empty line */
+ if (FILTER_READ(0, sv, 0) > 0)
+ return ( SvPVX(sv) ) ;
+ else
+ return Nullch ;
+ }
+ else
+ return (sv_gets(sv, fp, 0)) ;
+
}
-static char* exp_name[] =
+#ifdef DEBUGGING
+ static char* exp_name[] =
{ "OPERATOR", "TERM", "REF", "STATE", "BLOCK", "TERMBLOCK" };
+#endif
extern int yychar; /* last token */
if (!in_eval && !preambled) {
preambled = TRUE;
sv_setpv(linestr,incl_perldb());
- if (autoboot_preamble)
- sv_catpv(linestr, autoboot_preamble);
+ if (SvCUR(linestr))
+ sv_catpv(linestr,";");
+ if (preambleav){
+ while(AvFILL(preambleav) >= 0) {
+ SV *tmpsv = av_shift(preambleav);
+ sv_catsv(linestr, tmpsv);
+ sv_catpv(linestr, ";");
+ sv_free(tmpsv);
+ }
+ sv_free((SV*)preambleav);
+ preambleav = NULL;
+ }
if (minus_n || minus_p) {
sv_catpv(linestr, "LINE: while (<>) {");
if (minus_l)
}
goto retry;
}
- /* Give cryptswitch a chance. Note that cryptswitch_fp may */
- /* be called several times owing to "goto retry;"'s below. */
- if (cryptswitch_fp)
- rsfp = (*cryptswitch_fp)(rsfp);
do {
- if ((s = sv_gets(linestr, rsfp, 0)) == Nullch) {
+ if ((s = filter_gets(linestr, rsfp)) == Nullch) {
fake_eof:
if (rsfp) {
if (preprocess && !in_eval)
if (*s == ':' && s[1] != ':') /* for csh execing sh scripts */
s++;
if (!in_eval && *s == '#' && s[1] == '!') {
- if (!instr(s,"perl") && !instr(s,"indir") &&
- instr(origargv[0],"perl")) {
+ d = instr(s,"perl -");
+ if (!d)
+ d = instr(s,"perl");
+ if (!d &&
+ !minus_c &&
+ !instr(s,"indir") &&
+ instr(origargv[0],"perl"))
+ {
char **newargv;
char *cmd;
execv(cmd,newargv);
croak("Can't exec %s", cmd);
}
- if (d = instr(s, "perl -")) {
+ if (d) {
int oldpdb = perldb;
int oldn = minus_n;
int oldp = minus_p;
- d += 6;
- /*SUPPRESS 530*/
- while (d = moreswitches(d)) ;
- if (perldb && !oldpdb ||
- minus_n && !oldn ||
- minus_p && !oldp)
- {
- sv_setpv(linestr, "");
- oldoldbufptr = oldbufptr = s = SvPVX(linestr);
- bufend = SvPVX(linestr) + SvCUR(linestr);
- preambled = FALSE;
- if (perldb)
- (void)gv_fetchfile(origfilename);
- goto retry;
+
+ while (*d && !isSPACE(*d)) d++;
+ while (*d == ' ') d++;
+
+ if (*d++ == '-') {
+ while (d = moreswitches(d)) ;
+ if (perldb && !oldpdb ||
+ ( minus_n || minus_p ) && !(oldn || oldp) )
+ /* if we have already added "LINE: while (<>) {",
+ we must not do it again */
+ {
+ sv_setpv(linestr, "");
+ oldoldbufptr = oldbufptr = s = SvPVX(linestr);
+ bufend = SvPVX(linestr) + SvCUR(linestr);
+ preambled = FALSE;
+ if (perldb)
+ (void)gv_fetchfile(origfilename);
+ goto retry;
+ }
}
}
}
case '-':
if (s[1] && isALPHA(s[1]) && !isALNUM(s[2])) {
s++;
+ bufptr = s;
+ tmp = *s++;
+
+ while (s < bufend && (*s == ' ' || *s == '\t'))
+ s++;
+
+ if (strnEQ(s,"=>",2)) {
+ if (dowarn)
+ warn("Ambiguous use of -%c => resolved to \"-%c\" =>",
+ tmp, tmp);
+ s = force_word(bufptr,WORD,FALSE,FALSE,FALSE);
+ OPERATOR('-'); /* unary minus */
+ }
last_uni = oldbufptr;
last_lop_op = OP_FTEREAD; /* good enough */
- switch (*s++) {
+ switch (tmp) {
case 'r': FTST(OP_FTEREAD);
case 'w': FTST(OP_FTEWRITE);
case 'x': FTST(OP_FTEEXEC);
case 'A': gv_fetchpv("\024",TRUE, SVt_PV); FTST(OP_FTATIME);
case 'C': gv_fetchpv("\024",TRUE, SVt_PV); FTST(OP_FTCTIME);
default:
- s -= 2;
+ croak("Unrecognized file test: -%c", tmp);
break;
}
}
s = force_word(s,METHOD,FALSE,TRUE,FALSE);
TOKEN(ARROW);
}
+ else if (*s == '$')
+ OPERATOR(ARROW);
else
- PREBLOCK(ARROW);
+ TERM(ARROW);
}
if (expect == XOPERATOR)
Aop(OP_SUBTRACT);
tokenbuf[0] = '%';
if (in_my) {
if (strchr(tokenbuf,':'))
- croak("\"my\" variable %s can't be in a package",tokenbuf);
+ croak(no_myglob,tokenbuf);
nextval[nexttoke].opval = newOP(OP_PADANY, 0);
nextval[nexttoke].opval->op_targ = pad_allocmy(tokenbuf);
force_next(PRIVATEREF);
OPERATOR(tmp);
case ')':
tmp = *s++;
+ s = skipspace(s);
+ if (*s == '{')
+ PREBLOCK(tmp);
TERM(tmp);
case ']':
s++;
lex_state = LEX_INTERPEND;
}
}
- TOKEN(']');
+ TERM(']');
case '{':
leftbracket:
s++;
lex_brackstack[lex_brackets++] = XOPERATOR;
OPERATOR(HASHBRACK);
break;
- case XBLOCK:
case XOPERATOR:
+ while (s < bufend && (*s == ' ' || *s == '\t'))
+ s++;
+ if (s < bufend && isALPHA(*s)) {
+ d = scan_word(s, tokenbuf, FALSE, &len);
+ while (d < bufend && (*d == ' ' || *d == '\t'))
+ d++;
+ if (*d == '}') {
+ if (dowarn &&
+ (keyword(tokenbuf, len) ||
+ perl_get_cv(tokenbuf, FALSE) ))
+ warn("Ambiguous use of {%s} resolved to {\"%s\"}",
+ tokenbuf, tokenbuf);
+ s = force_word(s,WORD,FALSE,TRUE,FALSE);
+ }
+ }
+ /* FALL THROUGH */
+ case XBLOCK:
lex_brackstack[lex_brackets++] = XSTATE;
expect = XSTATE;
break;
if (*s == '}')
OPERATOR(HASHBRACK);
if (isALPHA(*s)) {
- for (t = s; t < bufend && isALPHA(*t); t++) ;
+ for (t = s; t < bufend && isALNUM(*t); t++) ;
}
else if (*s == '\'' || *s == '"') {
t = strchr(s+1,*s);
lex_state = LEX_INTERPEND;
}
}
+ if (lex_brackets < lex_fakebrack) {
+ bufptr = s;
+ lex_fakebrack = 0;
+ return yylex(); /* ignore fake brackets */
+ }
force_next('}');
TOKEN(';');
case '&':
AOPERATOR(ANDAND);
s--;
if (expect == XOPERATOR) {
- if (isALPHA(*s) && bufptr == SvPVX(linestr)) {
+ if (dowarn && isALPHA(*s) && bufptr == SvPVX(linestr)) {
curcop->cop_line--;
warn(warn_nosemi);
curcop->cop_line++;
}
else
PREREF('&');
+ yylval.ival = (OPpENTERSUB_AMPER<<8);
TERM('&');
case '|':
if (dowarn && tmp && isSPACE(*s) && strchr("+-*/%.^&|<",tmp))
warn("Reversed %c= operator",tmp);
s--;
- if (isALPHA(tmp) && s == SvPVX(linestr)+1) {
+ if (expect == XSTATE && isALPHA(tmp) &&
+ (s == SvPVX(linestr)+1 || s[-2] == '\n') )
+ {
+ if (in_eval && !rsfp) {
+ d = bufend;
+ while (s < d) {
+ if (*s++ == '\n') {
+ incline(s);
+ if (strnEQ(s,"=cut",4)) {
+ s = strchr(s,'\n');
+ if (s)
+ s++;
+ else
+ s = d;
+ incline(s);
+ goto retry;
+ }
+ }
+ }
+ goto retry;
+ }
s = bufend;
doextract = TRUE;
goto retry;
Rop(OP_GT);
case '$':
- if (s[1] == '#' && (isALPHA(s[2]) || strchr("_{$", s[2]))) {
+ if (s[1] == '#' && (isALPHA(s[2]) || strchr("_{$:", s[2]))) {
s = scan_ident(s+1, bufend, tokenbuf+1, FALSE);
if (expect == XOPERATOR) {
if (lex_formbrack && lex_brackets == lex_formbrack) {
/* This kludge not intended to be bulletproof. */
if (tokenbuf[1] == '[' && !tokenbuf[2]) {
- yylval.opval = newSVOP(OP_CONST, OPf_SPECIAL,
+ yylval.opval = newSVOP(OP_CONST, 0,
newSViv((IV)compiling.cop_arybase));
+ yylval.opval->op_private = OPpCONST_ARYBASE;
TERM(THING);
}
tokenbuf[0] = '$';
if (*s == '{' && strEQ(tokenbuf, "$SIG") &&
(t = strchr(s,'}')) && (t = strchr(t,'='))) {
char tmpbuf[1024];
- char *d = tmpbuf;
STRLEN len;
for (t++; isSPACE(*t); t++) ;
- t = scan_word(t, tmpbuf, TRUE, &len);
- if (*t != '(' && perl_get_cv(tmpbuf, FALSE))
- warn("You need to quote \"%s\"", tmpbuf);
+ if (isIDFIRST(*t)) {
+ t = scan_word(t, tmpbuf, TRUE, &len);
+ if (*t != '(' && perl_get_cv(tmpbuf, FALSE))
+ warn("You need to quote \"%s\"", tmpbuf);
+ }
}
}
expect = XOPERATOR;
}
if (in_my) {
if (strchr(tokenbuf,':'))
- croak("\"my\" variable %s can't be in a package",tokenbuf);
+ croak(no_myglob,tokenbuf);
nextval[nexttoke].opval = newOP(OP_PADANY, 0);
nextval[nexttoke].opval->op_targ = pad_allocmy(tokenbuf);
force_next(PRIVATEREF);
}
else if (!strchr(tokenbuf,':')) {
- if (oldexpect != XREF) {
- if (*s == '[')
- tokenbuf[0] = '@';
- else if (*s == '{')
- tokenbuf[0] = '%';
+ if (oldexpect != XREF || oldoldbufptr == last_lop) {
+ if (intuit_more(s)) {
+ if (*s == '[')
+ tokenbuf[0] = '@';
+ else if (*s == '{')
+ tokenbuf[0] = '%';
+ }
}
if (tmp = pad_findmy(tokenbuf)) {
+ if (!tokenbuf[2] && *tokenbuf =='$' &&
+ tokenbuf[1] <= 'b' && tokenbuf[1] >= 'a')
+ {
+ for (d = in_eval ? oldoldbufptr : SvPVX(linestr);
+ d < bufend && *d != '\n';
+ d++)
+ {
+ if (strnEQ(d,"<=>",3) || strnEQ(d,"cmp",3)) {
+ croak("Can't use \"my %s\" in sort comparison",
+ tokenbuf);
+ }
+ }
+ }
nextval[nexttoke].opval = newOP(OP_PADANY, 0);
nextval[nexttoke].opval->op_targ = tmp;
force_next(PRIVATEREF);
expect = XOPERATOR;
if (in_my) {
if (strchr(tokenbuf,':'))
- croak("\"my\" variable %s can't be in a package",tokenbuf);
+ croak(no_myglob,tokenbuf);
nextval[nexttoke].opval = newOP(OP_PADANY, 0);
nextval[nexttoke].opval->op_targ = pad_allocmy(tokenbuf);
force_next(PRIVATEREF);
TERM('@');
}
else if (!strchr(tokenbuf,':')) {
- if (*s == '{')
- tokenbuf[0] = '%';
+ if (intuit_more(s)) {
+ if (*s == '{')
+ tokenbuf[0] = '%';
+ }
if (tmp = pad_findmy(tokenbuf)) {
nextval[nexttoke].opval = newOP(OP_PADANY, 0);
nextval[nexttoke].opval->op_targ = tmp;
}
/* Force them to make up their mind on "@foo". */
- if (lex_state != LEX_NORMAL &&
+ if (lex_state != LEX_NORMAL && !lex_brackets &&
( !(gv = gv_fetchpv(tokenbuf+1, FALSE, SVt_PVAV)) ||
(*tokenbuf == '@'
? !GvAV(gv)
OPERATOR(tmp);
case '.':
- if (lex_formbrack && lex_brackets == lex_formbrack && s == oldbufptr) {
+ if (lex_formbrack && lex_brackets == lex_formbrack && s[1] == '\n' &&
+ (s == SvPVX(linestr) || s[-1] == '\n') ) {
lex_formbrack = 0;
expect = XSTATE;
goto rightbracket;
}
if (!s)
missingterm((char*)0);
- yylval.ival = OP_STRINGIFY;
+ yylval.ival = OP_CONST;
+ for (d = SvPV(lex_stuff, len); len; len--, d++) {
+ if (*d == '$' || *d == '@' || *d == '\\') {
+ yylval.ival = OP_STRINGIFY;
+ break;
+ }
+ }
TERM(sublex_start());
case '`':
case '\\':
s++;
+ if (dowarn && lex_inwhat && isDIGIT(*s))
+ warn("Can't use \\%c to mean $%c in expression", *s, *s);
if (expect == XOPERATOR)
no_op("Backslash",s);
OPERATOR(REFGEN);
case 'z': case 'Z':
keylookup:
- d = s;
+ bufptr = s;
s = scan_word(s, tokenbuf, FALSE, &len);
+ if (*s == ':' && s[1] == ':' && strNE(tokenbuf, "CORE"))
+ goto just_a_word;
+
tmp = keyword(tokenbuf, len);
+
+ /* Is this a word before a => operator? */
+ d = s;
+ while (d < bufend && (*d == ' ' || *d == '\t'))
+ d++; /* no comments skipped here, or s### is misparsed */
+ if (strnEQ(d,"=>",2)) {
+ CLINE;
+ if (dowarn && (tmp || perl_get_cv(tokenbuf, FALSE)))
+ warn("Ambiguous use of %s => resolved to \"%s\" =>",
+ tokenbuf, tokenbuf);
+ yylval.opval = (OP*)newSVOP(OP_CONST, 0, newSVpv(tokenbuf,0));
+ yylval.opval->op_private = OPpCONST_BARE;
+ TERM(WORD);
+ }
+
if (tmp < 0) { /* second-class keyword? */
GV* gv;
if (expect != XOPERATOR &&
- (*s != ':' || s[1] != ':') &&
- (gv = gv_fetchpv(tokenbuf,FALSE, SVt_PVCV)) &&
- (GvFLAGS(gv) & GVf_IMPORTED) &&
- GvCV(gv))
+ (*s != ':' || s[1] != ':') &&
+ (gv = gv_fetchpv(tokenbuf, FALSE, SVt_PVCV)) &&
+ GvIMPORTED_CV(gv))
{
tmp = 0;
}
default: /* not a keyword */
just_a_word: {
GV *gv;
+ char lastchar = (bufptr == oldoldbufptr ? 0 : bufptr[-1]);
/* Get the rest if it looks like a package qualifier */
(expect == XREF ||
(opargs[last_lop_op] >> OASHIFT & 7) == OA_FILEREF) )
{
+ bool immediate_paren = *s == '(';
+
/* (Now we can afford to cross potential line boundary.) */
s = skipspace(s);
/* If not a declared subroutine, it's an indirect object. */
/* (But it's an indir obj regardless for sort.) */
- if (last_lop_op == OP_SORT || !gv || !GvCV(gv)) {
- expect = last_lop == oldoldbufptr ? XTERM : XOPERATOR;
- for (d = tokenbuf; *d && isLOWER(*d); d++) ;
- if (dowarn && !*d)
- warn(warn_reserved, tokenbuf);
- TOKEN(WORD);
+ if ((last_lop_op == OP_SORT ||
+ (!immediate_paren && (!gv || !GvCV(gv))) ) &&
+ (last_lop_op != OP_MAPSTART && last_lop_op != OP_GREPSTART)){
+ expect = (last_lop == oldoldbufptr) ? XTERM : XOPERATOR;
+ goto bareword;
}
}
nextval[nexttoke].opval = yylval.opval;
expect = XOPERATOR;
force_next(WORD);
+ yylval.ival = 0;
TOKEN('&');
}
/* Not a method, so call it a subroutine (if defined) */
if (gv && GvCV(gv)) {
- nextval[nexttoke].opval = yylval.opval;
+ CV* cv = GvCV(gv);
if (*s == '(') {
+ nextval[nexttoke].opval = yylval.opval;
expect = XTERM;
force_next(WORD);
+ yylval.ival = 0;
TOKEN('&');
}
+ if (lastchar == '-')
+ warn("Ambiguous use of -%s resolved as -&%s()",
+ tokenbuf, tokenbuf);
last_lop = oldbufptr;
last_lop_op = OP_ENTERSUB;
+ /* Resolve to GV now. */
+ op_free(yylval.opval);
+ yylval.opval = newCVREF(0, newGVOP(OP_GV, 0, gv));
+ /* Is there a prototype? */
+ if (SvPOK(cv)) {
+ STRLEN len;
+ char *proto = SvPV((SV*)cv, len);
+ if (!len)
+ TERM(FUNC0SUB);
+ if (strEQ(proto, "$"))
+ OPERATOR(UNIOPSUB);
+ if (*proto == '&' && *s == '{') {
+ sv_setpv(subname,"__ANON__");
+ PREBLOCK(LSTOPSUB);
+ }
+ }
+ nextval[nexttoke].opval = yylval.opval;
expect = XTERM;
force_next(WORD);
TOKEN(NOAMP);
}
- else if (hints & HINT_STRICT_SUBS &&
+
+ if (hints & HINT_STRICT_SUBS &&
+ lastchar != '-' &&
strnNE(s,"->",2) &&
last_lop_op != OP_ACCEPT &&
last_lop_op != OP_PIPE_OP &&
/* Call it a bare word */
- for (d = tokenbuf; *d && isLOWER(*d); d++) ;
- if (dowarn && !*d)
- warn(warn_reserved, tokenbuf);
+ bareword:
+ if (dowarn) {
+ if (lastchar != '-') {
+ for (d = tokenbuf; *d && isLOWER(*d); d++) ;
+ if (!*d)
+ warn(warn_reserved, tokenbuf);
+ }
+ }
+ if (lastchar && strchr("*%&", lastchar)) {
+ warn("Operator or semicolon missing before %c%s",
+ lastchar, tokenbuf);
+ warn("Ambiguous use of %c resolved as operator %c",
+ lastchar, lastchar);
+ }
TOKEN(WORD);
}
TERM(THING);
}
+ case KEY___DATA__:
case KEY___END__: {
GV *gv;
/*SUPPRESS 560*/
- if (!in_eval) {
- gv = gv_fetchpv("DATA",TRUE, SVt_PVIO);
- SvMULTI_on(gv);
+ if (rsfp && (!in_eval || tokenbuf[2] == 'D')) {
+ char dname[256];
+ char *pname = "main";
+ if (tokenbuf[2] == 'D')
+ pname = HvNAME(curstash ? curstash : defstash);
+ sprintf(dname,"%s::DATA", pname);
+ gv = gv_fetchpv(dname,TRUE, SVt_PVIO);
+ GvMULTI_on(gv);
if (!GvIO(gv))
GvIOp(gv) = newIO();
IoIFP(GvIOp(gv)) = rsfp;
case KEY_CORE:
if (*s == ':' && s[1] == ':') {
s += 2;
+ d = s;
s = scan_word(s, tokenbuf, FALSE, &len);
tmp = keyword(tokenbuf, len);
if (tmp < 0)
LOP(OP_CRYPT,XTERM);
case KEY_chmod:
- s = skipspace(s);
- if (dowarn && *s != '0' && isDIGIT(*s))
- yywarn("chmod: mode argument is missing initial 0");
+ if (dowarn) {
+ for (d = s; d < bufend && (isSPACE(*d) || *d == '('); d++) ;
+ if (*d != '0' && isDIGIT(*d))
+ yywarn("chmod: mode argument is missing initial 0");
+ }
LOP(OP_CHMOD,XTERM);
case KEY_chown:
checkcomma(s,tokenbuf,"filehandle");
LOP(OP_PRTF,XREF);
+ case KEY_prototype:
+ UNI(OP_PROTOTYPE);
+
case KEY_push:
LOP(OP_PUSH,XTERM);
OLDLOP(OP_RETURN);
case KEY_require:
+ *tokenbuf = '\0';
s = force_word(s,WORD,TRUE,TRUE,FALSE);
- if (*s == '<')
+ if (isIDFIRST(*tokenbuf))
+ gv_stashpv(tokenbuf, TRUE);
+ else if (*s == '<')
yyerror("<> should be quotes");
UNI(OP_REQUIRE);
case KEY_sub:
really_sub:
s = skipspace(s);
- if (*s == '{' && tmp == KEY_sub) {
- sv_setpv(subname,"__ANON__");
- PRETERMBLOCK(ANONSUB);
- }
- expect = XBLOCK;
+
if (isIDFIRST(*s) || *s == '\'' || *s == ':') {
char tmpbuf[128];
+ expect = XBLOCK;
d = scan_word(s, tmpbuf, TRUE, &len);
if (strchr(tmpbuf, ':'))
sv_setpv(subname, tmpbuf);
sv_catpvn(subname,tmpbuf,len);
}
s = force_word(s,WORD,FALSE,TRUE,TRUE);
+ s = skipspace(s);
}
- else
+ else {
+ expect = XTERMBLOCK;
sv_setpv(subname,"?");
+ }
- if (tmp != KEY_format)
- PREBLOCK(SUB);
+ if (tmp == KEY_format) {
+ s = skipspace(s);
+ if (*s == '=')
+ lex_formbrack = lex_brackets + 1;
+ OPERATOR(FORMAT);
+ }
- s = skipspace(s);
- if (*s == '=')
- lex_formbrack = lex_brackets + 1;
- OPERATOR(FORMAT);
+ /* Look for a prototype */
+ if (*s == '(') {
+ s = scan_str(s);
+ if (!s) {
+ if (lex_stuff)
+ SvREFCNT_dec(lex_stuff);
+ lex_stuff = Nullsv;
+ croak("Prototype not terminated");
+ }
+ nexttoke++;
+ nextval[1] = nextval[0];
+ nexttype[1] = nexttype[0];
+ nextval[0].opval = (OP*)newSVOP(OP_CONST, 0, lex_stuff);
+ nexttype[0] = THING;
+ if (nexttoke == 1) {
+ lex_defer = lex_state;
+ lex_expect = expect;
+ lex_state = LEX_KNOWNEXT;
+ }
+ lex_stuff = Nullsv;
+ }
+
+ if (*SvPV(subname,na) == '?') {
+ sv_setpv(subname,"__ANON__");
+ TOKEN(ANONSUB);
+ }
+ PREBLOCK(SUB);
case KEY_system:
set_csh();
case KEY_syscall:
LOP(OP_SYSCALL,XTERM);
+ case KEY_sysopen:
+ LOP(OP_SYSOPEN,XTERM);
+
case KEY_sysread:
LOP(OP_SYSREAD,XTERM);
case KEY_tie:
LOP(OP_TIE,XTERM);
+ case KEY_tied:
+ UNI(OP_TIED);
+
case KEY_time:
FUN0(OP_TIME);
LOP(OP_UTIME,XTERM);
case KEY_umask:
- s = skipspace(s);
- if (dowarn && *s != '0' && isDIGIT(*s))
- warn("umask: argument is missing initial 0");
+ if (dowarn) {
+ for (d = s; d < bufend && (isSPACE(*d) || *d == '('); d++) ;
+ if (*d != '0' && isDIGIT(*d))
+ yywarn("umask: argument is missing initial 0");
+ }
UNI(OP_UMASK);
case KEY_unshift:
if (d[1] == '_') {
if (strEQ(d,"__LINE__")) return -KEY___LINE__;
if (strEQ(d,"__FILE__")) return -KEY___FILE__;
+ if (strEQ(d,"__DATA__")) return KEY___DATA__;
if (strEQ(d,"__END__")) return KEY___END__;
}
break;
break;
case 6:
if (strEQ(d,"exists")) return KEY_exists;
+ if (strEQ(d,"elseif")) warn("elseif should be elsif");
break;
case 8:
if (strEQ(d,"endgrent")) return -KEY_endgrent;
case 7:
if (strEQ(d,"package")) return KEY_package;
break;
+ case 9:
+ if (strEQ(d,"prototype")) return KEY_prototype;
}
break;
case 'q':
if (strEQ(d,"system")) return -KEY_system;
break;
case 7:
+ if (strEQ(d,"sysopen")) return -KEY_sysopen;
if (strEQ(d,"sysread")) return -KEY_sysread;
if (strEQ(d,"symlink")) return -KEY_symlink;
if (strEQ(d,"syscall")) return -KEY_syscall;
break;
case 4:
if (strEQ(d,"tell")) return -KEY_tell;
+ if (strEQ(d,"tied")) return KEY_tied;
if (strEQ(d,"time")) return -KEY_time;
break;
case 5:
if (*s == ',') {
int kw;
*s = '\0';
- kw = keyword(w, s - w);
+ kw = keyword(w, s - w) || perl_get_cv(w, FALSE) != 0;
*s = ',';
if (kw)
return;
{
register char *d;
char *bracket = 0;
+ char funny = *s++;
if (lex_brackets == 0)
lex_fakebrack = 0;
- s++;
if (isSPACE(*s))
s = skipspace(s);
d = dest;
lex_state = LEX_INTERPENDMAYBE;
return s;
}
- if (*s == '$' && s[1] && (isALPHA(s[1]) || strchr("$_{", s[1])))
+ if (*s == '$' && s[1] &&
+ (isALPHA(s[1]) || strchr("$_{", s[1]) || strnEQ(s+1,"::",2)) )
return s;
if (*s == '{') {
- if (lex_state == LEX_NORMAL)
- return s;
bracket = s;
s++;
}
if (s < send)
*d = *s++;
d[1] = '\0';
- if (*d == '^' && (isUPPER(*s) || strchr("[\\]^_?", *s))) {
+ if (*d == '^' && *s && (isUPPER(*s) || strchr("[\\]^_?", *s))) {
*d = *s++ ^ 64;
}
if (bracket) {
+ if (isSPACE(s[-1])) {
+ while (s < send && (*s == ' ' || *s == '\t')) s++;
+ *d = *s;
+ }
if (isALPHA(*d) || *d == '_') {
d++;
- while (isALNUM(*s))
+ while (isALNUM(*s) || *s == ':')
*d++ = *s++;
*d = '\0';
- if ((*s == '[' || *s == '{') && !keyword(dest,d-dest)) {
- if (lex_brackets)
- croak("Can't use delimiter brackets within expression");
- lex_fakebrack = TRUE;
+ while (s < send && (*s == ' ' || *s == '\t')) s++;
+ if ((*s == '[' || *s == '{')) {
+ if (dowarn && keyword(dest, d - dest)) {
+ char *brack = *s == '[' ? "[...]" : "{...}";
+ warn("Ambiguous use of %c{%s%s} resolved to %c%s%s",
+ funny, dest, brack, funny, dest, brack);
+ }
+ lex_fakebrack = lex_brackets+1;
bracket++;
lex_brackstack[lex_brackets++] = XOPERATOR;
return s;
s++;
if (lex_state == LEX_INTERPNORMAL && !lex_brackets)
lex_state = LEX_INTERPEND;
+ if (funny == '#')
+ funny = '@';
+ if (dowarn &&
+ (keyword(dest, d - dest) || perl_get_cv(dest, FALSE)))
+ warn("Ambiguous use of %c{%s} resolved to %c%s",
+ funny, dest, funny, dest);
}
else {
s = bracket; /* let the parser handle it */
return s;
}
-#ifdef NOTDEF
-void
-scan_prefix(pm,string,len)
-PMOP *pm;
-char *string;
-I32 len;
-{
- register SV *tmpstr;
- register char *t;
- register char *d;
- register char *e;
- char *origstring = string;
-
- if (ninstr(string, string+len, vert, vert+1))
- return;
- if (*string == '^')
- string++, len--;
- tmpstr = NEWSV(86,len);
- sv_upgrade(tmpstr, SVt_PVBM);
- sv_setpvn(tmpstr,string,len);
- t = SvPVX(tmpstr);
- e = t + len;
- BmUSEFUL(tmpstr) = 100;
- for (d=t; d < e; ) {
- switch (*d) {
- case '{':
- if (isDIGIT(d[1]))
- e = d;
- else
- goto defchar;
- break;
- case '(':
- if (d[1] == '?') { /* All bets off. */
- SvREFCNT_dec(tmpstr);
- return;
- }
- /* FALL THROUGH */
- case '.': case '[': case '$': case ')': case '|': case '+':
- case '^':
- e = d;
- break;
- case '\\':
- if (d[1] && strchr("AGZwWbB0123456789sSdDlLuUExc",d[1])) {
- e = d;
- break;
- }
- Move(d+1,d,e-d,char);
- e--;
- switch(*d) {
- case 'n':
- *d = '\n';
- break;
- case 't':
- *d = '\t';
- break;
- case 'f':
- *d = '\f';
- break;
- case 'r':
- *d = '\r';
- break;
- case 'e':
- *d = '\033';
- break;
- case 'a':
- *d = '\007';
- break;
- }
- /* FALL THROUGH */
- default:
- defchar:
- if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
- e = d;
- break;
- }
- d++;
- }
- }
- if (d == t) {
- SvREFCNT_dec(tmpstr);
- return;
- }
- *d = '\0';
- SvCUR_set(tmpstr, d - t);
- if (d == t+len)
- pm->op_pmflags |= PMf_ALL;
- if (*origstring != '^')
- pm->op_pmflags |= PMf_SCANFIRST;
- pm->op_pmshort = tmpstr;
- pm->op_pmslen = d - t;
-}
-#endif
-
void pmflag(pmfl,ch)
U16* pmfl;
int ch;
while (*s && strchr("iogmsx", *s))
pmflag(&pm->op_pmflags,*s++);
+ pm->op_pmpermflags = pm->op_pmflags;
lex_op = (OP*)pm;
yylval.ival = OP_MATCH;
return s;
lex_repl = repl;
}
+ pm->op_pmpermflags = pm->op_pmflags;
lex_op = (OP*)pm;
yylval.ival = OP_SUBST;
return s;
else if (pm->op_pmflags & PMf_FOLD)
return;
pm->op_pmshort = SvREFCNT_inc(pm->op_pmregexp->regstart);
+ pm->op_pmslen = SvCUR(pm->op_pmshort);
}
else if (pm->op_pmregexp->regmust) {/* is there a better short-circuit? */
if (pm->op_pmshort &&
(SvCUR(pm->op_pmshort) < SvCUR(pm->op_pmregexp->regmust)) )){
SvREFCNT_dec(pm->op_pmshort); /* ok if null */
pm->op_pmshort = pm->op_pmregexp->regmust;
+ pm->op_pmslen = SvCUR(pm->op_pmshort);
pm->op_pmregexp->regmust = Nullsv;
pm->op_pmflags |= PMf_SCANFIRST;
}
SV *tmpstr;
char term;
register char *d;
+ char *peek;
s += 2;
d = tokenbuf;
if (!rsfp)
*d++ = '\n';
- if (*s && strchr("`'\"",*s)) {
+ for (peek = s; *peek == ' ' || *peek == '\t'; peek++) ;
+ if (*peek && strchr("`'\"",*peek)) {
+ s = peek;
term = *s++;
s = cpytill(d,s,bufend,term,&len);
if (s < bufend)
s++, term = '\'';
else
term = '"';
+ if (!isALNUM(*s))
+ deprecate("bare << to mean <<\"\"");
while (isALNUM(*s))
*d++ = *s++;
} /* assuming tokenbuf won't clobber */
else
s--, herewas = newSVpv(s,d-s);
s += SvCUR(herewas);
- if (term == '\'')
+
+ tmpstr = NEWSV(87,80);
+ sv_upgrade(tmpstr, SVt_PVIV);
+ if (term == '\'') {
op_type = OP_CONST;
- if (term == '`')
+ SvIVX(tmpstr) = -1;
+ }
+ else if (term == '`') {
op_type = OP_BACKTICK;
+ SvIVX(tmpstr) = '\\';
+ }
CLINE;
multi_start = curcop->cop_line;
multi_open = multi_close = '<';
- tmpstr = NEWSV(87,80);
- sv_upgrade(tmpstr, SVt_PVIV);
- SvIVX(tmpstr) = '\\';
term = *tokenbuf;
if (!rsfp) {
d = s;
sv_setpvn(tmpstr,"",0); /* avoid "uninitialized" warning */
while (s >= bufend) { /* multiple line string? */
if (!rsfp ||
- !(oldoldbufptr = oldbufptr = s = sv_gets(linestr, rsfp, 0))) {
+ !(oldoldbufptr = oldbufptr = s = filter_gets(linestr, rsfp))) {
curcop->cop_line = multi_start;
missingterm(tokenbuf);
}
else
croak("Unterminated <> operator");
- if (*d == '$') d++;
+ if (*d == '$' && d[1]) d++;
while (*d && (isALNUM(*d) || *d == '\'' || *d == ':'))
d++;
if (d - tokenbuf != len) {
if (s < bufend) break; /* string ends on this line? */
if (!rsfp ||
- !(oldoldbufptr = oldbufptr = s = sv_gets(linestr, rsfp, 0))) {
+ !(oldoldbufptr = oldbufptr = s = filter_gets(linestr, rsfp))) {
+ sv_free(sv);
curcop->cop_line = multi_start;
return Nullch;
}
}
s = eol;
if (rsfp) {
- s = sv_gets(linestr, rsfp, 0);
+ s = filter_gets(linestr, rsfp);
oldoldbufptr = oldbufptr = bufptr = SvPVX(linestr);
bufend = bufptr + SvCUR(linestr);
if (!s) {
start_subparse()
{
int oldsavestack_ix = savestack_ix;
+ CV* outsidecv = compcv;
+ AV* comppadlist;
+ if (compcv) {
+ assert(SvTYPE(compcv) == SVt_PVCV);
+ }
save_I32(&subline);
save_item(subname);
SAVEINT(padix);
SAVESPTR(curpad);
SAVESPTR(comppad);
SAVESPTR(comppad_name);
+ SAVESPTR(compcv);
SAVEINT(comppad_name_fill);
SAVEINT(min_intro_pending);
SAVEINT(max_intro_pending);
+ SAVEINT(pad_reset_pending);
+
+ compcv = (CV*)NEWSV(1104,0);
+ sv_upgrade((SV *)compcv, SVt_PVCV);
+
comppad = newAV();
- SAVEFREESV((SV*)comppad);
comppad_name = newAV();
- SAVEFREESV((SV*)comppad_name);
comppad_name_fill = 0;
min_intro_pending = 0;
av_push(comppad, Nullsv);
curpad = AvARRAY(comppad);
padix = 0;
-
subline = curcop->cop_line;
+
+ comppadlist = newAV();
+ AvREAL_off(comppadlist);
+ av_store(comppadlist, 0, (SV*)comppad_name);
+ av_store(comppadlist, 1, (SV*)comppad);
+
+ CvPADLIST(compcv) = comppadlist;
+ CvOUTSIDE(compcv) = (CV*)SvREFCNT_inc((SV*)outsidecv);
+
return oldsavestack_ix;
}
char *s;
{
--error_count;
- return yyerror(s);
+ in_eval |= 2;
+ yyerror(s);
+ in_eval &= ~2;
+ return 0;
}
int
if (lex_state == LEX_NORMAL ||
(lex_state == LEX_KNOWNEXT && lex_defer == LEX_NORMAL))
(void)strcpy(tname,"at end of line");
+ else if (lex_inpat)
+ (void)strcpy(tname,"within pattern");
else
(void)strcpy(tname,"within string");
}
multi_open,multi_close,(long)multi_start);
multi_end = 0;
}
- if (in_eval)
- sv_catpv(GvSV(gv_fetchpv("@",TRUE, SVt_PV)),buf);
+ if (in_eval & 2)
+ warn("%s",buf);
+ else if (in_eval)
+ sv_catpv(GvSV(errgv),buf);
else
fputs(buf,stderr);
if (++error_count >= 10)
croak("%s has too many errors.\n",
SvPVX(GvSV(curcop->cop_filegv)));
+ in_my = 0;
return 0;
}