util.ml 16 KB

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