+ append_elem(OP_LIST, $3,
+ newCVREF(0, scalar($1))));
+ TOKEN_GETMAD($2,$$,'(');
+ TOKEN_GETMAD($4,$$,')');
+ }
+ | subscripted '(' ')' /* $foo->{bar}->() */
+ { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
+ newCVREF(0, scalar($1)));
+ TOKEN_GETMAD($2,$$,'(');
+ TOKEN_GETMAD($3,$$,')');
+ }
+ | '(' expr ')' '[' expr ']' /* list slice */
+ { $$ = newSLICEOP(0, $5, $2);
+ TOKEN_GETMAD($1,$$,'(');
+ TOKEN_GETMAD($3,$$,')');
+ TOKEN_GETMAD($4,$$,'[');
+ TOKEN_GETMAD($6,$$,']');
+ }
+ | '(' ')' '[' expr ']' /* empty list slice! */
+ { $$ = newSLICEOP(0, $4, Nullop);
+ TOKEN_GETMAD($1,$$,'(');
+ TOKEN_GETMAD($2,$$,')');
+ TOKEN_GETMAD($3,$$,'[');
+ TOKEN_GETMAD($5,$$,']');
+ }
+ ;
+
+/* Binary operators between terms */
+termbinop: term ASSIGNOP term /* $x = $y */
+ { $$ = newASSIGNOP(OPf_STACKED, $1, IVAL($2), $3);
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term POWOP term /* $x ** $y */
+ { $$ = newBINOP(IVAL($2), 0, scalar($1), scalar($3));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term MULOP term /* $x * $y, $x x $y */
+ { if (IVAL($2) != OP_REPEAT)
+ scalar($1);
+ $$ = newBINOP(IVAL($2), 0, $1, scalar($3));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term ADDOP term /* $x + $y */
+ { $$ = newBINOP(IVAL($2), 0, scalar($1), scalar($3));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term SHIFTOP term /* $x >> $y, $x << $y */
+ { $$ = newBINOP(IVAL($2), 0, scalar($1), scalar($3));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term RELOP term /* $x > $y, etc. */
+ { $$ = newBINOP(IVAL($2), 0, scalar($1), scalar($3));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term EQOP term /* $x == $y, $x eq $y */
+ { $$ = newBINOP(IVAL($2), 0, scalar($1), scalar($3));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term BITANDOP term /* $x & $y */
+ { $$ = newBINOP(IVAL($2), 0, scalar($1), scalar($3));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term BITOROP term /* $x | $y */
+ { $$ = newBINOP(IVAL($2), 0, scalar($1), scalar($3));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term DOTDOT term /* $x..$y, $x...$y */
+ {
+ $$ = newRANGE(IVAL($2), scalar($1), scalar($3));
+ DO_MAD({
+ UNOP *op;
+ op = (UNOP*)$$;
+ op = (UNOP*)op->op_first; /* get to flop */
+ op = (UNOP*)op->op_first; /* get to flip */
+ op = (UNOP*)op->op_first; /* get to range */
+ token_getmad($2,(OP*)op,'o');
+ })
+ }
+ | term ANDAND term /* $x && $y */
+ { $$ = newLOGOP(OP_AND, 0, $1, $3);
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term OROR term /* $x || $y */
+ { $$ = newLOGOP(OP_OR, 0, $1, $3);
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term DORDOR term /* $x // $y */
+ { $$ = newLOGOP(OP_DOR, 0, $1, $3);
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term MATCHOP term /* $x =~ /$y/ */
+ { $$ = bind_match(IVAL($2), $1, $3);
+ TOKEN_GETMAD($2,
+ ($$->op_type == OP_NOT
+ ? ((UNOP*)$$)->op_first : $$),
+ '~');
+ }
+ ;
+
+/* Unary operators and terms */
+termunop : '-' term %prec UMINUS /* -$x */
+ { $$ = newUNOP(OP_NEGATE, 0, scalar($2));
+ TOKEN_GETMAD($1,$$,'o');
+ }
+ | '+' term %prec UMINUS /* +$x */
+ { $$ = IF_MAD(
+ newUNOP(OP_NULL, 0, $2),
+ $2
+ );
+ TOKEN_GETMAD($1,$$,'+');
+ }
+ | '!' term /* !$x */
+ { $$ = newUNOP(OP_NOT, 0, scalar($2));
+ TOKEN_GETMAD($1,$$,'o');
+ }
+ | '~' term /* ~$x */
+ { $$ = newUNOP(OP_COMPLEMENT, 0, scalar($2));
+ TOKEN_GETMAD($1,$$,'o');
+ }
+ | term POSTINC /* $x++ */
+ { $$ = newUNOP(OP_POSTINC, 0,
+ mod(scalar($1), OP_POSTINC));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | term POSTDEC /* $x-- */
+ { $$ = newUNOP(OP_POSTDEC, 0,
+ mod(scalar($1), OP_POSTDEC));
+ TOKEN_GETMAD($2,$$,'o');
+ }
+ | PREINC term /* ++$x */
+ { $$ = newUNOP(OP_PREINC, 0,
+ mod(scalar($2), OP_PREINC));
+ TOKEN_GETMAD($1,$$,'o');
+ }
+ | PREDEC term /* --$x */
+ { $$ = newUNOP(OP_PREDEC, 0,
+ mod(scalar($2), OP_PREDEC));
+ TOKEN_GETMAD($1,$$,'o');
+ }
+
+ ;
+
+/* Constructors for anonymous data */
+anonymous: '[' expr ']'
+ { $$ = newANONLIST($2);
+ TOKEN_GETMAD($1,$$,'[');
+ TOKEN_GETMAD($3,$$,']');
+ }
+ | '[' ']'
+ { $$ = newANONLIST(Nullop);
+ TOKEN_GETMAD($1,$$,'[');
+ TOKEN_GETMAD($2,$$,']');
+ }
+ | HASHBRACK expr ';' '}' %prec '(' /* { foo => "Bar" } */
+ { $$ = newANONHASH($2);
+ TOKEN_GETMAD($1,$$,'{');
+ TOKEN_GETMAD($3,$$,';');
+ TOKEN_GETMAD($4,$$,'}');
+ }
+ | HASHBRACK ';' '}' %prec '(' /* { } (';' by tokener) */
+ { $$ = newANONHASH(Nullop);
+ TOKEN_GETMAD($1,$$,'{');
+ TOKEN_GETMAD($2,$$,';');
+ TOKEN_GETMAD($3,$$,'}');
+ }
+ | ANONSUB startanonsub proto subattrlist block %prec '('
+ { SvREFCNT_inc_simple_void(PL_compcv);
+ $$ = newANONATTRSUB($2, $3, $4, $5);
+ TOKEN_GETMAD($1,$$,'o');
+ OP_GETMAD($3,$$,'s');
+ OP_GETMAD($4,$$,'a');
+ }
+
+ ;
+
+/* Things called with "do" */
+termdo : DO term %prec UNIOP /* do $filename */
+ { $$ = dofile($2, IVAL($1));
+ TOKEN_GETMAD($1,$$,'o');
+ }
+ | DO block %prec '(' /* do { code */
+ { $$ = newUNOP(OP_NULL, OPf_SPECIAL, scope($2));
+ TOKEN_GETMAD($1,$$,'D');
+ }
+ | DO WORD '(' ')' /* do somesub() */