from argparse import ArgumentParser from .memory import translate_memory from .arith_logic import translate_arith_logic from .compare import translate_compare from .utils import * def vm_translate(input_path): # program name, for static variable labels input_fn = input_path.split("/")[-1] prog = input_fn[:-3] if input_fn.endswith(".vm") else input_fn try: input_file = open(input_path) except: exit_on_error(f"Cannot open input file: {input_fn}", EXIT_CODE_FILE_ERROR) # load all vm commands from file vm_cmds = [] line = input_file.readline() while line: cmd = line.rstrip("\n").split("//", maxsplit=1)[0].strip() if cmd: vm_cmds.append(cmd) line = input_file.readline() input_file.close() asm = "" for cmd in vm_cmds: # tokenize vm_line, hand to sub-translators based on first token match cmd.split(): case []: continue case [("push" | "pop") as action, segment, index]: asm += translate_memory(action, segment, index, prog) case [("add" | "sub" | "neg" | "and" | "or" | "not") as command]: asm += translate_arith_logic(command) case [("lt" | "eq" | "gt") as command]: asm += translate_compare(command) case _: exit_on_error( f"Syntax error: invalid command: {cmd}", EXIT_CODE_SYNTAX_ERROR ) output_path = ( input_path[:-3] + ".asm" if input_path.endswith(".vm") else input_path + ".asm" ) try: output_file = open(output_path, "w") except: exit_on_error(f"Cannot open output file: {output_fn}", EXIT_CODE_FILE_ERROR) output_file.write(asm) output_file.close() print(f"Assembly written to {output_path}") if __name__ == "__main__": parser = ArgumentParser("hack-vm") parser.add_argument("input_path", help="input file in HACK VM") args = parser.parse_args() vm_translate(args.input_path)