- modify existing implementation to use variant types for a more accurate representation of the vm byte code - switch to fold from recursion for the main translate function - use separate modules for translating different vm commands - move static arithmetic command translations to a map
		
			
				
	
	
		
			62 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			OCaml
		
	
	
	
	
	
			
		
		
	
	
			62 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			OCaml
		
	
	
	
	
	
| open Core
 | |
| open Backend
 | |
| 
 | |
| let read_file file =
 | |
|   let lines = In_channel.read_lines file in
 | |
|   let not_empty str = not (String.is_empty str) in
 | |
|   List.filter lines ~f:not_empty
 | |
| 
 | |
| 
 | |
| let is_vm_file f =
 | |
|   match Filename.split_extension f with
 | |
|   | _, Some ext -> String.equal ext "vm"
 | |
|   | _, None -> false
 | |
| 
 | |
| 
 | |
| let generate_hack f =
 | |
|   let bytecode = read_file f in
 | |
|   let class_name = Filename.basename f in
 | |
|   Translate.translate class_name bytecode
 | |
| 
 | |
| 
 | |
| let write_hack path hack =
 | |
|   let output_channel = Out_channel.create path in
 | |
|   Out_channel.output_lines output_channel hack;
 | |
|   Out_channel.close output_channel
 | |
| 
 | |
| 
 | |
| let compile path =
 | |
|   let ext = ".asm" in
 | |
|   let absolute_path x = path ^ x in
 | |
|   let open Filename_base in
 | |
|     if Sys_unix.is_directory_exn path then
 | |
|       let output_file = concat path (basename path ^ ext) in
 | |
|       let hack =
 | |
|         path
 | |
|         |> Sys_unix.ls_dir
 | |
|         |> List.map ~f:absolute_path
 | |
|         |> List.filter ~f:is_vm_file
 | |
|         |> List.concat_map ~f:generate_hack
 | |
|         |> List.append Translate.bootstrap
 | |
|       in
 | |
|       write_hack output_file hack
 | |
|     else if Sys_unix.is_file_exn path && is_vm_file path then
 | |
|       let output_file = chop_extension path ^ ext in
 | |
|       let hack = generate_hack path in
 | |
|       write_hack output_file hack
 | |
|     else
 | |
|       failwith "Incompatible!"
 | |
| 
 | |
| 
 | |
| let command =
 | |
|   let summary = "Translate Jack byte code to Hack assembly" in
 | |
|   let readme () = "Compiler (backend) for project 7/8 of Nand2Tetris" in
 | |
|   let param_spec = Command.Param.(anon ("path" %: string)) in
 | |
|   let param_handler path () = compile path in
 | |
|   Command.basic
 | |
|     ~summary:summary ~readme:readme
 | |
|     (Command.Param.map param_spec ~f:param_handler)
 | |
| 
 | |
| 
 | |
| let () = Command_unix.run command
 |