util.ml 15 KB

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