util.ml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. open Printf
  2. open Str
  3. open Lexing
  4. open Types
  5. let rec repeat s n = if n < 1 then "" else s ^ (repeat s (n - 1))
  6. let expand n text = text ^ repeat " " (n - String.length text)
  7. (* Logging functions *)
  8. let hline = "-----------------------------------------------------------------"
  9. let prt_line = prerr_endline
  10. let prt_node node = prt_line (Stringify.node2str node)
  11. let log_plain_line verbosity line =
  12. if args.verbose >= verbosity then prt_line line
  13. let log_line verbosity line =
  14. log_plain_line verbosity (repeat " " 13 ^ line)
  15. let log_node verbosity node =
  16. if args.verbose >= verbosity then prt_node node
  17. (* Variable generation *)
  18. let var_counter = ref 0
  19. let fresh_var prefix =
  20. var_counter := !var_counter + 1;
  21. prefix ^ "$" ^ string_of_int !var_counter
  22. (* Constants are marked by a double $$ for recognition during constant
  23. * propagation *)
  24. let fresh_const prefix = fresh_var (prefix ^ "$")
  25. let loc_from_lexpos pstart pend =
  26. let (fname, ystart, yend, xstart, xend) = (
  27. pstart.pos_fname,
  28. pstart.pos_lnum,
  29. pend.pos_lnum,
  30. (pstart.pos_cnum - pstart.pos_bol + 1),
  31. (pend.pos_cnum - pend.pos_bol)
  32. ) in
  33. if ystart = yend && xend < xstart then
  34. (fname, ystart, yend, xstart, xstart)
  35. else
  36. (fname, ystart, yend, xstart, xend)
  37. let rec flatten_blocks lst =
  38. let flatten = flatten_blocks in
  39. let rec trav = function
  40. | Block body ->
  41. Block (flatten body)
  42. | FunDef (export, ret_type, name, params, body, ann) ->
  43. FunDef (export, ret_type, name, flatten params, trav body, ann)
  44. | If (cond, body, ann) ->
  45. If (cond, trav body, ann)
  46. | IfElse (cond, tbody, fbody, ann) ->
  47. IfElse (cond, trav tbody, trav fbody, ann)
  48. | While (cond, body, ann) ->
  49. While (cond, trav body, ann)
  50. | DoWhile (cond, body, ann) ->
  51. DoWhile (cond, trav body, ann)
  52. | For (counter, start, stop, step, body, ann) ->
  53. For (counter, start, stop, step, trav body, ann)
  54. | VarDecs decs ->
  55. VarDecs (flatten decs)
  56. | LocalFuns decs ->
  57. LocalFuns (flatten decs)
  58. | node -> node
  59. in
  60. match lst with
  61. | [] -> []
  62. | Block nodes :: tl -> flatten nodes @ (flatten tl)
  63. | DummyNode :: tl -> flatten tl
  64. | hd :: tl -> trav hd :: (flatten tl)
  65. (* Default tree transformation
  66. * (node -> node) -> node -> node *)
  67. let transform_children trav node =
  68. let trav_all nodes = List.map trav nodes in
  69. match node with
  70. | Program (decls, ann) ->
  71. Program (flatten_blocks (trav_all decls), ann)
  72. | FunDec (ret_type, name, params, ann) ->
  73. FunDec (ret_type, name, trav_all params, ann)
  74. | FunDef (export, ret_type, name, params, body, ann) ->
  75. FunDef (export, ret_type, name, trav_all params, trav body, ann)
  76. | GlobalDec (ctype, name, ann) ->
  77. GlobalDec (ctype, name, ann)
  78. | GlobalDef (export, ctype, name, Some init, ann) ->
  79. GlobalDef (export, ctype, name, Some (trav init), ann)
  80. | VarDecs decs ->
  81. VarDecs (trav_all decs)
  82. | LocalFuns funs ->
  83. LocalFuns (trav_all funs)
  84. | VarDec (ctype, name, Some init, ann) ->
  85. VarDec (ctype, name, Some (trav init), ann)
  86. | Assign (name, None, value, ann) ->
  87. Assign (name, None, trav value, ann)
  88. | Assign (name, Some dims, value, ann) ->
  89. Assign (name, Some (trav_all dims), trav value, ann)
  90. | VarLet (dec, None, value, ann) ->
  91. VarLet (dec, None, trav value, ann)
  92. | VarLet (dec, Some dims, value, ann) ->
  93. VarLet (dec, Some (trav_all dims), trav value, ann)
  94. | Return (value, ann) ->
  95. Return (trav value, ann)
  96. | If (cond, body, ann) ->
  97. If (trav cond, trav body, ann)
  98. | IfElse (cond, true_body, false_body, ann) ->
  99. IfElse (trav cond, trav true_body, trav false_body, ann)
  100. | While (cond, body, ann) ->
  101. While (trav cond, trav body, ann)
  102. | DoWhile (cond, body, ann) ->
  103. DoWhile (trav cond, trav body, ann)
  104. | For (counter, start, stop, step, body, ann) ->
  105. For (counter, trav start, trav stop, trav step, trav body, ann)
  106. | Allocate (dec, dims, ann) ->
  107. Allocate (dec, trav_all dims, ann)
  108. | Expr value ->
  109. Expr (trav value)
  110. | Block (body) ->
  111. Block (trav_all body)
  112. | Monop (op, value, ann) ->
  113. Monop (op, trav value, ann)
  114. | Binop (op, left, right, ann) ->
  115. Binop (op, trav left, trav right, ann)
  116. | Cond (cond, true_expr, false_expr, ann) ->
  117. Cond (trav cond, trav true_expr, trav false_expr, ann)
  118. | TypeCast (ctype, value, ann) ->
  119. TypeCast (ctype, trav value, ann)
  120. | FunCall (name, args, ann) ->
  121. FunCall (name, trav_all args, ann)
  122. | Arg value ->
  123. Arg (trav value)
  124. | ArrayInit (value, dims) ->
  125. ArrayInit (trav value, dims)
  126. | ArrayScalar value ->
  127. ArrayScalar (trav value)
  128. | Var (dec, Some dims, ann) ->
  129. Var (dec, Some (trav_all dims), ann)
  130. | VarUse (dec, Some dims, ann) ->
  131. VarUse (dec, Some (trav_all dims), ann)
  132. | FunUse (dec, params, ann) ->
  133. FunUse (dec, trav_all params, ann)
  134. | _ -> node
  135. let annotate a = function
  136. | Program (decls, ann) ->
  137. Program (decls, a :: ann)
  138. | FunDec (ret_type, name, params, ann) ->
  139. FunDec (ret_type, name, params, a :: ann)
  140. | FunDef (export, ret_type, name, params, body, ann) ->
  141. FunDef (export, ret_type, name, params, body, a :: ann)
  142. | GlobalDec (ctype, name, ann) ->
  143. GlobalDec (ctype, name, a :: ann)
  144. | GlobalDef (export, ctype, name, init, ann) ->
  145. GlobalDef (export, ctype, name, init, a :: ann)
  146. | VarDec (ctype, name, init, ann) ->
  147. VarDec (ctype, name, init, a :: ann)
  148. | Assign (name, dims, value, ann) ->
  149. Assign (name, dims, value, a :: ann)
  150. | VarLet (dec, dims, value, ann) ->
  151. VarLet (dec, dims, value, a :: ann)
  152. | Return (value, ann) ->
  153. Return (value, a :: ann)
  154. | If (cond, body, ann) ->
  155. If (cond, body, a :: ann)
  156. | IfElse (cond, true_body, false_body, ann) ->
  157. IfElse (cond, true_body, false_body, a :: ann)
  158. | While (cond, body, ann) ->
  159. While (cond, body, a :: ann)
  160. | DoWhile (cond, body, ann) ->
  161. DoWhile (cond, body, a :: ann)
  162. | For (counter, start, stop, step, body, ann) ->
  163. For (counter, start, stop, step, body, a :: ann)
  164. | Allocate (dec, dims, ann) ->
  165. Allocate (dec, dims, a :: ann)
  166. | Monop (op, value, ann) ->
  167. Monop (op, value, a :: ann)
  168. | Binop (op, left, right, ann) ->
  169. Binop (op, left, right, a :: ann)
  170. | Cond (cond, true_expr, false_expr, ann) ->
  171. Cond (cond, true_expr, false_expr, a :: ann)
  172. | TypeCast (ctype, value, ann) ->
  173. TypeCast (ctype, value, a :: ann)
  174. | FunCall (name, args, ann) ->
  175. FunCall (name, args, a :: ann)
  176. | Arg value ->
  177. Arg (value)
  178. | Var (dec, dims, ann) ->
  179. Var (dec, dims, a :: ann)
  180. | VarUse (dec, dims, ann) ->
  181. VarUse (dec, dims, a :: ann)
  182. | FunUse (dec, params, ann) ->
  183. FunUse (dec, params, a :: ann)
  184. | Const (BoolVal value, ann) ->
  185. Const (BoolVal value, a :: ann)
  186. | Const (IntVal value, ann) ->
  187. Const (IntVal value, a :: ann)
  188. | Const (FloatVal value, ann) ->
  189. Const (FloatVal value, a :: ann)
  190. | ArrayConst (value, ann) ->
  191. ArrayConst (value, a :: ann)
  192. | Param (ctype, name, ann) ->
  193. Param (ctype, name, a :: ann)
  194. | Dim (name, ann) ->
  195. Dim (name, a :: ann)
  196. | _ -> raise InvalidNode
  197. let rec annof = function
  198. | Program (_, ann)
  199. | Param (_, _, ann)
  200. | Dim (_, ann)
  201. | FunDec (_, _, _, ann)
  202. | FunDef (_, _, _, _, _, ann)
  203. | GlobalDec (_, _, ann)
  204. | GlobalDef (_, _, _, _, ann)
  205. | VarDec (_, _, _, ann)
  206. | Assign (_, _, _, ann)
  207. | VarLet (_, _, _, ann)
  208. | Return (_, ann)
  209. | If (_, _, ann)
  210. | IfElse (_, _, _, ann)
  211. | While (_, _, ann)
  212. | DoWhile (_, _, ann)
  213. | For (_, _, _, _, _, ann)
  214. | Allocate (_, _, ann)
  215. | Const (BoolVal _, ann)
  216. | Const (IntVal _, ann)
  217. | Const (FloatVal _, ann)
  218. | ArrayConst (_, ann)
  219. | Var (_, _, ann)
  220. | Monop (_, _, ann)
  221. | Binop (_, _, _, ann)
  222. | Cond (_, _, _, ann)
  223. | TypeCast (_, _, ann)
  224. | VarUse (_, _, ann)
  225. | FunUse (_, _, ann)
  226. | FunCall (_, _, ann) -> ann
  227. | ArrayInit (value, _)
  228. | ArrayScalar value
  229. | Expr value
  230. | Arg value -> annof value
  231. | _ -> raise InvalidNode
  232. let locof node =
  233. let rec trav = function
  234. | [] -> noloc
  235. | Loc loc :: _ -> loc
  236. | _ :: tl -> trav tl
  237. in trav (annof node)
  238. let depthof node =
  239. let rec trav = function
  240. | [] ->
  241. prerr_string "cannot get depth for: ";
  242. prt_node node;
  243. raise InvalidNode
  244. | Depth depth :: _ -> depth
  245. | _ :: tl -> trav tl
  246. in trav (annof node)
  247. let indexof node =
  248. let rec trav = function
  249. | [] ->
  250. prerr_string "cannot get index for: ";
  251. prt_node node;
  252. raise InvalidNode
  253. | Index index :: _ -> index
  254. | _ :: tl -> trav tl
  255. in trav (annof node)
  256. let typeof = function
  257. (* Some nodes have their type as property *)
  258. | VarDec (ctype, _, _, _)
  259. | Param (ctype, _, _)
  260. | FunDec (ctype, _, _, _)
  261. | FunDef (_, ctype, _, _, _, _)
  262. | GlobalDec (ctype, _, _)
  263. | GlobalDef (_, ctype, _, _, _)
  264. | TypeCast (ctype, _, _)
  265. -> ctype
  266. (* Dim nodes are always type Int, and are copied by context analysis before
  267. * they are annotated with Type Int, so this match is necessary *)
  268. | Dim _ -> Int
  269. (* Other nodes must be annotated during typechecking *)
  270. | node ->
  271. let rec trav = function
  272. | [] ->
  273. prerr_string "cannot get type for: ";
  274. prt_node node;
  275. raise InvalidNode
  276. | Type t :: _ -> t
  277. | _ :: tl -> trav tl
  278. in trav (annof node)
  279. let labelof node =
  280. let rec trav = function
  281. | [] ->
  282. prerr_string "cannot get label for: ";
  283. prt_node node;
  284. raise InvalidNode
  285. | LabelName label :: _ -> label
  286. | _ :: tl -> trav tl
  287. in trav (annof node)
  288. let const_type = function
  289. | BoolVal _ -> Bool
  290. | IntVal _ -> Int
  291. | FloatVal _ -> Float
  292. (*
  293. let get_line str n =
  294. let rec find_start from = function
  295. | n when n < 1 -> raise (Invalid_argument "n")
  296. | 1 -> from
  297. | n -> find_start ((String.index_from str from '\n') + 1) (n - 1)
  298. in
  299. let linestart = find_start 0 n in
  300. let len = String.length str in
  301. let lineend =
  302. try String.index_from str linestart '\n'
  303. with Not_found -> len
  304. in
  305. String.sub str linestart (lineend - linestart)
  306. *)
  307. let count_tabs str upto =
  308. let rec count n = function
  309. | 0 -> n
  310. | i -> count (if String.get str (i - 1) = '\t' then n + 1 else n) (i - 1)
  311. in count 0 upto
  312. let tabwidth = 4
  313. let retab str = global_replace (regexp "\t") (repeat " " tabwidth) str
  314. let indent n = repeat (repeat " " (tabwidth - 1)) n
  315. let prerr_loc (fname, ystart, yend, xstart, xend) =
  316. let file = open_in fname in
  317. (* skip lines until the first matched line *)
  318. for i = 1 to ystart - 1 do let _ = input_line file in () done;
  319. (* for each line in `loc`, print the source line with an underline *)
  320. for l = ystart to yend do
  321. let line = input_line file in
  322. let linewidth = String.length line in
  323. let left = if l = ystart then xstart else 1 in
  324. let right = if l = yend then xend else linewidth in
  325. if linewidth > 0 then (
  326. prerr_endline (retab line);
  327. prerr_string (indent (count_tabs line right));
  328. for i = 1 to left - 1 do prerr_char ' ' done;
  329. for i = left to right do prerr_char '^' done;
  330. prerr_endline "";
  331. )
  332. done;
  333. ()
  334. let prerr_loc_msg loc msg =
  335. if args.verbose >= 1 then (
  336. let (fname, ystart, yend, xstart, xend) = loc in
  337. if loc != noloc then (
  338. let line_s = if yend != ystart
  339. then sprintf "lines %d-%d" ystart yend
  340. else sprintf "line %d" ystart
  341. in
  342. let char_s = if xend != xstart || yend != ystart
  343. then sprintf "characters %d-%d" xstart xend
  344. else sprintf "character %d" xstart
  345. in
  346. eprintf "File \"%s\", %s, %s:\n" fname line_s char_s;
  347. );
  348. eprintf "%s\n" msg;
  349. if args.verbose >= 1 && loc != noloc then
  350. try prerr_loc loc
  351. with Sys_error _ -> ()
  352. );
  353. ()
  354. let block_body = function
  355. | Block nodes -> nodes
  356. | _ -> raise InvalidNode
  357. let basetypeof node = match typeof node with
  358. | ArrayDims (ctype, _)
  359. | Array ctype
  360. | ctype -> ctype
  361. let nameof = function
  362. | GlobalDec (_, name, _)
  363. | GlobalDef (_, _, name, _, _)
  364. | FunDec (_, name, _, _)
  365. | FunDef (_, _, name, _, _, _)
  366. | VarDec (_, name, _, _)
  367. | Param (_, name, _)
  368. | Dim (name, _) -> name
  369. | _ -> raise InvalidNode
  370. let optmap f = function
  371. | None -> None
  372. | Some lst -> Some (List.map f lst)
  373. let optmapl f = function
  374. | None -> []
  375. | Some lst -> List.map f lst
  376. let mapi f lst =
  377. let rec trav i = function
  378. | [] -> []
  379. | hd :: tl -> f i hd :: (trav (i + 1) tl)
  380. in trav 0 lst
  381. let is_immediate_const const =
  382. if args.optimize then List.mem const immediate_consts else false
  383. let is_array node = match typeof node with
  384. | ArrayDims _ | Array _ -> true
  385. | _ -> false
  386. let node_warning node msg =
  387. prerr_loc_msg (locof node) ("Warning: " ^ msg)