From 9a6001ad380e83a545188b58145387593b117b48 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Mon, 10 Apr 2023 21:10:16 +0300 Subject: Refactor into multipass compiler --- src/assembler.py | 94 ++++++++++---------------------------------------------- 1 file changed, 16 insertions(+), 78 deletions(-) (limited to 'src/assembler.py') diff --git a/src/assembler.py b/src/assembler.py index a4ddde4..fc7bc45 100755 --- a/src/assembler.py +++ b/src/assembler.py @@ -2,10 +2,12 @@ # Assemble ATK16 assembly to bytecode import sys -from typing import Callable -import importlib from assembler_ops import * from assembler_eval import * +from asm_pass1 import pass_1 +from asm_pass2 import pass_2 +from asm_pass3 import pass_3 +from asm_pass4 import pass_4 if len(sys.argv) != 3: print("usage: assembler.py # read from file") @@ -47,91 +49,27 @@ def parse(line: str) -> list[str]: result.append(acc) return list(filter(lambda x: len(x) > 0, result)) -# 1st pass, gather labels, set options, eval operations -options = Options() -address: int = 0 +result1 = pass_1(src_lines) +result2 = pass_2(result1) +result3 = pass_3(result2) +result4 = pass_4(result3) -for (lineNo, line) in enumerate(src_lines): - line = line.split(";")[0].strip() - if line == "": continue - keyword, *args = line.lower().split() - match keyword: - case "@address": - address = eval(args[0]) - continue - case "@label": - labels[args[0]] = address - # todo bugi: 1st pass ei ota monirivisiä käskyjä huomioon - continue - case "@opt": - opt_name, opt_value = args - match opt_name: - case "stack_pointer": options.stack_pointer = opt_value - case "csr_scratch": options.csr_scratch = opt_value - case _: raise Exception("Unknown @opt: " + opt_name) - case "@use": - module_name, ops = args[0].split(":") - ops_split = ops.split(",") - module = importlib.import_module(module_name) - mod_operations: dict[str, Callable[..., list[int]]] = module.operations - for op in mod_operations: - callable = mod_operations[op] - if ops == "*" or op in ops_split: - operations[op] = callable - case _: - pass - - address += 1 - -# 2nd pass - -address: int = 0 nop = bytearray([0b1000_0000, 0]) result = bytearray() # initially one nop result.extend(nop) -for (lineNo, line) in enumerate(src_lines): - line = line.split(";")[0].strip() - if line == "": continue - keyword, *args = parse(line.lower()) - - meta = Meta( - address=address, - options=options - ) - if keyword in operations: - words = operations[keyword](meta, *args) - else: - match keyword: - # Directives - case "@address": - address = eval_expr(args[0]) - continue - case "@label" | "@opt" | "@use": - continue - - # Default case: evaluate as is (e.g. data word) - case _: - try: - words = [eval_expr(keyword)] - except: - raise Exception(f"Invalid assembly at {infile_path}:{lineNo + 1}\n\n{line}") - - for (label, label_addr) in labels.items(): - if address == label_addr: +for line in result4.lines: + for (label, label_addr) in result4.labels.items(): + if line.address == label_addr: print(f"{label}:") - line_printed = False - for word in words: - if len(result) < 2 * address + 1: - result.extend((2 * address + 1 - len(result)) * nop) + if len(result) < 2 * line.address + 1: + result.extend((2 * line.address + 1 - len(result)) * nop) - print(f"{address:>08x} 0x{word:>04x} {line if not line_printed else '...'}") - result[2 * address + 0] = ((word >> 8) & 0xff) - result[2 * address + 1] = ((word >> 0) & 0xff) - address += 1 - line_printed = True + print(f"{line.address:>08x} 0x{line.word:>04x} {line.text}") + result[2 * line.address + 0] = ((line.word >> 8) & 0xff) + result[2 * line.address + 1] = ((line.word >> 0) & 0xff) with open(outfile_path, "wb") as f: f.write(result) -- cgit v1.3