258 lines
5.7 KiB
Python
258 lines
5.7 KiB
Python
'''
|
|
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()
|
|
|
|
|
|
|
|
|