''' 1. Kreieren der Symboltabelle 2. Einlesen der Datei a. Entfernen der Kommentare -- erledigt b. Suchen der (Label) und Ablegen dieser in die Symboltabelle -- erledigt c. Entfernen der (Label) aus dem ASM-File d. HACK-Code erzeugen ''' import sys, os from pathlib import Path import re from icecream import ic symboltable = {} asm = [] def appendTable(table, id, item): print("appendTable ",id, " ", item ) table["@"+ str(item)] = id symboltable = table def createSymboltable(): return { key: (value) for key, value in { **{'@SP': 0, '@LCL': 1, '@ARG': 2, '@THIS': 3, '@THAT': 4, '@SCREEN': 0x4000, '@KBD': 0x6000,}, **{f'@R{i}': i for i in range(16)} }.items()} def load_asm_file(filename): fp = open(filename, 'r') comment = r"^/" eol = r"^\n" tmp = [] t = fp.readlines() for l in t: if re.match(comment, l): pass elif re.match(eol, l): pass else: tmp.append(re.sub('\s', '', l).split('//')[0]) # Wenn noch ein Kommentar hinter der Anweisung steht dann Abtrenen fp.close() #ic("tmp = ", tmp) return tmp def label_to_symboltable(data): #ic(len(data)) i = 0 tmp = {} for l in data: if (l.startswith('(') and l.endswith(')')): l = l[:-1] l = l.lstrip('(') tmp['@'+str(l)] = i #ic(l) else: i=i+1 if len(tmp) != 0: symboltable.update(tmp) #ic(symboltable) #ic (data) # c. Löschen der (Label) aus der Liste count = 0 for i in tmp: #ic(tmp[i]) # Zeilennummern data.pop(tmp[i]-count) #ic(len(data)) searchSymbols(data) def searchSymbols(asm): ''' wenn Zeile mit @ beginnt schauen ob Variable in Symboltable sonst ist Variable @x ein int, dann ohne @ in die Symboltable übernehmen ''' #ic(asm) i = 16 for line in asm: if line.startswith('@'): if line[1:].isdigit(): if line not in symboltable: addtoSymboltable(line, int(line[1:])) elif line not in symboltable: addtoSymboltable(line, i) i = i+1 def ciinstruction(ci): c = "111" if ci.__contains__('='): c2 = ci.split('=') comp = c2[1] dest = c2[0] c = c + c_comp(comp) + c_dest(dest) +"000" elif ci.__contains__(";"): jmp = ci.split(';') comp = jmp[0] jmpinst = jmp[1] c = c + c_comp(comp) + "000" + c_jump(jmpinst) return c +"\n" def c_jump(jmp): match jmp: case "JGT": return "001" case "JEQ": return "010" case "JGE": return "011" case "JLT": return "100" case "JNE": return "101" case "JLE": return "110" case "JMP": return "111" case _: return "000" def c_comp(comp): match comp: # A = 0 case "D": return "0001100" case "0": return "0001100" case "1": return "0111111" case "-1": return "0111010" case "A": return "0110000" case "!D": return "0001101" case "!A": return "0110001" case "-D": return "0001111" case "-A": return "0110011" case "D+1": return "0011111" case "A+1": return "0110111" case "D-1": return "0001110" case "A-1": return "0110010" case "D+A": return "0000010" case "D-A": return "0010011" case "A-D": return "0000111" case "D&A": return "0000000" case "D|A": return "0010101" # a = 1 case "M": return "1110000" case "!M": return "1110001" case "-M": return "1110011" case "M+1": return "1110111" case "M-1": return "1110010" case "D+M": return "1000010" case "D-M": return "1010011" case "M-D": return "1000111" case "D&M": return "1000000" case "D|M": return "1010101" case _: return "" def c_dest(dest): match dest: case "M": return "001" case "D": return "010" case "MD": return "011" case "A": return "100" case "AM": return "101" case "AD": return "110" case "AMD": return "111" case _: return "000" #return '{0:016b}'.format(c)+"\n" #return bin(c)[2:]+"\n" # 111 in binär --> falscher Weg # dest = comp; jump def addtoSymboltable(key,value): symboltable[key]=value def createAsmFile(): datename = os.path.splitext(os.path.basename(filename))[0]+".hack" f = open(datename,"w") for line in asm: if line in symboltable: f.write('{0:016b}'.format(symboltable[line]) + "\n") else: f.write(ciinstruction(line)) f.close() if __name__ == "__main__": filename = sys.argv[1] #filename = "Pong.asm" symboltable = createSymboltable() asm = load_asm_file(filename) label_to_symboltable(asm) searchSymbols(asm) createAsmFile()