util.ml 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. open Printf
  2. open Lexing
  3. open Ast
  4. (* Default config *)
  5. let verbosity_default = 2 (* TODO: set to 1 when done with debugging *)
  6. let verbosity_debug = 3
  7. (* Commandline args are stored in a global struct
  8. * (yes, it IS dirty, but I'd rather have this than having to pass [args] around
  9. * everywhere) *)
  10. let args = {
  11. infile = None;
  12. outfile = None;
  13. verbose = verbosity_default;
  14. cpp = true;
  15. }
  16. (* Logging functions *)
  17. let log_line verbosity line =
  18. if args.verbose >= verbosity then prerr_endline line
  19. let log_node verbosity node = log_line verbosity (Stringify.node2str node)
  20. let dbg_line = log_line verbosity_debug
  21. let dbg_node = log_node verbosity_debug
  22. (* Variable generation *)
  23. let var_counter = ref 0
  24. let fresh_var prefix =
  25. var_counter := !var_counter + 1;
  26. prefix ^ "$" ^ string_of_int !var_counter
  27. let loc_from_lexpos pstart pend =
  28. let (fname, ystart, yend, xstart, xend) = (
  29. pstart.pos_fname,
  30. pstart.pos_lnum,
  31. pend.pos_lnum,
  32. (pstart.pos_cnum - pstart.pos_bol + 1),
  33. (pend.pos_cnum - pend.pos_bol)
  34. ) in
  35. if ystart = yend && xend < xstart then
  36. (fname, ystart, yend, xstart, xstart)
  37. else
  38. (fname, ystart, yend, xstart, xend)
  39. (* Default tree transformation
  40. * (node -> node) -> node -> node *)
  41. let transform_children trav node =
  42. let trav_all nodes = List.map trav nodes in
  43. match node with
  44. | Program (decls, loc) ->
  45. Program (trav_all decls, loc)
  46. | FunDec (ret_type, name, params, loc) ->
  47. FunDec (ret_type, name, trav_all params, loc)
  48. | FunDef (export, ret_type, name, params, body, loc) ->
  49. FunDef (export, ret_type, name, trav_all params, trav body, loc)
  50. | GlobalDec (ctype, name, loc) ->
  51. GlobalDec (ctype, name, loc)
  52. | GlobalDef (export, ctype, name, Some init, loc) ->
  53. GlobalDef (export, ctype, name, Some (trav init), loc)
  54. | VarDec (ctype, name, Some init, loc) ->
  55. VarDec (ctype, name, Some (trav init), loc)
  56. | Assign (name, None, value, loc) ->
  57. Assign (name, None, trav value, loc)
  58. | Assign (name, Some dims, value, loc) ->
  59. Assign (name, Some (trav_all dims), trav value, loc)
  60. | Return (value, loc) ->
  61. Return (trav value, loc)
  62. | If (cond, body, loc) ->
  63. If (trav cond, trav body, loc)
  64. | IfElse (cond, true_body, false_body, loc) ->
  65. IfElse (trav cond, trav true_body, trav false_body, loc)
  66. | While (cond, body, loc) ->
  67. While (trav cond, trav body, loc)
  68. | DoWhile (cond, body, loc) ->
  69. DoWhile (trav cond, trav body, loc)
  70. | For (counter, start, stop, step, body, loc) ->
  71. For (counter, trav start, trav stop, trav step, trav body, loc)
  72. | Allocate (name, dims, dec, loc) ->
  73. Allocate (name, trav_all dims, dec, loc)
  74. | Expr value ->
  75. Expr (trav value)
  76. | Block (body) ->
  77. Block (trav_all body)
  78. | Monop (op, value, loc) ->
  79. Monop (op, trav value, loc)
  80. | Binop (op, left, right, loc) ->
  81. Binop (op, trav left, trav right, loc)
  82. | Cond (cond, true_expr, false_expr, loc) ->
  83. Cond (trav cond, trav true_expr, trav false_expr, loc)
  84. | TypeCast (ctype, value, loc) ->
  85. TypeCast (ctype, trav value, loc)
  86. | FunCall (name, args, loc) ->
  87. FunCall (name, trav_all args, loc)
  88. | Arg value ->
  89. Arg (trav value)
  90. | Deref (name, dims, loc) ->
  91. Deref (name, trav_all dims, loc)
  92. | ArrayInit (value, dims) ->
  93. ArrayInit (trav value, dims)
  94. | ArrayScalar value ->
  95. ArrayScalar (trav value)
  96. | Type (value, ctype) ->
  97. Type (trav value, ctype)
  98. | VarLet (assign, def, depth) ->
  99. VarLet (trav assign, def, depth)
  100. | VarUse (var, def, depth) ->
  101. VarUse (trav var, def, depth)
  102. | FunUse (funcall, def, depth) ->
  103. FunUse (trav funcall, def, depth)
  104. | DimDec node ->
  105. DimDec (trav node)
  106. | _ -> node
  107. (* Default tree transformation
  108. * (node -> node) -> node -> node *)
  109. let rec transform_all trav = function
  110. | [] -> []
  111. | node :: tail -> trav node :: (transform_all trav tail)
  112. let rec locof = function
  113. | Program (_, loc)
  114. | Param (_, _, loc)
  115. | Dim (_, loc)
  116. | FunDec (_, _, _, loc)
  117. | FunDef (_, _, _, _, _, loc)
  118. | GlobalDec (_, _, loc)
  119. | GlobalDef (_, _, _, _, loc)
  120. | VarDec (_, _, _, loc)
  121. | Assign (_, _, _, loc)
  122. | Return (_, loc)
  123. | If (_, _, loc)
  124. | IfElse (_, _, _, loc)
  125. | While (_, _, loc)
  126. | DoWhile (_, _, loc)
  127. | For (_, _, _, _, _, loc)
  128. | Allocate (_, _, _, loc)
  129. | BoolConst (_, loc)
  130. | IntConst (_, loc)
  131. | FloatConst (_, loc)
  132. | ArrayConst (_, loc)
  133. | Var (_, loc)
  134. | Deref (_, _, loc)
  135. | Monop (_, _, loc)
  136. | Binop (_, _, _, loc)
  137. | Cond (_, _, _, loc)
  138. | TypeCast (_, _, loc)
  139. | FunCall (_, _, loc) -> loc
  140. | ArrayInit (value, _)
  141. | ArrayScalar value
  142. | Expr value
  143. | VarLet (value, _, _)
  144. | VarUse (value, _, _)
  145. | FunUse (value, _, _)
  146. | Arg value
  147. | Type (value, _)
  148. | DimDec value -> locof value
  149. | _ -> noloc
  150. let prerr_loc (fname, ystart, yend, xstart, xend) =
  151. let file = open_in fname in
  152. (* skip lines until the first matched line *)
  153. for i = 1 to ystart - 1 do input_line file done;
  154. (* for each line in `loc`, print the source line with an underline *)
  155. for l = ystart to yend do
  156. let line = input_line file in
  157. let linewidth = String.length line in
  158. let left = if l = ystart then xstart else 1 in
  159. let right = if l = yend then xend else linewidth in
  160. if linewidth > 0 then (
  161. prerr_endline line;
  162. for i = 1 to left - 1 do prerr_char ' ' done;
  163. for i = left to right do prerr_char '^' done;
  164. prerr_endline "";
  165. )
  166. done;
  167. ()
  168. let prerr_loc_msg loc msg verbose =
  169. let (fname, ystart, yend, xstart, xend) = loc in
  170. let line_s = if yend != ystart
  171. then sprintf "lines %d-%d" ystart yend
  172. else sprintf "line %d" ystart
  173. in
  174. let char_s = if xend != xstart || yend != ystart
  175. then sprintf "characters %d-%d" xstart xend
  176. else sprintf "character %d" xstart
  177. in
  178. eprintf "File \"%s\", %s, %s:\n" fname line_s char_s;
  179. eprintf "%s\n" msg;
  180. if verbose >= 2 then prerr_loc loc;
  181. ()
  182. let rec flatten_blocks = function
  183. | [] -> []
  184. | Block nodes :: t -> (flatten_blocks nodes) @ (flatten_blocks t)
  185. | h :: t -> h :: (flatten_blocks t)
  186. let ctypeof = function
  187. | VarDec (ctype, _, _, _)
  188. | Param (ctype, _, _)
  189. | FunDec (ctype, _, _, _)
  190. | FunDef (_, ctype, _, _, _, _)
  191. | GlobalDec (ctype, _, _)
  192. | GlobalDef (_, ctype, _, _, _)
  193. | TypeCast (ctype, _, _)
  194. | Type (_, ctype)
  195. -> ctype
  196. | DimDec _ -> Int
  197. | _ -> raise InvalidNode
  198. let block_body = function
  199. | Block nodes -> nodes
  200. | _ -> raise InvalidNode
  201. let rec list_size = function
  202. | [] -> 0
  203. | hd :: tl -> 1 + (list_size tl)
  204. let base_type = function
  205. | Array (ctype, _)
  206. | ctype -> ctype
  207. let array_depth = function
  208. | Array (_, dims) -> list_size dims
  209. | _ -> raise InvalidNode