Commit 6e38883c authored by POTTIER Francois's avatar POTTIER Francois

Fix my bug in [rename], where I forgot to add [x] to the set [used].

Fix another bug in [Action.rename], where a cascade of [let/in] was
used instead of a single [let/and], causing a capture.
Introduce a better renaming convention, using a suffix _inlined['0'-'9']+
instead of accumulating "'" suffixes.
parent 5718f2ea
...@@ -144,9 +144,11 @@ let rename f phi a = ...@@ -144,9 +144,11 @@ let rename f phi a =
let phi = !phi in let phi = !phi in
(* Construct a new semantic action, where [phi] is translated into (* Construct a new semantic action, where [phi] is translated into
a series of [let] bindings. *) a set of *simultaneous* [let] bindings. (We cannot use a series
of nested [let] bindings, as that would cause a capture if the
domain and codomain of [phi] have a nonempty intersection.) *)
let phi = List.map (fun (x, y) -> IL.PVar x, IL.EVar y) phi in let phi = List.map (fun (x, y) -> IL.PVar x, IL.EVar y) phi in
let expr = CodeBits.blet (phi, a.expr) in let expr = CodeBits.eletand (phi, a.expr) in
{ {
expr = expr; expr = expr;
......
(******************************************************************************)
(* *)
(* Menhir *)
(* *)
(* François Pottier, Inria Paris *)
(* Yann Régis-Gianas, PPS, Université Paris Diderot *)
(* *)
(* Copyright Inria. All rights reserved. This file is distributed under the *)
(* terms of the GNU General Public License version 2, as described in the *)
(* file LICENSE. *)
(* *)
(******************************************************************************)
(* Chopping [_inlined] off a name, if there is one,
and returning the numeric suffix that follows, if there is one. *)
rule chop = parse
| (_* as x) "_inlined" (['0'-'9']+ as n) eof
{ x, int_of_string n }
| (_* as x) "_inlined" eof
{ x, 0 }
| (_* as x) eof
{ x, 0 }
...@@ -164,14 +164,18 @@ let mlet formals actuals body = ...@@ -164,14 +164,18 @@ let mlet formals actuals body =
(* Simulating a [let/and] construct using tuples. *) (* Simulating a [let/and] construct using tuples. *)
let eletand (bindings, body) = let eletand (bindings, body) =
match bindings with let bindings = simplify bindings in
| [] -> match bindings, body with
| [], _ ->
(* special case: zero bindings *) (* special case: zero bindings *)
body body
| [ _ ] -> | [ PVar x1, e ], EVar x2 when x1 = x2 ->
(* Reduce [let x = e in x] to just [e]. *)
e
| [ _ ], _ ->
(* special case: one binding *) (* special case: one binding *)
ELet (bindings, body) ELet (bindings, body)
| _ :: _ :: _ -> | _ :: _ :: _, _ ->
(* general case: at least two bindings *) (* general case: at least two bindings *)
let pats, exprs = List.split bindings in let pats, exprs = List.split bindings in
ELet ([ PTuple pats, ETuple exprs ], body) ELet ([ PTuple pats, ETuple exprs ], body)
......
...@@ -57,7 +57,8 @@ val type2scheme: typ -> typescheme ...@@ -57,7 +57,8 @@ val type2scheme: typ -> typescheme
val pat2var: pattern -> string val pat2var: pattern -> string
(* Building a [let] construct, with on-the-fly simplification. *) (* Building a [let] construct, with on-the-fly simplification. These two
functions construct a nested sequence of [let] definitions. *)
val blet: (pattern * expr) list * expr -> expr val blet: (pattern * expr) list * expr -> expr
val mlet: pattern list -> expr list -> expr -> expr val mlet: pattern list -> expr list -> expr -> expr
......
...@@ -97,20 +97,29 @@ let names (producers : producers) : StringSet.t = ...@@ -97,20 +97,29 @@ let names (producers : producers) : StringSet.t =
StringSet.add id ids StringSet.add id ids
) StringSet.empty producers ) StringSet.empty producers
(* [fresh names x] returns a fresh name that is not in the set [names].
The new name is based on [x] in an unspecified way. *)
let rec fresh names x =
if StringSet.mem x names then
let x =
(* Propose a new candidate name. A fairly arbitrary construction
can be used here; we just need it to produce an infinite sequence
of names, so that eventually we fall outside of [names]. We also
need it to produce reasonably concise names, as this construction
can be iterated several times in practice; I have observed up to
9 iterations in real-world grammars. *)
let x, n = ChopInlined.chop (Lexing.from_string x) in
let n = n + 1 in
Printf.sprintf "%s_inlined%d" x n
in
fresh names x
else
x
(* Inline a grammar. The resulting grammar does not contain any definitions (* Inline a grammar. The resulting grammar does not contain any definitions
that can be inlined. *) that can be inlined. *)
let inline grammar = let inline grammar =
(* This function returns a fresh name that begins with [prefix] (although
this is not essential!) and that is not in the set [names]. *)
let rec fresh names prefix =
if StringSet.mem prefix names then
let prefix = prefix ^ "'" in
fresh names prefix
else
prefix
in
(* This table associates a color to each non terminal that can be expanded. *) (* This table associates a color to each non terminal that can be expanded. *)
let expanded_non_terminals = let expanded_non_terminals =
Hashtbl.create 13 Hashtbl.create 13
...@@ -162,11 +171,14 @@ let inline grammar = ...@@ -162,11 +171,14 @@ let inline grammar =
prefix, expand_rule nt p, nt, psym, suffix prefix, expand_rule nt p, nt, psym, suffix
(* We have to rename the producers [producers] of the inlined production (* We have to rename the producers [producers] of the inlined production
if they clash with the names of the producers of the host branch [b]. *) if they clash with the set [used] of the names used by the producers
and rename_if_necessary b producers = of the host branch. (Note that [used] need not contain the name of the
producer that is inlined away.)
(* Compute the set of the names already in use in the host branch. *) This function produces a pair of:
let used = names b.producers in 1. a substitution [phi], which represents the renaming that we have
performed, and which must be applied to the inner semantic action;
2. the renamed [producers]. *)
and rename (used : StringSet.t) producers: Action.subst * producers =
(* Compute a renaming and the new names of the inlined producers. *) (* Compute a renaming and the new names of the inlined producers. *)
let phi, _used, producers' = let phi, _used, producers' =
...@@ -178,7 +190,7 @@ let inline grammar = ...@@ -178,7 +190,7 @@ let inline grammar =
StringSet.add x' used, StringSet.add x' used,
{ producer with producer_identifier = x' } :: producers { producer with producer_identifier = x' } :: producers
else else
(phi, used, producer :: producers) (phi, StringSet.add x used, producer :: producers)
) ([], used, []) producers ) ([], used, []) producers
in in
phi, List.rev producers' phi, List.rev producers'
...@@ -189,7 +201,9 @@ let inline grammar = ...@@ -189,7 +201,9 @@ let inline grammar =
try try
(* [c] is the identifier under which the callee is known. *) (* [c] is the identifier under which the callee is known. *)
let prefix, p, nt, c, suffix = find_inline_producer b in let prefix, p, nt, c, suffix = find_inline_producer b in
(* use_inline := true; *) (* These are the names of the producers in the host branch,
minus the producer that is being inlined away. *)
let used = StringSet.union (names prefix) (names suffix) in
(* Inline a branch of [nt] at position [prefix] ... [suffix] in (* Inline a branch of [nt] at position [prefix] ... [suffix] in
the branch [b]. *) the branch [b]. *)
let inline_branch (pb : branch) : branch = let inline_branch (pb : branch) : branch =
...@@ -221,11 +235,11 @@ let inline grammar = ...@@ -221,11 +235,11 @@ let inline grammar =
(* Rename the producers of this branch if they conflict with (* Rename the producers of this branch if they conflict with
the name of the host's producers. *) the name of the host's producers. *)
let phi, inlined_producers = rename_if_necessary b pb.producers in let phi, inlined_producers = rename used pb.producers in
(* After inlining, the producers are as follows. *) (* After inlining, the producers are as follows. *)
let producers = prefix @ inlined_producers @ suffix in let producers = prefix @ inlined_producers @ suffix in
(* For debugging: check each producer carries a unique name. *) (* For debugging: check that each producer carries a unique name. *)
let (_ : StringSet.t) = names producers in let (_ : StringSet.t) = names producers in
let index2id = index2id producers in let index2id = index2id producers in
......
...@@ -16,27 +16,21 @@ bar: ...@@ -16,27 +16,21 @@ bar:
{ ( 2 )} { ( 2 )}
phrase: phrase:
x' = foo x'' = foo _3 = EOF x = foo x_inlined1 = foo _3 = EOF
{let t = {let t =
let x' = x'' in let x = x_inlined1 in
let x = let x = ( x ) in
let x = x' in
( x )
in
( x ) ( x )
in in
let y = let y =
let x = let x =
let x = let x = ( x ) in
let x = x' in
( x )
in
( x ) ( x )
in in
( x ) ( x )
in in
( y + t )} ( y + t )}
| x' = foo z = bar _3 = EOF | x = foo z = bar _3 = EOF
{let t = {let t =
let x = let x =
let _1 = let _1 =
...@@ -49,21 +43,15 @@ in ...@@ -49,21 +43,15 @@ in
in in
let y = let y =
let x = let x =
let x = let x = ( x ) in
let x = x' in
( x )
in
( x ) ( x )
in in
( x ) ( x )
in in
( y + t )} ( y + t )}
| z = bar x' = foo _3 = EOF | z = bar x = foo _3 = EOF
{let t = {let t =
let x = let x = ( x ) in
let x = x' in
( x )
in
( x ) ( x )
in in
let y = let y =
...@@ -74,9 +62,9 @@ let y = ...@@ -74,9 +62,9 @@ let y =
( x ) ( x )
in in
( y + t )} ( y + t )}
| z = bar z' = bar _3 = EOF | z = bar z_inlined1 = bar _3 = EOF
{let t = {let t =
let z = z' in let z = z_inlined1 in
let x = let x =
let _1 = let _1 =
let x = ( z ) in let x = ( z ) in
......
...@@ -21,21 +21,17 @@ midrule___anonymous_1_: ...@@ -21,21 +21,17 @@ midrule___anonymous_1_:
list___anonymous_0_A_B__: list___anonymous_0_A_B__:
{ ( [] )} { ( [] )}
| x' = A xs = list___anonymous_0_A_B__ | x = A xs = list___anonymous_0_A_B__
{let x = {let x = ( Left x ) in
let x = x' in
( Left x )
in
( x :: xs )} ( x :: xs )}
| y = B xs = list___anonymous_0_A_B__ | y = B xs = list___anonymous_0_A_B__
{let x = ( Right y ) in {let x = ( Right y ) in
( x :: xs )} ( x :: xs )}
phrase: phrase:
_1 = C _2 = list___anonymous_0_A_B__ _1' = D _2' = list___anonymous_0_A_B__ _3 = EOF _1 = C _2 = list___anonymous_0_A_B__ _1_inlined1 = D _2_inlined1 = list___anonymous_0_A_B__ _3 = EOF
{let ys = {let ys =
let _2 = _2' in let (_2, _1) = (_2_inlined1, _1_inlined1) in
let _1 = _1' in
( _1 ) ( _1 )
in in
let xs = ( _1 ) in let xs = ( _1 ) in
......
...@@ -11,11 +11,8 @@ ...@@ -11,11 +11,8 @@
list___anonymous_0_A_B__: list___anonymous_0_A_B__:
{ ( [] )} { ( [] )}
| x' = A xs = list___anonymous_0_A_B__ | x = A xs = list___anonymous_0_A_B__
{let x = {let x = ( Left x ) in
let x = x' in
( Left x )
in
( x :: xs )} ( x :: xs )}
| y = B xs = list___anonymous_0_A_B__ | y = B xs = list___anonymous_0_A_B__
{let x = ( Right y ) in {let x = ( Right y ) in
...@@ -24,11 +21,8 @@ in ...@@ -24,11 +21,8 @@ in
list___anonymous_0_C_D__: list___anonymous_0_C_D__:
{ ( [] )} { ( [] )}
| x' = C xs = list___anonymous_0_C_D__ | x = C xs = list___anonymous_0_C_D__
{let x = {let x = ( Left x ) in
let x = x' in
( Left x )
in
( x :: xs )} ( x :: xs )}
| y = D xs = list___anonymous_0_C_D__ | y = D xs = list___anonymous_0_C_D__
{let x = ( Right y ) in {let x = ( Right y ) in
......
...@@ -10,33 +10,21 @@ ...@@ -10,33 +10,21 @@
list___anonymous_0_: list___anonymous_0_:
{ ( [] )} { ( [] )}
| x' = A xs = list___anonymous_0_ | x = A xs = list___anonymous_0_
{let x = {let x = ( x ) in
let x = x' in
( x )
in
( x :: xs )} ( x :: xs )}
| x' = B xs = list___anonymous_0_ | x = B xs = list___anonymous_0_
{let x = {let x = ( x ) in
let x = x' in
( x )
in
( x :: xs )} ( x :: xs )}
| x' = C xs = list___anonymous_0_ | x = C xs = list___anonymous_0_
{let x = {let x = ( x ) in
let x = x' in
( x )
in
( x :: xs )} ( x :: xs )}
list___anonymous_1_: list___anonymous_1_:
{ ( [] )} { ( [] )}
| x' = D y = D xs = list___anonymous_1_ | x = D y = D xs = list___anonymous_1_
{let x = {let x = ( x + y ) in
let x = x' in
( x + y )
in
( x :: xs )} ( x :: xs )}
phrase: phrase:
......
...@@ -127,11 +127,10 @@ file: ...@@ -127,11 +127,10 @@ file:
{ ( cs )} { ( cs )}
contract: contract:
_1 = CONTRACT name = IDENT _1' = LPAR xs' = loption_separated_nonempty_list_COMMA_arg__ _3 = RPAR _4 = LBRACE css = list_case_ _6 = RBRACE _1 = CONTRACT name = IDENT _1_inlined1 = LPAR xs = loption_separated_nonempty_list_COMMA_arg__ _3 = RPAR _4 = LBRACE css = list_case_ _6 = RBRACE
{let args = {let args =
let _1 = _1' in let _1 = _1_inlined1 in
let xs = let xs =
let xs = xs' in
let x = ( xs ) in let x = ( xs ) in
( x ) ( x )
in in
...@@ -141,11 +140,10 @@ in ...@@ -141,11 +140,10 @@ in
({ Syntax.contract_cases = css ({ Syntax.contract_cases = css
; contract_name = name ; contract_name = name
; contract_arguments = args}) )} ; contract_arguments = args}) )}
| _1 = EVENT name = IDENT _1' = LPAR xs' = loption_separated_nonempty_list_COMMA_event_arg__ _3 = RPAR _4 = SEMICOLON | _1 = EVENT name = IDENT _1_inlined1 = LPAR xs = loption_separated_nonempty_list_COMMA_event_arg__ _3 = RPAR _4 = SEMICOLON
{let args = {let args =
let _1 = _1' in let _1 = _1_inlined1 in
let xs = let xs =
let xs = xs' in
let x = ( xs ) in let x = ( xs ) in
( x ) ( x )
in in
...@@ -170,11 +168,10 @@ block: ...@@ -170,11 +168,10 @@ block:
case_header: case_header:
_1 = DEFAULT _1 = DEFAULT
{ ( Syntax.DefaultCaseHeader )} { ( Syntax.DefaultCaseHeader )}
| _1 = CASE _2 = LPAR return_typ = typ name = IDENT _1' = LPAR xs' = loption_separated_nonempty_list_COMMA_arg__ _3 = RPAR _6 = RPAR | _1 = CASE _2 = LPAR return_typ = typ name = IDENT _1_inlined1 = LPAR xs = loption_separated_nonempty_list_COMMA_arg__ _3 = RPAR _6 = RPAR
{let args = {let args =
let _1 = _1' in let _1 = _1_inlined1 in
let xs = let xs =
let xs = xs' in
let x = ( xs ) in let x = ( xs ) in
( x ) ( x )
in in
...@@ -186,12 +183,10 @@ in ...@@ -186,12 +183,10 @@ in
; case_arguments = args ; case_arguments = args
} }
)} )}
| _1 = CASE _2 = LPAR _3 = VOID name = IDENT _1' = LPAR xs' = loption_separated_nonempty_list_COMMA_arg__ _3' = RPAR _6 = RPAR | _1 = CASE _2 = LPAR _3 = VOID name = IDENT _1_inlined1 = LPAR xs = loption_separated_nonempty_list_COMMA_arg__ _3_inlined1 = RPAR _6 = RPAR
{let args = {let args =
let _3 = _3' in let (_3, _1) = (_3_inlined1, _1_inlined1) in
let _1 = _1' in
let xs = let xs =
let xs = xs' in
let x = ( xs ) in let x = ( xs ) in
( x ) ( x )
in in
...@@ -257,9 +252,9 @@ sentence: ...@@ -257,9 +252,9 @@ sentence:
)} )}
| _1 = VOID _2 = SINGLE_EQ value = exp _4 = SEMICOLON | _1 = VOID _2 = SINGLE_EQ value = exp _4 = SEMICOLON
{ ( Syntax.ExpSentence value )} { ( Syntax.ExpSentence value )}
| _1 = IF _2 = LPAR cond = exp _4 = RPAR s = sentence _6 = ELSE s' = sentence | _1 = IF _2 = LPAR cond = exp _4 = RPAR s = sentence _6 = ELSE s_inlined1 = sentence
{let bodyF = {let bodyF =
let s = s' in let s = s_inlined1 in
([s]) ([s])
in in
let bodyT = ([s]) in let bodyT = ([s]) in
...@@ -272,9 +267,9 @@ let bodyT = ([s]) in ...@@ -272,9 +267,9 @@ let bodyT = ([s]) in
{let bodyF = ([s]) in {let bodyF = ([s]) in
let bodyT = (b) in let bodyT = (b) in
( Syntax.IfThenElse (cond, bodyT, bodyF) )} ( Syntax.IfThenElse (cond, bodyT, bodyF) )}
| _1 = IF _2 = LPAR cond = exp _4 = RPAR b = block _6 = ELSE b' = block | _1 = IF _2 = LPAR cond = exp _4 = RPAR b = block _6 = ELSE b_inlined1 = block
{let bodyF = {let bodyF =
let b = b' in let b = b_inlined1 in
(b) (b)
in in
let bodyT = (b) in let bodyT = (b) in
...@@ -285,12 +280,11 @@ let bodyT = (b) in ...@@ -285,12 +280,11 @@ let bodyT = (b) in
| _1 = IF _2 = LPAR cond = exp _4 = RPAR b = block | _1 = IF _2 = LPAR cond = exp _4 = RPAR b = block
{let body = (b) in {let body = (b) in
( Syntax.IfThenOnly (cond, body) )} ( Syntax.IfThenOnly (cond, body) )}
| _1 = LOG name = IDENT _1' = LPAR xs' = loption_separated_nonempty_list_COMMA_exp__ _3 = RPAR _4 = SEMICOLON | _1 = LOG name = IDENT _1_inlined1 = LPAR xs = loption_separated_nonempty_list_COMMA_exp__ _3 = RPAR _4 = SEMICOLON
{let lst = {let lst =
let _1 = _1' in let _1 = _1_inlined1 in
let lst = let lst =
let xs = let xs =
let xs = xs' in
let x = ( xs ) in let x = ( xs ) in
( x ) ( x )
in in
...@@ -346,11 +340,10 @@ exp: ...@@ -346,11 +340,10 @@ exp:
{ ( Syntax.IdentifierExp s, () )} { ( Syntax.IdentifierExp s, () )}
| _1 = LPAR e = exp _3 = RPAR | _1 = LPAR e = exp _3 = RPAR
{ ( Syntax.ParenthExp e, () )} { ( Syntax.ParenthExp e, () )}
| s = IDENT _1 = LPAR xs' = loption_separated_nonempty_list_COMMA_exp__ _3 = RPAR | s = IDENT _1 = LPAR xs = loption_separated_nonempty_list_COMMA_exp__ _3 = RPAR
{let lst = {let lst =
let lst = let lst =
let xs = let xs =
let xs = xs' in
let x = ( xs ) in let x = ( xs ) in
( x ) ( x )
in in
...@@ -359,12 +352,11 @@ exp: ...@@ -359,12 +352,11 @@ exp:
(lst) (lst)
in in
( Syntax.FunctionCallExp {Syntax.call_head = s; call_args = lst }, () )} ( Syntax.FunctionCallExp {Syntax.call_head = s; call_args = lst }, () )}
| _1 = DEPLOY s = IDENT _1' = LPAR xs' = loption_separated_nonempty_list_COMMA_exp__ _3 = RPAR m = msg_info | _1 = DEPLOY s = IDENT _1_inlined1 = LPAR xs = loption_separated_nonempty_list_COMMA_exp__ _3 = RPAR m = msg_info
{let lst = {let lst =
let _1 = _1' in let _1 = _1_inlined1 in
let lst = let lst =
let xs = let xs =
let xs = xs' in
let x = ( xs ) in let x = ( xs ) in
( x ) ( x )
in in
...@@ -376,11 +368,10 @@ in ...@@ -376,11 +368,10 @@ in
| contr = exp _2 = DOT _3 = DEFAULT _4 = LPAR _5 = RPAR m = msg_info | contr = exp _2 = DOT _3 = DEFAULT _4 = LPAR _5 = RPAR m = msg_info
{ ( Syntax.SendExp { Syntax.send_head_contract = contr; send_head_method = None { ( Syntax.SendExp { Syntax.send_head_contract = contr; send_head_method = None
; send_args = []; send_msg_info = m }, () )} ; send_args = []; send_msg_info = m }, () )}
| contr = exp _2 = DOT mtd = IDENT _1 = LPAR xs' = loption_separated_nonempty_list_COMMA_exp__ _3 = RPAR m = msg_info | contr = exp _2 = DOT mtd = IDENT _1 = LPAR xs = loption_separated_nonempty_list_COMMA_exp__ _3 = RPAR m = msg_info
{let lst = {let lst =
let lst = let lst =
let xs = let xs =
let xs = xs' in
let x = ( xs ) in let x = ( xs ) in
( x ) ( x )
in in
......
...@@ -18,26 +18,22 @@ main: ...@@ -18,26 +18,22 @@ main:
additive_expr: additive_expr:
_1 = multiplicative_expr _1 = multiplicative_expr
{_1} {_1}
| additive_expr = additive_expr _1' = PLUS multiplicative_expr = multiplicative_expr | additive_expr = additive_expr _1 = PLUS multiplicative_expr = multiplicative_expr
{let _1 = _1' in {let x =
let x =
let additive_op = ( OpPlus ) in let additive_op = ( OpPlus ) in
EBinOp (additive_expr, additive_op, multiplicative_expr) EBinOp (additive_expr, additive_op, multiplicative_expr)
in in
let _endpos_x_ = _endpos_multiplicative_expr_ in let (_endpos_x_, _startpos_x_) = (_endpos_multiplicative_expr_, _startpos_additive_expr_) in
let _startpos_x_ = _startpos_additive_expr_ in
let _endpos = _endpos_x_ in let _endpos = _endpos_x_ in
let _startpos = _startpos_x_ in let _startpos = _startpos_x_ in
let _loc = (_startpos, _endpos) in let _loc = (_startpos, _endpos) in
( { loc = _loc; value = x } )} ( { loc = _loc; value = x } )}
| additive_expr = additive_expr _1' = MINUS multiplicative_expr = multiplicative_expr | additive_expr = additive_expr _1 = MINUS multiplicative_expr = multiplicative_expr
{let _1 = _1' in {let x =
let x =
let additive_op = ( OpMinus ) in let additive_op = ( OpMinus ) in
EBinOp (additive_expr, additive_op, multiplicative_expr) EBinOp (additive_expr, additive_op, multiplicative_expr)
in in
let _endpos_x_ = _endpos_multiplicative_expr_ in let (_endpos_x_, _startpos_x_) = (_endpos_multiplicative_expr_, _startpos_additive_expr_) in
let _startpos_x_ = _startpos_additive_expr_ in
let _endpos = _endpos_x_ in let _endpos = _endpos_x_ in
let _startpos = _startpos_x_ in let _startpos = _startpos_x_ in
let _loc = (_startpos, _endpos) in let _loc = (_startpos, _endpos) in
...@@ -46,57 +42,46 @@ let _loc = (_startpos, _endpos) in ...@@ -46,57 +42,46 @@ let _loc = (_startpos, _endpos) in
multiplicative_expr: multiplicative_expr:
_1 = atomic_expr _1 = atomic_expr
{_1} {_1}
| multiplicative_expr = multiplicative_expr _1' = TIMES atomic_expr = atomic_expr | multiplicative_expr = multiplicative_expr _1 = TIMES atomic_expr = atomic_expr
{let _1 = _1' in {let x =
let x =
let multiplicative_op = ( OpTimes ) in let multiplicative_op = ( OpTimes ) in
EBinOp (multiplicative_expr, multiplicative_op, atomic_expr) EBinOp (multiplicative_expr, multiplicative_op, atomic_expr)
in in
let _endpos_x_ = _endpos_atomic_expr_ in let (_endpos_x_, _startpos_x_) = (_endpos_atomic_expr_, _startpos_multiplicative_expr_) in
let _startpos_x_ = _startpos_multiplicative_expr_ in
let _endpos = _endpos_x_ in let _endpos = _endpos_x_ in
let _startpos = _startpos_x_ in let _startpos = _startpos_x_ in
let _loc = (_startpos, _endpos) in let _loc = (_startpos, _endpos) in
( { loc = _loc; value = x } )} ( { loc = _loc; value = x } )}
| multiplicative_expr = multiplicative_expr _1' = DIV atomic_expr = atomic_expr | multiplicative_expr = multiplicative_expr _1 = DIV atomic_expr = atomic_expr
{let _1 = _1' in {let x =
let x =
let multiplicative_op = ( OpDiv ) in let multiplicative_op = ( OpDiv ) in
EBinOp (multiplicative_expr, multiplicative_op, atomic_expr) EBinOp (multiplicative_expr, multiplicative_op, atomic_expr)
in in
let _endpos_x_ = _endpos_atomic_expr_ in let (_endpos_x_, _startpos_x_) = (_endpos_atomic_expr_, _startpos_multiplicative_expr_) in
let _startpos_x_ = _startpos_multiplicative_expr_ in
let _endpos = _endpos_x_ in let _endpos = _endpos_x_ in
let _startpos = _startpos_x_ in let _startpos = _startpos_x_ in
let _loc = (_startpos, _endpos) in let _loc = (_startpos, _endpos) in
( { loc = _loc; value = x } )} ( { loc = _loc; value = x } )}
atomic_expr: atomic_expr:
_1 = LPAREN _1' = additive_expr _3 = RPAREN _1 = LPAREN _1_inlined1 = additive_expr _3 = RPAREN
{_1'} {_1_inlined1}
| _1' = INT | _1 = INT
{let _endpos__1_ = _endpos__1'_ in {let x =
let _startpos__1_ = _startpos__1'_ in
let _1 = _1' in
let x =
let _1_1 = _1 in let _1_1 = _1 in
ELiteral _1_1 ELiteral _1_1
in in
let _endpos_x_ = _endpos__1_ in let (_endpos_x_, _startpos_x_) = (_endpos__1_, _startpos__1_) in
let _startpos_x_ = _startpos__1_ in
let _endpos = _endpos_x_ in let _endpos = _endpos_x_ in
let _startpos = _startpos_x_ in let _startpos = _startpos_x_ in
let _loc = (_startpos, _endpos) in let _loc = (_startpos, _endpos) in