(* Langages de Programmation et Compilation (J.-C. Filliatre) 2013-2014 Alex AUVOLAT Parser for Mini-C++ *) %{ open Ast type var = | VId of ident | VPtr of var | VRef of var let rec reverse_var bt v = match v with | VId(i) -> i, bt | VPtr(vv) -> let id, ty = reverse_var bt vv in id, TPtr(ty) | VRef(vv) -> let id, ty = reverse_var bt vv in id, TRef(ty) %} %token INTVAL %token STRVAL %token IDENT %token TIDENT (* this is stupid *) %token INCLUDE_IOSTREAM STD_COUT (* keywords *) %token CLASS ELSE FALSE FOR IF INT NEW NULL PUBLIC RETURN %token THIS TRUE VIRTUAL VOID WHILE (* operators *) %token ASSIGN LOR LAND EQ NE LT LE GT GE PLUS MINUS %token TIMES DIV MOD NOT INCR DECR REF %token LPAREN RPAREN RARROW DOT (* other symbols *) %token SEMICOLON COLON DOUBLECOLON LFLOW LBRACE RBRACE COMMA EOF (* operator priority *) %right ASSIGN %left LOR %left LAND %left EQ NE %left LT LE GT GE %left PLUS MINUS %left TIMES DIV MOD %left RARROW DOT LPAREN %start prog %% prog: INCLUDE_IOSTREAM? decls = declaration* EOF { List.flatten decls } ; declaration: | ident = typed_var LPAREN args = typed_var* RPAREN b = block { [ DFunction({p_ret_type = snd ident; p_name = fst ident; p_args = args}, b) ] } | vars = typed_vars SEMICOLON { List.map (fun k -> DGlobal(k)) vars } ; typed_var: | b = base_type x = var { reverse_var b x } ; typed_vars: | b = base_type x = separated_nonempty_list(COMMA, var) { List.map (reverse_var b) x } ; base_type: | VOID { TVoid } | INT { TInt } | t = TIDENT { TIdent(t) } ; var: | t = IDENT { VId(t) } | TIMES v = var { VPtr(v) } | REF v = var { VRef(v) } ; block: | LBRACE i = statement* RBRACE { i } ; statement: | k = common_statement { k } | IF LPAREN c = expression RPAREN s = statement { SIf(c, s, SEmpty) } | IF LPAREN c = expression RPAREN s = no_if_statement ELSE t = statement { SIf(c, s, t) } | WHILE LPAREN c = expression RPAREN s = statement { SWhile(c, s) } | FOR LPAREN k = separated_list(COMMA, expression) SEMICOLON c = expression? SEMICOLON r = separated_list(COMMA, expression) RPAREN b = statement { SFor(k, c, r, b) } ; no_if_statement: | WHILE LPAREN c = expression RPAREN s = no_if_statement { SWhile(c, s) } | FOR LPAREN k = separated_list(COMMA, expression) SEMICOLON c = expression? SEMICOLON r = separated_list(COMMA, expression) RPAREN b = no_if_statement { SFor(k, c, r, b) } | c = common_statement { c } ; common_statement: | SEMICOLON { SEmpty } | e = expression SEMICOLON { SExpr(e) } | b = block { SBlock (b) } | RETURN e = expression? SEMICOLON { SReturn (e) } | k = typed_var v = preceded(ASSIGN, expression)? SEMICOLON { SDeclare(fst k, snd k, v) } ; expression: | e1 = expression ASSIGN e2 = expression { EAssign(e1, e2) } | a = expression b = binop c = expression { EBinary(a, b, c) } | a = expression LPAREN arg = separated_list(COMMA, expression) RPAREN { ECall(a, arg) } | a = unop { a } ; primary: | NULL { ENull } | i = INTVAL { EInt(i) } | TRUE { EBool(true) } | FALSE { EBool(false) } | i = IDENT { EIdent(i) } | LPAREN e = expression RPAREN { e } ; %inline binop: | EQ {Equal } | NE { NotEqual } | LAND { Land } | LOR { Lor } | GT { Gt } | GE { Ge } | LT { Lt } | LE { Le } | PLUS { Add } | MINUS { Sub } | TIMES { Mul } | DIV { Div } | MOD { Modulo } ; unop: | e = lunop { e } | e = unop INCR { EUnary(PostIncr, e) } | e = unop DECR { EUnary(PostDecr, e) } ; lunop: | NOT e = lunop { EUnary(Not, e) } | MINUS e = lunop { EUnary(Minus, e) } | PLUS e = lunop { EUnary(Plus, e) } | REF e = lunop { EUnary(Ref, e) } | TIMES e = lunop { EUnary(Deref, e) } | INCR e = lunop { EUnary(PreIncr, e) } | DECR e = lunop { EUnary(PreDecr, e) } | e = primary { e } ;