summaryrefslogtreecommitdiffstats
path: root/perl_checker.src/parser.mly
diff options
context:
space:
mode:
authorPascal Rigaux <pixel@mandriva.com>2002-11-14 20:03:21 +0000
committerPascal Rigaux <pixel@mandriva.com>2002-11-14 20:03:21 +0000
commitd22a970196e532292d20dbaa5dc25ed5c35f6bc1 (patch)
tree88114434c6b9080a268f8bfe2f26e07939c05c7e /perl_checker.src/parser.mly
parenta4a7e80c8c89ae1e962a86ae14e2f1865f95d1f7 (diff)
downloadperl-MDK-Common-d22a970196e532292d20dbaa5dc25ed5c35f6bc1.tar
perl-MDK-Common-d22a970196e532292d20dbaa5dc25ed5c35f6bc1.tar.gz
perl-MDK-Common-d22a970196e532292d20dbaa5dc25ed5c35f6bc1.tar.bz2
perl-MDK-Common-d22a970196e532292d20dbaa5dc25ed5c35f6bc1.tar.xz
perl-MDK-Common-d22a970196e532292d20dbaa5dc25ed5c35f6bc1.zip
*** empty log message ***
Diffstat (limited to 'perl_checker.src/parser.mly')
-rw-r--r--perl_checker.src/parser.mly291
1 files changed, 150 insertions, 141 deletions
diff --git a/perl_checker.src/parser.mly b/perl_checker.src/parser.mly
index 20d9229..8352c97 100644
--- a/perl_checker.src/parser.mly
+++ b/perl_checker.src/parser.mly
@@ -8,7 +8,7 @@
%}
-%token <unit * (Types.spaces * Types.raw_pos)> EOF
+%token <unit * (Types.spaces * Types.raw_pos)> EOF DEFINED
%token <string * (Types.spaces * Types.raw_pos)> NUM STRING BAREWORD BAREWORD_PAREN REVISION COMMENT POD LABEL PRINT_TO_STAR PRINT_TO_SCALAR
%token <string * (Types.spaces * Types.raw_pos)> COMMAND_STRING QUOTEWORDS COMPACT_HASH_SUBSCRIPT
@@ -37,15 +37,15 @@
%token <unit * (Types.spaces * Types.raw_pos)> POWER
%token <unit * (Types.spaces * Types.raw_pos)> TIGHT_NOT BIT_NEG REF
%token <unit * (Types.spaces * Types.raw_pos)> PATTERN_MATCH PATTERN_MATCH_NOT
-%token <unit * (Types.spaces * Types.raw_pos)> MULT DIVISION MODULO REPLICATE
-%token <unit * (Types.spaces * Types.raw_pos)> PLUS MINUS CONCAT
-%token <unit * (Types.spaces * Types.raw_pos)> BIT_SHIFT_LEFT BIT_SHIFT_RIGHT
+%token <string * (Types.spaces * Types.raw_pos)> MULT
+%token <string * (Types.spaces * Types.raw_pos)> PLUS
+%token <string * (Types.spaces * Types.raw_pos)> BIT_SHIFT
%token <unit * (Types.spaces * Types.raw_pos)> LT GT
%token <unit * (Types.spaces * Types.raw_pos)> BIT_AND
%token <unit * (Types.spaces * Types.raw_pos)> BIT_OR BIT_XOR
%token <unit * (Types.spaces * Types.raw_pos)> AND_TIGHT
%token <unit * (Types.spaces * Types.raw_pos)> OR_TIGHT
-%token <unit * (Types.spaces * Types.raw_pos)> DOTDOT DOTDOTDOT
+%token <string * (Types.spaces * Types.raw_pos)> DOTDOT
%token <unit * (Types.spaces * Types.raw_pos)> QUESTION_MARK COLON
%token <unit * (Types.spaces * Types.raw_pos)> COMMA RIGHT_ARROW
%token <unit * (Types.spaces * Types.raw_pos)> NOT
@@ -63,7 +63,7 @@
%right ASSIGN
%right QUESTION_MARK COLON
-%nonassoc DOTDOT DOTDOTDOT
+%nonassoc DOTDOT
%left OR_TIGHT
%left AND_TIGHT
%left BIT_OR BIT_XOR
@@ -71,9 +71,9 @@
%nonassoc EQ_OP
%nonassoc LT GT COMPARE_OP
%nonassoc UNIOP
-%left BIT_SHIFT_LEFT BIT_SHIFT_RIGHT
-%left PLUS MINUS CONCAT
-%left MULT DIVISION MODULO REPLICATE
+%left BIT_SHIFT
+%left PLUS
+%left MULT
%left PATTERN_MATCH PATTERN_MATCH_NOT
%right TIGHT_NOT BIT_NEG REF UNARY_MINUS
%right POWER
@@ -85,13 +85,13 @@
%left ARRAYREF BRACKET
%type <Types.fromparser list> prog
-%type <Types.fromparser * (Types.spaces * Types.raw_pos)> expr
+%type <(Types.priority * Types.fromparser) * (Types.spaces * Types.raw_pos)> expr
%start prog
%%
-prog: lines EOF { fst $1 }
+prog: lines EOF {check_package (fst $1); fst $1}
lines: /* A collection of "lines" in the program */
| {[], (Space_none, bpos)}
@@ -108,23 +108,23 @@ line:
| BRACKET lines BRACKET_END {sp_p($2); sp_p($3); Block(fst $2), snd $1}
if_then_else: /* Real conditional expressions */
-| IF PAREN expr PAREN_END BRACKET lines BRACKET_END elsif else_ {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); Call_op("if", fst $3 :: Block(fst $6) :: fst $8 @ fst $9), snd $1}
-| UNLESS PAREN expr PAREN_END BRACKET lines BRACKET_END elsif else_ {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); Call_op("unless", fst $3 :: Block(fst $6) :: fst $8 @ fst $9), snd $1}
+| IF PAREN expr PAREN_END BRACKET lines BRACKET_END elsif else_ {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); Call_op("if", prio_lo P_loose $3 :: Block(fst $6) :: fst $8 @ fst $9), snd $1}
+| UNLESS PAREN expr PAREN_END BRACKET lines BRACKET_END elsif else_ {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); Call_op("unless", prio_lo P_loose $3 :: Block(fst $6) :: fst $8 @ fst $9), snd $1}
elsif:
| {[], (Space_none, bpos)}
-| ELSIF PAREN expr PAREN_END BRACKET lines BRACKET_END elsif {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); fst $3 :: Block(fst $6) :: fst $8, snd $1}
+| ELSIF PAREN expr PAREN_END BRACKET lines BRACKET_END elsif {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); prio_lo P_loose $3 :: Block(fst $6) :: fst $8, snd $1}
else_:
| { [], (Space_none, bpos) }
| ELSE BRACKET lines BRACKET_END {sp_p($1); sp_n($2); sp_p($3); sp_p($4); [ Block(fst $3) ], snd $1 }
loop:
-| WHILE PAREN expr PAREN_END BRACKET lines BRACKET_END cont {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); Call_op("while", fst $3 :: fst $6), snd $1}
-| UNTIL PAREN expr PAREN_END BRACKET lines BRACKET_END cont {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); Call_op("until", fst $3 :: fst $6), snd $1}
-| FOR MY SCALAR_IDENT PAREN expr PAREN_END BRACKET lines BRACKET_END cont {sp_p($1); check_foreach($1); sp_n($4); sp_0($5); sp_0_or_cr($6); sp_p($7); sp_p($8); sp_p($9); Call_op("foreach my", to_Ident $3 :: fst $5 :: fst $8), snd $1}
+| WHILE PAREN expr PAREN_END BRACKET lines BRACKET_END cont {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); Call_op("while", prio_lo P_loose $3 :: fst $6), snd $1}
+| UNTIL PAREN expr PAREN_END BRACKET lines BRACKET_END cont {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); Call_op("until", prio_lo P_loose $3 :: fst $6), snd $1}
+| FOR MY SCALAR_IDENT PAREN expr PAREN_END BRACKET lines BRACKET_END cont {sp_p($1); check_foreach($1); sp_n($4); sp_0($5); sp_0_or_cr($6); sp_p($7); sp_p($8); sp_p($9); Call_op("foreach my", to_Ident $3 :: prio_lo P_loose $5 :: fst $8), snd $1}
| FOR SCALAR_IDENT PAREN expr PAREN_END BRACKET lines BRACKET_END cont { die_rule "don't use for without \"my\"ing the iteration variable" }
-| FOR PAREN expr PAREN_END BRACKET lines BRACKET_END cont {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); check_foreach($1); Call_op("foreach", fst $3 :: fst $6), snd $1}
+| FOR PAREN expr PAREN_END BRACKET lines BRACKET_END cont {sp_p($1); sp_n($2); sp_0($3); sp_0_or_cr($4); sp_p($5); sp_p($6); sp_p($7); check_foreach($1); Call_op("foreach", prio_lo P_loose $3 :: fst $6), snd $1}
| FOR PAREN expr_or_empty semi_colon expr_or_empty semi_colon expr_or_empty PAREN_END BRACKET lines BRACKET_END {sp_p($1); sp_n($2); sp_0($3); check_for($1); Call_op("for", fst $3 :: fst $5 :: fst $7 :: fst $10), snd $1}
cont: /* Continue blocks */
@@ -132,28 +132,28 @@ cont: /* Continue blocks */
| CONTINUE BRACKET lines BRACKET_END {sp_p($1); sp_n($2); sp_p($3); sp_p($4); (), snd $1}
sideff: /* An expression which may have a side-effect */
-| expr {$1}
-| expr IF expr {let f = "if" in sp_p($2); sp_p($3); check_no_paren f $3; Call_op(f ^ " infix", [ fst $1 ; fst $3 ]), snd $1}
-| expr UNLESS expr {let f = "unless" in sp_p($2); sp_p($3); check_no_paren f $3; Call_op(f ^ " infix", [ fst $1 ; fst $3 ]), snd $1}
-| expr WHILE expr {let f = "while" in sp_p($2); sp_p($3); check_no_paren f $3; Call_op(f ^ " infix", [ fst $1 ; fst $3 ]), snd $1}
-| expr UNTIL expr {let f = "until" in sp_p($2); sp_p($3); check_no_paren f $3; Call_op(f ^ " infix", [ fst $1 ; fst $3 ]), snd $1}
-| expr FOR expr {let f = "for" in sp_p($2); sp_p($3); check_foreach($2); check_no_paren f $3; Call_op(f ^ " infix", [ fst $1 ; fst $3 ]), snd $1}
+| expr {sndfst $1, snd $1}
+| expr IF expr {sp_p($2); sp_p($3); Call_op("if infix" , [ prio_lo P_loose $1 ; prio_lo P_loose $3 ]), snd $1}
+| expr UNLESS expr {sp_p($2); sp_p($3); Call_op("unless infix", [ prio_lo P_loose $1 ; prio_lo P_loose $3 ]), snd $1}
+| expr WHILE expr {sp_p($2); sp_p($3); Call_op("while infix" , [ prio_lo P_loose $1 ; prio_lo P_loose $3 ]), snd $1}
+| expr UNTIL expr {sp_p($2); sp_p($3); Call_op("until infix" , [ prio_lo P_loose $1 ; prio_lo P_loose $3 ]), snd $1}
+| expr FOR expr {sp_p($2); sp_p($3); check_foreach($2); Call_op("for infix" , [ prio_lo P_loose $1 ; prio_lo P_loose $3 ]), snd $1}
decl:
| FORMAT BAREWORD ASSIGN {Too_complex, snd $1}
| FORMAT ASSIGN {Too_complex, snd $1}
-| func_decl semi_colon {die_rule (if snd (fst $1) = "" then "there is no need to pre-declare in Perl!" else "please don't use prototype pre-declaration") }
+| func_decl semi_colon {die_rule (if sndfst $1 = "" then "there is no need to pre-declare in Perl!" else "please don't use prototype pre-declaration") }
| func_decl BRACKET BRACKET_END {sp_n($2); sp_0_or_cr($3); let name, proto = fst $1 in sub_declaration (name, proto) [], snd $1}
| func_decl BRACKET lines BRACKET_END {sp_n($2); check_lines_after_BRACKET($3); sp_p($4); sub_declaration (fst $1) (fst $3), snd $1}
-| func_decl BRACKET BRACKET expr BRACKET_END BRACKET_END {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($6); sub_declaration (fst $1) [Ref(I_hash, fst $4)], snd $1}
-| func_decl BRACKET BRACKET expr BRACKET_END semi_colon BRACKET_END {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($7); sub_declaration (fst $1) [Ref(I_hash, fst $4)], snd $1}
+| func_decl BRACKET BRACKET expr BRACKET_END BRACKET_END {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($6); sub_declaration (fst $1) [Ref(I_hash, prio_lo P_loose $4)], snd $1}
+| func_decl BRACKET BRACKET expr BRACKET_END semi_colon BRACKET_END {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($7); sub_declaration (fst $1) [Ref(I_hash, prio_lo P_loose $4)], snd $1}
| PACKAGE word semi_colon {sp_0_or_cr($1); sp_1($2); Package(fst $2), snd $1}
| BEGIN BRACKET lines BRACKET_END {sp_0_or_cr($1); sp_1($2); sp_p($3); sp_p($4); Sub_declaration(Ident(None, "BEGIN", get_pos $1), "", fst $3), snd $1}
| END BRACKET lines BRACKET_END {sp_0_or_cr($1); sp_1($2); sp_p($3); sp_p($4); Sub_declaration(Ident(None, "END", get_pos $1), "", fst $3), snd $1}
| use {$1}
use:
-| use_word listexpr semi_colon {sp_n($2); Use(fst $1, fst $2), snd $1}
+| use_word listexpr semi_colon {sp_n($2); Use(fst $1, sndfst $2), snd $1}
use_word:
| use_revision word comma {fst $2, snd $1}
@@ -167,146 +167,176 @@ use_revision:
func_decl:
| SUB word {(fst $2, ""), snd $1}
-| FUNC_DECL_WITH_PROTO {(Ident(None, fst(fst $1), get_pos $1), snd(fst $1)), snd $1}
+| FUNC_DECL_WITH_PROTO {(Ident(None, fstfst $1, get_pos $1), sndfst $1), snd $1}
listexpr: /* Basic list expressions */
-| %prec PREC_LOW {[], (Space_none, bpos)}
+| %prec PREC_LOW {(P_tok, []), (Space_none, bpos)}
| argexpr %prec PREC_LOW {$1}
expr: /* Ordinary expressions; logical combinations */
-| expr AND expr {sp_p($2); sp_p($3); Call_op("and", [ fst $1; fst $3 ]), snd $1}
-| expr OR expr {sp_p($2); sp_p($3); Call_op("or", [ fst $1; fst $3 ]), snd $1}
-| argexpr %prec PREC_LOW {List(fst $1), snd $1}
+| expr AND expr {sp_p($2); sp_p($3); (P_and, Call_op("and", [ prio_lo P_and $1; prio_lo_after P_and $3 ])), snd $1}
+| expr OR expr {sp_p($2); sp_p($3); (P_or, Call_op("or", [ prio_lo P_or $1; prio_lo_after P_or $3 ])), snd $1}
+| argexpr %prec PREC_LOW {(fstfst $1, List(sndfst $1)), snd $1}
argexpr: /* Expressions are a list of terms joined by commas */
-| argexpr comma {fst $1, snd $1}
-| argexpr comma term {if not_simple (fst $3) then sp_p($3); fst $1 @ [fst $3], snd $1}
-| argexpr comma BRACKET expr BRACKET_END {sp_p($3); sp_p($5); fst $1 @ [ Ref(I_hash, fst $4) ], snd $1}
-| term %prec PREC_LOW {[fst $1], snd $1}
+| argexpr comma {(P_comma, sndfst $1), snd $1}
+| argexpr comma term {if not_simple (sndfst $3) then sp_p($3); (P_comma, sndfst $1 @ [sndfst $3]), snd $1}
+| argexpr comma BRACKET expr BRACKET_END {sp_p($3); sp_p($5); (P_comma, sndfst $1 @ [ Ref(I_hash, sndfst $4) ]), snd $1}
+| term %prec PREC_LOW {(fstfst $1, [sndfst $1]), snd $1}
/********************************************************************************/
term:
-| term binop term {call_op(fst $2, $3, [fst $1 ; fst $3]), snd $1}
-| term binop BRACKET expr BRACKET_END {sp_p($3); sp_p($4); sp_p($5); call_op(fst $2, $3, [fst $1 ; Ref(I_hash, fst $4)]), snd $1}
-| term LT term {sp_n($2); sp_p($3); Call_op("<", [fst $1 ; fst $3]), snd $1}
-| term GT term {sp_n($2); sp_p($3); Call_op(">", [fst $1 ; fst $3]), snd $1}
+| term ASSIGN term {let pri = P_assign in call_op(op_p pri (fst $2) $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term PLUS term {let pri = P_add in call_op(op pri (fst $2) $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term COMPARE_OP term {let pri = P_cmp in call_op(op_p pri (fst $2) $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term LT term {let pri = P_cmp in call_op(op_p pri "<" $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term GT term {let pri = P_cmp in call_op(op_p pri ">" $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term EQ_OP term {let pri = P_eq in call_op(op_p pri (fst $2) $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term POWER term {let pri = P_tight in call_op(op pri "**" $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term BIT_AND term {let pri = P_expr in call_op(op_p pri "&" $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term BIT_OR term {let pri = P_expr in call_op(op pri "|" $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term BIT_XOR term {let pri = P_expr in call_op(op_p pri "^" $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term AND_TIGHT term {let pri = P_tight_and in call_op(op_p pri "&&" $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term OR_TIGHT term {let pri = P_tight_or in call_op(op_p pri "||" $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term MULT term {let pri = P_mul in call_op(op pri (fst $2) $2, $3, [prio_lo_concat $1; prio_lo_after pri $3]), snd $1}
+| term DOTDOT term {let pri = P_paren_wanted P_expr in call_op(op pri (fst $2) $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term BIT_SHIFT term {let pri = P_paren_wanted P_tight in call_op(op pri (fst $2) $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
+| term XOR term {let pri = P_paren_wanted P_expr in call_op(op_p pri "xor" $2, $3, [prio_lo pri $1; prio_lo_after pri $3]), snd $1}
-| term PATTERN_MATCH PATTERN {sp_n($2); sp_p($3); Call_op("m//", fst $1 :: from_PATTERN $3), snd $1}
-| term PATTERN_MATCH_NOT PATTERN {sp_n($2); sp_p($3); Call_op("!m//", fst $1 :: from_PATTERN $3), snd $1}
-| term PATTERN_MATCH PATTERN_SUBST {sp_n($2); sp_p($3); Call_op("s///", fst $1 :: from_PATTERN_SUBST $3), snd $1}
+| term ASSIGN BRACKET expr BRACKET_END {sp_p($3); sp_p($4); sp_p($5); call_op(op_p P_assign (fst $2) $2, $3, [prio_lo P_assign $1; Ref(I_hash, sndfst $4)]), snd $1}
+| term AND_TIGHT BRACKET expr BRACKET_END {sp_p($3); sp_p($4); sp_p($5); call_op(op_p P_tight_and "&&" $2, $3, [prio_lo P_assign $1; Ref(I_hash, sndfst $4)]), snd $1}
+| term OR_TIGHT BRACKET expr BRACKET_END {sp_p($3); sp_p($4); sp_p($5); call_op(op_p P_tight_or "||" $2, $3, [prio_lo P_assign $1; Ref(I_hash, sndfst $4)]), snd $1}
-| term PATTERN_MATCH scalar { Too_complex, snd $1 }
-| term PATTERN_MATCH_NOT scalar { Too_complex, snd $1 }
-| term PATTERN_MATCH STRING {failwith (msg_with_pos (snd (snd $3)) "use a regexp, not a string")}
-| term PATTERN_MATCH_NOT STRING {failwith (msg_with_pos (snd (snd $3)) "use a regexp, not a string")}
+| term PATTERN_MATCH PATTERN {sp_n($2); sp_p($3); (P_expr, Call_op("m//", sndfst $1 :: from_PATTERN $3)), snd $1}
+| term PATTERN_MATCH_NOT PATTERN {sp_n($2); sp_p($3); (P_expr, Call_op("!m//", sndfst $1 :: from_PATTERN $3)), snd $1}
+| term PATTERN_MATCH PATTERN_SUBST {sp_n($2); sp_p($3); (P_expr, Call_op("s///", sndfst $1 :: from_PATTERN_SUBST $3)), snd $1}
+
+| term PATTERN_MATCH scalar { (P_expr, Too_complex), snd $1 }
+| term PATTERN_MATCH_NOT scalar { (P_expr, Too_complex), snd $1 }
+
+| term PATTERN_MATCH STRING {failwith (msg_with_pos (sndsnd $3) "use a regexp, not a string")}
+| term PATTERN_MATCH_NOT STRING {failwith (msg_with_pos (sndsnd $3) "use a regexp, not a string")}
+
+
+| term QUESTION_MARK term COLON term {sp_n($2); sp_p($3); sp_p($4); sp_p($5); (P_ternary, Call_op("?:", [ prio_lo P_ternary $1 ; prio_lo_after P_ternary $3; prio_lo_after P_ternary $5])), snd $1}
+| term QUESTION_MARK term COLON BRACKET expr BRACKET_END {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($6); sp_p($7); (P_ternary, Call_op("?:", [ prio_lo P_ternary $1 ; prio_lo_after P_ternary $3; sndfst $6])), snd $1}
+| term QUESTION_MARK BRACKET expr BRACKET_END COLON term {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($6); sp_p($7); (P_ternary, Call_op("?:", [ prio_lo P_ternary $1 ; sndfst $4; prio_lo_after P_ternary $7])), snd $1}
+| term QUESTION_MARK BRACKET expr BRACKET_END COLON BRACKET expr BRACKET_END {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($6); sp_p($7); sp_p($8); sp_p($9); (P_ternary, Call_op("?:", [ prio_lo P_ternary $1 ; sndfst $4; sndfst $8])), snd $1}
+
/* Unary operators and terms */
-| MINUS term %prec UNARY_MINUS {sp_0($2); Call_op("- unary", [fst $2]), snd $1}
-| TIGHT_NOT term {Call_op("not", [fst $2]), snd $1}
-| BIT_NEG term {Call_op("~", [fst $2]), snd $1}
-| INCR term {sp_0($2); Call_op("++", [fst $2]), snd $1}
-| DECR term {sp_0($2); Call_op("--", [fst $2]), snd $1}
-| term INCR {sp_0($2); Call_op("++ post", [fst $1]), snd $1}
-| term DECR {sp_0($2); Call_op("-- post", [fst $1]), snd $1}
+| PLUS term %prec UNARY_MINUS {if fst $1 <> "-" then die_rule "syntax error"; sp_0($2); (P_tight, Call_op("- unary", [sndfst $2])), snd $1}
+| TIGHT_NOT term {(P_tight, Call_op("not", [sndfst $2])), snd $1}
+| BIT_NEG term {(P_expr, Call_op("~", [sndfst $2])), snd $1}
+| INCR term {sp_0($2); (P_tight, Call_op("++", [sndfst $2])), snd $1}
+| DECR term {sp_0($2); (P_tight, Call_op("--", [sndfst $2])), snd $1}
+| term INCR {sp_0($2); (P_tight, Call_op("++ post", [sndfst $1])), snd $1}
+| term DECR {sp_0($2); (P_tight, Call_op("-- post", [sndfst $1])), snd $1}
+
+| DEFINED scalar {(P_expr, Call(Ident(None, "defined", get_pos $1), [fst $2])), snd $1}
+| DEFINED subscripted {(P_expr, Call(Ident(None, "defined", get_pos $1), [fst $2])), snd $1}
+| DEFINED parenthesized {(P_expr, Call(Ident(None, "defined", get_pos $1), sndfst $2)), snd $1}
+| DEFINED word_paren parenthesized {(P_expr, Call(Ident(None, "defined", get_pos $1), [Call(fst $2, sndfst $3)])), snd $1}
-| NOT argexpr {Call_op("not", fst $2), snd $1}
+| NOT argexpr {(P_and, Call_op("not", sndfst $2)), snd $1}
/* Constructors for anonymous data */
-| ARRAYREF ARRAYREF_END {sp_0($2); Ref(I_array, List[]), snd $1}
-| arrayref_start ARRAYREF_END {Ref(I_array, List(fst $1)), snd $1}
-| arrayref_start expr ARRAYREF_END {Ref(I_array, List(fst $1 @ [fst $2])), snd $1}
-| arrayref_start BRACKET expr BRACKET_END ARRAYREF_END {Ref(I_array, List(fst $1 @ [Ref(I_hash, fst $3)])), snd $1}
+| ARRAYREF ARRAYREF_END {sp_0($2); (P_expr, Ref(I_array, List[])), snd $1}
+| arrayref_start ARRAYREF_END {(P_expr, Ref(I_array, List(fst $1))), snd $1}
+| arrayref_start expr ARRAYREF_END {(P_expr, Ref(I_array, List(fst $1 @ [sndfst $2]))), snd $1}
+| arrayref_start BRACKET expr BRACKET_END ARRAYREF_END {(P_expr, Ref(I_array, List(fst $1 @ [Ref(I_hash, sndfst $3)]))), snd $1}
-| BRACKET BRACKET_END {Ref(I_hash, List []), snd $1} /* empty hash */
-| BRACKET_HASHREF expr BRACKET_END %prec PREC_HIGH {sp_p($3); Ref(I_hash, fst $2), snd $1} /* { foo => "Bar" } */
-| SUB BRACKET BRACKET_END %prec PREC_HIGH {sp_n($2); sp_0($3); Anonymous_sub(Block[]), snd $1}
-| SUB BRACKET lines BRACKET_END %prec PREC_HIGH {sp_n($2); check_lines_after_BRACKET($3); sp_p($4); Anonymous_sub(Block(fst $3)), snd $1}
+| BRACKET BRACKET_END {(P_expr, Ref(I_hash, List [])), snd $1} /* empty hash */
+| BRACKET_HASHREF expr BRACKET_END %prec PREC_HIGH {sp_p($3); (P_expr, Ref(I_hash, sndfst $2)), snd $1} /* { foo => "Bar" } */
+| SUB BRACKET BRACKET_END %prec PREC_HIGH {sp_n($2); sp_0($3); (P_expr, Anonymous_sub(Block[])), snd $1}
+| SUB BRACKET lines BRACKET_END %prec PREC_HIGH {sp_n($2); check_lines_after_BRACKET($3); sp_p($4); (P_expr, Anonymous_sub(Block(fst $3))), snd $1}
-| termdo {$1}
-| term question_mark_ colon_ { Call_op("?:", [ fst $1 ; fst $2; fst $3]), snd $1}
-| REF term { Ref(I_scalar, fst $2), snd $1} /* \$x, \@y, \%z */
-| my %prec UNIOP {List(fst $1), snd $1}
-| LOCAL term %prec UNIOP {sp_n($2); Local(fst $2), snd $1}
+| termdo {(P_tok, fst $1), snd $1}
+| REF term {(P_expr, Ref(I_scalar, sndfst $2)), snd $1} /* \$x, \@y, \%z */
+| my %prec UNIOP {(P_expr, List(fst $1)), snd $1}
+| LOCAL term %prec UNIOP {sp_n($2); (P_expr, Local(sndfst $2)), snd $1}
-| parenthesized {List(fst $1), snd $1} /* (1, 2) */
-| parenthesized arrayref {sp_0($2); Deref_with(I_array, List(fst $1), List(fst $2)), snd $1} /* list slice */
+| parenthesized {(fstfst $1, List(sndfst $1)), snd $1} /* (1, 2) */
+| parenthesized arrayref {sp_0($2); (P_tok, Deref_with(I_array, List(sndfst $1), List(fst $2))), snd $1} /* list slice */
-| variable {$1}
+| variable {(P_tok, fst $1), snd $1}
-| subscripted {$1}
+| subscripted {(P_tok, fst $1), snd $1}
-| array arrayref { Deref_with(I_array, fst $1, List(fst $2)), snd $1} /* array slice: @array[vals] */
-| array BRACKET expr BRACKET_END {sp_0($2); sp_0($3); sp_0($4); Deref_with(I_hash, array_ident_to_hash_ident $1, fst $3), snd $1} /* hash slice: @hash{@keys} */
+| array arrayref {(P_expr, Deref_with(I_array, fst $1, List(fst $2))), snd $1} /* array slice: @array[vals] */
+| array BRACKET expr BRACKET_END {sp_0($2); sp_0($3); sp_0($4); (P_expr, Deref_with(I_hash, array_ident_to_hash_ident $1, sndfst $3)), snd $1} /* hash slice: @hash{@keys} */
/* function_calls */
-| func parenthesized {sp_0($2); Call(fst $1, fst $2), snd $1} /* &foo(@args) */
-| word argexpr {check_parenthesized_first_argexpr (string_of_Ident (fst $1)) $2; Call(fst $1, fst $2), snd $1} /* foo $a, $b */
-| word_paren parenthesized {Call(fst $1, fst $2), snd $1} /* foo(@args) */
-| word BRACKET lines BRACKET_END listexpr %prec LSTOP {sp_n($2); check_lines_after_BRACKET($3); sp_p($4); Call(fst $1, Anonymous_sub(Block(fst $3)) :: fst $5), snd $1} /* map { foo } @bar */
-| word BRACKET BRACKET expr BRACKET_END BRACKET_END listexpr %prec LSTOP {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($6); Call(fst $1, Anonymous_sub(Ref(I_hash, fst $4)) :: fst $7), snd $1} /* map { { foo } } @bar */
-| word BRACKET BRACKET expr BRACKET_END semi_colon BRACKET_END listexpr %prec LSTOP {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($7); Call(fst $1, Anonymous_sub(Ref(I_hash, fst $4)) :: fst $8), snd $1} /* map { { foo }; } @bar */
-
-| term ARROW word_or_scalar parenthesized {sp_0($2); sp_0($3); sp_0($4); Method_call(fst $1, fst $3, fst $4), snd $1} /* $foo->bar(list) */
-| term ARROW word_or_scalar {sp_0($2); sp_0($3); Method_call(fst $1, fst $3, []), snd $1} /* $foo->bar */
-
-| NEW word listexpr { Method_call(fst $2, Ident(None, "new", get_pos $1), fst $3), snd $1} /* new Class @args */
-
-| PRINT { Call_op("print", var_STDOUT :: [ var_dollar_ ]), snd $1 }
-| PRINT argexpr {check_parenthesized_first_argexpr (fst $1) $2; Call_op("print", var_STDOUT :: fst $2), snd $1 }
-| PRINT_TO_STAR { Call_op("print", Deref(I_star, Ident(None, fst $1, get_pos $1)) :: [ var_dollar_ ]), snd $1 }
-| PRINT_TO_STAR argexpr { Call_op("print", Deref(I_star, Ident(None, fst $1, get_pos $1)) :: fst $2), snd $1 }
-| PRINT_TO_SCALAR { Call_op("print", var_STDOUT :: [ Deref(I_scalar, Ident(None, fst $1, get_pos $1)) ]), snd $1 }
-| PRINT_TO_SCALAR argexpr { Call_op("print", Deref(I_scalar, Ident(None, fst $1, get_pos $1)) :: fst $2), snd $1 }
-
-| word {check_word_alone $1, snd $1}
-
-| NUM {Num(fst $1, get_pos $1), snd $1}
-| STRING {to_String $1, snd $1}
-| REVISION {to_String $1, snd $1}
-| COMMAND_STRING {Call_op("``", [to_String $1]), snd $1}
-| QUOTEWORDS {Call_op("qw", [to_String $1]), snd $1}
-| HERE_DOC {String(fst!(fst $1), get_pos $1), snd $1}
-| PATTERN {Call_op("m//", var_dollar_ :: from_PATTERN $1), snd $1}
-| PATTERN_SUBST {Call_op("s///", var_dollar_ :: from_PATTERN_SUBST $1), snd $1}
-| diamond {$1}
+| func parenthesized {sp_0($2); (P_tok, call(fst $1, sndfst $2)), snd $1} /* &foo(@args) */
+| word argexpr {check_parenthesized_first_argexpr (string_of_Ident (fst $1)) $2; (P_call_no_paren, call(fst $1, sndfst $2)), snd $1} /* foo $a, $b */
+| word_paren parenthesized {(P_tok, call(fst $1, sndfst $2)), snd $1} /* foo(@args) */
+| word BRACKET lines BRACKET_END listexpr %prec LSTOP {sp_n($2); check_lines_after_BRACKET($3); sp_p($4); ((if sndfst $5 = [] then P_tok else P_call_no_paren), call(fst $1, Anonymous_sub(Block(fst $3)) :: sndfst $5)), snd $1} /* map { foo } @bar */
+| word BRACKET BRACKET expr BRACKET_END BRACKET_END listexpr %prec LSTOP {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($6); ((if sndfst $7 = [] then P_tok else P_call_no_paren), call(fst $1, Anonymous_sub(Ref(I_hash, sndfst $4)) :: sndfst $7)), snd $1} /* map { { foo } } @bar */
+| word BRACKET BRACKET expr BRACKET_END semi_colon BRACKET_END listexpr %prec LSTOP {sp_n($2); sp_p($3); sp_p($4); sp_p($5); sp_p($7); ((if sndfst $8 = [] then P_tok else P_call_no_paren), call(fst $1, Anonymous_sub(Ref(I_hash, sndfst $4)) :: sndfst $8)), snd $1} /* map { { foo }; } @bar */
+
+| term ARROW word_or_scalar parenthesized {sp_0($2); sp_0($3); sp_0($4); (P_tok, Method_callP(sndfst $1, fst $3, sndfst $4)), snd $1} /* $foo->bar(list) */
+| term ARROW word_or_scalar {sp_0($2); sp_0($3); (P_tok, Method_callP(sndfst $1, fst $3, [])), snd $1} /* $foo->bar */
+
+| NEW word listexpr { (P_call_no_paren, Method_call(fst $2, Ident(None, "new", get_pos $1), sndfst $3)), snd $1} /* new Class @args */
+
+| PRINT { (P_call_no_paren, Call_op("print", var_STDOUT :: [ var_dollar_ ])), snd $1 }
+| PRINT argexpr {check_parenthesized_first_argexpr (fst $1) $2; (P_call_no_paren, Call_op("print", var_STDOUT :: sndfst $2)), snd $1 }
+| PRINT_TO_STAR { (P_call_no_paren, Call_op("print", Deref(I_star, Ident(None, fst $1, get_pos $1)) :: [ var_dollar_ ])), snd $1 }
+| PRINT_TO_STAR argexpr { (P_call_no_paren, Call_op("print", Deref(I_star, Ident(None, fst $1, get_pos $1)) :: sndfst $2)), snd $1 }
+| PRINT_TO_SCALAR { (P_call_no_paren, Call_op("print", var_STDOUT :: [ Deref(I_scalar, Ident(None, fst $1, get_pos $1)) ])), snd $1 }
+| PRINT_TO_SCALAR argexpr { (P_call_no_paren, Call_op("print", Deref(I_scalar, Ident(None, fst $1, get_pos $1)) :: sndfst $2)), snd $1 }
+
+| hash PKG_SCOPE {sp_0($2); (P_tok, Too_complex), snd $1}
+
+| word {(P_tok, check_word_alone $1), snd $1}
+
+| NUM {(P_tok, Num(fst $1, get_pos $1)), snd $1}
+| STRING {(P_tok, to_String $1), snd $1}
+| REVISION {(P_tok, to_String $1), snd $1}
+| COMMAND_STRING {(P_expr, Call_op("``", [to_String $1])), snd $1}
+| QUOTEWORDS {(P_tok, Call_op("qw", [to_String $1])), snd $1}
+| HERE_DOC {(P_tok, String(fst!(fst $1), get_pos $1)), snd $1}
+| PATTERN {(P_expr, Call_op("m//", var_dollar_ :: from_PATTERN $1)), snd $1}
+| PATTERN_SUBST {(P_expr, Call_op("s///", var_dollar_ :: from_PATTERN_SUBST $1)), snd $1}
+| diamond {(P_expr, fst $1), snd $1}
diamond:
| LT GT {sp_0($2); Call_op("<>", []), snd $1}
-| LT term GT {sp_0($2); sp_0($3); Call_op("<>", [fst $2]), snd $1}
+| LT term GT {sp_0($2); sp_0($3); Call_op("<>", [sndfst $2]), snd $1}
subscripted: /* Some kind of subscripted expression */
| variable PKG_SCOPE bracket_subscript {sp_0($2); sp_0($3); Too_complex, snd $1} /* $foo::{something} */
| scalar bracket_subscript {sp_0($2); Deref_with(I_hash , fst $1, fst $2), snd $1} /* $foo{bar} */
| scalar arrayref {sp_0($2); Deref_with(I_array, fst $1, only_one $2), snd $1} /* $array[$element] */
-| term ARROW bracket_subscript {sp_0($2); sp_0($3); Deref_with(I_hash , fst $1, fst $3), snd $1} /* somehref->{bar} */
-| term ARROW arrayref {sp_0($2); sp_0($3); Deref_with(I_array, fst $1, only_one $3), snd $1} /* somearef->[$element] */
-| term ARROW parenthesized {sp_0($2); sp_0($3); Deref_with(I_func , fst $1, List(fst $3)), snd $1} /* $subref->(@args) */
+| term ARROW bracket_subscript {sp_0($2); sp_0($3); Deref_with(I_hash , sndfst $1, fst $3), snd $1} /* somehref->{bar} */
+| term ARROW arrayref {sp_0($2); sp_0($3); Deref_with(I_array, sndfst $1, only_one $3), snd $1} /* somearef->[$element] */
+| term ARROW parenthesized {sp_0($2); sp_0($3); Deref_with(I_func , sndfst $1, List(sndfst $3)), snd $1} /* $subref->(@args) */
| subscripted bracket_subscript {sp_0($2); Deref_with(I_hash , fst $1, fst $2), snd $1} /* $foo->[bar]{baz} */
| subscripted arrayref {sp_0($2); Deref_with(I_array, fst $1, only_one $2), snd $1} /* $foo->[$bar][$baz] */
-| subscripted parenthesized {sp_0($2); Deref_with(I_func , fst $1, List(fst $2)), snd $1} /* $foo->{bar}(@args) */
+| subscripted parenthesized {sp_0($2); Deref_with(I_func , fst $1, List(sndfst $2)), snd $1} /* $foo->{bar}(@args) */
arrayref:
| arrayref_start ARRAYREF_END {sp_0($2); fst $1, snd $1}
-| arrayref_start expr ARRAYREF_END {sp_0($3); fst $1 @ [fst $2], snd $1}
-| arrayref_start BRACKET expr BRACKET_END ARRAYREF_END {sp_p($2); sp_p($4); sp_0($5); fst $1 @ [Ref(I_hash, fst $3)], snd $1}
+| arrayref_start expr ARRAYREF_END {sp_0($3); fst $1 @ [sndfst $2], snd $1}
+| arrayref_start BRACKET expr BRACKET_END ARRAYREF_END {sp_p($2); sp_p($4); sp_0($5); fst $1 @ [Ref(I_hash, sndfst $3)], snd $1}
parenthesized:
-| parenthesized_start PAREN_END {sp_0_or_cr($2); fst $1, snd $1}
-| parenthesized_start expr PAREN_END {sp_0_or_cr($3); fst $1 @ [fst $2], snd $1}
-| parenthesized_start BRACKET expr BRACKET_END PAREN_END {sp_p($4); sp_0_or_cr($5); fst $1 @ [Ref(I_hash, fst $3)], snd $1}
+| parenthesized_start PAREN_END {sp_0_or_cr($2); ((if fst $1 = [] then P_tok else P_paren P_comma), fst $1), snd $1}
+| parenthesized_start expr PAREN_END {sp_0_or_cr($3); (P_paren(if fst $1 = [] then fstfst $2 else P_comma), fst $1 @ [sndfst $2]), snd $1}
+| parenthesized_start BRACKET expr BRACKET_END PAREN_END {sp_p($4); sp_0_or_cr($5); (P_paren(if fst $1 = [] then P_expr else P_comma), fst $1 @ [Ref(I_hash, sndfst $3)]), snd $1}
arrayref_start:
| ARRAYREF {[], snd $1}
-| arrayref_start BRACKET expr BRACKET_END comma {sp_p($2); sp_p($3); sp_p($4); fst $1 @ [Ref(I_hash, fst $3)], snd $1}
+| arrayref_start BRACKET expr BRACKET_END comma {sp_p($2); sp_p($3); sp_p($4); fst $1 @ [Ref(I_hash, sndfst $3)], snd $1}
parenthesized_start:
| PAREN {[], snd $1}
-| parenthesized_start BRACKET expr BRACKET_END comma {(if fst $1 = [] then sp_0_or_cr else sp_p)($2); sp_p($3); sp_p($4); fst $1 @ [Ref(I_hash, fst $3)], snd $1}
+| parenthesized_start BRACKET expr BRACKET_END comma {(if fst $1 = [] then sp_0_or_cr else sp_p)($2); sp_p($3); sp_p($4); fst $1 @ [Ref(I_hash, sndfst $3)], snd $1}
my: /* Things that can be "my"'d */
-| MY parenthesized {List.map (fun e -> My e) (fst $2), snd $1}
+| MY parenthesized {List.map (fun e -> My e) (sndfst $2), snd $1}
| MY scalar {[My(fst $2)], snd $1}
| MY hash {[My(fst $2)], snd $1}
| MY array {[My(fst $2)], snd $1}
@@ -315,31 +345,10 @@ termdo: /* Things called with "do" */
| DO term %prec UNIOP { die_rule "\"do EXPR\" not allowed" } /* do $filename */
| DO BRACKET lines BRACKET_END %prec PREC_HIGH {sp_n($2); check_lines_after_BRACKET($3); sp_p($4); Block(fst $3), snd $1} /* do { code */
-question_mark_:
-| QUESTION_MARK term {sp_n($1); fst $2, snd $1}
-| QUESTION_MARK BRACKET expr BRACKET_END {sp_n($1); sp_p($2); sp_p($4); Ref(I_hash, fst $3), snd $1}
-colon_:
-| COLON term {sp_p($1); fst $2, snd $1}
-| COLON BRACKET expr BRACKET_END {sp_p($1); sp_p($2); sp_p($3); sp_p($4); Ref(I_hash, fst $3), snd $1}
-
bracket_subscript:
| BRACKET expr BRACKET_END {sp_0($1); sp_0($2); sp_0($3); only_one_in_List $2, snd $1}
| COMPACT_HASH_SUBSCRIPT {sp_0($1); to_String $1, snd $1}
-binop:
-| ASSIGN {op_p "=" $1, snd $1}
-| POWER {op "**" $1, snd $1}
-| MULT {op "*" $1, snd $1} | DIVISION {op "/" $1, snd $1} | MODULO {op "%" $1, snd $1} | REPLICATE {op_p "x" $1, snd $1}
-| PLUS {op "+" $1, snd $1} | MINUS {op "-" $1, snd $1} | CONCAT {op "." $1, snd $1}
-| BIT_SHIFT_LEFT {op "<<" $1, snd $1} | BIT_SHIFT_RIGHT {op ">>" $1, snd $1}
-| COMPARE_OP {op_p (fst $1) $1, snd $1}
-| EQ_OP {op_p (fst $1) $1, snd $1}
-| BIT_AND {op_p "&" $1, snd $1}
-| BIT_OR {op "|" $1, snd $1} | BIT_XOR {op_p "^" $1, snd $1}
-| DOTDOT {op ".." $1, snd $1} | DOTDOTDOT {op_p "..." $1, snd $1}
-| AND_TIGHT {op_p "&&" $1, snd $1}
-| OR_TIGHT {op_p "||" $1, snd $1} | XOR {op_p "xor" $1, snd $1}
-
variable:
| scalar %prec PREC_HIGH {$1}
| star %prec PREC_HIGH {$1}
@@ -371,10 +380,10 @@ word_paren:
| RAW_IDENT_PAREN { to_Ident $1, snd $1 }
arraylen: ARRAYLEN_IDENT {Deref(I_arraylen, to_Ident $1), snd $1} | ARRAYLEN scalar {sp_0($2); Deref(I_arraylen, fst $2), snd $1} | ARRAYLEN BRACKET lines BRACKET_END {sp_0($2); sp_same $3 $4; Deref(I_arraylen, Block(fst $3)), snd $1}
-scalar: SCALAR_IDENT {Deref(I_scalar , to_Ident $1), snd $1} | DOLLAR scalar {sp_0($2); Deref(I_scalar , fst $2), snd $1} | DOLLAR BRACKET lines BRACKET_END {sp_0($2); sp_same $3 $4; Deref(I_scalar , Block(fst $3)), snd $1} | DOLLAR BRACKET BRACKET expr BRACKET_END BRACKET_END {sp_0($2); sp_0($3); sp_p($5); sp_0($6); Deref(I_scalar, Ref(I_hash, fst $4)), snd $1}
+scalar: SCALAR_IDENT {Deref(I_scalar , to_Ident $1), snd $1} | DOLLAR scalar {sp_0($2); Deref(I_scalar , fst $2), snd $1} | DOLLAR BRACKET lines BRACKET_END {sp_0($2); sp_same $3 $4; Deref(I_scalar , Block(fst $3)), snd $1} | DOLLAR BRACKET BRACKET expr BRACKET_END BRACKET_END {sp_0($2); sp_0($3); sp_p($5); sp_0($6); Deref(I_scalar, Ref(I_hash, sndfst $4)), snd $1}
func: FUNC_IDENT {Deref(I_func , to_Ident $1), snd $1} | AMPERSAND scalar {sp_0($2); Deref(I_func , fst $2), snd $1} | AMPERSAND BRACKET lines BRACKET_END {sp_0($2); sp_same $3 $4; Deref(I_func , Block(fst $3)), snd $1}
array: ARRAY_IDENT {Deref(I_array , to_Ident $1), snd $1} | AT scalar {sp_0($2); Deref(I_array , fst $2), snd $1} | AT BRACKET lines BRACKET_END {sp_0($2); sp_same $3 $4; Deref(I_array , Block(fst $3)), snd $1}
hash: HASH_IDENT {Deref(I_hash , to_Ident $1), snd $1} | PERCENT scalar {sp_0($2); Deref(I_hash , fst $2), snd $1} | PERCENT BRACKET lines BRACKET_END {sp_0($2); sp_same $3 $4; Deref(I_hash , Block(fst $3)), snd $1}
star: STAR_IDENT {Deref(I_star , to_Ident $1), snd $1} | STAR scalar {sp_0($2); Deref(I_star , fst $2), snd $1} | STAR BRACKET lines BRACKET_END {sp_0($2); sp_same $3 $4; Deref(I_star , Block(fst $3)), snd $1}
-expr_or_empty: {Block [], (Space_none, bpos)} | expr {$1}
+expr_or_empty: {Block [], (Space_none, bpos)} | expr {sndfst $1, snd $1}