/* FIXME for MAD - is the new mintro on while and until important? */
-%start prog
+%start grammar
%union {
I32 ival; /* __DEFAULT__ (marker for regen_perly.pl;
#endif
}
+%token <ival> GRAMPROG GRAMFULLSTMT GRAMSTMTSEQ
+
%token <i_tkval> '{' '}' '[' ']' '-' '+' '$' '@' '%' '*' '&' ';'
-%token <opval> WORD METHOD FUNCMETH THING PMFUNC PRIVATEREF
+%token <opval> WORD METHOD FUNCMETH THING PMFUNC PRIVATEREF QWLIST
%token <opval> FUNC0SUB UNIOPSUB LSTOPSUB
%token <opval> PLUGEXPR PLUGSTMT
%token <p_tkval> LABEL
%token <i_tkval> LOCAL MY MYSUB REQUIRE
%token <i_tkval> COLONATTR
-%type <ival> prog progstart remember mremember
+%type <i_tkval> lpar_or_qw
+
+%type <ival> grammar prog progstart remember mremember
%type <ival> startsub startanonsub startformsub
/* FIXME for MAD - are these two ival? */
%type <ival> mydefsv mintro
-%type <opval> decl format subrout mysubrout package use peg
-
+%type <opval> fullstmt decl format subrout mysubrout package use peg
%type <opval> block package_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
%% /* RULES */
+/* Top-level choice of what kind of thing yyparse was called to parse */
+grammar : GRAMPROG prog
+ { $$ = $2; }
+ | GRAMFULLSTMT fullstmt
+ {
+ PL_eval_root = $2;
+ $$ = 0;
+ yyunlex();
+ parser->yychar = YYEOF;
+ }
+ | GRAMSTMTSEQ
+ {
+ parser->expect = XSTATE;
+ }
+ lineseq
+ {
+ PL_eval_root = $3;
+ $$ = 0;
+ }
+ ;
+
/* The whole program */
prog : progstart
/*CONTINUED*/ lineseq
{ $$ = (OP*)NULL; }
| lineseq decl
{
- $$ = IF_MAD(
- append_list(OP_LINESEQ,
- (LISTOP*)$1, (LISTOP*)$2),
- $1);
+ $$ = IF_MAD(op_append_list(OP_LINESEQ, $1, $2), $1);
}
| lineseq line
- { $$ = append_list(OP_LINESEQ,
- (LISTOP*)$1, (LISTOP*)$2);
+ { $$ = op_append_list(OP_LINESEQ, $1, $2);
PL_pad_reset_pending = TRUE;
if ($1 && $2)
PL_hints |= HINT_BLOCK_SCOPE;
}
;
-/* A "line" in the program */
+/* A statement, or "line", in the program */
+fullstmt: decl
+ { $$ = $1; }
+ | line
+ {
+ PL_pad_reset_pending = TRUE;
+ $$ = $1;
+ }
+ ;
+
+/* A non-declaration statement */
line : label cond
{ $$ = newSTATEOP(0, PVAL($1), $2);
TOKEN_GETMAD($1,((LISTOP*)$$)->op_first,'L'); }
{ $$ = newSTATEOP(0, NULL,
newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
NOLINE, (OP*)NULL, $1,
- (OP*)NULL, 0));
- TOKEN_GETMAD($1,((LISTOP*)$$)->op_first,'L'); }
+ (OP*)NULL, 0)); }
| label PLUGSTMT
{ $$ = newSTATEOP(0, PVAL($1), $2); }
;
{ ($2)->op_flags |= OPf_PARENS; $$ = scope($2);
TOKEN_GETMAD($1,$$,'o');
}
- | ELSIF '(' mexpr ')' mblock else
+ | ELSIF lpar_or_qw mexpr ')' mblock else
{ PL_parser->copline = (line_t)IVAL($1);
$$ = newCONDOP(0, newSTATEOP(OPf_SPECIAL,NULL,$3), scope($5), $6);
PL_hints |= HINT_BLOCK_SCOPE;
;
/* Real conditional expressions */
-cond : IF '(' remember mexpr ')' mblock else
+cond : IF lpar_or_qw remember mexpr ')' mblock else
{ PL_parser->copline = (line_t)IVAL($1);
$$ = block_end($3,
newCONDOP(0, $4, scope($6), $7));
TOKEN_GETMAD($2,$$,'(');
TOKEN_GETMAD($5,$$,')');
}
- | UNLESS '(' remember miexpr ')' mblock else
+ | UNLESS lpar_or_qw remember miexpr ')' mblock else
{ PL_parser->copline = (line_t)IVAL($1);
$$ = block_end($3,
newCONDOP(0, $4, scope($6), $7));
;
/* Cases for a switch statement */
-case : WHEN '(' remember mexpr ')' mblock
+case : WHEN lpar_or_qw remember mexpr ')' mblock
{ $$ = block_end($3,
newWHENOP($4, scope($6))); }
| DEFAULT block
;
/* Loops: while, until, for, and a bare block */
-loop : label WHILE '(' remember texpr ')' mintro mblock cont
+loop : label WHILE lpar_or_qw remember texpr ')' mintro mblock cont
{ OP *innerop;
PL_parser->copline = (line_t)IVAL($2);
$$ = block_end($4,
TOKEN_GETMAD($6,innerop,')');
}
- | label UNTIL '(' remember iexpr ')' mintro mblock cont
+ | label UNTIL lpar_or_qw remember iexpr ')' mintro mblock cont
{ OP *innerop;
PL_parser->copline = (line_t)IVAL($2);
$$ = block_end($4,
TOKEN_GETMAD($3,innerop,'(');
TOKEN_GETMAD($6,innerop,')');
}
- | label FOR MY remember my_scalar '(' mexpr ')' mblock cont
+ | label FOR MY remember my_scalar lpar_or_qw mexpr ')' mblock cont
{ OP *innerop;
$$ = block_end($4,
innerop = newFOROP(0, PVAL($1), (line_t)IVAL($2),
TOKEN_GETMAD($6,((LISTOP*)innerop)->op_first->op_sibling,'(');
TOKEN_GETMAD($8,((LISTOP*)innerop)->op_first->op_sibling,')');
}
- | label FOR scalar '(' remember mexpr ')' mblock cont
+ | label FOR scalar lpar_or_qw remember mexpr ')' mblock cont
{ OP *innerop;
$$ = block_end($5,
innerop = newFOROP(0, PVAL($1), (line_t)IVAL($2),
TOKEN_GETMAD($4,((LISTOP*)innerop)->op_first->op_sibling,'(');
TOKEN_GETMAD($7,((LISTOP*)innerop)->op_first->op_sibling,')');
}
- | label FOR '(' remember mexpr ')' mblock cont
+ | label FOR lpar_or_qw remember mexpr ')' mblock cont
{ OP *innerop;
$$ = block_end($4,
innerop = newFOROP(0, PVAL($1), (line_t)IVAL($2),
TOKEN_GETMAD($3,((LISTOP*)innerop)->op_first->op_sibling,'(');
TOKEN_GETMAD($6,((LISTOP*)innerop)->op_first->op_sibling,')');
}
- | label FOR '(' remember mnexpr ';' texpr ';' mintro mnexpr ')'
+ | label FOR lpar_or_qw remember mnexpr ';' texpr ';' mintro mnexpr ')'
mblock
/* basically fake up an initialize-while lineseq */
{ OP *forop;
IVAL($2), scalar($7),
$12, $10, $9));
#ifdef MAD
- forop = newUNOP(OP_NULL, 0, append_elem(OP_LINESEQ,
+ forop = newUNOP(OP_NULL, 0, op_append_elem(OP_LINESEQ,
newSTATEOP(0,
CopLABEL_alloc(($1)->tk_lval.pval),
($5 ? $5 : newOP(OP_NULL, 0)) ),
token_getmad($1,forop,'L');
#else
if ($5) {
- forop = append_elem(OP_LINESEQ,
+ forop = op_append_elem(OP_LINESEQ,
newSTATEOP(0, CopLABEL_alloc($1), $5),
forop);
}
;
/* Switch blocks */
-switch : label GIVEN '(' remember mydefsv mexpr ')' mblock
+switch : label GIVEN lpar_or_qw remember mydefsv mexpr ')' mblock
{ PL_parser->copline = (line_t) IVAL($2);
$$ = block_end($4,
newSTATEOP(0, PVAL($1),
package_block: PACKAGE WORD WORD '{' remember
{
+ int save_3_latefree = $3->op_latefree;
+ $3->op_latefree = 1;
package($3);
- if ($2)
+ $3->op_latefree = save_3_latefree;
+ if ($2) {
+ int save_2_latefree = $2->op_latefree;
+ $2->op_latefree = 1;
package_version($2);
+ $2->op_latefree = save_2_latefree;
+ }
}
lineseq '}'
{ if (PL_parser->copline > (line_t)IVAL($4))
$$ = block_end($5, $7);
TOKEN_GETMAD($4,$$,'{');
TOKEN_GETMAD($8,$$,'}');
+ op_free($3);
+ if ($2)
+ op_free($2);
}
;
#ifdef MAD
OP* op = newNULLLIST();
token_getmad($2,op,',');
- $$ = append_elem(OP_LIST, $1, op);
+ $$ = op_append_elem(OP_LIST, $1, op);
#else
$$ = $1;
#endif
term = newUNOP(OP_NULL, 0, term);
token_getmad($2,term,',');
)
- $$ = append_elem(OP_LIST, $1, term);
+ $$ = op_append_elem(OP_LIST, $1, term);
}
| term %prec PREC_LOW
;
/* List operators */
listop : LSTOP indirob argexpr /* map {...} @args or print $fh @args */
{ $$ = convert(IVAL($1), OPf_STACKED,
- prepend_elem(OP_LIST, newGVREF(IVAL($1),$2), $3) );
+ op_prepend_elem(OP_LIST, newGVREF(IVAL($1),$2), $3) );
TOKEN_GETMAD($1,$$,'o');
}
| FUNC '(' indirob expr ')' /* print ($fh @args */
{ $$ = convert(IVAL($1), OPf_STACKED,
- prepend_elem(OP_LIST, newGVREF(IVAL($1),$3), $4) );
+ op_prepend_elem(OP_LIST, newGVREF(IVAL($1),$3), $4) );
TOKEN_GETMAD($1,$$,'o');
TOKEN_GETMAD($2,$$,'(');
TOKEN_GETMAD($5,$$,')');
}
- | term ARROW method '(' listexprcom ')' /* $foo->bar(list) */
+ | term ARROW method lpar_or_qw listexprcom ')' /* $foo->bar(list) */
{ $$ = convert(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST,
- prepend_elem(OP_LIST, scalar($1), $5),
+ op_append_elem(OP_LIST,
+ op_prepend_elem(OP_LIST, scalar($1), $5),
newUNOP(OP_METHOD, 0, $3)));
TOKEN_GETMAD($2,$$,'A');
TOKEN_GETMAD($4,$$,'(');
}
| term ARROW method /* $foo->bar */
{ $$ = convert(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST, scalar($1),
+ op_append_elem(OP_LIST, scalar($1),
newUNOP(OP_METHOD, 0, $3)));
TOKEN_GETMAD($2,$$,'A');
}
| METHOD indirob listexpr /* new Class @args */
{ $$ = convert(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST,
- prepend_elem(OP_LIST, $2, $3),
+ op_append_elem(OP_LIST,
+ op_prepend_elem(OP_LIST, $2, $3),
newUNOP(OP_METHOD, 0, $1)));
}
| FUNCMETH indirob '(' listexprcom ')' /* method $object (@args) */
{ $$ = convert(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST,
- prepend_elem(OP_LIST, $2, $4),
+ op_append_elem(OP_LIST,
+ op_prepend_elem(OP_LIST, $2, $4),
newUNOP(OP_METHOD, 0, $1)));
TOKEN_GETMAD($3,$$,'(');
TOKEN_GETMAD($5,$$,')');
$<opval>$ = newANONATTRSUB($2, 0, (OP*)NULL, $3); }
listexpr %prec LSTOP /* ... @bar */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST,
- prepend_elem(OP_LIST, $<opval>4, $5), $1));
+ op_append_elem(OP_LIST,
+ op_prepend_elem(OP_LIST, $<opval>4, $5), $1));
}
;
}
| term ARROW '(' expr ')' /* $subref->(@args) */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST, $4,
+ op_append_elem(OP_LIST, $4,
newCVREF(0, scalar($1))));
TOKEN_GETMAD($2,$$,'a');
TOKEN_GETMAD($3,$$,'(');
TOKEN_GETMAD($5,$$,')');
}
- | subscripted '(' expr ')' /* $foo->{bar}->(@args) */
+ | subscripted lpar_or_qw expr ')' /* $foo->{bar}->(@args) */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST, $3,
+ op_append_elem(OP_LIST, $3,
newCVREF(0, scalar($1))));
TOKEN_GETMAD($2,$$,'(');
TOKEN_GETMAD($4,$$,')');
}
- | subscripted '(' ')' /* $foo->{bar}->() */
+ | subscripted lpar_or_qw ')' /* $foo->{bar}->() */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
newCVREF(0, scalar($1)));
TOKEN_GETMAD($2,$$,'(');
TOKEN_GETMAD($4,$$,'[');
TOKEN_GETMAD($6,$$,']');
}
+ | QWLIST '[' expr ']' /* list literal slice */
+ { $$ = newSLICEOP(0, $3, $1);
+ TOKEN_GETMAD($2,$$,'[');
+ TOKEN_GETMAD($4,$$,']');
+ }
| '(' ')' '[' expr ']' /* empty list slice! */
{ $$ = newSLICEOP(0, $4, (OP*)NULL);
TOKEN_GETMAD($1,$$,'(');
{ $$ = newUNOP(OP_NULL, OPf_SPECIAL, scope($2));
TOKEN_GETMAD($1,$$,'D');
}
- | DO WORD '(' ')' /* do somesub() */
+ | DO WORD lpar_or_qw ')' /* do somesub() */
{ $$ = newUNOP(OP_ENTERSUB,
OPf_SPECIAL|OPf_STACKED,
- prepend_elem(OP_LIST,
+ op_prepend_elem(OP_LIST,
scalar(newCVREF(
(OPpENTERSUB_AMPER<<8),
scalar($2)
TOKEN_GETMAD($3,$$,'(');
TOKEN_GETMAD($4,$$,')');
}
- | DO WORD '(' expr ')' /* do somesub(@args) */
+ | DO WORD lpar_or_qw expr ')' /* do somesub(@args) */
{ $$ = newUNOP(OP_ENTERSUB,
OPf_SPECIAL|OPf_STACKED,
- append_elem(OP_LIST,
+ op_append_elem(OP_LIST,
$4,
scalar(newCVREF(
(OPpENTERSUB_AMPER<<8),
TOKEN_GETMAD($3,$$,'(');
TOKEN_GETMAD($5,$$,')');
}
- | DO scalar '(' ')' /* do $subref () */
+ | DO scalar lpar_or_qw ')' /* do $subref () */
{ $$ = newUNOP(OP_ENTERSUB, OPf_SPECIAL|OPf_STACKED,
- prepend_elem(OP_LIST,
+ op_prepend_elem(OP_LIST,
scalar(newCVREF(0,scalar($2))), (OP*)NULL)); dep();
TOKEN_GETMAD($1,$$,'o');
TOKEN_GETMAD($3,$$,'(');
TOKEN_GETMAD($4,$$,')');
}
- | DO scalar '(' expr ')' /* do $subref (@args) */
+ | DO scalar lpar_or_qw expr ')' /* do $subref (@args) */
{ $$ = newUNOP(OP_ENTERSUB, OPf_SPECIAL|OPf_STACKED,
- prepend_elem(OP_LIST,
+ op_prepend_elem(OP_LIST,
$4,
scalar(newCVREF(0,scalar($2))))); dep();
TOKEN_GETMAD($1,$$,'o');
TOKEN_GETMAD($1,$$,'(');
TOKEN_GETMAD($3,$$,')');
}
+ | QWLIST
+ { $$ = IF_MAD(newUNOP(OP_NULL,0,$1), $1); }
| '(' ')'
{ $$ = sawparens(newNULLLIST());
TOKEN_GETMAD($1,$$,'(');
| subscripted
{ $$ = $1; }
| ary '[' expr ']' /* array slice */
- { $$ = prepend_elem(OP_ASLICE,
+ { $$ = op_prepend_elem(OP_ASLICE,
newOP(OP_PUSHMARK, 0),
newLISTOP(OP_ASLICE, 0,
list($3),
TOKEN_GETMAD($4,$$,']');
}
| ary '{' expr ';' '}' /* @hash{@keys} */
- { $$ = prepend_elem(OP_HSLICE,
+ { $$ = op_prepend_elem(OP_HSLICE,
newOP(OP_PUSHMARK, 0),
newLISTOP(OP_HSLICE, 0,
list($3),
{ $$ = $1; }
| amper /* &foo; */
{ $$ = newUNOP(OP_ENTERSUB, 0, scalar($1)); }
- | amper '(' ')' /* &foo() */
+ | amper lpar_or_qw ')' /* &foo() */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED, scalar($1));
TOKEN_GETMAD($2,$$,'(');
TOKEN_GETMAD($3,$$,')');
}
- | amper '(' expr ')' /* &foo(@args) */
+ | amper lpar_or_qw expr ')' /* &foo(@args) */
{
$$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST, $3, scalar($1)));
+ op_append_elem(OP_LIST, $3, scalar($1)));
DO_MAD({
OP* op = $$;
if (op->op_type == OP_CONST) { /* defeat const fold */
}
| NOAMP WORD listexpr /* foo(@args) */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST, $3, scalar($2)));
+ op_append_elem(OP_LIST, $3, scalar($2)));
TOKEN_GETMAD($1,$$,'o');
}
| LOOPEX /* loop exiting command (goto, last, dump, etc) */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED, scalar($1)); }
| UNIOPSUB term /* Sub treated as unop */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST, $2, scalar($1))); }
+ op_append_elem(OP_LIST, $2, scalar($1))); }
| FUNC0 /* Nullary operator */
{ $$ = newOP(IVAL($1), 0);
TOKEN_GETMAD($1,$$,'o');
{ $$ = (OP*)NULL; }
| expr
{ $$ = $1; }
- | expr ','
- {
-#ifdef MAD
- OP* op = newNULLLIST();
- token_getmad($2,op,',');
- $$ = append_elem(OP_LIST, $1, op);
-#else
- $$ = $1;
-#endif
+ ;
- }
+lpar_or_qw: '('
+ { $$ = $1; }
+ | QWLIST
+ { munge_qwlist_to_paren_list($1); }
+ '('
+ { $$ = $3; }
;
/* A little bit of trickery to make "for my $foo (@bar)" actually be