Files
nand2tetris/asm/asm02.py
2024-04-10 20:38:16 +02:00

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()