def main(infile): # read the input file into a list, remove whitespace input = [] binary_lines = [] with open(infile) as f: input = f.readlines() # first pass, build symbol table parser = Parser(input) symbol_table = SymbolTable() rom_addr = 0 while parser.has_more_commands(): parser.advance() try: if parser.command_type( ) == parser.C_COMMAND or parser.command_type() == parser.A_COMMAND: rom_addr += 1 elif parser.command_type() == parser.L_COMMAND: symbol = parser.symbol() symbol_table.add_entry(symbol, rom_addr) except ParseError as err: print("Parser error. Expression: {}. Error detail: {}".format( err.expression, err.message)) exit(1) # second pass parser = Parser(input) ram_addr = 16 while parser.has_more_commands(): parser.advance() try: if parser.command_type() == parser.A_COMMAND: symbol = parser.symbol() try: # if the symbol is a constant (int), translate it int_symbol = int(symbol) binary_lines.append(translate_a_instruction(int_symbol)) except ValueError: # symbol is not an integer, so either look it up, or its a new variable if symbol_table.contains(symbol): binary_lines.append( translate_a_instruction( symbol_table.get_address(symbol))) else: symbol_table.add_entry(symbol, ram_addr) binary_lines.append(translate_a_instruction(ram_addr)) ram_addr += 1 elif parser.command_type() == parser.C_COMMAND: # Translate C command binary_lines.append( translate_c_instruction(parser.comp(), parser.dest(), parser.jump())) except ParseError as err: print("Parser error. Expression: {}. Error detail: {}".format( err.expression, err.message)) exit(1) # translation is done. output to new .hack file outfile = infile.replace(".asm", "") outfile = "{}.hack".format(outfile) with open(outfile, "w") as f: for line in binary_lines: f.write(line) f.write("\n")
def main(input): infiles = [] # determine if the inputs is a directory or vmfile if re.search("\.vm$", input): # input is a single .vm file infiles.append(input) output = input.strip(".vm") output = "{}.asm".format(output) else: # input is a directory # output file name should be <dirname>.asm located in that directory try: files = os.listdir(input) for f in files: if re.search("\.vm$", f): infiles.append(os.path.join(input, f)) # generate output filename input = re.sub("/$", "", input) output = os.path.join(os.path.abspath(input), "{}.asm".format(os.path.split(input)[1])) except Exception as e: print("Error attempting to read directory: {}".format(e)) exit(1) # if empty, output error and exit if not infiles: print("No files found with .vm suffix in {} directory. Exiting".format( input)) exit(1) # single code generator for all vm files, single ASM output code_gen = CodeGenerator() asm_output = code_gen.generate_init() #asm_output = [] # loop through all .vm files for file in infiles: # open and load the file into a list vm_input = [] with open(file) as f: vm_input = f.readlines() vmfile = file.strip(".vm") vmfile = os.path.split(vmfile)[-1] # each vm file gets its own parser parser = Parser(vm_input) while parser.has_more_commands(): # set vmfile name, used to generate static variable symbols code_gen.vmfile = vmfile parser.advance() try: if parser.command_type() is config.C_EMPTY_LINE: # skip whitespace/blank lines continue elif parser.command_type() in config.PUSH_POP_COMMANDS: asm_output.extend( code_gen.generate_push_pop(parser.command_type(), parser.arg1(), parser.arg2())) elif parser.command_type() == config.C_ARITHMETIC: asm_output.extend( code_gen.generate_arithmetic(parser.arg1())) elif parser.command_type() == config.C_LABEL: asm_output.extend(code_gen.generate_label(parser.arg1())) elif parser.command_type() == config.C_GOTO: asm_output.extend(code_gen.generate_goto(parser.arg1())) elif parser.command_type() == config.C_IF: asm_output.extend(code_gen.generate_if(parser.arg1())) elif parser.command_type() == config.C_FUNCTION: asm_output.extend( code_gen.generate_function(parser.arg1(), parser.arg2())) elif parser.command_type() == config.C_CALL: asm_output.extend( code_gen.generate_call(parser.arg1(), parser.arg2())) elif parser.command_type() == config.C_RETURN: asm_output.extend(code_gen.generate_return()) except ParseError as err: print( "Parser error. Expression: <{}>. Error detail: {}".format( err.expression, err.message)) exit(1) except CodeError as err: print( "Code generator error. Expression: <{}>. Error detail: {}". format(err.expression, err.message)) exit(1) # write out asm file with open(output, "w") as f: for line in asm_output: f.write(line) f.write("\n")