Assembler erweitert
This commit is contained in:
156
asm/assembler04.py
Normal file
156
asm/assembler04.py
Normal 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')
|
||||
Reference in New Issue
Block a user