This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add the madly parser. I believe that this is all the C code. Now to
[perl5.git] / madly.y
CommitLineData
00e74f14
NC
1/* perly.y
2 *
3 * Copyright (c) 1991-2002, 2003, 2004 Larry Wall
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
7 *
8 */
9
10/*
11 * 'I see,' laughed Strider. 'I look foul and feel fair. Is that it?
12 * All that is gold does not glitter, not all those who wander are lost.'
13 */
14
15/* Make the parser re-entrant. */
16
17%pure_parser
18
19%start prog
20
21%union {
22 I32 ival;
23 char *pval;
24 TOKEN* tkval;
25 OP *opval;
26 GV *gvval;
27}
28
29%token <tkval> '{' '}' '[' ']' '-' '+' '$' '@' '%' '*'
30
31%token <opval> WORD METHOD FUNCMETH THING PMFUNC PRIVATEREF
32%token <opval> FUNC0SUB UNIOPSUB LSTOPSUB
33%token <tkval> LABEL
34%token <tkval> FORMAT SUB ANONSUB PACKAGE USE
35%token <tkval> WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE FOR
36%token <tkval> LOOPEX DOTDOT
37%token <tkval> FUNC0 FUNC1 FUNC UNIOP LSTOP
38%token <tkval> RELOP EQOP MULOP ADDOP
39%token <tkval> DOLSHARP DO HASHBRACK NOAMP
40%token <tkval> LOCAL MY MYSUB
41%token <tkval> COLONATTR
42
43%type <ival> prog progstart remember mremember savescope
44%type <ival> startsub startanonsub startformsub mintro
45
46%type <tkval> '&' ';'
47
48%type <opval> decl format subrout mysubrout package use peg
49
50%type <opval> block mblock lineseq line loop cond else
51%type <opval> expr term subscripted scalar ary hsh arylen star amper sideff
52%type <opval> argexpr nexpr texpr iexpr mexpr mnexpr miexpr
53%type <opval> listexpr listexprcom indirob listop method
54%type <opval> formname subname proto subbody cont my_scalar
55%type <opval> subattrlist myattrlist myattrterm myterm
56%type <opval> termbinop termunop anonymous termdo
57%type <tkval> label
58
59%nonassoc <tkval> PREC_LOW
60%nonassoc LOOPEX
61
62%left <tkval> OROP DOROP
63%left <tkval> ANDOP
64%right <tkval> NOTOP
65%nonassoc LSTOP LSTOPSUB
66%left <tkval> ','
67%right <tkval> ASSIGNOP
68%right <tkval> '?' ':'
69%nonassoc DOTDOT
70%left <tkval> OROR DORDOR
71%left <tkval> ANDAND
72%left <tkval> BITOROP
73%left <tkval> BITANDOP
74%nonassoc EQOP
75%nonassoc RELOP
76%nonassoc UNIOP UNIOPSUB
77%left <tkval> SHIFTOP
78%left ADDOP
79%left MULOP
80%left <tkval> MATCHOP
81%right <tkval> '!' '~' UMINUS REFGEN
82%right <tkval> POWOP
83%nonassoc <tkval> PREINC PREDEC POSTINC POSTDEC
84%left <tkval> ARROW
85%nonassoc <tkval> ')'
86%left <tkval> '('
87%left '[' '{'
88
89%token <tkval> PEG
90
91%% /* RULES */
92
93/* The whole program */
94prog : progstart
95 /*CONTINUED*/ lineseq
96 { $$ = $1; newPROG(block_end($1,$2)); }
97 ;
98
99/* An ordinary block */
100block : '{' remember lineseq '}'
101 { if (PL_copline > (line_t)($1)->tk_lval.ival)
102 PL_copline = (line_t)($1)->tk_lval.ival;
103 $$ = block_end($2, $3);
104 token_getmad($1,$$,'{');
105 token_getmad($4,$$,'}');
106 }
107 ;
108
109remember: /* NULL */ /* start a full lexical scope */
110 { $$ = block_start(TRUE); }
111 ;
112
113progstart:
114 {
115 PL_expect = XSTATE; $$ = block_start(TRUE);
116 }
117 ;
118
119
120mblock : '{' mremember lineseq '}'
121 { if (PL_copline > (line_t)($1)->tk_lval.ival)
122 PL_copline = (line_t)($1)->tk_lval.ival;
123 $$ = block_end($2, $3);
124 token_getmad($1,$$,'{');
125 token_getmad($4,$$,'}');
126 }
127 ;
128
129mremember: /* NULL */ /* start a partial lexical scope */
130 { $$ = block_start(FALSE); }
131 ;
132
133savescope: /* NULL */ /* remember stack pos in case of error */
134 { $$ = PL_savestack_ix; }
135
136/* A collection of "lines" in the program */
137lineseq : /* NULL */
138 { $$ = Nullop; }
139 | lineseq decl
140/* { $$ = $1 } */
141 { $$ = append_list(OP_LINESEQ,
142 (LISTOP*)$1, (LISTOP*)$2); }
143 | lineseq savescope line
144 { LEAVE_SCOPE($2);
145 $$ = append_list(OP_LINESEQ,
146 (LISTOP*)$1, (LISTOP*)$3);
147 PL_pad_reset_pending = TRUE;
148 if ($1 && $3) PL_hints |= HINT_BLOCK_SCOPE; }
149 ;
150
151/* A "line" in the program */
152line : label cond
153 { $$ = newSTATEOP(0, ($1)->tk_lval.pval, $2);
154 token_getmad($1,((LISTOP*)$$)->op_first,'L'); }
155 | loop /* loops add their own labels */
156 | label ';'
157 {
158 if (($1)->tk_lval.pval) {
159 $$ = newSTATEOP(0, ($1)->tk_lval.pval, newOP(OP_NULL, 0));
160 token_getmad($1,$$,'L');
161 token_getmad($2,((LISTOP*)$$)->op_first,';');
162 }
163 else {
164 $$ = newOP(OP_NULL, 0);
165 PL_copline = NOLINE;
166 token_free($1);
167 token_getmad($2,$$,';');
168 }
169 PL_expect = XSTATE;
170 }
171 | label sideff ';'
172 { OP* op;
173 $$ = newSTATEOP(0, ($1)->tk_lval.pval, $2);
174 PL_expect = XSTATE;
175 /* sideff might already have a nexstate */
176 op = ((LISTOP*)$$)->op_first;
177 if (op) {
178 while (op->op_sibling &&
179 op->op_sibling->op_type == OP_NEXTSTATE)
180 op = op->op_sibling;
181 token_getmad($1,op,'L');
182 token_getmad($3,op,';');
183 }
184 }
185 ;
186
187/* An expression which may have a side-effect */
188sideff : error
189 { $$ = Nullop; }
190 | expr
191 { $$ = $1; }
192 | expr IF expr
193 { $$ = newLOGOP(OP_AND, 0, $3, $1);
194 token_getmad($2,$$,'i');
195 }
196 | expr UNLESS expr
197 { $$ = newLOGOP(OP_OR, 0, $3, $1);
198 token_getmad($2,$$,'i');
199 }
200 | expr WHILE expr
201 { $$ = newLOOPOP(OPf_PARENS, 1, scalar($3), $1);
202 token_getmad($2,$$,'w');
203 }
204 | expr UNTIL iexpr
205 { $$ = newLOOPOP(OPf_PARENS, 1, $3, $1);
206 token_getmad($2,$$,'w');
207 }
208 | expr FOR expr
209 { $$ = newFOROP(0, Nullch, (line_t)($2)->tk_lval.ival,
210 Nullop, $3, $1, Nullop);
211 token_getmad($2,((LISTOP*)$$)->op_first->op_sibling,'w');
212 }
213 ;
214
215/* else and elsif blocks */
216else : /* NULL */
217 { $$ = Nullop; }
218 | ELSE mblock
219 { ($2)->op_flags |= OPf_PARENS; $$ = scope($2);
220 token_getmad($1,$$,'o');
221 }
222 | ELSIF '(' mexpr ')' mblock else
223 { PL_copline = (line_t)($1)->tk_lval.ival;
224 $$ = newCONDOP(0, $3, scope($5), $6);
225 PL_hints |= HINT_BLOCK_SCOPE;
226 token_getmad($1,$$,'I');
227 token_getmad($2,$$,'(');
228 token_getmad($4,$$,')');
229 }
230 ;
231
232/* Real conditional expressions */
233cond : IF '(' remember mexpr ')' mblock else
234 { PL_copline = (line_t)($1)->tk_lval.ival;
235 $$ = block_end($3,
236 newCONDOP(0, $4, scope($6), $7));
237 token_getmad($1,$$,'I');
238 token_getmad($2,$$,'(');
239 token_getmad($5,$$,')');
240 }
241 | UNLESS '(' remember miexpr ')' mblock else
242 { PL_copline = (line_t)($1)->tk_lval.ival;
243 $$ = block_end($3,
244 newCONDOP(0, $4, scope($6), $7));
245 token_getmad($1,$$,'I');
246 token_getmad($2,$$,'(');
247 token_getmad($5,$$,')');
248 }
249 ;
250
251/* Continue blocks */
252cont : /* NULL */
253 { $$ = Nullop; }
254 | CONTINUE block
255 { $$ = scope($2);
256 token_getmad($1,$$,'o');
257 }
258 ;
259
260/* Loops: while, until, for, and a bare block */
261loop : label WHILE '(' remember texpr ')' mintro mblock cont
262 { OP *innerop;
263 PL_copline = (line_t)$2;
264 $$ = block_end($4,
265 newSTATEOP(0, ($1)->tk_lval.pval,
266 innerop = newWHILEOP(0, 1, (LOOP*)Nullop,
267 ($2)->tk_lval.ival, $5, $8, $9, $7)));
268 token_getmad($1,innerop,'L');
269 token_getmad($2,innerop,'W');
270 token_getmad($3,innerop,'(');
271 token_getmad($6,innerop,')');
272 }
273 | label UNTIL '(' remember iexpr ')' mintro mblock cont
274 { OP *innerop;
275 PL_copline = (line_t)$2;
276 $$ = block_end($4,
277 newSTATEOP(0, ($1)->tk_lval.pval,
278 innerop = newWHILEOP(0, 1, (LOOP*)Nullop,
279 ($2)->tk_lval.ival, $5, $8, $9, $7)));
280 token_getmad($1,innerop,'L');
281 token_getmad($2,innerop,'W');
282 token_getmad($3,innerop,'(');
283 token_getmad($6,innerop,')');
284 }
285 | label FOR MY remember my_scalar '(' mexpr ')' mblock cont
286 { OP *innerop;
287 $$ = block_end($4,
288 innerop = newFOROP(0, ($1)->tk_lval.pval, (line_t)($2)->tk_lval.ival, $5, $7, $9, $10));
289 token_getmad($1,((LISTOP*)innerop)->op_first,'L');
290 token_getmad($2,((LISTOP*)innerop)->op_first->op_sibling,'W');
291 token_getmad($3,((LISTOP*)innerop)->op_first->op_sibling,'d');
292 token_getmad($6,((LISTOP*)innerop)->op_first->op_sibling,'(');
293 token_getmad($8,((LISTOP*)innerop)->op_first->op_sibling,')');
294 }
295 | label FOR scalar '(' remember mexpr ')' mblock cont
296 { OP *innerop;
297 $$ = block_end($5,
298 innerop = newFOROP(0, ($1)->tk_lval.pval, (line_t)($2)->tk_lval.ival, mod($3, OP_ENTERLOOP),
299 $6, $8, $9));
300 token_getmad($1,((LISTOP*)innerop)->op_first,'L');
301 token_getmad($2,((LISTOP*)innerop)->op_first->op_sibling,'W');
302 token_getmad($4,((LISTOP*)innerop)->op_first->op_sibling,'(');
303 token_getmad($7,((LISTOP*)innerop)->op_first->op_sibling,')');
304 }
305 | label FOR '(' remember mexpr ')' mblock cont
306 { OP *innerop;
307 $$ = block_end($4,
308 innerop = newFOROP(0, ($1)->tk_lval.pval, (line_t)($2)->tk_lval.ival, Nullop, $5, $7, $8));
309 token_getmad($1,((LISTOP*)innerop)->op_first,'L');
310 token_getmad($2,((LISTOP*)innerop)->op_first->op_sibling,'W');
311 token_getmad($3,((LISTOP*)innerop)->op_first->op_sibling,'(');
312 token_getmad($6,((LISTOP*)innerop)->op_first->op_sibling,')');
313 }
314 | label FOR '(' remember mnexpr ';' texpr ';' mintro mnexpr ')' mblock
315 /* basically fake up an initialize-while lineseq */
316 { OP *forop;
317 PL_copline = (line_t)($2)->tk_lval.ival;
318 forop = newSTATEOP(0, ($1)->tk_lval.pval,
319 newWHILEOP(0, 1, (LOOP*)Nullop,
320 ($2)->tk_lval.ival, scalar($7),
321 $12, $10, $9));
322 if (!$5)
323 $5 = newOP(OP_NULL, 0);
324 forop = newUNOP(OP_NULL, 0, append_elem(OP_LINESEQ,
325 newSTATEOP(0,
326 (($1)->tk_lval.pval
327 ?savepv(($1)->tk_lval.pval):Nullch),
328 $5),
329 forop));
330
331 token_getmad($2,forop,'3');
332 token_getmad($3,forop,'(');
333 token_getmad($6,forop,'1');
334 token_getmad($8,forop,'2');
335 token_getmad($11,forop,')');
336 token_getmad($1,forop,'L');
337 $$ = block_end($4, forop);
338 }
339 | label block cont /* a block is a loop that happens once */
340 { $$ = newSTATEOP(0, ($1)->tk_lval.pval,
341 newWHILEOP(0, 1, (LOOP*)Nullop,
342 NOLINE, Nullop, $2, $3, 0));
343 token_getmad($1,((LISTOP*)$$)->op_first,'L'); }
344 ;
345
346/* determine whether there are any new my declarations */
347mintro : /* NULL */
348 { $$ = (PL_min_intro_pending &&
349 PL_max_intro_pending >= PL_min_intro_pending);
350 intro_my(); }
351
352
353/* Normal expression */
354nexpr : /* NULL */
355 { $$ = Nullop; }
356 | sideff
357 ;
358
359/* Boolean expression */
360texpr : /* NULL means true */
361 { YYSTYPE tmplval;
362 (void)scan_num("1", &tmplval);
363 $$ = tmplval.opval; }
364 | expr
365 ;
366
367/* Inverted boolean expression */
368iexpr : expr
369 { $$ = invert(scalar($1)); }
370 ;
371
372/* Expression with its own lexical scope */
373mexpr : expr
374 { $$ = $1; intro_my(); }
375 ;
376
377mnexpr : nexpr
378 { $$ = $1; intro_my(); }
379 ;
380
381miexpr : iexpr
382 { $$ = $1; intro_my(); }
383 ;
384
385/* Optional "MAIN:"-style loop labels */
386label : /* empty */
387 { YYSTYPE tmplval;
388 tmplval.pval = Nullch;
389 $$ = newTOKEN(OP_NULL, tmplval, 0); }
390 | LABEL
391 ;
392
393/* Some kind of declaration - just hang on peg in the parse tree */
394decl : format
395 { $$ = $1; }
396 | subrout
397 { $$ = $1; }
398 | mysubrout
399 { $$ = $1; }
400 | package
401 { $$ = $1; }
402 | use
403 { $$ = $1; }
404 | peg
405 { $$ = $1; }
406 ;
407
408peg : PEG
409 { $$ = newOP(OP_NULL,0);
410 token_getmad($1,$$,'p');
411 }
412 ;
413
414format : FORMAT startformsub formname block
415 { $$ = newFORM($2, $3, $4);
416 prepend_madprops($1->tk_mad, $$, 'F');
417 $1->tk_mad = 0;
418 token_free($1);
419 }
420 ;
421
422formname: WORD { $$ = $1; }
423 | /* NULL */ { $$ = Nullop; }
424 ;
425
426/* Unimplemented "my sub foo { }" */
427mysubrout: MYSUB startsub subname proto subattrlist subbody
428 { $$ = newMYSUB($2, $3, $4, $5, $6);
429 token_getmad($1,$$,'d');
430 }
431 ;
432
433/* Subroutine definition */
434subrout : SUB startsub subname proto subattrlist subbody
435 { OP* o = newSVOP(OP_ANONCODE, 0,
436 (SV*)newATTRSUB($2, $3, $4, $5, $6));
437 $$ = newOP(OP_NULL,0);
438 op_getmad(o,$$,'&');
439 op_getmad($3,$$,'n');
440 op_getmad($4,$$,'s');
441 op_getmad($5,$$,'a');
442 token_getmad($1,$$,'d');
443 append_madprops($6->op_madprop, $$, 0);
444 $6->op_madprop = 0;
445 }
446 ;
447
448startsub: /* NULL */ /* start a regular subroutine scope */
449 { $$ = start_subparse(FALSE, 0); }
450 ;
451
452startanonsub: /* NULL */ /* start an anonymous subroutine scope */
453 { $$ = start_subparse(FALSE, CVf_ANON); }
454 ;
455
456startformsub: /* NULL */ /* start a format subroutine scope */
457 { $$ = start_subparse(TRUE, 0); }
458 ;
459
460/* Name of a subroutine - must be a bareword, could be special */
461subname : WORD { STRLEN n_a; char *name = SvPV(((SVOP*)$1)->op_sv,n_a);
462 if (strEQ(name, "BEGIN") || strEQ(name, "END")
463 || strEQ(name, "INIT") || strEQ(name, "CHECK"))
464 CvSPECIAL_on(PL_compcv);
465 $$ = $1; }
466 ;
467
468/* Subroutine prototype */
469proto : /* NULL */
470 { $$ = Nullop; }
471 | THING
472 ;
473
474/* Optional list of subroutine attributes */
475subattrlist: /* NULL */
476 { $$ = Nullop; }
477 | COLONATTR THING
478 { $$ = $2;
479 token_getmad($1,$$,':');
480 }
481 | COLONATTR
482 { $$ = newOP(OP_NULL, 0);
483 token_getmad($1,$$,':');
484 }
485 ;
486
487/* List of attributes for a "my" variable declaration */
488myattrlist: COLONATTR THING
489 { $$ = $2;
490 token_getmad($1,$$,':');
491 }
492 | COLONATTR
493 { $$ = newOP(OP_NULL, 0);
494 token_getmad($1,$$,':');
495 }
496 ;
497
498/* Subroutine body - either null or a block */
499subbody : block { $$ = $1; }
500 | ';' { $$ = newOP(OP_NULL,0); PL_expect = XSTATE;
501 token_getmad($1,$$,';');
502 }
503 ;
504
505package : PACKAGE WORD ';'
506 { $$ = package($2);
507 token_getmad($1,$$,'o');
508 token_getmad($3,$$,';');
509 }
510 ;
511
512use : USE startsub
513 { CvSPECIAL_on(PL_compcv); /* It's a BEGIN {} */ }
514 WORD WORD listexpr ';'
515 { $$ = utilize(($1)->tk_lval.ival, $2, $4, $5, $6);
516 token_getmad($1,$$,'o');
517 token_getmad($7,$$,';');
518 if (PL_rsfp_filters && AvFILLp(PL_rsfp_filters) >= 0)
519 append_madprops(newMADPROP('!', MAD_PV, "", 0), $$, 0);
520 }
521 ;
522
523/* Ordinary expressions; logical combinations */
524expr : expr ANDOP expr
525 { $$ = newLOGOP(OP_AND, 0, $1, $3);
526 token_getmad($2,$$,'o');
527 }
528 | expr OROP expr
529 { $$ = newLOGOP(($2)->tk_lval.ival, 0, $1, $3);
530 token_getmad($2,$$,'o');
531 }
532 | expr DOROP expr
533 { $$ = newLOGOP(OP_DOR, 0, $1, $3);
534 token_getmad($2,$$,'o');
535 }
536 | argexpr %prec PREC_LOW
537 ;
538
539/* Expressions are a list of terms joined by commas */
540argexpr : argexpr ','
541 { OP* op = newNULLLIST();
542 token_getmad($2,op,',');
543 $$ = append_elem(OP_LIST, $1, op);
544 }
545 | argexpr ',' term
546 {
547 $3 = newUNOP(OP_NULL, 0, $3);
548 token_getmad($2,$3,',');
549 $$ = append_elem(OP_LIST, $1, $3);
550 }
551 | term %prec PREC_LOW
552 ;
553
554/* List operators */
555listop : LSTOP indirob argexpr /* print $fh @args */
556 { $$ = convert(($1)->tk_lval.ival, OPf_STACKED,
557 prepend_elem(OP_LIST, newGVREF(($1)->tk_lval.ival,$2), $3) );
558 token_getmad($1,$$,'o');
559 }
560 | FUNC '(' indirob expr ')' /* print ($fh @args */
561 { $$ = convert(($1)->tk_lval.ival, OPf_STACKED,
562 prepend_elem(OP_LIST, newGVREF(($1)->tk_lval.ival,$3), $4) );
563 token_getmad($1,$$,'o');
564 token_getmad($2,$$,'(');
565 token_getmad($5,$$,')');
566 }
567 | term ARROW method '(' listexprcom ')' /* $foo->bar(list) */
568 { $$ = convert(OP_ENTERSUB, OPf_STACKED,
569 append_elem(OP_LIST,
570 prepend_elem(OP_LIST, scalar($1), $5),
571 newUNOP(OP_METHOD, 0, $3)));
572 token_getmad($2,$$,'A');
573 token_getmad($4,$$,'(');
574 token_getmad($6,$$,')');
575 }
576 | term ARROW method /* $foo->bar */
577 { $$ = convert(OP_ENTERSUB, OPf_STACKED,
578 append_elem(OP_LIST, scalar($1),
579 newUNOP(OP_METHOD, 0, $3)));
580 token_getmad($2,$$,'A');
581 }
582 | METHOD indirob listexpr /* new Class @args */
583 { $$ = convert(OP_ENTERSUB, OPf_STACKED,
584 append_elem(OP_LIST,
585 prepend_elem(OP_LIST, $2, $3),
586 newUNOP(OP_METHOD, 0, $1)));
587 }
588 | FUNCMETH indirob '(' listexprcom ')' /* method $object (@args) */
589 { $$ = convert(OP_ENTERSUB, OPf_STACKED,
590 append_elem(OP_LIST,
591 prepend_elem(OP_LIST, $2, $4),
592 newUNOP(OP_METHOD, 0, $1)));
593 token_getmad($3,$$,'(');
594 token_getmad($5,$$,')');
595 }
596 | LSTOP listexpr /* print @args */
597 { $$ = convert(($1)->tk_lval.ival, 0, $2);
598 token_getmad($1,$$,'o');
599 }
600 | FUNC '(' listexprcom ')' /* print (@args) */
601 { $$ = convert(($1)->tk_lval.ival, 0, $3);
602 token_getmad($1,$$,'o');
603 token_getmad($2,$$,'(');
604 token_getmad($4,$$,')');
605 }
606 | LSTOPSUB startanonsub block /* map { foo } ... */
607 { $3 = newANONATTRSUB($2, 0, Nullop, $3); }
608 listexpr %prec LSTOP /* ... @bar */
609 { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
610 append_elem(OP_LIST,
611 prepend_elem(OP_LIST, $3, $5), $1));
612 }
613 ;
614
615/* Names of methods. May use $object->$methodname */
616method : METHOD
617 | scalar
618 ;
619
620/* Some kind of subscripted expression */
621subscripted: star '{' expr ';' '}' /* *main::{something} */
622 /* In this and all the hash accessors, ';' is
623 * provided by the tokeniser */
624 { $$ = newBINOP(OP_GELEM, 0, $1, scalar($3));
625 PL_expect = XOPERATOR;
626 token_getmad($2,$$,'{');
627 token_getmad($4,$$,';');
628 token_getmad($5,$$,'}');
629 }
630 | scalar '[' expr ']' /* $array[$element] */
631 { $$ = newBINOP(OP_AELEM, 0, oopsAV($1), scalar($3));
632 token_getmad($2,$$,'[');
633 token_getmad($4,$$,']');
634 }
635 | term ARROW '[' expr ']' /* somearef->[$element] */
636 { $$ = newBINOP(OP_AELEM, 0,
637 ref(newAVREF($1),OP_RV2AV),
638 scalar($4));
639 token_getmad($2,$$,'a');
640 token_getmad($3,$$,'[');
641 token_getmad($5,$$,']');
642 }
643 | subscripted '[' expr ']' /* $foo->[$bar]->[$baz] */
644 { $$ = newBINOP(OP_AELEM, 0,
645 ref(newAVREF($1),OP_RV2AV),
646 scalar($3));
647 token_getmad($2,$$,'[');
648 token_getmad($4,$$,']');
649 }
650 | scalar '{' expr ';' '}' /* $foo->{bar();} */
651 { $$ = newBINOP(OP_HELEM, 0, oopsHV($1), jmaybe($3));
652 PL_expect = XOPERATOR;
653 token_getmad($2,$$,'{');
654 token_getmad($4,$$,';');
655 token_getmad($5,$$,'}');
656 }
657 | term ARROW '{' expr ';' '}' /* somehref->{bar();} */
658 { $$ = newBINOP(OP_HELEM, 0,
659 ref(newHVREF($1),OP_RV2HV),
660 jmaybe($4));
661 PL_expect = XOPERATOR;
662 token_getmad($2,$$,'a');
663 token_getmad($3,$$,'{');
664 token_getmad($5,$$,';');
665 token_getmad($6,$$,'}');
666 }
667 | subscripted '{' expr ';' '}' /* $foo->[bar]->{baz;} */
668 { $$ = newBINOP(OP_HELEM, 0,
669 ref(newHVREF($1),OP_RV2HV),
670 jmaybe($3));
671 PL_expect = XOPERATOR;
672 token_getmad($2,$$,'{');
673 token_getmad($4,$$,';');
674 token_getmad($5,$$,'}');
675 }
676 | term ARROW '(' ')' /* $subref->() */
677 { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
678 newCVREF(0, scalar($1)));
679 token_getmad($2,$$,'a');
680 token_getmad($3,$$,'(');
681 token_getmad($4,$$,')');
682 }
683 | term ARROW '(' expr ')' /* $subref->(@args) */
684 { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
685 append_elem(OP_LIST, $4,
686 newCVREF(0, scalar($1))));
687 token_getmad($2,$$,'a');
688 token_getmad($3,$$,'(');
689 token_getmad($5,$$,')');
690 }
691
692 | subscripted '(' expr ')' /* $foo->{bar}->(@args) */
693 { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
694 append_elem(OP_LIST, $3,
695 newCVREF(0, scalar($1))));
696 token_getmad($2,$$,'(');
697 token_getmad($4,$$,')');
698 }
699 | subscripted '(' ')' /* $foo->{bar}->() */
700 { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
701 newCVREF(0, scalar($1)));
702 token_getmad($2,$$,'(');
703 token_getmad($3,$$,')');
704 }
705 ;
706
707/* Binary operators between terms */
708termbinop: term ASSIGNOP term /* $x = $y */
709 { $$ = newASSIGNOP(OPf_STACKED, $1, ($2)->tk_lval.ival, $3);
710 token_getmad($2,$$,'o');
711 }
712 | term POWOP term /* $x ** $y */
713 { $$ = newBINOP(($2)->tk_lval.ival, 0, scalar($1), scalar($3));
714 token_getmad($2,$$,'o');
715 }
716 | term MULOP term /* $x * $y, $x x $y */
717 { if (($2)->tk_lval.ival != OP_REPEAT)
718 scalar($1);
719 $$ = newBINOP(($2)->tk_lval.ival, 0, $1, scalar($3));
720 token_getmad($2,$$,'o');
721 }
722 | term ADDOP term /* $x + $y */
723 { $$ = newBINOP(($2)->tk_lval.ival, 0, scalar($1), scalar($3));
724 token_getmad($2,$$,'o');
725 }
726 | term SHIFTOP term /* $x >> $y, $x << $y */
727 { $$ = newBINOP(($2)->tk_lval.ival, 0, scalar($1), scalar($3));
728 token_getmad($2,$$,'o');
729 }
730 | term RELOP term /* $x > $y, etc. */
731 { $$ = newBINOP(($2)->tk_lval.ival, 0, scalar($1), scalar($3));
732 token_getmad($2,$$,'o');
733 }
734 | term EQOP term /* $x == $y, $x eq $y */
735 { $$ = newBINOP(($2)->tk_lval.ival, 0, scalar($1), scalar($3));
736 token_getmad($2,$$,'o');
737 }
738 | term BITANDOP term /* $x & $y */
739 { $$ = newBINOP(($2)->tk_lval.ival, 0, scalar($1), scalar($3));
740 token_getmad($2,$$,'o');
741 }
742 | term BITOROP term /* $x | $y */
743 { $$ = newBINOP(($2)->tk_lval.ival, 0, scalar($1), scalar($3));
744 token_getmad($2,$$,'o');
745 }
746 | term DOTDOT term /* $x..$y, $x...$y */
747 { UNOP *op;
748 $$ = newRANGE(($2)->tk_lval.ival, scalar($1), scalar($3));
749 op = (UNOP*)$$;
750 op = (UNOP*)op->op_first; /* get to flop */
751 op = (UNOP*)op->op_first; /* get to flip */
752 op = (UNOP*)op->op_first; /* get to range */
753 token_getmad($2,(OP*)op,'o');
754 }
755 | term ANDAND term /* $x && $y */
756 { $$ = newLOGOP(OP_AND, 0, $1, $3);
757 token_getmad($2,$$,'o');
758 }
759 | term OROR term /* $x || $y */
760 { $$ = newLOGOP(OP_OR, 0, $1, $3);
761 token_getmad($2,$$,'o');
762 }
763 | term DORDOR term /* $x // $y */
764 { $$ = newLOGOP(OP_DOR, 0, $1, $3);
765 token_getmad($2,$$,'o');
766 }
767 | term MATCHOP term /* $x =~ /$y/ */
768 { $$ = bind_match(($2)->tk_lval.ival, $1, $3);
769 if ($$->op_type == OP_NOT)
770 token_getmad($2,((UNOP*)$$)->op_first,'~');
771 else
772 token_getmad($2,$$,'~');
773 }
774 ;
775
776/* Unary operators and terms */
777termunop : '-' term %prec UMINUS /* -$x */
778 { $$ = newUNOP(OP_NEGATE, 0, scalar($2));
779 token_getmad($1,$$,'o');
780 }
781 | '+' term %prec UMINUS /* +$x */
782 { $$ = newUNOP(OP_NULL, 0, $2);
783 token_getmad($1,$$,'+');
784 }
785 | '!' term /* !$x */
786 { $$ = newUNOP(OP_NOT, 0, scalar($2));
787 token_getmad($1,$$,'o');
788 }
789 | '~' term /* ~$x */
790 { $$ = newUNOP(OP_COMPLEMENT, 0, scalar($2));
791 token_getmad($1,$$,'o');
792 }
793 | term POSTINC /* $x++ */
794 { $$ = newUNOP(OP_POSTINC, 0,
795 mod(scalar($1), OP_POSTINC));
796 token_getmad($2,$$,'o');
797 }
798 | term POSTDEC /* $x-- */
799 { $$ = newUNOP(OP_POSTDEC, 0,
800 mod(scalar($1), OP_POSTDEC));
801 token_getmad($2,$$,'o');
802 }
803 | PREINC term /* ++$x */
804 { $$ = newUNOP(OP_PREINC, 0,
805 mod(scalar($2), OP_PREINC));
806 token_getmad($1,$$,'o');
807 }
808 | PREDEC term /* --$x */
809 { $$ = newUNOP(OP_PREDEC, 0,
810 mod(scalar($2), OP_PREDEC));
811 token_getmad($1,$$,'o');
812 }
813
814 ;
815
816/* Constructors for anonymous data */
817anonymous: '[' expr ']'
818 { $$ = newANONLIST($2);
819 token_getmad($1,$$,'[');
820 token_getmad($3,$$,']');
821 }
822 | '[' ']'
823 { $$ = newANONLIST(Nullop);
824 token_getmad($1,$$,'[');
825 token_getmad($2,$$,']');
826 }
827 | HASHBRACK expr ';' '}' %prec '(' /* { foo => "Bar" } */
828 { $$ = newANONHASH($2);
829 token_getmad($1,$$,'{');
830 token_getmad($3,$$,';');
831 token_getmad($4,$$,'}');
832 }
833 | HASHBRACK ';' '}' %prec '(' /* { } (';' by tokener) */
834 { $$ = newANONHASH(Nullop);
835 token_getmad($1,$$,'{');
836 token_getmad($2,$$,';');
837 token_getmad($3,$$,'}');
838 }
839 | ANONSUB startanonsub proto subattrlist block %prec '('
840 { $$ = newANONATTRSUB($2, $3, $4, $5);
841 token_getmad($1,$$,'o');
842 op_getmad($3,$$,'s');
843 op_getmad($4,$$,'a');
844 }
845
846 ;
847
848/* Things called with "do" */
849termdo : DO term %prec UNIOP /* do $filename */
850 { $$ = dofile($2, $1);
851 token_getmad($1,$$,'o');
852 }
853 | DO block %prec '(' /* do { code */
854 { $$ = newUNOP(OP_NULL, OPf_SPECIAL, scope($2));
855 token_getmad($1,$$,'D');
856 }
857 | DO WORD '(' ')' /* do somesub() */
858 { $$ = newUNOP(OP_ENTERSUB,
859 OPf_SPECIAL|OPf_STACKED,
860 prepend_elem(OP_LIST,
861 scalar(newCVREF(
862 (OPpENTERSUB_AMPER<<8),
863 scalar($2)
864 )),Nullop)); dep();
865 token_getmad($1,$$,'o');
866 token_getmad($3,$$,'(');
867 token_getmad($4,$$,')');
868 }
869 | DO WORD '(' expr ')' /* do somesub(@args) */
870 { $$ = newUNOP(OP_ENTERSUB,
871 OPf_SPECIAL|OPf_STACKED,
872 append_elem(OP_LIST,
873 $4,
874 scalar(newCVREF(
875 (OPpENTERSUB_AMPER<<8),
876 scalar($2)
877 )))); dep();
878 token_getmad($1,$$,'o');
879 token_getmad($3,$$,'(');
880 token_getmad($5,$$,')');
881 }
882 | DO scalar '(' ')' /* do $subref () */
883 { $$ = newUNOP(OP_ENTERSUB, OPf_SPECIAL|OPf_STACKED,
884 prepend_elem(OP_LIST,
885 scalar(newCVREF(0,scalar($2))), Nullop)); dep();
886 token_getmad($1,$$,'o');
887 token_getmad($3,$$,'(');
888 token_getmad($4,$$,')');
889 }
890 | DO scalar '(' expr ')' /* do $subref (@args) */
891 { $$ = newUNOP(OP_ENTERSUB, OPf_SPECIAL|OPf_STACKED,
892 prepend_elem(OP_LIST,
893 $4,
894 scalar(newCVREF(0,scalar($2))))); dep();
895 token_getmad($1,$$,'o');
896 token_getmad($3,$$,'(');
897 token_getmad($5,$$,')');
898 }
899
900 ;
901
902term : termbinop
903 | termunop
904 | anonymous
905 | termdo
906 | term '?' term ':' term
907 { $$ = newCONDOP(0, $1, $3, $5);
908 token_getmad($2,$$,'?');
909 token_getmad($4,$$,':');
910 }
911 | REFGEN term /* \$x, \@y, \%z */
912 { $$ = newUNOP(OP_REFGEN, 0, mod($2,OP_REFGEN));
913 token_getmad($1,$$,'o');
914 }
915 | myattrterm %prec UNIOP
916 { $$ = $1; }
917 | LOCAL term %prec UNIOP
918 { $$ = localize($2,($1)->tk_lval.ival);
919 token_getmad($1,$$,'d');
920 }
921 | '(' expr ')'
922 { $$ = sawparens(newUNOP(OP_NULL,0,$2));
923 token_getmad($1,$$,'(');
924 token_getmad($3,$$,')');
925 }
926 | '(' ')'
927 { $$ = sawparens(newNULLLIST());
928 token_getmad($1,$$,'(');
929 token_getmad($2,$$,')');
930 }
931 | scalar %prec '('
932 { $$ = $1; }
933 | star %prec '('
934 { $$ = $1; }
935 | hsh %prec '('
936 { $$ = $1; }
937 | ary %prec '('
938 { $$ = $1; }
939 | arylen %prec '(' /* $#x, $#{ something } */
940 { $$ = newUNOP(OP_AV2ARYLEN, 0, ref($1, OP_AV2ARYLEN));}
941 | subscripted
942 { $$ = $1; }
943 | '(' expr ')' '[' expr ']' /* list slice */
944 { $$ = newSLICEOP(0, $5, $2);
945 token_getmad($1,$$,'(');
946 token_getmad($3,$$,')');
947 token_getmad($4,$$,'[');
948 token_getmad($6,$$,']');
949 }
950 | '(' ')' '[' expr ']' /* empty list slice! */
951 { $$ = newSLICEOP(0, $4, Nullop);
952 token_getmad($1,$$,'(');
953 token_getmad($2,$$,')');
954 token_getmad($3,$$,'[');
955 token_getmad($5,$$,']');
956 }
957 | ary '[' expr ']' /* array slice */
958 { $$ = prepend_elem(OP_ASLICE,
959 newOP(OP_PUSHMARK, 0),
960 newLISTOP(OP_ASLICE, 0,
961 list($3),
962 ref($1, OP_ASLICE)));
963 token_getmad($2,$$,'[');
964 token_getmad($4,$$,']');
965 }
966 | ary '{' expr ';' '}' /* @hash{@keys} */
967 { $$ = prepend_elem(OP_HSLICE,
968 newOP(OP_PUSHMARK, 0),
969 newLISTOP(OP_HSLICE, 0,
970 list($3),
971 ref(oopsHV($1), OP_HSLICE)));
972 PL_expect = XOPERATOR;
973 token_getmad($2,$$,'{');
974 token_getmad($4,$$,';');
975 token_getmad($5,$$,'}');
976 }
977 | THING %prec '('
978 { $$ = $1; }
979 | amper /* &foo; */
980 { $$ = newUNOP(OP_ENTERSUB, 0, scalar($1)); }
981 | amper '(' ')' /* &foo() */
982 { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED, scalar($1));
983 token_getmad($2,$$,'(');
984 token_getmad($3,$$,')');
985 }
986 | amper '(' expr ')' /* &foo(@args) */
987 { OP* op;
988 $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
989 append_elem(OP_LIST, $3, scalar($1)));
990 op = $$;
991 if (op->op_type == OP_CONST) { /* defeat const fold */
992 op = (OP*)op->op_madprop->mad_val;
993 }
994 token_getmad($2,op,'(');
995 token_getmad($4,op,')');
996 }
997 | NOAMP WORD listexpr /* foo(@args) */
998 { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
999 append_elem(OP_LIST, $3, scalar($2)));
1000 token_getmad($1,$$,'o');
1001 }
1002 | LOOPEX /* loop exiting command (goto, last, dump, etc) */
1003 { $$ = newOP(($1)->tk_lval.ival, OPf_SPECIAL);
1004 PL_hints |= HINT_BLOCK_SCOPE;
1005 token_getmad($1,$$,'o');
1006 }
1007 | LOOPEX term
1008 { $$ = newLOOPEX(($1)->tk_lval.ival,$2);
1009 token_getmad($1,$$,'o');
1010 }
1011 | NOTOP argexpr /* not $foo */
1012 { $$ = newUNOP(OP_NOT, 0, scalar($2));
1013 token_getmad($1,$$,'o');
1014 }
1015 | UNIOP /* Unary op, $_ implied */
1016 { $$ = newOP(($1)->tk_lval.ival, 0);
1017 token_getmad($1,$$,'o');
1018 }
1019 | UNIOP block /* eval { foo }, I *think* */
1020 { $$ = newUNOP(($1)->tk_lval.ival, 0, $2);
1021 token_getmad($1,$$,'o');
1022 }
1023 | UNIOP term /* Unary op */
1024 { $$ = newUNOP(($1)->tk_lval.ival, 0, $2);
1025 token_getmad($1,$$,'o');
1026 }
1027 | UNIOPSUB term /* Sub treated as unop */
1028 { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
1029 append_elem(OP_LIST, $2, scalar($1)));
1030 }
1031 | FUNC0 /* Nullary operator */
1032 { $$ = newOP(($1)->tk_lval.ival, 0);
1033 token_getmad($1,$$,'o');
1034 }
1035 | FUNC0 '(' ')'
1036 { $$ = newOP(($1)->tk_lval.ival, 0);
1037 token_getmad($1,$$,'o');
1038 token_getmad($2,$$,'(');
1039 token_getmad($3,$$,')');
1040 }
1041 | FUNC0SUB /* Sub treated as nullop */
1042 { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
1043 scalar($1)); }
1044 | FUNC1 '(' ')' /* not () */
1045 { $$ = newOP(($1)->tk_lval.ival, OPf_SPECIAL);
1046 token_getmad($1,$$,'o');
1047 token_getmad($2,$$,'(');
1048 token_getmad($3,$$,')');
1049 }
1050 | FUNC1 '(' expr ')' /* not($foo) */
1051 { $$ = newUNOP(($1)->tk_lval.ival, 0, $3);
1052 token_getmad($1,$$,'o');
1053 token_getmad($2,$$,'(');
1054 token_getmad($4,$$,')');
1055 }
1056 | PMFUNC '(' argexpr ')' /* m//, s///, tr/// */
1057 { $$ = pmruntime($1, $3, 1);
1058 token_getmad($2,$$,'(');
1059 token_getmad($4,$$,')');
1060 }
1061 | WORD
1062 | listop
1063 ;
1064
1065/* "my" declarations, with optional attributes */
1066myattrterm: MY myterm myattrlist
1067 { $$ = my_attrs($2,$3);
1068 token_getmad($1,$$,'d');
1069 append_madprops($3->op_madprop, $$, 'a');
1070 $3->op_madprop = 0;
1071 }
1072 | MY myterm
1073 { $$ = localize($2,($1)->tk_lval.ival);
1074 token_getmad($1,$$,'d');
1075 }
1076 ;
1077
1078/* Things that can be "my"'d */
1079myterm : '(' expr ')'
1080 { $$ = sawparens($2);
1081 token_getmad($1,$$,'(');
1082 token_getmad($3,$$,')');
1083 }
1084 | '(' ')'
1085 { $$ = sawparens(newNULLLIST());
1086 token_getmad($1,$$,'(');
1087 token_getmad($2,$$,')');
1088 }
1089 | scalar %prec '('
1090 { $$ = $1; }
1091 | hsh %prec '('
1092 { $$ = $1; }
1093 | ary %prec '('
1094 { $$ = $1; }
1095 ;
1096
1097/* Basic list expressions */
1098listexpr: /* NULL */ %prec PREC_LOW
1099 { $$ = Nullop; }
1100 | argexpr %prec PREC_LOW
1101 { $$ = $1; }
1102 ;
1103
1104listexprcom: /* NULL */
1105 { $$ = Nullop; }
1106 | expr
1107 { $$ = $1; }
1108 | expr ','
1109 { OP* op = newNULLLIST();
1110 token_getmad($2,op,',');
1111 $$ = append_elem(OP_LIST, $1, op);
1112 }
1113 ;
1114
1115/* A little bit of trickery to make "for my $foo (@bar)" actually be
1116 lexical */
1117my_scalar: scalar
1118 { PL_in_my = 0; $$ = my($1); }
1119 ;
1120
1121amper : '&' indirob
1122 { $$ = newCVREF(($1)->tk_lval.ival,$2);
1123 token_getmad($1,$$,'&');
1124 }
1125 ;
1126
1127scalar : '$' indirob
1128 { $$ = newSVREF($2);
1129 token_getmad($1,$$,'$');
1130 }
1131 ;
1132
1133ary : '@' indirob
1134 { $$ = newAVREF($2);
1135 token_getmad($1,$$,'@');
1136 }
1137 ;
1138
1139hsh : '%' indirob
1140 { $$ = newHVREF($2);
1141 token_getmad($1,$$,'%');
1142 }
1143 ;
1144
1145arylen : DOLSHARP indirob
1146 { $$ = newAVREF($2);
1147 token_getmad($1,$$,'l');
1148 }
1149 ;
1150
1151star : '*' indirob
1152 { $$ = newGVREF(0,$2);
1153 token_getmad($1,$$,'*');
1154 }
1155 ;
1156
1157/* Indirect objects */
1158indirob : WORD
1159 { $$ = scalar($1); }
1160 | scalar %prec PREC_LOW
1161 { $$ = scalar($1); }
1162 | block
1163 { $$ = scope($1); }
1164
1165 | PRIVATEREF
1166 { $$ = $1; }
1167 ;