move assembler out of project dir
This commit is contained in:
1
projects/06/assembler/.gitignore
vendored
1
projects/06/assembler/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
_build
|
@@ -1,2 +0,0 @@
|
||||
profile = janestreet
|
||||
version = 0.24.1
|
@@ -1 +0,0 @@
|
||||
|
@@ -1,31 +0,0 @@
|
||||
open Core
|
||||
open Hack
|
||||
|
||||
let read_file file =
|
||||
let not_empty str = not (String.is_empty str) in
|
||||
List.filter (In_channel.read_lines file) ~f:not_empty
|
||||
;;
|
||||
|
||||
let outfile file = String.concat [ Filename.chop_extension file; ".hack" ]
|
||||
|
||||
let gen_hack file =
|
||||
let assembly = read_file file in
|
||||
let binary = Translate.translate assembly in
|
||||
let outchan = Out_channel.create (outfile file) in
|
||||
Out_channel.output_lines outchan binary;
|
||||
Out_channel.close outchan
|
||||
;;
|
||||
|
||||
let param =
|
||||
let open Command.Param in
|
||||
anon ("filename" %: string)
|
||||
;;
|
||||
|
||||
let command =
|
||||
Command.basic
|
||||
~summary:"Translate <filename>.asm to <filename>.hack"
|
||||
~readme:(fun () -> "Assembler for project 6 of Nand2Tetris")
|
||||
(Command.Param.map param ~f:(fun filename () -> gen_hack filename))
|
||||
;;
|
||||
|
||||
let () = Command_unix.run command
|
@@ -1,3 +0,0 @@
|
||||
(executable
|
||||
(name assembler)
|
||||
(libraries hack core core_unix.command_unix))
|
@@ -1,2 +0,0 @@
|
||||
(lang dune 3.3)
|
||||
(using menhir 2.0)
|
@@ -1,6 +0,0 @@
|
||||
type expr =
|
||||
| Comment of string
|
||||
| Aconst of int
|
||||
| Ainstr of string
|
||||
| Ginstr of string
|
||||
| Cinstr of string * string * string
|
@@ -1,24 +0,0 @@
|
||||
{
|
||||
open Parser
|
||||
}
|
||||
|
||||
let white = [' ' '\t']+
|
||||
let comment = "//" _*
|
||||
let newline = '\n' | '\r'
|
||||
let digit = ['0'-'9']
|
||||
let letter = ['a'-'z' 'A'-'Z']
|
||||
let special = ['.' '$' '_' '-' '+' '&' '!' '|']
|
||||
let id = (digit | letter | special)+
|
||||
|
||||
|
||||
rule read =
|
||||
parse
|
||||
| white { read lexbuf }
|
||||
| "@" { AT }
|
||||
| "(" { LPAREN }
|
||||
| ")" { RPAREN }
|
||||
| ";" { SCOLON }
|
||||
| "=" { EQUALS }
|
||||
| comment as c { COMMENT (c) }
|
||||
| id as id { ID (id) }
|
||||
| eof { EOF }
|
@@ -1,30 +0,0 @@
|
||||
%{
|
||||
open Ast
|
||||
%}
|
||||
|
||||
%token <string> ID
|
||||
%token <string> COMMENT
|
||||
%token AT
|
||||
%token LPAREN
|
||||
%token RPAREN
|
||||
%token SCOLON
|
||||
%token EQUALS
|
||||
%token EOF
|
||||
|
||||
%start <Ast.expr> prog
|
||||
|
||||
%%
|
||||
|
||||
prog:
|
||||
| e = expr; EOF { e }
|
||||
;
|
||||
|
||||
expr:
|
||||
| c = COMMENT { Comment c }
|
||||
| AT; a = ID; { Ainstr a }
|
||||
| LPAREN; s = ID; RPAREN { Ginstr s }
|
||||
| c = ID; SCOLON; j = ID { Cinstr ("", c, j) }
|
||||
| d = ID; EQUALS; c = ID { Cinstr (d, c, "") }
|
||||
| c = ID; { Cinstr ("", c, "") }
|
||||
| e = expr; COMMENT { e }
|
||||
;
|
@@ -1,89 +0,0 @@
|
||||
open Base
|
||||
|
||||
let symbols =
|
||||
Map.of_alist_exn
|
||||
(module String)
|
||||
[ "R0", 0
|
||||
; "R1", 1
|
||||
; "R2", 2
|
||||
; "R3", 3
|
||||
; "R4", 4
|
||||
; "R5", 5
|
||||
; "R6", 6
|
||||
; "R7", 7
|
||||
; "R8", 8
|
||||
; "R9", 9
|
||||
; "R10", 10
|
||||
; "R11", 11
|
||||
; "R12", 12
|
||||
; "R13", 13
|
||||
; "R14", 14
|
||||
; "R15", 15
|
||||
; "SP", 0
|
||||
; "LCL", 1
|
||||
; "ARG", 2
|
||||
; "THIS", 3
|
||||
; "THAT", 4
|
||||
; "SCREEN", 16384
|
||||
; "KBD", 24576
|
||||
]
|
||||
;;
|
||||
|
||||
let comp c =
|
||||
match c with
|
||||
| "0" -> "0101010"
|
||||
| "1" -> "0111111"
|
||||
| "-1" -> "0111010"
|
||||
| "D" -> "0001100"
|
||||
| "A" -> "0110000"
|
||||
| "M" -> "1110000"
|
||||
| "!D" -> "0001101"
|
||||
| "!A" -> "0110001"
|
||||
| "!M" -> "1110001"
|
||||
| "-D" -> "0001111"
|
||||
| "-A" -> "0110011"
|
||||
| "-M" -> "1110011"
|
||||
| "D+1" -> "0011111"
|
||||
| "A+1" -> "0110111"
|
||||
| "M+1" -> "1110111"
|
||||
| "D-1" -> "0001110"
|
||||
| "A-1" -> "0110010"
|
||||
| "M-1" -> "1110010"
|
||||
| "D+A" -> "0000010"
|
||||
| "D+M" -> "1000010"
|
||||
| "D-A" -> "0010011"
|
||||
| "D-M" -> "1010011"
|
||||
| "A-D" -> "0000111"
|
||||
| "M-D" -> "1000111"
|
||||
| "D&A" -> "0000000"
|
||||
| "D&M" -> "1000000"
|
||||
| "D|A" -> "0010101"
|
||||
| "D|M" -> "1010101"
|
||||
| _ -> failwith "Unknown COMP Instruction"
|
||||
;;
|
||||
|
||||
let dest d =
|
||||
match d with
|
||||
| "" -> "000"
|
||||
| "M" -> "001"
|
||||
| "D" -> "010"
|
||||
| "MD" -> "011"
|
||||
| "A" -> "100"
|
||||
| "AM" -> "101"
|
||||
| "AD" -> "110"
|
||||
| "ADM" -> "111"
|
||||
| _ -> failwith "Unknown DEST Instruction"
|
||||
;;
|
||||
|
||||
let jump j =
|
||||
match j with
|
||||
| "" -> "000"
|
||||
| "JGT" -> "001"
|
||||
| "JEQ" -> "010"
|
||||
| "JGE" -> "011"
|
||||
| "JLT" -> "100"
|
||||
| "JNE" -> "101"
|
||||
| "JLE" -> "110"
|
||||
| "JMP" -> "111"
|
||||
| _ -> failwith "Unknown JUMP Instruction"
|
||||
;;
|
@@ -1,74 +0,0 @@
|
||||
open Base
|
||||
open Ast
|
||||
open Predef
|
||||
|
||||
let add_symbol map k d = if Map.mem map k then map else Map.add_exn map ~key:k ~data:d
|
||||
|
||||
let rec first_pass exprs st loc =
|
||||
match exprs with
|
||||
| [] -> st
|
||||
| Ginstr s :: t -> first_pass t (add_symbol st s loc) loc
|
||||
| (Ainstr _ | Aconst _ | Cinstr _) :: t -> first_pass t st (loc + 1)
|
||||
| _ :: t -> first_pass t st loc
|
||||
;;
|
||||
|
||||
let rec second_pass exprs st loc =
|
||||
let is_new a = not (Map.mem st a) in
|
||||
match exprs with
|
||||
| [] -> st
|
||||
| Ainstr a :: t when is_new a -> second_pass t (add_symbol st a loc) (loc + 1)
|
||||
| _ :: t -> second_pass t st loc
|
||||
;;
|
||||
|
||||
let translate_ainstr addr =
|
||||
let pad binary =
|
||||
let length = 16 - String.length binary in
|
||||
let prefix = String.init length ~f:(fun _ -> '0') in
|
||||
String.concat [ prefix; binary ]
|
||||
in
|
||||
let rec to_binary a =
|
||||
match a with
|
||||
| 0 -> ""
|
||||
| _ ->
|
||||
let rem = a % 2 in
|
||||
(match rem with
|
||||
| 0 -> to_binary (a / 2) ^ "0"
|
||||
| _ -> to_binary (a / 2) ^ "1")
|
||||
in
|
||||
pad (to_binary addr)
|
||||
;;
|
||||
|
||||
let translate_cinstr (d, c, j) = String.concat [ "111"; comp c; dest d; jump j ]
|
||||
|
||||
let parse s =
|
||||
let lexbuf = Lexing.from_string s in
|
||||
let ast = Parser.prog Lexer.read lexbuf in
|
||||
let eval_ainstr str =
|
||||
try Aconst (Int.of_string str) with
|
||||
| Failure _ -> Ainstr str
|
||||
in
|
||||
let _parse expr =
|
||||
match expr with
|
||||
| Ainstr str -> eval_ainstr str
|
||||
| _ -> expr
|
||||
in
|
||||
_parse ast
|
||||
;;
|
||||
|
||||
let generate_exprs lines = List.map lines ~f:parse
|
||||
let generate_st exprs = second_pass exprs (first_pass exprs symbols 0) 16
|
||||
|
||||
let rec _translate exprs st tt =
|
||||
match exprs with
|
||||
| [] -> tt
|
||||
| Aconst a :: t -> translate_ainstr a :: _translate t st tt
|
||||
| Ainstr a :: t -> translate_ainstr (Map.find_exn st a) :: _translate t st tt
|
||||
| Cinstr (d, c, j) :: t -> translate_cinstr (d, c, j) :: _translate t st tt
|
||||
| _ :: t -> _translate t st tt
|
||||
;;
|
||||
|
||||
let translate lines =
|
||||
let exprs = generate_exprs lines in
|
||||
let st = generate_st exprs in
|
||||
_translate exprs st []
|
||||
;;
|
@@ -1,8 +0,0 @@
|
||||
(ocamllex Lexer)
|
||||
|
||||
(menhir
|
||||
(modules Parser))
|
||||
|
||||
(library
|
||||
(name hack)
|
||||
(libraries base))
|
Reference in New Issue
Block a user