binary_code = [] ram_address = 16 flag = 0 register_symble(parser, symbol_table) parser.reset_idx() while parser.hasMoreCommands(): parser.advance() cmdtype = parser.commandType() if cmdtype == "A_COMMAND": symbol = parser.symbol() if re.search("[A-Za-z]", symbol) != None: if symbol_table.contains(symbol): address = symbol_table.getAddress(symbol) #16進数 else: address = format(ram_address, '04x') #16進数 symbol_table.addEntry(symbol, address) ram_address += 1 symbol = int(address, 16) binary = bin(int(symbol))[2:] bit16 = ("0" * (16 - len(binary))) + binary elif cmdtype == "C_COMMAND": dest_bin = code.dest2bin(parser.dest()) comp_bin = code.comp2bin(parser.comp()) jump_bin = code.jump2bin(parser.jump()) bit16 = "111" + comp_bin + dest_bin + jump_bin
class Parser(object): A_CMD = 'A_COMMAND' C_CMD = 'C_COMMAND' L_CMD = 'L_COMMAND' def __init__(self, file_name): self.lines = [] self.current_position = 0 self.symbol_table = SymbolTable() self.readInFile(file_name) self.addLabelsToSymbolTable() self.substituteVars() def readInFile(self, file_name): with open (file_name, "r") as fp: for line in fp.readlines(): line = line.strip() # skip empty newlines and comments if not line or line.startswith("//"): continue self.lines.append(line.split()[0]) def addLabelsToSymbolTable(self): line_count = 1 while (self.hasMoreCommands()): self.advance() if self.commandType() == Parser.L_CMD: # TODO check this, this is wonky self.symbol_table.addEntry(self.symbol(), line_count-1) else: line_count += 1 # reset current_position after reading self.current_position = 0 def substituteVars(self): while (self.hasMoreCommands()): self.advance() if self.commandType() != Parser.A_CMD: continue var = self.symbol() if var.isdigit(): continue if not self.symbol_table.contains(var): self.symbol_table.addEntry(var) self.lines[self.current_position-1] = "@{}".format(self.symbol_table.getAddress(var)) # reset current_position after reading self.current_position = 0 def commandType(self): if not self.current_command: raise Exception("current_command is empty") if self.current_command.startswith("@"): return self.A_CMD if self.current_command.startswith("("): return self.L_CMD return self.C_CMD def hasMoreCommands(self): return self.current_position < len(self.lines) def advance(self): self.current_command = self.lines[self.current_position] self.current_position += 1 def symbol(self): return self.current_command.strip("@()") def dest(self): if len(self.current_command.split("=")) == 2: return self.current_command.split("=")[0] def comp(self): if len(self.current_command.split(";")) == 2: return self.current_command.split(";")[0] elif len(self.current_command.split("=")) == 2: return self.current_command.split("=")[1] def jump(self): if len(self.current_command.split(";")) == 2: return self.current_command.split(";")[1]
class Parser: def __init__(self, assembly_path: str) -> None: self.coder = Code() self.symbol_table = SymbolTable() self.assembly = [] self.idx = 0 f = open(assembly_path, 'r') while True: line = f.readline() if not line: break if line[:2] == "//": continue if [e for e in line if e != " "] == ["\n"]: continue self.assembly.append(line) f.close() def reset_idx(self): self.idx = 0 def hasMoreCommands(self) -> bool: return self.idx < len(self.assembly) def advance(self) -> None: if self.hasMoreCommands(): self.idx += 1 def commandType(self) -> str: if self.hasMoreCommands(): curr = self.assembly[self.idx] if "@" in curr: print("A", curr) return A elif "=" in curr or ";" in curr: print("C", curr) return C elif "(" in curr: return L else: return None def symbol(self) -> str: symbol = "".join([s for s in self.assembly[self.idx] if s != " "]) symbol = symbol.split("\n")[0] if self.commandType() == A: symbol = symbol[1:] if not self.symbol_table.contains(symbol): try: address = int(symbol) self.symbol_table.addEntry(symbol, str(address)) except: self.symbol_table.addEntry(symbol, str(self.symbol_table.idx)) self.symbol_table.advance() self.assembly[ self.idx] = "@" + self.symbol_table.getAddress(symbol) elif self.commandType() == L: symbol = symbol[1:-1] if not self.symbol_table.contains(symbol): self.symbol_table.addEntry(symbol, str(self.idx)) self.assembly = self.assembly[:self.idx] + self.assembly[self.idx + 1:] else: return "" return self.symbol_table.getAddress(symbol) def dest(self) -> str: if self.commandType() == C: return self.coder.dest(self.assembly[self.idx]) else: raise NotImplementedError def comp(self) -> str: if self.commandType() == C: return self.coder.comp(self.assembly[self.idx]) else: raise NotImplementedError def jump(self) -> str: if self.commandType() == C: return self.coder.jump(self.assembly[self.idx]) else: raise NotImplementedError # def address(self) -> str: # if self.commandType() == A: # return self.coder.address(self.assembly[self.idx]) # else: # raise NotImplementedError def address(self) -> str: instruction = self.assembly[self.idx] instruction = "".join([i for i in instruction if i != " "]) instruction = instruction[1:].split("\n")[0] if self.symbol_table.contains(instruction): address = self.symbol_table.getAddress(instruction) else: address = instruction b = bin(int(address))[2:] address = "0" * (16 - len(b)) + b return address
def assemble(self): # # first pass - build the symbol table for labels # parser = Parser(self.source_filename) symbol_table = SymbolTable() # the current instruction instruction = 0 # parse each command while parser.hasMoreCommands(): # advance to the next command parser.advance() # parse the command type and look for symbols command_type = parser.commandType() if command_type == "L": # look for an instruction label symbol symbol = parser.symbol() if symbol not in symbol_table: symbol_table.addEntry(symbol, instruction) else: # increment the instruction count if this was not a label if command_type != "L": instruction += 1 # # second pass - build the symbol table for variables # parser = Parser(self.source_filename) # the memory location for the next variable variable_address = 16 # parse each command while parser.hasMoreCommands(): # advance to the next command parser.advance() # parse the command type and look for symbols command_type = parser.commandType() if command_type == "A": # look for a variable value symbol symbol = parser.symbol() if symbol[0] not in map(str, range(0, 10)): # the symbol is not a number; that is, it is actually a symbol if symbol not in symbol_table: symbol_table.addEntry(symbol, variable_address) variable_address += 1 # # third pass - generate assembly # parser = Parser(self.source_filename) code = Code() # parse all commands while parser.hasMoreCommands(): # advance to the next command parser.advance() command_type = parser.commandType() if command_type == "A": # a command symbol = parser.symbol() if symbol in symbol_table: symbol = symbol_table.getAddress(symbol) symbol_binary = code.decimalToBinary(symbol) self.destination_file.write("0" + symbol_binary + "\n") elif command_type == "C": # c command comp = code.comp(parser.comp()) dest = code.dest(parser.dest()) jump = code.jump(parser.jump()) self.destination_file.write("111" + comp + dest + jump + "\n") elif command_type == "L": # label - do nothing in this stage pass else: # unknown command raise Exception("ERROR: Unknown command type encountered") # close the output file self.destination_file.close()
class AssemblerSymb: def __init__(self, path): self.parser = Parser(path) self.code = Code() self.symb_table = SymbolTable() ind1 = path.find('/') ind2 = path.find('.') writefile = path[:ind1] + "/" + path[ind1+1:ind2] self.file = open(writefile + '2.hack', 'w') def binary(self, s): return "{0:b}".format(int(s)) def firstPass(self): counter = 0 while self.parser.hasMoreCommands(): self.parser.advance() command_type = self.parser.commandType() if command_type in ['A_COMMAND', 'C_COMMAND']: counter += 1 elif command_type == 'L_COMMAND': symbol = self.parser.symbol() self.symb_table.addEntry(symbol, counter) else: raise ValueError("Unexpected command type encountered") def secondPass(self): ram_address = 16 self.parser.i = -1 while self.parser.hasMoreCommands(): self.parser.advance() command_type = self.parser.commandType() if command_type == 'A_COMMAND': symbol = self.parser.symbol() if (not symbol.isdigit()) and (not self.symb_table.contains(symbol)): self.symb_table.addEntry(symbol, ram_address) ram_address += 1 def createOutput(self): self.parser.i = -1 while self.parser.hasMoreCommands(): self.parser.advance() command_type = self.parser.commandType() # if A command if command_type == 'A_COMMAND': symbol = self.parser.symbol() if symbol.isdigit(): bin_symbol = self.binary(symbol) else: symb_add = self.symb_table.getAddress(symbol) bin_symbol = self.binary(symb_add) a_command = '0' * (16 - len(bin_symbol)) + bin_symbol self.file.write(a_command + '\n') elif command_type == 'C_COMMAND': dest_mnem = self.parser.dest() dest = self.code.dest(dest_mnem) comp_mnem = self.parser.comp() comp = self.code.comp(comp_mnem) jump_mnem = self.parser.jump() jump = self.code.jump(jump_mnem) c_command = '111' + comp + dest + jump self.file.write(c_command + '\n') else: pass self.file.close()