%union {
I32 ival;
char *pval;
+#ifdef PERL_MAD
+ TOKEN* tkval;
+#endif
OP *opval;
GV *gvval;
}
%token <pval> LABEL
%token <ival> FORMAT SUB ANONSUB PACKAGE USE
%token <ival> WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE FOR
+%token <ival> GIVEN WHEN DEFAULT
%token <ival> LOOPEX DOTDOT
%token <ival> FUNC0 FUNC1 FUNC UNIOP LSTOP
%token <ival> RELOP EQOP MULOP ADDOP
%token <ival> DOLSHARP DO HASHBRACK NOAMP
-%token <ival> LOCAL MY MYSUB
+%token <ival> LOCAL MY MYSUB REQUIRE
%token COLONATTR
%type <ival> prog decl format startsub startanonsub startformsub mintro
-%type <ival> progstart remember mremember '&' savescope
+%type <ival> progstart remember mremember '&' savescope mydefsv
%type <opval> block mblock lineseq line loop cond else
%type <opval> expr term subscripted scalar ary hsh arylen star amper sideff
%type <opval> argexpr nexpr texpr iexpr mexpr mnexpr miexpr
%type <opval> formname subname proto subbody cont my_scalar
%type <opval> subattrlist myattrlist mysubrout myattrterm myterm
%type <opval> termbinop termunop anonymous termdo
+%type <opval> switch case
%type <pval> label
%nonassoc PREC_LOW
%nonassoc EQOP
%nonassoc RELOP
%nonassoc UNIOP UNIOPSUB
+%nonassoc REQUIRE
%left <ival> SHIFTOP
%left ADDOP
%left MULOP
%left '('
%left '[' '{'
+%token PEG
+
%% /* RULES */
/* The whole program */
{ $$ = block_start(TRUE); }
;
+mydefsv: /* NULL */ /* lexicalize $_ */
+ { $$ = (I32) allocmy("$_"); }
+ ;
+
progstart:
{
PL_expect = XSTATE; $$ = block_start(TRUE);
line : label cond
{ $$ = newSTATEOP(0, $1, $2); }
| loop /* loops add their own labels */
+ | switch /* ... and so do switches */
+ { $$ = $1; }
+ | label case
+ { $$ = newSTATEOP(0, $1, $2); }
| label ';'
{ if ($1 != Nullch) {
$$ = newSTATEOP(0, $1, newOP(OP_NULL, 0));
newCONDOP(0, $4, scope($6), $7)); }
;
+/* Cases for a switch statement */
+case : WHEN '(' remember mexpr ')' mblock
+ { $$ = block_end($3,
+ newWHENOP($4, scope($6))); }
+ | DEFAULT block
+ { $$ = newWHENOP(0, scope($2)); }
+ ;
+
/* Continue blocks */
cont : /* NULL */
{ $$ = Nullop; }
NOLINE, Nullop, $2, $3, 0)); }
;
+/* Switch blocks */
+switch : label GIVEN '(' remember mydefsv mexpr ')' mblock
+ { PL_copline = (line_t) $2;
+ $$ = block_end($4,
+ newSTATEOP(0, $1,
+ newGIVENOP($6, scope($8),
+ (PADOFFSET) $5) )); }
+ ;
+
/* determine whether there are any new my declarations */
mintro : /* NULL */
{ $$ = (PL_min_intro_pending &&
;
format : FORMAT startformsub formname block
- { newFORM($2, $3, $4); }
+ { SvREFCNT_inc(PL_compcv);
+ newFORM($2, $3, $4); }
;
formname: WORD { $$ = $1; }
/* Unimplemented "my sub foo { }" */
mysubrout: MYSUB startsub subname proto subattrlist subbody
- { newMYSUB($2, $3, $4, $5, $6); }
+ { SvREFCNT_inc(PL_compcv);
+ newMYSUB($2, $3, $4, $5, $6); }
;
/* Subroutine definition */
subrout : SUB startsub subname proto subattrlist subbody
- { newATTRSUB($2, $3, $4, $5, $6); }
+ { SvREFCNT_inc(PL_compcv);
+ newATTRSUB($2, $3, $4, $5, $6); }
;
startsub: /* NULL */ /* start a regular subroutine scope */
- { $$ = start_subparse(FALSE, 0); }
+ { $$ = start_subparse(FALSE, 0);
+ SAVEFREESV(PL_compcv); }
;
startanonsub: /* NULL */ /* start an anonymous subroutine scope */
- { $$ = start_subparse(FALSE, CVf_ANON); }
+ { $$ = start_subparse(FALSE, CVf_ANON);
+ SAVEFREESV(PL_compcv); }
;
startformsub: /* NULL */ /* start a format subroutine scope */
- { $$ = start_subparse(TRUE, 0); }
+ { $$ = start_subparse(TRUE, 0);
+ SAVEFREESV(PL_compcv); }
;
/* Name of a subroutine - must be a bareword, could be special */
-subname : WORD { STRLEN n_a; const char *name = SvPV_const(((SVOP*)$1)->op_sv,n_a);
+subname : WORD { const char *const name = SvPV_nolen_const(((SVOP*)$1)->op_sv);
if (strEQ(name, "BEGIN") || strEQ(name, "END")
|| strEQ(name, "INIT") || strEQ(name, "CHECK"))
CvSPECIAL_on(PL_compcv);
use : USE startsub
{ CvSPECIAL_on(PL_compcv); /* It's a BEGIN {} */ }
WORD WORD listexpr ';'
- { utilize($1, $2, $4, $5, $6); }
+ { SvREFCNT_inc(PL_compcv);
+ utilize($1, $2, $4, $5, $6); }
;
/* Ordinary expressions; logical combinations */
| FUNC '(' listexprcom ')' /* print (@args) */
{ $$ = convert($1, 0, $3); }
| LSTOPSUB startanonsub block /* sub f(&@); f { foo } ... */
- { $3 = newANONATTRSUB($2, 0, Nullop, $3); }
+ { SvREFCNT_inc(PL_compcv);
+ $3 = newANONATTRSUB($2, 0, Nullop, $3); }
listexpr %prec LSTOP /* ... @bar */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
append_elem(OP_LIST,
| HASHBRACK ';' '}' %prec '(' /* { } (';' by tokener) */
{ $$ = newANONHASH(Nullop); }
| ANONSUB startanonsub proto subattrlist block %prec '('
- { $$ = newANONATTRSUB($2, $3, $4, $5); }
+ { SvREFCNT_inc(PL_compcv);
+ $$ = newANONATTRSUB($2, $3, $4, $5); }
;
/* Things called with "do" */
termdo : DO term %prec UNIOP /* do $filename */
- { $$ = dofile($2); }
+ { $$ = dofile($2, $1); }
| DO block %prec '(' /* do { code */
{ $$ = newUNOP(OP_NULL, OPf_SPECIAL, scope($2)); }
| DO WORD '(' ')' /* do somesub() */
{ $$ = newUNOP($1, 0, $2); }
| UNIOP term /* Unary op */
{ $$ = newUNOP($1, 0, $2); }
+ | REQUIRE /* require, $_ implied */
+ { $$ = newOP(OP_REQUIRE, $1 ? OPf_SPECIAL : 0); }
+ | REQUIRE term /* require Foo */
+ { $$ = newUNOP(OP_REQUIRE, $1 ? OPf_SPECIAL : 0, $2); }
| UNIOPSUB term /* Sub treated as unop */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
append_elem(OP_LIST, $2, scalar($1))); }