parser.mly 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. %{
  2. (**
  3. * Parser for the CiviC language.
  4. *
  5. * Note that some shift/reduce conflicts exist, but these need not be solved
  6. * since menhir can automatically resolve them
  7. *)
  8. open Lexing
  9. open Types
  10. let loc start stop = [Loc (Util.loc_from_lexpos start stop)]
  11. let rec make_args = function
  12. | [] -> []
  13. | h::t -> Arg h :: (make_args t)
  14. %}
  15. (* Tokens *)
  16. %token LPAREN RPAREN LBRACK RBRACK LBRACE RBRACE SEMICOL COMMA
  17. %token NOT ADD SUB MUL DIV MOD
  18. %token EQ NE LT LE GT GE
  19. %token AND OR
  20. %token ASSIGN IF ELSE WHILE DO FOR RETURN EXTERN EXPORT
  21. %token INT BOOL FLOAT VOID
  22. %token EOF
  23. %token <bool> BOOL_CONST
  24. %token <float> FLOAT_CONST
  25. %token <int32> INT_CONST
  26. %token <string> ID
  27. (* Precedence *)
  28. (*%right ASSIGN*)
  29. %left OR
  30. %left AND
  31. %left EQ NE
  32. %left LT LE GT GE
  33. %left ADD SUB
  34. %left MUL DIV MOD
  35. %right NOT NEG CAST
  36. %nonassoc IF
  37. %nonassoc ELSE
  38. (* Start symbol *)
  39. %type <Types.node> program
  40. %start program
  41. %%
  42. (* Left-recursive list (use List.rev to obtain original list) *)
  43. llist(x):
  44. | { [] }
  45. | llist(x) x { $2 :: $1 }
  46. (* Shorthand for comma-separated list *)
  47. %inline clist(x):
  48. | lst=separated_list(COMMA, x)
  49. { lst }
  50. basic_type:
  51. | FLOAT { Float }
  52. | INT { Int }
  53. | BOOL { Bool }
  54. program:
  55. | decl+ EOF
  56. { Program ($1, loc $startpos $endpos) }
  57. decl:
  58. (* function: use location of function name *)
  59. | EXTERN hdr=fun_header SEMICOL
  60. { let (t, n, p, nameloc) = hdr in
  61. FunDec(t, n, p, nameloc) }
  62. | export=boption(EXPORT) hdr=fun_header LBRACE body=fun_body RBRACE
  63. { let (t, n, p, nameloc) = hdr in
  64. FunDef (export, t, n, p, Block body, nameloc) }
  65. (* global variable declaration: use location of variable name *)
  66. | EXTERN ctype=basic_type name=ID SEMICOL
  67. { let nameloc = loc $startpos(name) $endpos(name) in
  68. GlobalDec (ctype, name, nameloc) }
  69. | EXTERN ctype=basic_type LBRACK dims=dimlist RBRACK name=ID SEMICOL
  70. { let nameloc = loc $startpos(name) $endpos(name) in
  71. GlobalDec (ArrayDims (ctype, List.rev dims), name, nameloc) }
  72. | export=boption(EXPORT) ctype=basic_type name=ID SEMICOL
  73. { let loc = loc $startpos(name) $endpos(name) in
  74. GlobalDef (export, ctype, name, None, loc) }
  75. | export=boption(EXPORT) ctype=basic_type name=ID ASSIGN init=expr SEMICOL
  76. { let loc = loc $startpos(name) $endpos(name) in
  77. GlobalDef (export, ctype, name, Some init, loc) }
  78. | export=boption(EXPORT) ctype=basic_type LBRACK dims=clist(expr) RBRACK
  79. name=ID SEMICOL
  80. { let loc = loc $startpos(name) $endpos(name) in
  81. GlobalDef (export, ArrayDims (ctype, dims), name, None, loc) }
  82. | export=boption(EXPORT) ctype=basic_type LBRACK dims=clist(expr) RBRACK
  83. name=ID ASSIGN init=expr SEMICOL
  84. { let loc = loc $startpos(name) $endpos(name) in
  85. GlobalDef (export, ArrayDims (ctype, dims), name, Some init, loc) }
  86. %inline ret_type:
  87. | t=basic_type { t }
  88. | VOID { Void }
  89. fun_header:
  90. (* function header: use location of function name *)
  91. | ret=ret_type name=ID LPAREN params=clist(param) RPAREN
  92. { (ret, name, params, loc $startpos(name) $endpos(name)) }
  93. param:
  94. (* parameter: use location of parameter name *)
  95. | ctype=basic_type name=ID
  96. { Param (ctype, name, loc $startpos(name) $endpos(name)) }
  97. | ctype=basic_type LBRACK dims=dimlist RBRACK name=ID
  98. { let loc = loc $startpos(name) $endpos(name) in
  99. Param (ArrayDims (ctype, List.rev dims), name, loc) }
  100. dimlist:
  101. | name=ID
  102. { [Dim (name, loc $startpos(name) $endpos(name))] }
  103. | head=dimlist COMMA name=ID
  104. { Dim (name, loc $startpos(name) $endpos(name)) :: head }
  105. fun_body:
  106. | llist(var_dec) local_fun_dec* statement* loption(return_statement)
  107. { VarDecs (List.rev $1) :: LocalFuns $2 :: ($3 @ $4) }
  108. return_statement:
  109. (* return statement: use location of return value *)
  110. | RETURN value=expr SEMICOL
  111. { [Return (value, loc $startpos(value) $endpos(value))] }
  112. (* function: use location of function name *)
  113. local_fun_dec:
  114. | hdr=fun_header LBRACE body=fun_body RBRACE
  115. { let (t, n, p, nameloc) = hdr in
  116. FunDef (false, t, n, p, Block body, nameloc) }
  117. var_dec:
  118. (* variable declaration: use location of variable name *)
  119. | ctype=basic_type name=ID SEMICOL
  120. { VarDec (ctype, name, None, loc $startpos(name) $endpos(name)) }
  121. | ctype=basic_type name=ID ASSIGN init=expr SEMICOL
  122. { VarDec (ctype, name, Some init, loc $startpos(name) $endpos(name)) }
  123. | ctype=basic_type LBRACK dims=clist(expr) RBRACK name=ID SEMICOL
  124. { let loc = loc $startpos(name) $endpos(name) in
  125. VarDec (ArrayDims (ctype, dims), name, None, loc) }
  126. | ctype=basic_type LBRACK dims=clist(expr) RBRACK name=ID ASSIGN
  127. init=expr SEMICOL
  128. { let loc = loc $startpos(name) $endpos(name) in
  129. VarDec (ArrayDims (ctype, dims), name, Some init, loc) }
  130. statement:
  131. (* assignment: use location of assigned variable name *)
  132. | name=ID ASSIGN value=expr SEMICOL
  133. { Assign (name, None, value, loc $startpos(name) $endpos(name)) }
  134. | name=ID LBRACK dims=clist(expr) brk=RBRACK ASSIGN value=expr SEMICOL
  135. { Assign (name, Some dims, value, loc $startpos(name) $endpos(brk)) }
  136. | name=ID LPAREN args=clist(expr) RPAREN SEMICOL
  137. { Expr (FunCall (name, make_args args, loc $startpos(name) $endpos(name))) }
  138. (* if-statements and (do-)while-loops: use location of condition *)
  139. | IF LPAREN cond=expr RPAREN body=block
  140. { If (cond, Block body, loc $startpos $endpos) } %prec IF
  141. | IF LPAREN c=expr RPAREN t=block ELSE f=block
  142. { IfElse (c, Block t, Block f, loc $startpos(c) $endpos(c)) } (* %prec ELSE *)
  143. | WHILE LPAREN cond=expr RPAREN body=block
  144. { While (cond, Block body, loc $startpos(cond) $endpos(cond)) }
  145. | DO body=block WHILE LPAREN cond=expr RPAREN SEMICOL
  146. { DoWhile (cond, Block body, loc $startpos(cond) $endpos(cond)) }
  147. (* for-loop: use location of counter id *)
  148. | FOR LPAREN INT cnt=ID ASSIGN start=expr COMMA stop=expr RPAREN body=block
  149. { let loc = loc $startpos(cnt) $endpos(cnt) in
  150. For (cnt, start, stop, Const (IntVal 1l, []), Block body, loc) }
  151. | FOR LPAREN INT cnt=ID ASSIGN start=expr COMMA stop=expr COMMA step=expr
  152. RPAREN body=block
  153. { let loc = loc $startpos(cnt) $endpos(cnt) in
  154. For (cnt, start, stop, step, Block body, loc) }
  155. block:
  156. | LBRACE stats=statement* RBRACE { stats }
  157. | stat=statement { [stat] }
  158. expr:
  159. | name=ID LPAREN args=clist(expr) RPAREN
  160. { FunCall (name, make_args args, loc $startpos $endpos) }
  161. | LPAREN expr RPAREN { $2 }
  162. | ID { Var ($1, None, loc $startpos $endpos) }
  163. | l=expr op=binop r=expr { Binop (op, l, r, loc $startpos $endpos) }
  164. | SUB expr { Monop (Neg, $2, loc $startpos $endpos) } %prec NEG
  165. | NOT expr { Monop (Not, $2, loc $startpos $endpos) }
  166. | LPAREN basic_type RPAREN expr { TypeCast ($2, $4, loc $startpos $endpos) } %prec CAST
  167. | FLOAT_CONST { Const (FloatVal $1, loc $startpos $endpos) }
  168. | INT_CONST { Const (IntVal $1, loc $startpos $endpos) }
  169. | BOOL_CONST { Const (BoolVal $1, loc $startpos $endpos) }
  170. | ID array_const { Var ($1, Some $2, loc $startpos $endpos) }
  171. | array_const { ArrayConst ($1, loc $startpos $endpos) }
  172. %inline binop:
  173. | ADD { Add }
  174. | SUB { Sub }
  175. | MUL { Mul }
  176. | DIV { Div }
  177. | MOD { Mod }
  178. | EQ { Eq }
  179. | NE { Ne }
  180. | LT { Lt }
  181. | LE { Le }
  182. | GT { Gt }
  183. | GE { Ge }
  184. | AND { And }
  185. | OR { Or }
  186. array_const:
  187. | LBRACK values=clist(expr) RBRACK
  188. { values }
  189. %%