/* 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
+
%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> FORMAT SUB ANONSUB PACKAGE USE
%token <i_tkval> WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE FOR
%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> block mblock lineseq line loop cond else
+%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
%type <opval> listexpr listexprcom indirob listop method
%% /* 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;
+ }
+ ;
+
/* The whole program */
prog : progstart
/*CONTINUED*/ lineseq
;
mydefsv: /* NULL */ /* lexicalize $_ */
- { $$ = (I32) allocmy("$_"); }
+ { $$ = (I32) Perl_allocmy(aTHX_ STR_WITH_LEN("$_"), 0); }
;
progstart:
}
;
-/* 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'); }
}
})
}
+ | package_block
+ { $$ = newSTATEOP(0, NULL,
+ newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
+ NOLINE, (OP*)NULL, $1,
+ (OP*)NULL, 0)); }
+ | label PLUGSTMT
+ { $$ = newSTATEOP(0, PVAL($1), $2); }
;
/* An expression which may have a side-effect */
{ ($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)$2;
+ PL_parser->copline = (line_t)IVAL($2);
$$ = block_end($4,
newSTATEOP(0, PVAL($1),
innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
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)$2;
+ PL_parser->copline = (line_t)IVAL($2);
$$ = block_end($4,
newSTATEOP(0, PVAL($1),
innerop = newWHILEOP(0, 1, (LOOP*)(OP*)NULL,
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;
;
/* Switch blocks */
-switch : label GIVEN '(' remember mydefsv mexpr ')' mblock
- { PL_parser->copline = (line_t) $2;
+switch : label GIVEN lpar_or_qw remember mydefsv mexpr ')' mblock
+ { PL_parser->copline = (line_t) IVAL($2);
$$ = block_end($4,
newSTATEOP(0, PVAL($1),
newGIVENOP($6, scope($8),
;
format : FORMAT startformsub formname block
- { SvREFCNT_inc_simple_void(PL_compcv);
+ {
+ CV *fmtcv = PL_compcv;
+ SvREFCNT_inc_simple_void(PL_compcv);
#ifdef MAD
$$ = newFORM($2, $3, $4);
prepend_madprops($1->tk_mad, $$, 'F');
newFORM($2, $3, $4);
$$ = (OP*)NULL;
#endif
+ if (CvOUTSIDE(fmtcv) && !CvUNIQUE(CvOUTSIDE(fmtcv))) {
+ SvREFCNT_inc_simple_void(fmtcv);
+ pad_add_anon((SV*)fmtcv, OP_NULL);
+ }
}
;
}
;
-package : PACKAGE WORD ';'
+package : PACKAGE WORD WORD ';'
{
#ifdef MAD
- $$ = package($2);
+ $$ = package($3);
token_getmad($1,$$,'o');
- token_getmad($3,$$,';');
+ if ($2)
+ package_version($2);
+ token_getmad($4,$$,';');
#else
- package($2);
+ package($3);
+ if ($2)
+ package_version($2);
$$ = (OP*)NULL;
#endif
}
;
+package_block: PACKAGE WORD WORD '{' remember
+ {
+ int save_3_latefree = $3->op_latefree;
+ $3->op_latefree = 1;
+ package($3);
+ $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))
+ 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);
+ }
+ ;
+
use : USE startsub
{ CvSPECIAL_on(PL_compcv); /* It's a BEGIN {} */ }
WORD WORD listexpr ';'
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),
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,
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,
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,
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,
scalar(newCVREF(0,scalar($2))), (OP*)NULL)); dep();
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,
$4,
TOKEN_GETMAD($1,$$,'(');
TOKEN_GETMAD($3,$$,')');
}
+ | QWLIST
+ { $$ = IF_MAD(newUNOP(OP_NULL,0,$1), $1); }
| '(' ')'
{ $$ = sawparens(newNULLLIST());
TOKEN_GETMAD($1,$$,'(');
{ $$ = $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)));
newSVOP(OP_CONST, 0, newSVpvs("Unimplemented")));
TOKEN_GETMAD($1,$$,'X');
}
+ | PLUGEXPR
;
/* "my" declarations, with optional attributes */
{ $$ = (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