def main(): parser = argparse.ArgumentParser(description='Process some integers.') parser.add_argument('asm_file', type=str, help='asm file') args = parser.parse_args() asm_file = args.asm_file save_file = os.path.splitext(asm_file)[0] + ".hack" st = SymbolTable() with HackParser(asm_file) as hp: op_address = 0 while hp.advance() != None: cmd_type = hp.command_type() if cmd_type == A_COMMAND or cmd_type == C_COMMAND: op_address += 1 elif cmd_type == L_COMMAND: st.add_entry(hp.symbol(), op_address) with HackParser(asm_file) as hp: with open(save_file, 'w') as wf: while hp.advance() != None: cmd_type = hp.command_type() if cmd_type == A_COMMAND: symbol = hp.symbol() m = symbol_pattern.match(symbol) if m.group(1): # @value bincode = "0" + int2bin(int(m.group(1)), 15) elif m.group(2): # @symbol symbol = m.group(2) if st.contains(symbol): address = st.get_address(symbol) bincode = "0" + int2bin(address, 15) else: st.add_variable(symbol) address = st.get_address(symbol) bincode = "0" + int2bin(address, 15) elif cmd_type == C_COMMAND: bincode = '111' + code_writer.comp( hp.comp()) + code_writer.dest( hp.dest()) + code_writer.jump(hp.jump()) if cmd_type != L_COMMAND: wf.write(bincode + '\n')
def main(): parser = argparse.ArgumentParser(description='Process some integers.') parser.add_argument('asm_file', type=str, help='asm file') args = parser.parse_args() asm_file = args.asm_file save_file = os.path.splitext(asm_file)[0] + ".hack" st = SymbolTable() with HackParser(asm_file) as hp: op_address = 0 while hp.advance() != None: cmd_type = hp.command_type() if cmd_type == A_COMMAND or cmd_type == C_COMMAND: op_address += 1 elif cmd_type == L_COMMAND: st.add_entry(hp.symbol(), op_address) with HackParser(asm_file) as hp: with open(save_file, 'w') as wf: while hp.advance() != None: cmd_type = hp.command_type() if cmd_type == A_COMMAND: symbol = hp.symbol() m = symbol_pattern.match(symbol) if m.group(1): # @value bincode = "0" + int2bin(int(m.group(1)), 15) elif m.group(2): # @symbol symbol = m.group(2) if st.contains(symbol): address = st.get_address(symbol) bincode = "0" + int2bin(address, 15) else: st.add_variable(symbol) address = st.get_address(symbol) bincode = "0" + int2bin(address, 15) elif cmd_type == C_COMMAND: bincode = '111' + code_writer.comp(hp.comp()) + code_writer.dest(hp.dest()) + code_writer.jump(hp.jump()) if cmd_type != L_COMMAND: wf.write(bincode + '\n')
def second_pass(): """ docstring """ code_parser = Parser(sys.argv[1]) memory_counter = 16 with open(output_file, 'w') as file_object: while (code_parser.has_more_commands()): code_parser.advance() word = '' if code_parser.command_type() == 'C_COMMAND': word = '111' + code_trans.comp( code_parser.comp()) + code_trans.dest( code_parser.dest()) + code_trans.jump( code_parser.jump()) + '\n' elif code_parser.command_type() == 'A_COMMAND': if is_integer(code_parser.symbol()): word = binary_word(code_parser.symbol()) + '\n' elif SymbolTable.contains(code_parser.symbol()): word = SymbolTable.get_address(code_parser.symbol()) + '\n' elif not SymbolTable.contains(code_parser.symbol()): SymbolTable.add_entry(code_parser.symbol(), binary_word(memory_counter)) word = binary_word(memory_counter) + '\n' memory_counter = memory_counter + 1 elif code_parser.command_type() == 'L_COMMAND': pass file_object.write(word)
def main(): filename = sys.argv[1].split('.')[0] symbol_table = SymbolTable() first_iter(symbol_table) parser = Parser(filename) code = Code() output = [] address = 16 while (parser.has_more_commands()): parser.advance() if parser.command_type() == 'C_COMMAND': dest = parser.dest() comp = parser.comp() jump = parser.jump() # print(parser.current_command, code.dest(dest), code.comp(comp), code.jump(jump)) output.append("111" + code.comp(comp) + code.dest(dest) + code.jump(jump)) else: symbol = parser.symbol() try: symbol_address = int(symbol) except: if not symbol_table.contains(symbol): symbol_table.add_entry(symbol, address) address += 1 symbol_address = symbol_table.get_address(symbol) finally: output.append(bin(symbol_address)[2:].zfill(16)) # print(parser.current_command, bin(symbol_table.get_address(symbol))) # if not symbol_table.contains(symbol): # symbol_table.add_entry(symbol, address) # address += 1 # symbol_address = symbol_table.get_address(symbol) # print(symbol_address) # output.append(bin(symbol_table.get_address(symbol))[2:].zfill(16)) # print(parser.current_command, bin(symbol_table.get_address(symbol))) # print(symbol_address) # output.append(bin(symbol_table.get_address(symbol))[2:].zfill(16)) # print(parser.current_command, bin(symbol_table.get_address(symbol))) parser.close() hack_file = open(filename + '.hack', 'w') for line in output: hack_file.write(line + '\n') hack_file.close()
def two_pass_assembly(self): symbol_table = SymbolTable() rom_address = 0 print("starting first pass") while(self.parser.has_more_commands()): cmd = self.parser.get_current_command() if(self.parser.commands.L_COMMAND==self.parser.command_type()): print "L: " + self.parser.symbol() symbol_table.add_entry(self.parser.symbol(),rom_address) else: rom_address += 1 self.parser.advance() self.parser.reset() #the second pass is the same as the first without the print statements, #and without handling (Xxx) syntax print("starting second pass") while(self.parser.has_more_commands()): cmd = self.parser.get_current_command() if(self.parser.commands.A_COMMAND==self.parser.command_type()): sym = self.parser.symbol() if(sym.isdigit()): val = sym else: if(symbol_table.contains(sym)): val = symbol_table.get_address(sym) else: symbol_table.add_entry(sym, rom_address) rom_address += 1 val = rom_address self.parser.output.write("0" + '{0:015b}'.format(int(val))+"\n") elif(self.parser.commands.C_COMMAND==self.parser.command_type()): self.parser.output.write("111" + self.code.comp(self.parser.comp()) + self.code.dest(self.parser.dest()) + self.code.jump(self.parser.jump()) +"\n") self.parser.advance()
class Assembler: def __init__(self): self._code = Code() self._lexer = Lexer() self._parser = Parser() self._symbol_table = SymbolTable() def assemble(self, path): # Read file content content = self._read_file_contents(path) # Lex the file contents self._lexer.lex(content) # Pass the tokens to ther parser self._parser.set_tokens(self._lexer.tokens()) # Build symbols self._build_symbols() # Translate to symbolless asm self._write_symbolless_asm(path) # Translate binary self._write_binary(path) def _write_symbolless_asm(self, path): basename = os.path.basename(path) name = basename.rsplit('.asm', 1)[0] file = open('%s/%sL.asm' % (os.path.dirname(path), name), 'w') self._parser.reset_pos() while self._parser.has_commands(): command_type = self._parser.command_type() if command_type is Command.L_COMMAND: self._parser.advance() continue elif command_type is Command.A_COMMAND: value = None symbol = self._parser.symbol() if symbol is not None: value = self._symbol_table.get_address(symbol) if value is None: sys.stderr.write('[Assembler]: Symbol not defined %s' % symbol) file.close() sys.exit(1) else: value = self._parser.value() file.write('@%s' % value) elif command_type in [ Command.C_COMMAND_JMP, Command.C_COMMAND_COMP ]: file.write(self._parser.text()) file.write('\n') self._parser.advance() file.close() def _write_binary(self, path): basename = os.path.basename(path) name = basename.rsplit('.asm', 1)[0] file = open('%s/%s.hack' % (os.path.dirname(path), name), 'w') binary = self._translate() file.write(binary) file.close() def _build_symbols(self): symbols_count = 0 self._init_symbol_table() # First pass - get label symbols while self._parser.has_commands(): if self._parser.command_type() is Command.L_COMMAND: symbol = self._parser.symbol() if self._symbol_table.contains(symbol): sys.stderr.write( '[Assembler]: Symbol %s is used more than once' % symbol) sys.exit(1) address = self._parser.pos() - symbols_count self._symbol_table.add_entry(symbol, address) symbols_count += 1 self._parser.advance() # Second pass - get variable symbols variable_address = 16 self._parser.reset_pos() while self._parser.has_commands(): command_type = self._parser.command_type() if command_type is Command.A_COMMAND: symbol = self._parser.symbol() if symbol is not None and \ not self._symbol_table.contains(symbol): address = variable_address self._symbol_table.add_entry(symbol, address) variable_address += 1 self._parser.advance() def _translate(self): output = '' self._parser.reset_pos() while self._parser.has_commands(): command_type = self._parser.command_type() if command_type is Command.A_COMMAND: symbol = self._parser.symbol() if symbol is not None: if not self._symbol_table.contains(symbol): sys.stderr.write('[Assembler]: Unknown symbol: %s' % symbol) sys.exit(1) address = self._symbol_table.get_address(symbol) output += self._to_binary(address) + '\n' else: value = self._parser.value() output += self._to_binary(int(value)) + '\n' elif command_type is Command.C_COMMAND_COMP: comp = self._code.comp(self._parser.comp()) dest = self._code.dest(self._parser.dest()) output += '111' + comp + dest + '000\n' elif command_type is Command.C_COMMAND_JMP: comp = self._code.comp(self._parser.comp()) jump = self._code.jump(self._parser.jump()) output += '111' + comp + '000' + jump + '\n' self._parser.advance() return output def _init_symbol_table(self): self._symbol_table.clear() entries = { 'SP': 0, 'LCL': 1, 'ARG': 2, 'THIS': 3, 'THAT': 4, 'SCREEN': 16384, 'KBD': 24576, } # R0 to R15 for address in range(16): entries['R%d' % address] = address # Initialize symbol table with predefined symbols for key, value in entries.items(): self._symbol_table.add_entry(key, value) def _read_file_contents(self, path): file = open(path, 'r') content = file.read() file.close() return content def _to_binary(self, value): return format(value, '016b')
class Assembler: def __init__(self, filename): self.asm_filename = filename self.hack_filename = self.asm_filename[:-3] + 'hack' self.outfile = open(self.hack_filename, 'w') self.parser = Parser(self.asm_filename) self.code = Code() self.symbol_table = SymbolTable() self.next_available_address = 16 def translate(self): """Translates all the commands in the .asm file, writing the resulting binary code to the .hack file. """ self.first_pass() self.parser.reset() self.second_pass() self.outfile.close() def first_pass(self): """Goes through the input file, adding all the labels to the symbol table. """ label = self.parser.first_label() while not self.parser.is_done(): self.symbol_table.add_entry(label, self.parser.label_address()) label = self.parser.next_label() def second_pass(self): """Goes through the input file fo a second time, translating the commands into binary, and adding symbols to the symbol table as required. """ while not self.parser.is_done(): self.process_command() self.parser.next_command() def process_command(self): """Translates the current command of the parser, writing the corresponding binary command to the output file (including a newline character). """ if self.parser.command_type() == 'C_COMMAND': self.process_c_command() elif self.parser.command_type() == 'A_COMMAND': self.process_a_command() else: #Command is a label return def process_c_command(self): """Translates the current C-command of the parser, writing the corresponding binary command to the output file (including a newline character). """ dest_binary = self.code.dest(self.parser.dest) comp_binary = self.code.comp(self.parser.comp) jump_binary = self.code.jump(self.parser.jump) binary_command = '111' + comp_binary + dest_binary + jump_binary self.outfile.write(binary_command + '\n') def process_a_command(self): """Translates the current C-command of the parser, writing the corresponding binary command to the output file (including a newline character). """ symbol = self.parser.symbol if symbol.isnumeric(): address = int(symbol) elif self.symbol_table.contains(symbol): address = self.symbol_table.get_address(symbol) else: address = self.next_available_address self.symbol_table.add_entry(symbol, address) self.next_available_address += 1 binary_command = self.binary_number(address) self.outfile.write(binary_command + '\n') def binary_number(self, symbol): """Takes a decimal number in the form of a string and converts it to a 16-bit binary number in the form of a string. """ binary = bin(int(symbol)) return binary[2:].zfill(16)
class Parser(): """Parser: Encapsulates access to the input code. Reads an assembly language command, parses it, and provides convenient access to the command's components (fields and symbols). In addition, removes all white space and comments.""" def __init__(self, in_file): """Get the input file and gets ready to parse it. Instantiate a Code2bin for binary translation""" self.in_file = in_file self.code2bin = Code2Bin() self.symb_table = SymbolTable() def read_in_file(self): """Read the input file and process lines, put lines containing codes to a buffer""" self.code_contents = [] ROM_address = 0 with open(self.in_file, 'r', encoding='utf_8') as inf: for line in inf: command = self.process(line) # If returned command is an empty line after processed, skip it if not command: continue self.code_contents.append(command) cmd_type = self.command_type(command) if cmd_type == 'L_COMMAND': # cmd_type is 'L_COMMAND', add new entry to the symbol table symbol = self.get_symbol(command) self.symb_table.add_entry(symbol, ROM_address) else: ROM_address += 1 def process(self, line): """Removes all white space and comments""" return line.split('//')[0].strip() def command_type(self, command): """ Returns the type of the current command: A_COMMAND for @Xxx where Xxx is either a symbol or a decimal number C_COMMAND for dest=comp;jump (Either the dest or jump fields may be empty. If dest is empty, the "=" is omitted; If jump is empty, the ";" is omitted.) L_COMMAND (pseudo-command) for (Xxx) where Xxx is a symbol """ if '@' in command: return 'A_COMMAND' elif '=' in command or ';' in command: return 'C_COMMAND' elif '(' in command and ')' in command: return 'L_COMMAND' def get_symbol(self, command): """Returns the symbol or decimal Xxx of the current command @Xxx or (Xxx). Should be called only when command_type() is A_COMMAND or L_COMMAND.""" return command.replace('@', '').replace('(', '').replace(')', '') def get_dest_comp_jump(self, command): """Returns the dest, comp, jump mnemonic in the current C-command. Should be called only when command_type()is C_COMMAND""" if ';' not in command: dest, comp = command.split('=') jump = 'null' elif '=' not in command: dest = 'null' comp, jump = command.split(';') else: dest = command.split('=')[0] comp, jump = command.split('=')[1].split(';') # jump = command.split('=')[1].split(';')[1] return dest, comp, jump def translate(self): """Second pass, translate code_contents to binary contens""" self.out_binarys = [] available_RAM_address = 16 for command in self.code_contents: cmd_type = self.command_type(command) if cmd_type == 'A_COMMAND': symbol = self.get_symbol(command) if symbol.isdigit(): binary_line = '0{:015b}'.format(int(symbol)) self.out_binarys.append(binary_line) elif self.symb_table.contains(symbol): binary_line = '0{:015b}'.format( int(self.symb_table.get_address(symbol))) self.out_binarys.append(binary_line) else: self.symb_table.add_entry(symbol, available_RAM_address) binary_line = '0{:015b}'.format(available_RAM_address) self.out_binarys.append(binary_line) available_RAM_address += 1 elif cmd_type == 'C_COMMAND': dest, comp, jump = self.get_dest_comp_jump(command) dest_binary = self.code2bin.dest2bin(dest) comp_binary = self.code2bin.comp2bin(comp) jump_binary = self.code2bin.jump2bin(jump) binary_line = '111' + comp_binary + dest_binary + jump_binary self.out_binarys.append(binary_line) def write_out_binarys(self): out_file = self.in_file.replace('asm', 'hack') with open(out_file, 'w', encoding='utf_8') as outf: for binary in self.out_binarys: outf.write(binary + '\n') print(out_file, 'finished assembling.') def parse(self): self.read_in_file() self.translate() self.write_out_binarys()
def main(): filename = os.path.join(os.getcwd(), Util.getCommandLineArg(1)) first_parser = Parser(filename) second_parser = Parser(filename) symbol_table = SymbolTable() hack_filename = filename.replace('asm', 'hack') hack_file = open(hack_filename, 'w') ann_filename = filename.replace('asm', 'ann') ann_file = open(ann_filename, 'w') rom_address = 0 ram_address = 16 assembly = '' while first_parser.has_more_commands(): first_parser.advance() if first_parser.command_type() is 'A_COMMAND' or first_parser.command_type() is 'C_COMMAND': rom_address += 1 elif first_parser.command_type() is 'L_COMMAND': symbol_table.add_entry(first_parser.symbol(), rom_address, 'LAB') while second_parser.has_more_commands(): second_parser.advance() machine_command = '' if second_parser.command_type() is 'A_COMMAND': if second_parser.symbol()[0].isdigit(): binary = second_parser.symbol() else: if symbol_table.contains(second_parser.symbol()): binary = symbol_table.get_address(second_parser.symbol()) else: binary = ram_address symbol_table.add_entry(second_parser.symbol(), ram_address, 'VAR') ram_address += 1 machine_command = '{0:016b}\n'.format(int(binary)) hack_file.write(machine_command) elif second_parser.command_type() is 'C_COMMAND': dest = Code.dest(second_parser.dest()) comp = Code.comp(second_parser.comp()) jump = Code.jump(second_parser.jump()) machine_command = '111{0}{1}{2}\n'.format(comp, dest, jump) hack_file.write(machine_command) assembly = second_parser.original_command().strip() mc = machine_command.strip() annotated_machine = '{} {} {} {}'.format(mc[0:4], mc[4:8], mc[8:12], mc[12:16]) symbolless_command = '' if second_parser.command_type() is 'L_COMMAND': symbolless_command = symbol_table.get_address(second_parser.symbol()) elif second_parser.command_type() is 'A_COMMAND' and not second_parser.symbol().isdigit(): symbolless_command = '@{}'.format(symbol_table.get_address(second_parser.symbol())) else: symbolless_command = second_parser.command annotated_command = '{:<39} {} {:<11} {}\n'.format(assembly, '//' if second_parser.command_type() else '', symbolless_command, annotated_machine) ann_file.write(annotated_command) ann_file.write('\n// Symbol Table:\n') for symbol, address in symbol_table.symbol_table.items(): ann_file.write('// {}: {:<30} -> {}\n'.format(address[1], symbol, address[0])) hack_file.close() ann_file.close()
def main(): # If there is an invalid number of arguments the program stops. if len(sys.argv) != 2: print("ERROR: Invalid number of arguments. Expected: file_name.asm ") exit(1) # The assembler only accepts asm files to be translated into hack files elif sys.argv[1][-4:] != ".asm": print("ERROR: Invalid file type. Expected: asm file") exit(1) input_file = sys.argv[1] # Initialize the symbol table with the predefined symbols. symbol_table = SymbolTable() translator_c_command = Code() # Counters to keep track of the ROM and RAM memory address. count_ROM = 0 count_variable = 16 # List containing all the translated commands from the file. commands_translation = [] # First pass parser = Parser(input_file) # Reads the whole file. while parser.has_more_commands(): parser.advance() # Checks if the current command is has a label to and adds it to the table. if parser.command_type() == "L_COMMAND": # Takes the symbol from the label. label = parser.symbol() # Check if the label does not start with a number and adds the symbol to the table. if not label[0].isdigit(): symbol_table.add_entry(label, count_ROM) else: print("ERROR: invalid label indentifier") exit(1) else: # If it finds an A_COMMAND or C_COMMAND adds one to the ROM counter. count_ROM += 1 # Reset the parser pointer to read the file parser.file.seek(0) # Second pass #Reads the whole file while parser.has_more_commands(): parser.advance() # Checks if the current command is type "A_COMMAND". if parser.command_type() == "A_COMMAND": # Get the variable variable = parser.symbol() # Checks the variable starts with a letter. if not variable[0].isdigit(): # If the table does not contain the symbol, adds it to the table, does the translation to binary code, # adds it to the list of translations and ads one to the RAM counter. if not symbol_table.contains(variable): symbol_table.add_entry(variable, count_variable) binary_address = "{:016b}".format(count_variable) commands_translation.append(binary_address) count_variable += 1 # If the table contains the symbol, gets the address associated with the symbol, # does the translation to binary code and adds it to the translated list. else: address = symbol_table.get_address(variable) binary_address = "{:016b}".format(address) commands_translation.append(binary_address) # Check if the variable is a number, translates it to its binary code and adds it to the translated list. elif variable.isdigit(): binary_address = "{:016b}".format(int(variable)) commands_translation.append(binary_address) # If the variable is not a number o starts with a letter theres a mistake in the command and the program stops. else: print("ERROR: The symbol " + variable + " is invalid") exit(1) # Check if the current command is type "C_COMMAND". elif parser.command_type() == "C_COMMAND": # Gets the dest, comp and jump mnemonic. command_dest = parser.dest() command_comp = parser.comp() command_jump = parser.jump() # Translates each mnemonic into its binary code. binary_dest = translator_c_command.dest(command_dest) binary_comp = translator_c_command.comp(command_comp) binary_jump = translator_c_command.jump(command_jump) # Put together all the binary codes addring three '1's at the beging and adds it to the translated list. binary_code = "111" + binary_comp + binary_dest + binary_jump commands_translation.append(binary_code) # Creates the hack file using the input file dot_index = input_file.find(".") hack_file = input_file[:dot_index] + ".hack" # Opens the hack file, if it does not exist creates it file = open(hack_file, "w") # For each command in the translated list, writes the binary code on the hack file and adds a new line for command in commands_translation: file.write(command) file.write("\n") # Close the hack file file.close() exit(0)
line_address += 1 parser.seek_head() var_address = 16 while parser.has_more_commands(): parser.advance() if parser.command_type() == 'L_COMMAND': continue elif parser.command_type() == 'A_COMMAND': symbol = parser.symbol() if symbol.isdigit(): address = int(symbol) elif symbol_table.contains(symbol): address = symbol_table.get_address(symbol) else: address = var_address symbol_table.add_entry(symbol, address) var_address += 1 machine_code = address elif parser.command_type() == 'C_COMMAND': comp = Code.comp(parser.comp()) dest = Code.dest(parser.dest()) jump = Code.jump(parser.jump()) machine_code = 0b111 << 13 | comp << 6 | dest << 3 | jump machine_code_str = "{0:016b}".format(machine_code) hack_file.write(machine_code_str + '\n')
# If the address is already taken increment it by 1 until a free spot in RAM is found # Generates all A and C-command mnemonics and binaries while not assembly_program.is_parsed(): current_command = assembly_program.advance() command_type = assembly_program.get_command_type(current_command) if command_type == 'A_COMMAND': symbol = current_command[1:] # Check if the A_COMMAND is a decimal number or a @symbol (variable) if assembly_program.is_decimal(symbol): translated_program.append(convert_to_bin(symbol)) elif not symbol_table.contains_symbol(symbol): symbol_table.add_symbol(symbol) translated_program.append( convert_to_bin(symbol_table.get_address(symbol))) else: translated_program.append( convert_to_bin(symbol_table.get_address(symbol))) else: # It's a C_COMMAND dest_mnemonics = assembly_program.get_dest_mnemonics(current_command) comp_mnemonics = assembly_program.get_comp_mnemonics(current_command) jump_mnemonics = assembly_program.get_jump_mnemonics(current_command) # Generate a Translator object, # which contains the converted command mnemonics to bits mnemonics_to_bin = Translator(dest_mnemonics, comp_mnemonics, jump_mnemonics) c_command_bin = '111' + mnemonics_to_bin.comp_bits + \
class Assembler: def __init__(self): self.table = SymbolTable() self.address = 16 def first_pass(self, filename): # first pass: advancing through file step by step to build up symbol table p = Parser(filename) current_address = 0 while p.has_more_commands(): p.advance() c_type = p.command_type() if c_type == Commands.C_COMMAND or c_type == Commands.A_COMMAND: # incrementing the instruction address current_address += 1 elif c_type == Commands.L_COMMAND: # adding new symbol/label to table self.table.add_entry(p.symbol(), current_address) def second_pass(self, filename): # second pass: actually generate the binary for each instruction using the # symbol table built up from the first pass p = Parser(filename) # creating new file name, with .hack ending newfile = filename.split('.')[0] + '.hack' with open(newfile, 'w') as f: while p.has_more_commands(): p.advance() c_type = p.command_type() if c_type == Commands.C_COMMAND: d, c, j = p.tokenize_C_inst() line = code.get_C_inst(d, c, j) elif c_type == Commands.A_COMMAND: # we need to check if the symbol is in the table and get its value line = code.get_A_inst(self.check_symbol(p.symbol())) else: # if its anything else, don't write anything and start again from # next line continue # writing the line to file f.write(line + '\n') f.close() def check_symbol(self, symbol): # method for checking if the symbol is a symbol and getting its value # from the table if symbol.isdigit(): # if it's a digit, then return itself since we want that value return symbol else: if symbol not in self.table.table: # if not in table, then add it to the table starting from address 16 self.table.add_entry(symbol, self.address) self.address += 1 return self.table.get_address(symbol) def assemble(self, filename): #print('First pass...') self.first_pass(filename) #print('Second pass...') self.second_pass(filename)
class AssmParser(AssmCommandType, Parser): def __init__(self, file_name): """ Open the input file/stream and gets ready to parse it """ super(AssmParser, self).__init__(file_name) self.RAM = 16 self.symbol_table = SymbolTable(self.buff) self.symbol_table.find_symbols() def symbol(self): """ returns the symbol or decimal Xxx of the current command @Xxx of (Xxx). Should be called only when commandType() is A_COMMAND or L_COMMAND return string """ self.current_symbol = self.current_command[1:] def dest(self): """ returns the dest mnemonic in the current C_COMMAND (8 possibilities). Should be called only when AssmCommandType() is C_COMMAND returns string """ # semicolon: 000 dest if '=' in self.current_command: d = self.current_command.split('=')[0] else: d='null' code = Code() self.current_dest = code.dest(d) def comp(self): """ Returns the comp menomonic in the current C_COMMAND (28 possibilities) Should be called only when commandType() is C_COMMAND return string """ if '=' in self.current_command: c = self.current_command.split('=')[1] elif ';' in self.current_command: c = self.current_command.split(';')[0] code = Code() self.current_comp, self.current_a = code.comp(c) #def a(self): ##TODO: figure out how to know 'a' bit ## I believe it has to do whether the previous command is an l or a command #self.current_a = '0' def jump(self): """ Returns the jump mnemonic in the current C_COMMAND (8 possibilities) Should be called only when commandType() is C_COMMAND returns string """ # equal: 000 jump if ';' in self.current_command: j = self.current_command.split(';')[1] elif '=' in self.current_command: j='null' else: j = None code = Code() self.current_jump = code.jump(j) def __repr__(self): return self.asmfile + '\n'.join(self.buff) def binarize_c_command(self): self.comp() self.dest() self.jump() self.bin_current = '111' + self.current_a + self.current_comp + self.current_dest + self.current_jump def binarize_a_symbol(self): if not self.symbol_table.contains(self.current_command): self.symbol_table.addEntry(self.current_command, self.RAM) self.RAM = self.RAM + 1 address = self.symbol_table.get_address(self.current_command) bin_address = bin(address)[2:] self.bin_current = '0' * (16 - len(bin_address)) + bin_address def binarize_a_address(self): address = int(self.current_command[1:]) bin_address = bin(address)[2:] self.bin_current = '0'*(16 - len(bin_address)) + bin_address def binarize_a_command(self): if re.match(r'^@[0-9].*$', self.current_command): self.binarize_a_address() else: self.binarize_a_symbol()
class Assembler(object): """ lalala """ def __init__(self, asm_file): self.asm_file = asm_file self.hack_file = ''.join([asm_file.split('.')[0], '.hack']) self.parser = Parser(asm_file) self.code = Code() self.symbol_table = SymbolTable() def assembly(self): print('Starting to assembly {} file...'.format(self.asm_file)) with open(self.hack_file, 'w') as hack_f: ################## ### First pass ### ################## line_number = 0 while self.parser.advance(): command_type = self.parser.command_type() if command_type == self.parser.c_command or command_type == self.parser.a_command: line_number += 1 elif command_type == self.parser.l_command: symbol = self.parser.symbol() self.symbol_table.add_entry(symbol, line_number) else: raise ValueError('Ups!') ################### ### Second pass ### ################### next_var_address = 16 while self.parser.advance(): command_type = self.parser.command_type() if command_type == self.parser.c_command: dest_bin = self.code.dest_mnemonic[self.parser.dest()] comp_bin = self.code.comp_mnemonic[self.parser.comp()] jump_bin = self.code.jump_mnemonic[self.parser.jump()] word_16 = ''.join( ['111', comp_bin, dest_bin, jump_bin, '\n']) elif command_type == self.parser.a_command: symbol = self.parser.symbol() if symbol.isdigit(): address_bin = format(int(symbol), 'b').zfill(15) else: if self.symbol_table.contains(symbol) == False: self.symbol_table.add_entry( symbol, next_var_address) next_var_address += 1 address_int = self.symbol_table.get_address(symbol) address_bin = format(address_int, 'b').zfill(15) word_16 = ''.join(['0', address_bin, '\n']) elif command_type == self.parser.l_command: continue else: raise ValueError('Ups!') hack_f.write(word_16) print('Successfully finished the assembly process :)')
def main(): filename = os.path.join(os.getcwd(), Util.getCommandLineArg(1)) first_parser = Parser(filename) second_parser = Parser(filename) symbol_table = SymbolTable() hack_filename = filename.replace('asm', 'hack') hack_file = open(hack_filename, 'w') ann_filename = filename.replace('asm', 'ann') ann_file = open(ann_filename, 'w') rom_address = 0 ram_address = 16 assembly = '' while first_parser.has_more_commands(): first_parser.advance() if first_parser.command_type( ) is 'A_COMMAND' or first_parser.command_type() is 'C_COMMAND': rom_address += 1 elif first_parser.command_type() is 'L_COMMAND': symbol_table.add_entry(first_parser.symbol(), rom_address, 'LAB') while second_parser.has_more_commands(): second_parser.advance() machine_command = '' if second_parser.command_type() is 'A_COMMAND': if second_parser.symbol()[0].isdigit(): binary = second_parser.symbol() else: if symbol_table.contains(second_parser.symbol()): binary = symbol_table.get_address( second_parser.symbol()) else: binary = ram_address symbol_table.add_entry(second_parser.symbol(), ram_address, 'VAR') ram_address += 1 machine_command = '{0:016b}\n'.format(int(binary)) hack_file.write(machine_command) elif second_parser.command_type() is 'C_COMMAND': dest = Code.dest(second_parser.dest()) comp = Code.comp(second_parser.comp()) jump = Code.jump(second_parser.jump()) machine_command = '111{0}{1}{2}\n'.format(comp, dest, jump) hack_file.write(machine_command) assembly = second_parser.original_command().strip() mc = machine_command.strip() annotated_machine = '{} {} {} {}'.format(mc[0:4], mc[4:8], mc[8:12], mc[12:16]) symbolless_command = '' if second_parser.command_type() is 'L_COMMAND': symbolless_command = symbol_table.get_address( second_parser.symbol()) elif second_parser.command_type( ) is 'A_COMMAND' and not second_parser.symbol().isdigit(): symbolless_command = '@{}'.format( symbol_table.get_address(second_parser.symbol())) else: symbolless_command = second_parser.command annotated_command = '{:<39} {} {:<11} {}\n'.format( assembly, '//' if second_parser.command_type() else '', symbolless_command, annotated_machine) ann_file.write(annotated_command) ann_file.write('\n// Symbol Table:\n') for symbol, address in symbol_table.symbol_table.items(): ann_file.write('// {}: {:<30} -> {}\n'.format( address[1], symbol, address[0])) hack_file.close() ann_file.close()