print.ml 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. open Types
  2. open Util
  3. open Stringify
  4. let tab = " "
  5. let si = string_of_int
  6. let rec repeat s n = if n < 1 then "" else s ^ (repeat s (n - 1))
  7. let expand n text = text ^ repeat " " (n - String.length text)
  8. let ctype2str = Stringify.type2str
  9. let type2str = function
  10. | Array (t, dims) -> ctype2str t ^ repeat "," (List.length dims - 1)
  11. | t -> ctype2str t
  12. let op2str = function
  13. | Neg -> "neg"
  14. | Not -> "not"
  15. | Add -> "add"
  16. | Sub -> "sub"
  17. | Mul -> "mul"
  18. | Div -> "div"
  19. | Mod -> "rem"
  20. | Eq -> "eq"
  21. | Ne -> "ne"
  22. | Lt -> "lt"
  23. | Le -> "le"
  24. | Gt -> "gt"
  25. | Ge -> "ge"
  26. | _ -> raise (CompileError ("operator unsupported by VM"))
  27. let prefix = function
  28. | Bool _ -> "b"
  29. | Int _ -> "i"
  30. | Float _ -> "f"
  31. | Void -> ""
  32. | _ -> "a"
  33. let rec instr2str = function
  34. (* Global / directives *)
  35. | Comment comment ->
  36. if args.verbose >= 2 then "# " ^ comment else ""
  37. | InlineComment (instr, comment) ->
  38. if args.verbose >= 2 then
  39. expand 20 (instr2str instr) ^ "# " ^ comment
  40. else ""
  41. | Label name ->
  42. name ^ ":"
  43. | Export (name, ret_type, arg_types, label) ->
  44. let types = List.map type2str (ret_type :: arg_types) in
  45. ".export \"" ^ name ^ "\" " ^ (String.concat " " types) ^ " " ^ label
  46. | Import (name, ret_type, arg_types) ->
  47. let types = List.map type2str (ret_type :: arg_types) in
  48. ".import \"" ^ name ^ "\" " ^ (String.concat " " types)
  49. | Global ctype ->
  50. ".global " ^ (type2str ctype)
  51. | ConstDef node ->
  52. ".const " ^ (const2str node)
  53. (* Store *)
  54. | StoreGlob (ctype, index) ->
  55. tab ^ prefix ctype ^ "storeg " ^ si index
  56. | StoreLoc (ctype, index) ->
  57. tab ^ prefix ctype ^ "store " ^ si index
  58. | StoreRel (ctype, nesting, index) ->
  59. tab ^ prefix ctype ^ "storen " ^ si nesting ^ " " ^ si index
  60. (* Load *)
  61. | LoadGlob (ctype, index) ->
  62. tab ^ prefix ctype ^ "loadg " ^ si index
  63. | LoadLoc (ctype, index) ->
  64. tab ^ prefix ctype ^ "load " ^ si index
  65. | LoadRel (ctype, nesting, index) ->
  66. tab ^ prefix ctype ^ "loadn " ^ si nesting ^ " " ^ si index
  67. | LoadConst (ctype, index) ->
  68. tab ^ prefix ctype ^ "loadc " ^ si index
  69. | LoadImm (Const (BoolVal b, _)) ->
  70. tab ^ "bloadc_" ^ (if b then "t" else "f")
  71. | LoadImm (Const (IntVal i, _)) when i < 0 ->
  72. tab ^ "iloadc_m" ^ si (-i)
  73. | LoadImm (Const (IntVal i, _)) ->
  74. tab ^ "iloadc_" ^ si i
  75. | LoadImm (Const (FloatVal i, _)) ->
  76. tab ^ "floadc_" ^ si (int_of_float i)
  77. | Op (op, ctype) ->
  78. tab ^ prefix ctype ^ op2str op
  79. | Convert (src, tgt) ->
  80. tab ^ prefix src ^ "2" ^ prefix tgt
  81. (* Control flow *)
  82. | RtnEnter stack_len ->
  83. tab ^ "esr " ^ si stack_len
  84. | Ret ctype ->
  85. tab ^ prefix ctype ^ "return"
  86. | EmptyLine -> ""
  87. | DummyInstr -> tab ^ "<dummy>"
  88. | _ -> tab ^ "<unknown instruction>"
  89. let rec print_assembly oc instrs =
  90. let output_line line =
  91. output_string oc line;
  92. output_char oc '\n';
  93. in
  94. let endbuf = ref [] in
  95. let rec trav = function
  96. | [] -> ()
  97. | hd :: tl ->
  98. let line = instr2str hd in
  99. (if String.length line > 0 && line.[0] = '.' then
  100. endbuf := line :: !endbuf
  101. else
  102. output_line line
  103. );
  104. trav tl
  105. in
  106. trav instrs;
  107. if List.length !endbuf > 1 then (
  108. output_line (instr2str (Comment ("globals:")));
  109. let cmp a b = compare (String.sub a 0 7) (String.sub b 0 7) in
  110. List.iter output_line (List.sort cmp (List.rev !endbuf))
  111. ); ()
  112. let phase = function
  113. | Ast node as input ->
  114. if args.verbose >= 2 then (
  115. prerr_endline "--------------------------------------------------";
  116. prerr_endline (node2str node);
  117. prerr_endline "--------------------------------------------------"
  118. );
  119. input
  120. | FileContent (display_name, content) as input ->
  121. if args.verbose >= 2 then (
  122. prerr_endline "--------------------------------------------------";
  123. prerr_endline (display_name ^ ":\n");
  124. prerr_endline content;
  125. prerr_endline "--------------------------------------------------"
  126. );
  127. input
  128. | Assembly instrs as input ->
  129. (match args.outfile with
  130. | Some filename ->
  131. let oc = open_out filename in
  132. print_assembly oc instrs;
  133. close_out oc
  134. | None ->
  135. if args.verbose >= 2 then
  136. prerr_endline "--------------------------------------------------";
  137. print_assembly stdout instrs;
  138. );
  139. input
  140. | _ -> raise (InvalidInput "print")