+/* List operators */
+listop : LSTOP indirob argexpr /* map {...} @args or print $fh @args */
+ { $$ = convert($1, OPf_STACKED,
+ prepend_elem(OP_LIST, newGVREF($1,$2), $3) ); }
+ | FUNC '(' indirob expr ')' /* print ($fh @args */
+ { $$ = convert($1, OPf_STACKED,
+ prepend_elem(OP_LIST, newGVREF($1,$3), $4) ); }
+ | term ARROW method '(' listexprcom ')' /* $foo->bar(list) */
+ { $$ = convert(OP_ENTERSUB, OPf_STACKED,
+ append_elem(OP_LIST,
+ prepend_elem(OP_LIST, scalar($1), $5),
+ newUNOP(OP_METHOD, 0, $3))); }
+ | term ARROW method /* $foo->bar */
+ { $$ = convert(OP_ENTERSUB, OPf_STACKED,
+ append_elem(OP_LIST, scalar($1),
+ newUNOP(OP_METHOD, 0, $3))); }
+ | METHOD indirob listexpr /* new Class @args */
+ { $$ = convert(OP_ENTERSUB, OPf_STACKED,
+ append_elem(OP_LIST,
+ prepend_elem(OP_LIST, $2, $3),
+ newUNOP(OP_METHOD, 0, $1))); }
+ | FUNCMETH indirob '(' listexprcom ')' /* method $object (@args) */
+ { $$ = convert(OP_ENTERSUB, OPf_STACKED,
+ append_elem(OP_LIST,
+ prepend_elem(OP_LIST, $2, $4),
+ newUNOP(OP_METHOD, 0, $1))); }
+ | LSTOP listexpr /* print @args */
+ { $$ = convert($1, 0, $2); }
+ | FUNC '(' listexprcom ')' /* print (@args) */
+ { $$ = convert($1, 0, $3); }
+ | LSTOPSUB startanonsub block /* sub f(&@); f { foo } ... */
+ { $3 = newANONATTRSUB($2, 0, Nullop, $3); }
+ listexpr %prec LSTOP /* ... @bar */
+ { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
+ append_elem(OP_LIST,
+ prepend_elem(OP_LIST, $3, $5), $1)); }
+ ;
+
+/* Names of methods. May use $object->$methodname */
+method : METHOD
+ | scalar
+ ;
+
+/* Some kind of subscripted expression */
+subscripted: star '{' expr ';' '}' /* *main::{something} */
+ /* In this and all the hash accessors, ';' is
+ * provided by the tokeniser */
+ { $$ = newBINOP(OP_GELEM, 0, $1, scalar($3));
+ PL_expect = XOPERATOR; }
+ | scalar '[' expr ']' /* $array[$element] */
+ { $$ = newBINOP(OP_AELEM, 0, oopsAV($1), scalar($3)); }
+ | term ARROW '[' expr ']' /* somearef->[$element] */
+ { $$ = newBINOP(OP_AELEM, 0,
+ ref(newAVREF($1),OP_RV2AV),
+ scalar($4));}
+ | subscripted '[' expr ']' /* $foo->[$bar]->[$baz] */
+ { $$ = newBINOP(OP_AELEM, 0,
+ ref(newAVREF($1),OP_RV2AV),
+ scalar($3));}
+ | scalar '{' expr ';' '}' /* $foo->{bar();} */
+ { $$ = newBINOP(OP_HELEM, 0, oopsHV($1), jmaybe($3));
+ PL_expect = XOPERATOR; }
+ | term ARROW '{' expr ';' '}' /* somehref->{bar();} */
+ { $$ = newBINOP(OP_HELEM, 0,
+ ref(newHVREF($1),OP_RV2HV),
+ jmaybe($4));
+ PL_expect = XOPERATOR; }
+ | subscripted '{' expr ';' '}' /* $foo->[bar]->{baz;} */
+ { $$ = newBINOP(OP_HELEM, 0,
+ ref(newHVREF($1),OP_RV2HV),
+ jmaybe($3));
+ PL_expect = XOPERATOR; }
+ | term ARROW '(' ')' /* $subref->() */
+ { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
+ newCVREF(0, scalar($1))); }
+ | term ARROW '(' expr ')' /* $subref->(@args) */
+ { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
+ append_elem(OP_LIST, $4,
+ newCVREF(0, scalar($1)))); }
+
+ | subscripted '(' expr ')' /* $foo->{bar}->(@args) */
+ { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
+ append_elem(OP_LIST, $3,
+ newCVREF(0, scalar($1)))); }
+ | subscripted '(' ')' /* $foo->{bar}->() */
+ { $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
+ newCVREF(0, scalar($1))); }
+ ;
+
+/* Binary operators between terms */
+termbinop : term ASSIGNOP term /* $x = $y */
+ { $$ = newASSIGNOP(OPf_STACKED, $1, $2, $3); }
+ | term POWOP term /* $x ** $y */
+ { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
+ | term MULOP term /* $x * $y, $x x $y */
+ { if ($2 != OP_REPEAT)
+ scalar($1);
+ $$ = newBINOP($2, 0, $1, scalar($3)); }
+ | term ADDOP term /* $x + $y */
+ { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
+ | term SHIFTOP term /* $x >> $y, $x << $y */
+ { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
+ | term RELOP term /* $x > $y, etc. */
+ { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
+ | term EQOP term /* $x == $y, $x eq $y */
+ { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
+ | term BITANDOP term /* $x & $y */
+ { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
+ | term BITOROP term /* $x | $y */
+ { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
+ | term DOTDOT term /* $x..$y, $x...$y */
+ { $$ = newRANGE($2, scalar($1), scalar($3));}
+ | term ANDAND term /* $x && $y */
+ { $$ = newLOGOP(OP_AND, 0, $1, $3); }
+ | term OROR term /* $x || $y */
+ { $$ = newLOGOP(OP_OR, 0, $1, $3); }
+ | term DORDOR term /* $x // $y */
+ { $$ = newLOGOP(OP_DOR, 0, $1, $3); }
+ | term MATCHOP term /* $x =~ /$y/ */
+ { $$ = bind_match($2, $1, $3); }
+ ;
+
+/* Unary operators and terms */
+termunop : '-' term %prec UMINUS /* -$x */
+ { $$ = newUNOP(OP_NEGATE, 0, scalar($2)); }
+ | '+' term %prec UMINUS /* +$x */