%start file %{ open Xi_lib open Ast open Parser_utils let mkTag = let i = ref 0 in fun () -> let tag = !i in incr i; NodeTag tag %} %token EOF %token COMMA %token SEMICOLON %token LPAREN %token RPAREN %token LBRACKET %token RBRACKET %token LSBRACKET %token RSBRACKET %token COLON %token OP_PLUS %token OP_MINUS %token OP_MULT %token OP_DIV %token OP_REM %token OP_AND %token OP_OR %token OP_EQ %token OP_NEQ %token OP_LE %token OP_GE %token OP_LT %token OP_GT %token OP_NOT %token ASSIGN %token IF %token ELSE %token WHILE %token RETURN %token LENGTH %token INT %token IDENTIFIER %token STRING %token CHAR %token BOOL %token UNDERSCORE %token T_BOOL %token T_INT %% file: | declarations= list(func) EOF { ModuleDefinition {global_declarations=declarations } } func: | id=identifier LPAREN parameters=separated_list(COMMA,var_decl) RPAREN return=return_type body=option(statement_block) { GDECL_Function { loc=mkLocation $startpos; id=id;formal_parameters=parameters; return_types=return;body=body} } var_decl: | id = identifier COLON t=typ { VarDecl {loc=mkLocation $startpos;id=id;tp=t} } option_var_decl: | decl=var_decl { Some decl } | UNDERSCORE { None } return_type: | return = option(preceded(COLON,separated_list(COMMA,typ) ) ) { match return with | None -> [] | Some l -> l } typ: | t=base_type { t } | t=typ LSBRACKET dim=option(expression) RSBRACKET { TEXPR_Array { loc=mkLocation $startpos; sub=t;dim=dim } } base_type: | T_INT {TEXPR_Int {loc=mkLocation $startpos} } | T_BOOL {TEXPR_Bool {loc=mkLocation $startpos} } op_unary: | OP_MINUS { UNOP_Neg } | OP_NOT { UNOP_Not } op_mult_prec: | OP_MULT {BINOP_Mult} | OP_DIV {BINOP_Div} | OP_REM {BINOP_Rem} op_add_prec: | OP_PLUS {BINOP_Add} | OP_MINUS {BINOP_Sub} op_cmp_prec: | OP_LE {RELOP_Le} | OP_LT {RELOP_Lt} | OP_GE {RELOP_Ge} | OP_GT {RELOP_Gt} op_eq_prec: | OP_EQ {RELOP_Eq} | OP_NEQ {RELOP_Ne} expression: | node=expression_or {node} expression_or: | node=expression_and {node} | left=expression_or OP_OR right=expression_and {EXPR_Binop {tag=mkTag ();loc=mkLocation $startpos; op=BINOP_Or;lhs=left;rhs=right } } expression_and: | node=expression_eq {node} | left=expression_and OP_AND right=expression_eq {EXPR_Binop {tag=mkTag ();loc=mkLocation $startpos; op=BINOP_And;lhs=left;rhs=right } } expression_eq: | node=expression_cmp {node} | left=expression_eq op=op_eq_prec right=expression_cmp {EXPR_Relation {tag=mkTag ();loc=mkLocation $startpos; op=op;lhs=left;rhs=right } } expression_cmp: | node=expression_add {node} | left=expression_cmp op=op_cmp_prec right=expression_add {EXPR_Relation {tag=mkTag ();loc=mkLocation $startpos; op=op;lhs=left;rhs=right } } expression_add: | node=expression_mult { node } | left=expression_add op=op_add_prec right=expression_mult {EXPR_Binop {tag=mkTag ();loc=mkLocation $startpos; op=op;lhs=left;rhs=right } } expression_mult: | node=expression_unary { node } | left=expression_mult op=op_mult_prec right=expression_unary {EXPR_Binop {tag=mkTag ();loc=mkLocation $startpos; op=op;lhs=left;rhs=right } } expression_unary: | node=expression_highest_prec { node } | op=op_unary right=expression_unary {EXPR_Unop {tag=mkTag ();loc=mkLocation $startpos; op=op;sub=right } } expression_highest_prec: | node=expression_base { node } | node=expression_call { node } | node=expression_length { node } | node=expression_index { node } expression_base: | node=expression_identifier { node } | node=expression_integer { node } | node=expression_char { node } | node=expression_string { node } | node=expression_bool { node } | node=expression_struct { node } | LPAREN node=expression RPAREN { node } expression_index: | sub=expression_base index=delimited(LSBRACKET,expression,RSBRACKET) { EXPR_Index {tag=mkTag (); loc=mkLocation $startpos; expr=sub; index=index} } | sub=expression_index index=delimited(LSBRACKET,expression,RSBRACKET) { EXPR_Index {tag=mkTag (); loc=mkLocation $startpos; expr=sub; index=index} } expression_identifier: | id=identifier { EXPR_Id {tag= mkTag ();loc=mkLocation $startpos; id=id} } expression_integer: | value=INT { EXPR_Int {tag= mkTag ();loc=mkLocation $startpos; value=Int32.of_int value} } expression_char: | value=CHAR { EXPR_Char {tag= mkTag ();loc=mkLocation $startpos; value=value} } expression_string: | value=STRING { EXPR_String {tag= mkTag ();loc=mkLocation $startpos; value=value} } expression_bool: | value=BOOL { EXPR_Bool {tag= mkTag ();loc=mkLocation $startpos; value=value} } expression_call: | value=call { EXPR_Call value } expression_struct: | LBRACKET elements=separated_list(COMMA,expression) RBRACKET { EXPR_Struct { tag=mkTag (); loc=mkLocation $startpos; elements=elements} } expression_length: | LENGTH LPAREN argument=expression RPAREN { EXPR_Length { tag=mkTag (); loc=mkLocation $startpos; arg=argument } } statement_block: | LBRACKET body=append(list(terminated(statement,semicolons)),loption(terminated(return_stmt,semicolons))) RBRACKET { STMTBlock { loc=mkLocation $startpos;body=body } } statement: | left=lvalue ASSIGN right=expression { STMT_Assign {loc=mkLocation $startpos; lhs=left;rhs=right} } | block=statement_block {STMT_Block block } | call=call {STMT_Call call } | var=var_decl init=option(preceded(ASSIGN,expression)) {STMT_VarDecl { var=var;init=init } } | WHILE cond=expression body=statement { STMT_While {loc=mkLocation $startpos;cond=cond;body=body } } | IF cond=expression then_branch=statement2 else_branch=option(preceded(ELSE,statement)) (*Menhir attempts to mimic ocamlyacc’s specification, that is, to resolve shift/reduce conflicts in favor of shifting*) { STMT_If {loc=mkLocation $startpos;cond=cond;then_branch=then_branch; else_branch=else_branch } } | head=option_var_decl COMMA tail=separated_nonempty_list(COMMA, option_var_decl) ASSIGN call=call { STMT_MultiVarDecl {loc=mkLocation $startpos; vars= head::tail; init=call } } statement2: | left=lvalue ASSIGN right=expression { STMT_Assign {loc=mkLocation $startpos; lhs=left;rhs=right} } | block=statement_block {STMT_Block block } | call=call {STMT_Call call } | var=var_decl init=option(preceded(ASSIGN,expression)) {STMT_VarDecl { var=var;init=init } } | WHILE cond=expression body=statement2 { STMT_While {loc=mkLocation $startpos;cond=cond;body=body } } | IF cond=expression then_branch=statement2 ELSE else_branch=statement2 { STMT_If {loc=mkLocation $startpos;cond=cond;then_branch=then_branch; else_branch=Some else_branch } } | head=option_var_decl COMMA tail=separated_nonempty_list(COMMA, option_var_decl) ASSIGN call=call { STMT_MultiVarDecl {loc=mkLocation $startpos; vars= head::tail; init=call } } return_stmt: | RETURN values=separated_list(COMMA,expression) { [STMT_Return { loc=mkLocation $startpos; values=values }] } call: | callee=identifier LPAREN arguments=separated_list(COMMA,expression) RPAREN { Call { tag=mkTag (); loc=mkLocation $startpos; callee=callee; arguments=arguments } } lvalue: | id=identifier {LVALUE_Id {loc=mkLocation $startpos;id=id} } | sub=lvalue_index LSBRACKET index=expression RSBRACKET {LVALUE_Index {loc=mkLocation $startpos;sub=sub;index=index} } lvalue_index: | node=expression_identifier {node} | node=expression_call {node} | sub=lvalue_index LSBRACKET index=expression RSBRACKET {EXPR_Index {tag=mkTag (); loc=mkLocation $startpos; expr=sub; index=index} } semicolons: | option(SEMICOLON) {} identifier: | IDENTIFIER { Identifier $1 } (* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ----------------------------------------------------------------------------- *)