def main(debug, b_reg): """ in: bool debug, bool b register out: void """ ML = [] st = SymbolTable() if len(sys.argv) < 2: no_file_arg() input_file = sys.argv[1] name = os.path.splitext(input_file)[0] parsed = Parser(input_file, debug, b_reg) rom_address = 0 ram_address = 16 """ First pass """ while parsed.has_more_cmds(): if parsed.command_type() == "C_COMMAND" or parsed.command_type() == "A_COMMAND": rom_address += 1 elif parsed.command_type() == "L_COMMAND": st.add_entry(parsed.symbol(), rom_address) parsed.advance() parsed.reset() """ Second pass """ i = 0 while parsed.has_more_cmds(): cc = parsed.b_cc() # account for b reg command_type = parsed.command_type() if command_type == "A_COMMAND": """ Handle A commands. """ if st.contains(cc[1:]): ML.append(parsed.a_int_to_binary(st.get_address(cc[1:]))) elif parsed.cc_is_int(): ML.append(parsed.a_int_to_binary(cc)) elif not st.contains(cc[1:]): st.add_entry(cc[1:], ram_address) ML.append(parsed.a_int_to_binary(str(st.get_address(cc[1:])))) ram_address += 1 else: ML.append(parsed.c_to_binary(cc, command_type, st)) parsed.advance() i += 1 create_file(ML, name)
class Main(object): def __init__(self, f): self.asm_file = f self.table = SymbolTable() self.data = self.read_file() self.parser = Parser(self.data) self.commands = self.parser.commands self.translator = Translator() self.filename = self.asm_file.split(".")[0] def read_file(self): with open(self.asm_file) as f: data = f.readlines() return data def write_file(self, output_lines): with open('%sassembled.hack' % self.filename, 'w') as output_file: for line in output_lines: output_file.write(line + '\n') def assemble(self): self.first_pass() output_lines = self.second_pass() self.write_file(output_lines) def first_pass(self): program_line = 0 for line in self.commands: # if we have encountered a label pseudocommand # check if it is in the table, if not assign it to value of next program line # don't increment program counter because this shouldn't count as a program line if line[0] == '(': if not self.table.contains(line[1:-1]): self.table.add_entry(line[1:-1], program_line) continue # if none of these conditions are hit, keep incrementing program line program_line += 1 def second_pass(self): translated_commands = [] next_available_RAM = 16 for line in self.commands: if line[0] == '@': symbol = line[1:] try: # translate directly if @ is referencing a specific value translated_commands.append('{0:016b}'.format(int(symbol))) continue except ValueError: pass # check if symbol is already in the symbol table and convert value to binary if self.table.contains(symbol): translated_commands.append('{0:016b}'.format( self.table.get_address(symbol))) # add symbol to symbol table, increment available RAM count, and translate to binary else: self.table.add_entry(symbol, next_available_RAM) next_available_RAM += 1 translated_commands.append('{0:016b}'.format( self.table.get_address(symbol))) elif line[0] == '(': continue else: translated_commands.append( self.translator.handle_C_instruction(line)) return translated_commands
class Assembler(): ''' Takes a single .asm file as input and outputs a .hack file with the same name. The assembling takes three passes. - Preprocess: Remove whitespace and comments - First Pass: Generate symbol table and remove symbolic labels - Second Pass: Translates the .asm file into a .hack file, line by line. ''' def __init__(self, filename): self._input = self.preprocess(filename) self._name = filename.split('/')[-1] self._name = self._name.split('.')[0] self._table = SymbolTable() self.first_pass() self._parser = Parser(self._input) self._output = [] self._code = Code() self.second_pass() self.write_output() def preprocess(self, filename): with open(filename, 'r') as temp: assembly = temp.readlines() temp = [] for line in assembly: # remove comments and white space line = line.split('//')[0].strip().replace(' ', '') if line: # if nonempty, then it should contain valid asm temp += [line] return temp def first_pass(self): rom_addr = 0 temp = [] for line in self._input: if '(' in line: symbol = line[1:-1] self._table.add_entry(symbol, rom_addr) else: temp += [line] rom_addr += 1 self._input = temp def second_pass(self): while self._parser.has_more_commands(): self._parser.advance() if self._parser.command_type() == 'A': # A type command value = self._parser.symbol() if set(value) <= set('0123456789'): # symbol is a number value = int(value) elif self._table.contains(value): # symbol is a label value = self._table.get_address(value) else: # symbol is a variable self._table.add_entry(value) value = self._table.get_address(value) self._output += ['0' + "{0:015b}".format(value) + '\n'] elif self._parser.command_type() == 'C': # C type command self._output += [ '111' + self._code.comp(self._parser.comp()) + self._code.dest(self._parser.dest()) + self._code.jump(self._parser.jump()) + '\n' ] def write_output(self): with open('hack/' + self._name + '.hack', 'w') as temp: temp.writelines(self._output) print(self._name + '.asm', 'translated to', 'hack/' + self._name + '.hack')