nand2tetris/projects/06/assembler/lib/Translate.ml

79 lines
1.8 KiB
OCaml
Raw Normal View History

2022-07-18 19:16:54 +00:00
open Base
open Ast
open Predef
2022-07-19 17:27:14 +00:00
let add_symbol map k d = if Map.mem map k then map else Map.add_exn map ~key:k ~data:d
2022-07-18 19:16:54 +00:00
let rec first_pass exprs st loc =
match exprs with
| [] -> st
2022-07-19 17:27:14 +00:00
| Ginstr s :: t -> first_pass t (add_symbol st s loc) loc
| (Ainstr _ | Cinstr _) :: t -> first_pass t st (loc + 1)
| _ :: t -> first_pass t st loc
2022-07-18 19:16:54 +00:00
;;
let rec second_pass exprs st loc =
2022-07-19 17:27:14 +00:00
let is_new s =
try
Int.of_string s |> ignore;
false
with
| Failure _ -> not (Map.mem st s)
in
2022-07-18 19:16:54 +00:00
match exprs with
| [] -> st
2022-07-19 17:27:14 +00:00
| Ainstr a :: t when is_new a -> second_pass t (add_symbol st a loc) (loc + 1)
| _ :: t -> second_pass t st loc
;;
2022-07-18 19:16:54 +00:00
let translate_ainstr addr st =
2022-07-19 17:27:14 +00:00
let to_int addr =
try Map.find_exn st addr with
| Not_found_s _ -> Int.of_string addr
in
let pad binary =
2022-07-18 19:16:54 +00:00
let length = 16 - String.length binary in
let prefix = String.init length ~f:(fun _ -> '0') in
2022-07-19 17:27:14 +00:00
String.concat [ prefix; binary ]
in
2022-07-18 19:16:54 +00:00
let rec to_binary a =
match a with
| 0 -> ""
| _ ->
let rem = a % 2 in
2022-07-19 17:27:14 +00:00
(match rem with
| 0 -> to_binary (a / 2) ^ "0"
| _ -> to_binary (a / 2) ^ "1")
in
2022-07-18 19:16:54 +00:00
pad (to_binary (to_int addr))
;;
2022-07-19 17:27:14 +00:00
let translate_cinstr (d, c, j) = String.concat [ "111"; comp c; dest d; jump j ]
2022-07-18 19:16:54 +00:00
2022-07-19 17:27:14 +00:00
let rec _translate exprs st tt =
2022-07-18 19:16:54 +00:00
match exprs with
| [] -> tt
2022-07-19 17:27:14 +00:00
| Ainstr a :: t -> translate_ainstr a st :: _translate t st tt
| Cinstr (d, c, j) :: t -> translate_cinstr (d, c, j) :: _translate t st tt
| _ :: t -> _translate t st tt
2022-07-18 19:16:54 +00:00
;;
let parse s =
let lexbuf = Lexing.from_string s in
2022-07-19 17:27:14 +00:00
let ast = Parser.prog Lexer.read lexbuf in
2022-07-18 19:16:54 +00:00
ast
;;
2022-07-19 17:27:14 +00:00
let generate_exprs lines = List.map lines ~f:parse
2022-07-18 19:16:54 +00:00
2022-07-19 17:27:14 +00:00
let generate_st exprs =
2022-07-18 19:16:54 +00:00
let _st = first_pass exprs symbols 0 in
second_pass exprs _st 16
;;
2022-07-19 17:27:14 +00:00
let translate lines =
2022-07-18 19:16:54 +00:00
let exprs = generate_exprs lines in
let st = generate_st exprs in
_translate exprs st []
;;