Assembler erweitert

This commit is contained in:
Sven Riwoldt
2024-04-04 19:37:49 +02:00
parent c7bc862c6f
commit efc4bd08a5
6 changed files with 326 additions and 22 deletions

156
asm/assembler04.py Normal file
View File

@@ -0,0 +1,156 @@
#import re
#import sys
import argparse
def convert_assembly_to_binary_file(asm_file, binary_file):
with open(asm_file, "r") as f:
result = translate_lines(f.readlines())
output = "\n".join([l for l in result if l])
with open(binary_file, "w") as f:
f.write(output)
def translate_lines(lines):
lines = strip_whitespace_and_comments(lines)
symbol_table = build_symbol_table(lines)
translate_instruction = build_instruction_translator(symbol_table)
return [translate_instruction(x) for x in lines]
def strip_whitespace_and_comments(lines):
instructions = []
for line in lines:
stripped_line = line.strip()
if stripped_line:
if not stripped_line.startswith("//"):
if "//" in stripped_line:
instructions.append(stripped_line.split("//")[0].strip())
else:
instructions.append(stripped_line)
return instructions
def build_symbol_table(lines):
symbols = {
"R0": "0000000000000000",
"R1": "0000000000000001",
"R2": "0000000000000010",
"R3": "0000000000000011",
"R4": "0000000000000100",
"R5": "0000000000000101",
"R6": "0000000000000110",
"R7": "0000000000000111",
"R8": "0000000000001000",
"R9": "0000000000001001",
"R10": "0000000000001010",
"R11": "0000000000001011",
"R12": "0000000000001100",
"R13": "0000000000001101",
"R14": "0000000000001110",
"R15": "0000000000001111",
"SP": "0000000000000000",
"ARG": "0000000000000010",
"LCL": "0000000000000001",
"THIS": "0000000000000011",
"THAT": "0000000000000100",
"KBD": "0110000000000000",
"SCREEN": "0100000000000000"
}
is_address_instruction = lambda x: x.startswith("@")
is_compute_instruction = lambda x: "=" in x or ";" in x
label_value = lambda x: x.replace("(", "").replace(")", "").strip()
current_line_num = 0
for line in lines:
if is_address_instruction(line) or is_compute_instruction(line):
current_line_num +=1
elif is_label(line):
symbols[label_value(line)] = decimal_to_binary(current_line_num)
base_address = 16
for line in lines:
if line.startswith("@"):
value = line[1:]
if value not in symbols and not value.isnumeric():
symbols[value] = decimal_to_binary(base_address)
base_address += 1
return symbols
def build_instruction_translator(symbol_table):
COMPUTATIONS = {
"0": "0101010",
"1": "0111111",
"-1": "0111010",
"D": "0001100",
"A": "0110000",
"!D": "0001101",
"!A": "0110001",
"-D": "0001111",
"-A": "0110011",
"D+1": "0011111",
"A+1": "0110111",
"D-1": "0001110",
"A-1": "0110010",
"D+A": "0000010",
"D-A": "0010011",
"A-D": "0000111",
"D&A": "0000000",
"D|A": "0010101",
"M": "1110000",
"!M": "1110001",
"-M": "1110011",
"M+1": "1110111",
"M-1": "1110010",
"D+M": "1000010",
"D-M": "1010011",
"M-D": "1000111",
"D&M": "1000000",
"D|M": "1010101"
}
DESTINATIONS = {
"": "000",
"M": "001",
"D": "010",
"MD": "011",
"A": "100",
"AM": "101",
"AD": "110",
"AMD": "111"
}
JUMPS = {
"": "000",
"JGT": "001",
"JEQ": "010",
"JGE": "011",
"JLT": "100",
"JNE": "101",
"JLE": "110",
"JMP": "111"
}
def fn(line):
if is_label(line):
return
if line.startswith("@"):
value = line[1:]
if value in symbol_table:
return symbol_table[value]
return decimal_to_binary(int(value))
dest, jump = "", ""
comp = line.split("=").pop().split(";")[0]
if "=" in line:
dest = line.split("=")[0]
if ";" in line:
jump = line.split(";").pop()
return f"111{COMPUTATIONS.get(comp, '0000000')}{DESTINATIONS.get(dest, '000')}{JUMPS.get(jump, '000')}"
return fn
def is_label(line):
return line.startswith("(") and line.endswith(")")
def decimal_to_binary(decimal_value):
return f"{decimal_value:0>16b}"
if __name__ == "__main__":
#parser = argparse.ArgumentParser(description="Generates a hack binary file from assembly")
#parser.add_argument("Rect.asm")
#parser.add_argument("Rect.hack")
#parser.add_argument("asm_file", help="name of a HACK assembly file, i.e input.asm")
#parser.add_argument("binary_file", help="name of the HACK file, i.e output.hack")
#args = parser.parse_args()
#convert_assembly_to_binary_file(args.asm_file, args.binary_file)
convert_assembly_to_binary_file('Rect.asm', 'Rect.hack')