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
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 */
94 prog    :       progstart
95         /*CONTINUED*/   lineseq
96                         { $$ = $1; newPROG(block_end($1,$2)); }
97         ;
98
99 /* An ordinary block */
100 block   :       '{' 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
109 remember:       /* NULL */      /* start a full lexical scope */
110                         { $$ = block_start(TRUE); }
111         ;
112
113 progstart:
114                 {
115                     PL_expect = XSTATE; $$ = block_start(TRUE);
116                 }
117         ;
118
119
120 mblock  :       '{' 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
129 mremember:      /* NULL */      /* start a partial lexical scope */
130                         { $$ = block_start(FALSE); }
131         ;
132
133 savescope:      /* NULL */      /* remember stack pos in case of error */
134                 { $$ = PL_savestack_ix; }
135
136 /* A collection of "lines" in the program */
137 lineseq :       /* 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 */
152 line    :       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 */
188 sideff  :       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 */
216 else    :       /* 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 */
233 cond    :       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 */
252 cont    :       /* 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 */
261 loop    :       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 */
347 mintro  :       /* NULL */
348                         { $$ = (PL_min_intro_pending &&
349                             PL_max_intro_pending >=  PL_min_intro_pending);
350                           intro_my(); }
351
352
353 /* Normal expression */
354 nexpr   :       /* NULL */
355                         { $$ = Nullop; }
356         |       sideff
357         ;
358
359 /* Boolean expression */
360 texpr   :       /* NULL means true */
361                         { YYSTYPE tmplval;
362                           (void)scan_num("1", &tmplval);
363                           $$ = tmplval.opval; }
364         |       expr
365         ;
366
367 /* Inverted boolean expression */
368 iexpr   :       expr
369                         { $$ = invert(scalar($1)); }
370         ;
371
372 /* Expression with its own lexical scope */
373 mexpr   :       expr
374                         { $$ = $1; intro_my(); }
375         ;
376
377 mnexpr  :       nexpr
378                         { $$ = $1; intro_my(); }
379         ;
380
381 miexpr  :       iexpr
382                         { $$ = $1; intro_my(); }
383         ;
384
385 /* Optional "MAIN:"-style loop labels */
386 label   :       /* 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 */
394 decl    :       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
408 peg     :       PEG
409                         { $$ = newOP(OP_NULL,0);
410                           token_getmad($1,$$,'p');
411                         }
412         ;
413
414 format  :       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
422 formname:       WORD            { $$ = $1; }
423         |       /* NULL */      { $$ = Nullop; }
424         ;
425
426 /* Unimplemented "my sub foo { }" */
427 mysubrout:      MYSUB startsub subname proto subattrlist subbody
428                         { $$ = newMYSUB($2, $3, $4, $5, $6);
429                           token_getmad($1,$$,'d');
430                         }
431         ;
432
433 /* Subroutine definition */
434 subrout :       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
448 startsub:       /* NULL */      /* start a regular subroutine scope */
449                         { $$ = start_subparse(FALSE, 0); }
450         ;
451
452 startanonsub:   /* NULL */      /* start an anonymous subroutine scope */
453                         { $$ = start_subparse(FALSE, CVf_ANON); }
454         ;
455
456 startformsub:   /* 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 */
461 subname :       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 */
469 proto   :       /* NULL */
470                         { $$ = Nullop; }
471         |       THING
472         ;
473
474 /* Optional list of subroutine attributes */
475 subattrlist:    /* 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 */
488 myattrlist:     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 */
499 subbody :       block   { $$ = $1; }
500         |       ';'     { $$ = newOP(OP_NULL,0); PL_expect = XSTATE;
501                           token_getmad($1,$$,';');
502                         }
503         ;
504
505 package :       PACKAGE WORD ';'
506                         { $$ = package($2);
507                           token_getmad($1,$$,'o');
508                           token_getmad($3,$$,';');
509                         }
510         ;
511
512 use     :       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 */
524 expr    :       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 */
540 argexpr :       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 */
555 listop  :       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 */
616 method  :       METHOD
617         |       scalar
618         ;
619
620 /* Some kind of subscripted expression */
621 subscripted:    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 */
708 termbinop:      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 */
777 termunop : '-' 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 */
817 anonymous:      '[' 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" */
849 termdo  :       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
902 term    :       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 */
1066 myattrterm:     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 */
1079 myterm  :       '(' 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 */
1098 listexpr:       /* NULL */ %prec PREC_LOW
1099                         { $$ = Nullop; }
1100         |       argexpr    %prec PREC_LOW
1101                         { $$ = $1; }
1102         ;
1103
1104 listexprcom:    /* 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 */
1117 my_scalar:      scalar
1118                         { PL_in_my = 0; $$ = my($1); }
1119         ;
1120
1121 amper   :       '&' indirob
1122                         { $$ = newCVREF(($1)->tk_lval.ival,$2);
1123                           token_getmad($1,$$,'&');
1124                         }
1125         ;
1126
1127 scalar  :       '$' indirob
1128                         { $$ = newSVREF($2);
1129                           token_getmad($1,$$,'$');
1130                         }
1131         ;
1132
1133 ary     :       '@' indirob
1134                         { $$ = newAVREF($2);
1135                           token_getmad($1,$$,'@');
1136                         }
1137         ;
1138
1139 hsh     :       '%' indirob
1140                         { $$ = newHVREF($2);
1141                           token_getmad($1,$$,'%');
1142                         }
1143         ;
1144
1145 arylen  :       DOLSHARP indirob
1146                         { $$ = newAVREF($2);
1147                           token_getmad($1,$$,'l');
1148                         }
1149         ;
1150
1151 star    :       '*' indirob
1152                         { $$ = newGVREF(0,$2);
1153                           token_getmad($1,$$,'*');
1154                         }
1155         ;
1156
1157 /* Indirect objects */
1158 indirob :       WORD
1159                         { $$ = scalar($1); }
1160         |       scalar %prec PREC_LOW
1161                         { $$ = scalar($1); }
1162         |       block
1163                         { $$ = scope($1); }
1164
1165         |       PRIVATEREF
1166                         { $$ = $1; }
1167         ;