|
|
@@ -1,12 +1,18 @@
|
|
|
%{
|
|
|
-open Lexing
|
|
|
-open Ast
|
|
|
+ (**
|
|
|
+ * Parser for the CiviC language.
|
|
|
+ *
|
|
|
+ * Note that some shift/reduce conflicts exist, but these need not be solved
|
|
|
+ * since menhir can automatically resolve them
|
|
|
+ *)
|
|
|
|
|
|
-let loc = Util.loc_from_lexpos
|
|
|
-%}
|
|
|
+ open Lexing
|
|
|
+ open Ast
|
|
|
|
|
|
-/* Tokens */
|
|
|
+ let loc = Util.loc_from_lexpos
|
|
|
+%}
|
|
|
|
|
|
+(* Tokens *)
|
|
|
%token LPAREN RPAREN LBRACK RBRACK LBRACE RBRACE SEMICOL COMMA
|
|
|
%token NOT ADD SUB MUL DIV MOD
|
|
|
%token EQ NE LT LE GT GE
|
|
|
@@ -20,9 +26,8 @@ let loc = Util.loc_from_lexpos
|
|
|
%token <int> INT_CONST
|
|
|
%token <string> ID
|
|
|
|
|
|
-/* Precedence */
|
|
|
-
|
|
|
-%right ASSIGN
|
|
|
+(* Precedence *)
|
|
|
+(*%right ASSIGN*)
|
|
|
%left OR
|
|
|
%left AND
|
|
|
%left EQ NE
|
|
|
@@ -34,115 +39,176 @@ let loc = Util.loc_from_lexpos
|
|
|
%nonassoc IF
|
|
|
%nonassoc ELSE
|
|
|
|
|
|
-/* Start symbol */
|
|
|
-
|
|
|
+(* Start symbol *)
|
|
|
%type <Ast.node> program
|
|
|
%start program
|
|
|
|
|
|
%%
|
|
|
|
|
|
-basic_type : FLOAT { Float }
|
|
|
- | INT { Int }
|
|
|
- | BOOL { Bool }
|
|
|
-
|
|
|
-program : decl*; EOF
|
|
|
- { Program ($1, loc $startpos $endpos) }
|
|
|
-
|
|
|
-decl : EXTERN; fun_header; SEMICOL
|
|
|
- { let (t, n, p) = $2 in FunDec(t, n, p, loc $startpos $endpos) }
|
|
|
- | boption(EXPORT); fun_header; LBRACE; fun_body; RBRACE
|
|
|
- { let (t, n, p) = $2 in FunDef ($1, t, n, p, Block $4, loc $startpos $endpos) }
|
|
|
-
|
|
|
- | EXTERN; basic_type; ID; SEMICOL
|
|
|
- { GlobalDec ($2, $3, loc $startpos $endpos) }
|
|
|
- | EXTERN; t=basic_type; LBRACK; d=separated_list(COMMA, ID); RBRACK; n=ID; SEMICOL
|
|
|
- { GlobalDec (ArrayDec (t, d), n, loc $startpos $endpos) }
|
|
|
-
|
|
|
- | boption(EXPORT); basic_type; ID; SEMICOL
|
|
|
- { GlobalDef ($1, $2, $3, None, loc $startpos $endpos) }
|
|
|
- | boption(EXPORT); basic_type; ID; ASSIGN; expr; SEMICOL
|
|
|
- { GlobalDef ($1, $2, $3, Some $5, loc $startpos $endpos) }
|
|
|
-
|
|
|
- | e=boption(EXPORT); t=basic_type; LBRACK; d=separated_list(COMMA, expr);
|
|
|
- RBRACK; n=ID; SEMICOL
|
|
|
- { GlobalDef (e, ArrayDef (t, d), n, None, loc $startpos $endpos) }
|
|
|
- | e=boption(EXPORT); t=basic_type; LBRACK; d=separated_list(COMMA, expr);
|
|
|
- RBRACK; n=ID; ASSIGN; v=expr; SEMICOL
|
|
|
- { GlobalDef (e, ArrayDef (t, d), n, Some v, loc $startpos $endpos) }
|
|
|
-
|
|
|
-fun_header : ret=basic_type; name=ID; LPAREN; params=separated_list(COMMA, param); RPAREN
|
|
|
- { (ret, name, params) }
|
|
|
- | VOID; name=ID; LPAREN; params=separated_list(COMMA, param); RPAREN
|
|
|
- { (Void, name, params) }
|
|
|
-
|
|
|
-param : basic_type; ID { Param ($1, $2, loc $startpos $endpos) }
|
|
|
-
|
|
|
-fun_body : var_dec* local_fun_dec* statement* loption(return_statement)
|
|
|
- { $1 @ $2 @ $3 @ $4 }
|
|
|
-
|
|
|
-local_fun_dec : fun_header; LBRACE; fun_body; RBRACE
|
|
|
- { let (t, n, p) = $1 in FunDef (false, t, n, p, Block $3, loc $startpos $endpos) }
|
|
|
-
|
|
|
-var_dec : basic_type; ID; SEMICOL
|
|
|
- { VarDec ($1, $2, None, loc $startpos $endpos) }
|
|
|
- | basic_type; ID; ASSIGN; expr; SEMICOL
|
|
|
- { VarDec ($1, $2, Some $4, loc $startpos $endpos) }
|
|
|
- | t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; SEMICOL
|
|
|
- { VarDec (ArrayDef (t, d), n, None, loc $startpos $endpos) }
|
|
|
- | t=basic_type; LBRACK; d=separated_list(COMMA, expr); RBRACK; n=ID; ASSIGN; v=expr; SEMICOL
|
|
|
- { VarDec (ArrayDef (t, d), n, Some v, loc $startpos $endpos) }
|
|
|
-
|
|
|
-statement : ID; ASSIGN; expr; SEMICOL
|
|
|
- { Assign ($1, $3, loc $startpos $endpos) }
|
|
|
- | name=ID; LPAREN; params=separated_list(COMMA, expr); RPAREN; SEMICOL
|
|
|
- { Expr (FunCall (name, params, loc $startpos $endpos)) }
|
|
|
- | IF; LPAREN; expr; RPAREN; block
|
|
|
- { If ($3, Block $5, loc $startpos $endpos) } %prec IF
|
|
|
- | IF; LPAREN; expr; RPAREN; block; ELSE; block
|
|
|
- { IfElse ($3, Block $5, Block $7, loc $startpos $endpos) } %prec ELSE
|
|
|
- | WHILE; LPAREN; expr; RPAREN; block
|
|
|
- { While ($3, Block $5, loc $startpos $endpos) }
|
|
|
- | DO; block; WHILE; LPAREN; expr; RPAREN; SEMICOL
|
|
|
- { DoWhile ($5, Block $2, loc $startpos $endpos) }
|
|
|
- | FOR; LPAREN; INT; id=ID; ASSIGN; start=expr; COMMA; stop=expr; RPAREN; body=block
|
|
|
- { For (id, start, stop, IntConst (1, noloc), Block body, loc $startpos $endpos) }
|
|
|
- | FOR; LPAREN; INT; id=ID; ASSIGN; start=expr; COMMA; stop=expr;
|
|
|
- COMMA; step=expr; RPAREN; body=block
|
|
|
- { For (id, start, stop, step, Block body, loc $startpos $endpos) }
|
|
|
-
|
|
|
-return_statement : RETURN; expr; SEMICOL { [Return ($2, loc $startpos $endpos)] }
|
|
|
-
|
|
|
-block : LBRACE; statement*; RBRACE { $2 }
|
|
|
- | statement { [$1] }
|
|
|
-
|
|
|
-expr : LPAREN; expr; RPAREN { $2 }
|
|
|
- | name=ID; LPAREN; params=separated_list(COMMA, expr); RPAREN
|
|
|
- { FunCall (name, params, loc $startpos $endpos) }
|
|
|
- | ID { Var ($1, loc $startpos $endpos) }
|
|
|
- | l=expr; op=binop; r=expr { Binop (op, l, r, loc $startpos $endpos) }
|
|
|
- | SUB; expr { Monop (Neg, $2, loc $startpos $endpos) } %prec NEG
|
|
|
- | NOT; expr { Monop (Not, $2, loc $startpos $endpos) }
|
|
|
- | LPAREN; basic_type; RPAREN; expr { TypeCast ($2, $4, loc $startpos $endpos) } %prec CAST
|
|
|
- | FLOAT_CONST { FloatConst ($1, loc $startpos $endpos) }
|
|
|
- | INT_CONST { IntConst ($1, loc $startpos $endpos) }
|
|
|
- | BOOL_CONST { BoolConst ($1, loc $startpos $endpos) }
|
|
|
- | ID; array_const { Deref ($1, $2, loc $startpos $endpos) }
|
|
|
- | array_const { ArrayConst ($1, loc $startpos $endpos) }
|
|
|
-
|
|
|
-array_const : LBRACK; values=separated_list(COMMA, expr); RBRACK { values }
|
|
|
-
|
|
|
-%inline binop : ADD { Add }
|
|
|
- | SUB { Sub }
|
|
|
- | MUL { Mul }
|
|
|
- | DIV { Div }
|
|
|
- | MOD { Mod }
|
|
|
- | EQ { Eq }
|
|
|
- | NE { Ne }
|
|
|
- | LT { Lt }
|
|
|
- | LE { Le }
|
|
|
- | GT { Gt }
|
|
|
- | GE { Ge }
|
|
|
- | AND { And }
|
|
|
- | OR { Or }
|
|
|
+basic_type:
|
|
|
+ | FLOAT { Float }
|
|
|
+ | INT { Int }
|
|
|
+ | BOOL { Bool }
|
|
|
+
|
|
|
+program:
|
|
|
+ decl*; EOF
|
|
|
+ { Program ($1, loc $startpos $endpos) }
|
|
|
+
|
|
|
+decl:
|
|
|
+ (* function: use location of function name *)
|
|
|
+ | EXTERN; hdr=fun_header; SEMICOL
|
|
|
+ { let (t, n, p, nameloc) = hdr in
|
|
|
+ FunDec(t, n, p, nameloc) }
|
|
|
+
|
|
|
+ | export=boption(EXPORT); hdr=fun_header; LBRACE; body=fun_body; RBRACE
|
|
|
+ { let (t, n, p, nameloc) = hdr in
|
|
|
+ FunDef (export, t, n, p, Block body, nameloc) }
|
|
|
+
|
|
|
+ (* global variable declaration: use location of variable name *)
|
|
|
+ | EXTERN; ctype=basic_type; name=ID; SEMICOL
|
|
|
+ { GlobalDec (ctype, name, loc $startpos $endpos) }
|
|
|
+
|
|
|
+ | EXTERN; ctype=basic_type;
|
|
|
+ LBRACK; dims=separated_list(COMMA, ID); RBRACK;
|
|
|
+ name=ID; SEMICOL
|
|
|
+ { let loc = loc $startpos(name) $endpos(name) in
|
|
|
+ GlobalDec (ArrayDec (ctype, dims), name, loc) }
|
|
|
+
|
|
|
+ | export=boption(EXPORT); ctype=basic_type; name=ID; SEMICOL
|
|
|
+ { let loc = loc $startpos(name) $endpos(name) in
|
|
|
+ GlobalDef (export, ctype, name, None, loc) }
|
|
|
+
|
|
|
+ | export=boption(EXPORT); ctype=basic_type; name=ID; ASSIGN; init=expr; SEMICOL
|
|
|
+ { let loc = loc $startpos(name) $endpos(name) in
|
|
|
+ GlobalDef (export, ctype, name, Some init, loc) }
|
|
|
+
|
|
|
+ | export=boption(EXPORT); ctype=basic_type;
|
|
|
+ LBRACK; dims=separated_list(COMMA, expr); RBRACK;
|
|
|
+ name=ID; SEMICOL
|
|
|
+ { let loc = loc $startpos(name) $endpos(name) in
|
|
|
+ GlobalDef (export, ArrayDef (ctype, dims), name, None, loc) }
|
|
|
+
|
|
|
+ | export=boption(EXPORT); ctype=basic_type;
|
|
|
+ LBRACK; dims=separated_list(COMMA, expr); RBRACK;
|
|
|
+ name=ID; ASSIGN; init=expr; SEMICOL
|
|
|
+ { let loc = loc $startpos(name) $endpos(name) in
|
|
|
+ GlobalDef (export, ArrayDef (ctype, dims), name, Some init, loc) }
|
|
|
+
|
|
|
+fun_header:
|
|
|
+ (* function header: use location of function name *)
|
|
|
+ | ret=basic_type; name=ID; LPAREN; params=separated_list(COMMA, param); RPAREN
|
|
|
+ { (ret, name, params, loc $startpos(name) $endpos(name)) }
|
|
|
+
|
|
|
+ | VOID; name=ID; LPAREN; params=separated_list(COMMA, param); RPAREN
|
|
|
+ { (Void, name, params, loc $startpos(name) $endpos(name)) }
|
|
|
+
|
|
|
+param:
|
|
|
+ (* parameter: use location of parameter name *)
|
|
|
+ ctype=basic_type; name=ID
|
|
|
+ { Param (ctype, name, loc $startpos(name) $endpos(name)) }
|
|
|
+
|
|
|
+fun_body:
|
|
|
+ var_dec* local_fun_dec* statement* loption(return_statement)
|
|
|
+ { $1 @ $2 @ $3 @ $4 }
|
|
|
+
|
|
|
+return_statement:
|
|
|
+ (* return statement: use location of return value *)
|
|
|
+ RETURN; value=expr; SEMICOL
|
|
|
+ { [Return (value, loc $startpos(value) $endpos(value))] }
|
|
|
+
|
|
|
+(* function: use location of function name *)
|
|
|
+local_fun_dec:
|
|
|
+ hdr=fun_header; LBRACE; body=fun_body; RBRACE
|
|
|
+ { let (t, n, p, nameloc) = hdr in
|
|
|
+ FunDef (false, t, n, p, Block body, nameloc) }
|
|
|
+
|
|
|
+var_dec:
|
|
|
+ (* variable declaration: use location of variable name *)
|
|
|
+ | ctype=basic_type; name=ID; SEMICOL
|
|
|
+ { VarDec (ctype, name, None, loc $startpos(name) $endpos(name)) }
|
|
|
+
|
|
|
+ | ctype=basic_type; name=ID; ASSIGN; init=expr; SEMICOL
|
|
|
+ { VarDec (ctype, name, Some init, loc $startpos(name) $endpos(name)) }
|
|
|
+
|
|
|
+ | ctype=basic_type; LBRACK; dims=separated_list(COMMA, expr); RBRACK;
|
|
|
+ name=ID; SEMICOL
|
|
|
+ { let loc = loc $startpos(name) $endpos(name) in
|
|
|
+ VarDec (ArrayDef (ctype, dims), name, None, loc) }
|
|
|
+
|
|
|
+ | ctype=basic_type; LBRACK; dims=separated_list(COMMA, expr); RBRACK;
|
|
|
+ name=ID; ASSIGN; init=expr; SEMICOL
|
|
|
+ { let loc = loc $startpos(name) $endpos(name) in
|
|
|
+ VarDec (ArrayDef (ctype, dims), name, Some init, loc) }
|
|
|
+
|
|
|
+statement:
|
|
|
+ (* assignment: use location of assigned variable name *)
|
|
|
+ | name=ID; ASSIGN; value=expr; SEMICOL
|
|
|
+ { Assign (name, value, loc $startpos(name) $endpos(name)) }
|
|
|
+
|
|
|
+ | name=ID; LPAREN; params=separated_list(COMMA, expr); RPAREN; SEMICOL
|
|
|
+ { Expr (FunCall (name, params, loc $startpos $endpos)) }
|
|
|
+
|
|
|
+ (* if-statements and (do-)while-loops: use location of condition *)
|
|
|
+ | IF; LPAREN; cond=expr; RPAREN; body=block
|
|
|
+ { If (cond, Block body, loc $startpos $endpos) } %prec IF
|
|
|
+
|
|
|
+ | IF; LPAREN; c=expr; RPAREN; t=block; ELSE; f=block
|
|
|
+ { IfElse (c, Block t, Block f, loc $startpos(c) $endpos(c)) } %prec ELSE
|
|
|
+
|
|
|
+ | WHILE; LPAREN; cond=expr; RPAREN; body=block
|
|
|
+ { While (cond, Block body, loc $startpos(cond) $endpos(cond)) }
|
|
|
+
|
|
|
+ | DO; body=block; WHILE; LPAREN; cond=expr; RPAREN; SEMICOL
|
|
|
+ { DoWhile (cond, Block body, loc $startpos(cond) $endpos(cond)) }
|
|
|
+
|
|
|
+ (* for-loop: use location of counter id *)
|
|
|
+ | FOR; LPAREN; INT; cnt=ID; ASSIGN; start=expr; COMMA; stop=expr; RPAREN;
|
|
|
+ body=block
|
|
|
+ { let loc = loc $startpos(cnt) $endpos(cnt) in
|
|
|
+ For (cnt, start, stop, IntConst (1, noloc), Block body, loc) }
|
|
|
+
|
|
|
+ | FOR; LPAREN; INT; cnt=ID; ASSIGN; start=expr; COMMA; stop=expr; COMMA;
|
|
|
+ step=expr; RPAREN; body=block
|
|
|
+ { let loc = loc $startpos(cnt) $endpos(cnt) in
|
|
|
+ For (cnt, start, stop, step, Block body, loc) }
|
|
|
+
|
|
|
+block:
|
|
|
+ | LBRACE; stats=statement*; RBRACE { stats }
|
|
|
+ | stat=statement { [stat] }
|
|
|
+
|
|
|
+expr:
|
|
|
+ | name=ID; LPAREN; args=separated_list(COMMA, expr); RPAREN
|
|
|
+ { FunCall (name, args, loc $startpos $endpos) }
|
|
|
+
|
|
|
+ | LPAREN; expr; RPAREN { $2 }
|
|
|
+ | ID { Var ($1, loc $startpos $endpos) }
|
|
|
+ | l=expr; op=binop; r=expr { Binop (op, l, r, loc $startpos $endpos) }
|
|
|
+ | SUB; expr { Monop (Neg, $2, loc $startpos $endpos) } %prec NEG
|
|
|
+ | NOT; expr { Monop (Not, $2, loc $startpos $endpos) }
|
|
|
+ | LPAREN; basic_type; RPAREN; expr { TypeCast ($2, $4, loc $startpos $endpos) } %prec CAST
|
|
|
+ | FLOAT_CONST { FloatConst ($1, loc $startpos $endpos) }
|
|
|
+ | INT_CONST { IntConst ($1, loc $startpos $endpos) }
|
|
|
+ | BOOL_CONST { BoolConst ($1, loc $startpos $endpos) }
|
|
|
+ | ID; array_const { Deref ($1, $2, loc $startpos $endpos) }
|
|
|
+ | array_const { ArrayConst ($1, loc $startpos $endpos) }
|
|
|
+
|
|
|
+%inline binop:
|
|
|
+ | ADD { Add }
|
|
|
+ | SUB { Sub }
|
|
|
+ | MUL { Mul }
|
|
|
+ | DIV { Div }
|
|
|
+ | MOD { Mod }
|
|
|
+ | EQ { Eq }
|
|
|
+ | NE { Ne }
|
|
|
+ | LT { Lt }
|
|
|
+ | LE { Le }
|
|
|
+ | GT { Gt }
|
|
|
+ | GE { Ge }
|
|
|
+ | AND { And }
|
|
|
+ | OR { Or }
|
|
|
+
|
|
|
+array_const:
|
|
|
+ LBRACK; values=separated_list(COMMA, expr); RBRACK
|
|
|
+ { values }
|
|
|
|
|
|
%%
|