assemble.ml 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. open Printf
  2. open Types
  3. open Util
  4. open Stringify
  5. let comline comment = InlineComment (EmptyLine, comment)
  6. let assemble program =
  7. let labcounter = ref 0 in
  8. let genlabel suffix =
  9. labcounter := !labcounter + 1;
  10. string_of_int !labcounter ^ "_" ^ suffix
  11. in
  12. let consts = Hashtbl.create 20 in
  13. let rec trav node =
  14. let rec trav_all = function
  15. | [] -> []
  16. | hd :: tl -> trav hd @ (trav_all tl)
  17. in
  18. let rec traverse_localfuns = function
  19. | LocalFuns body -> List.concat (List.map trav body)
  20. | Block body -> List.concat (List.map traverse_localfuns body)
  21. | _ -> []
  22. in
  23. match node with
  24. (* Global *)
  25. | Program (decls, _) ->
  26. trav_all decls
  27. | GlobalDef (_, ctype, name, _, _) ->
  28. [Comment (sprintf "global var \"%s\" at index %d" name (indexof node));
  29. Global ctype]
  30. | FunDec (ret_type, name, params, _) ->
  31. [Comment (sprintf "extern fun \"%s\" at index %d" name (indexof node));
  32. Import (name, ret_type, List.map typeof params)]
  33. | FunDef (export, ret_type, name, params, body, _) ->
  34. let label = labelof node in
  35. (if export then
  36. let param_types = List.map typeof params in
  37. [Export (name, ret_type, param_types, label)]
  38. else []) @
  39. [
  40. Comment (sprintf "fun \"%s\" with %d local vars" label (indexof node));
  41. Label label;
  42. RtnEnter (indexof node);
  43. ] @
  44. (trav body) @
  45. (match ret_type with Void -> [Ret Void] | _ -> []) @
  46. [EmptyLine] @
  47. (traverse_localfuns body)
  48. | VarDec (_, name, _, _) ->
  49. [comline (sprintf "local var \"%s\" at index %d" name (indexof node))]
  50. | LocalFuns _ -> []
  51. | Block body | VarDecs body -> trav_all body
  52. (* Statements *)
  53. | VarLet (dec, None, value, _) ->
  54. let store = match (depthof dec, depthof node) with
  55. | (0, _) -> Store (typeof dec, Glob, indexof dec)
  56. | (a, b) when a = b -> Store (typeof dec, Current, indexof dec)
  57. | (a, b) -> Store (typeof dec, Rel (b - a), indexof dec)
  58. in
  59. trav value @ [InlineComment (store, node2str node)]
  60. | Return (value, _) ->
  61. trav value @ [InlineComment (Ret (typeof value), node2str node)]
  62. | If (cond, body, _) ->
  63. let endlabel = genlabel "end" in
  64. (trav cond) @
  65. [Branch (false, endlabel);
  66. comline ("if (" ^ (node2str cond) ^ ") {")] @
  67. (trav body) @
  68. [comline "}";
  69. Label endlabel]
  70. | IfElse (cond, true_body, false_body, _) ->
  71. let elselabel = genlabel "else" in
  72. let endlabel = genlabel "end" in
  73. (trav cond) @
  74. [Branch (false, elselabel);
  75. comline ("if (" ^ (node2str cond) ^ ") {")] @
  76. (trav true_body) @
  77. [Jump endlabel;
  78. comline "} else {";
  79. Label elselabel] @
  80. (trav false_body) @
  81. [comline "}";
  82. Label endlabel]
  83. | While (cond, body, _) ->
  84. let startlabel = genlabel "while" in
  85. let endlabel = genlabel "end" in
  86. let com = ("while (" ^ (node2str cond) ^ ") {") in
  87. [Label startlabel] @
  88. (trav cond) @
  89. [InlineComment (Branch (false, endlabel), com)] @
  90. (trav body) @
  91. [Jump startlabel;
  92. Label endlabel;
  93. comline "}"]
  94. | DoWhile (cond, body, _) ->
  95. let startlabel = genlabel "dowhile" in
  96. let com = ("} while (" ^ (node2str cond) ^ ");") in
  97. [comline "do {";
  98. Label startlabel] @
  99. (trav body) @
  100. (trav cond) @
  101. [InlineComment (Branch (true, startlabel), com)]
  102. (* Expression statement pops the disregarded expression value from the
  103. * stack, if any *)
  104. | Expr value ->
  105. let pop = match typeof value with
  106. | Void -> [comline (node2str node)]
  107. | ctype -> [InlineComment (Pop ctype, node2str node)]
  108. in
  109. (trav value) @ pop
  110. (* Expressions *)
  111. | Const (BoolVal _ as value, _) ->
  112. [LoadImm value]
  113. | Const (value, _) ->
  114. Hashtbl.replace consts value (typeof node, indexof node);
  115. let load = LoadConst (typeof node, indexof node) in
  116. [InlineComment (load, node2str node)]
  117. | VarUse (dec, None, _) ->
  118. let load = match (depthof dec, depthof node) with
  119. | (0, _) -> Load (typeof dec, Glob, indexof dec)
  120. | (a, b) when a = b -> Load (typeof dec, Current, indexof dec)
  121. | (a, b) -> Load (typeof dec, Rel (b - a), indexof dec)
  122. in
  123. [InlineComment (load, node2str node)]
  124. | Monop (op, value, _) ->
  125. (trav value) @
  126. [InlineComment (Op (op, typeof value), op2str op)]
  127. | Binop (op, left, right, _) ->
  128. (trav left) @
  129. (trav right) @
  130. [InlineComment (Op (op, typeof left), op2str op)]
  131. | TypeCast (ctype, value, _) ->
  132. let vtype = typeof value in
  133. (match (ctype, vtype) with
  134. | (Float, Int) | (Int, Float) -> ()
  135. | _ -> raise (NodeError (node, "invalid typecast"))
  136. );
  137. trav value @ [Convert (vtype, ctype)]
  138. (* Function calls *)
  139. | FunUse (dec, args, _) ->
  140. let init = match (depthof dec, depthof node) with
  141. | (0, _) -> RtnInit Glob
  142. | (a, b) when a = b -> RtnInit Current
  143. | (a, b) when a = b + 1 -> RtnInit Local
  144. | (a, b) -> RtnInit (Rel (b - a))
  145. in
  146. let jmp = match dec with
  147. | FunDec _ -> RtnJmp (ExternFun (indexof dec))
  148. | FunDef _ -> RtnJmp (LocalFun (List.length args, labelof dec))
  149. | _ -> raise InvalidNode
  150. in
  151. init :: (trav_all args) @ [jmp]
  152. | Arg value -> trav value
  153. (* Conditional expression (short-circuit evaluation) *)
  154. (* <cond>
  155. * branch_f else
  156. * <true_expr>
  157. * jump end
  158. * else:
  159. * <false_expr>
  160. * end:
  161. *)
  162. | Cond (cond, texp, fexp, _) ->
  163. let elselabel = genlabel "false_expr" in
  164. let endlabel = genlabel "end" in
  165. (trav cond) @
  166. [Branch (false, elselabel)] @
  167. (trav texp) @
  168. [Jump (endlabel);
  169. Label (elselabel)] @
  170. (trav fexp) @
  171. [InlineComment (Label (endlabel), node2str node)]
  172. (* Arrays *)
  173. | Allocate (dec, dims, _) ->
  174. let store = match (depthof dec, depthof node) with
  175. | (0, _) -> Store (typeof dec, Glob, indexof dec)
  176. | (a, b) when a = b -> Store (typeof dec, Current, indexof dec)
  177. | _ -> raise InvalidNode
  178. in
  179. trav_all dims @
  180. [NewArray (basetypeof dec, List.length dims);
  181. InlineComment (store, node2str node)]
  182. | VarUse (dec, Some dims, _) ->
  183. let load = match (depthof dec, depthof node) with
  184. | (0, _) -> Load (typeof dec, Glob, indexof dec)
  185. | (a, b) when a = b -> Load (typeof dec, Current, indexof dec)
  186. | (a, b) -> Load (typeof dec, Rel (b - a), indexof dec)
  187. in
  188. (trav_all dims) @ (* push dimensions *)
  189. [InlineComment (load, nameof dec)] @ (* push array reference *)
  190. [InlineComment (LoadArray (basetypeof dec), node2str node)]
  191. | VarLet (dec, Some dims, value, _) ->
  192. let load = match (depthof dec, depthof node) with
  193. | (0, _) -> Load (typeof dec, Glob, indexof dec)
  194. | (a, b) when a = b -> Load (typeof dec, Current, indexof dec)
  195. | (a, b) -> Load (typeof dec, Rel (b - a), indexof dec)
  196. in
  197. (trav value) @ (* push value *)
  198. (trav_all dims) @ (* push dimensions *)
  199. [InlineComment (load, nameof dec)] @ (* push array reference *)
  200. [InlineComment (StoreArray (basetypeof dec), node2str node)]
  201. | _ -> [Comment ("FIXME: " ^ Stringify.node2str node)]
  202. (*| _ -> raise InvalidNode*)
  203. in
  204. let instrs = trav program in
  205. (* Sort aggregated constants and add definitions
  206. * If possible, this should be rewritten in the future because it's a little
  207. * cumbersome right now... *)
  208. let pairs = ref [] in
  209. let add_pair value (ctype, index) =
  210. let com = sprintf "index %d" index in
  211. pairs := (InlineComment (ConstDef (ctype, value), com), index) :: !pairs;
  212. in
  213. Hashtbl.iter add_pair consts;
  214. let cmp (_, i) (_, j) = compare i j in
  215. let sorted_pairs = List.sort cmp !pairs in
  216. let const_defs = List.map (fun (d, _) -> d) sorted_pairs in
  217. instrs @ const_defs
  218. let rec phase input =
  219. log_line 1 "- Assembly";
  220. match input with
  221. | Ast node -> Assembly (assemble node)
  222. | _ -> raise (InvalidInput "assembly")