diff options
| author | Jan Tuomi <jans.tuomi@gmail.com> | 2023-11-12 16:15:40 +0200 |
|---|---|---|
| committer | Jan Tuomi <jans.tuomi@gmail.com> | 2023-11-12 16:15:40 +0200 |
| commit | e2b7385b03a6dc9c8c39dde5c049cd74b0768bd1 (patch) | |
| tree | 817c9dc2c23f72bd5b0e36ada52ad86bb5e39909 /src/ast_compiler.py | |
| parent | 6f68c0febdbfd6138fa95f77bc09785bde8a8371 (diff) | |
Remove options, improve functions
Diffstat (limited to 'src/ast_compiler.py')
| -rw-r--r-- | src/ast_compiler.py | 108 |
1 files changed, 90 insertions, 18 deletions
diff --git a/src/ast_compiler.py b/src/ast_compiler.py index e6e78bf..d3fd70e 100644 --- a/src/ast_compiler.py +++ b/src/ast_compiler.py @@ -28,9 +28,8 @@ class Reg(): return f"R{self.reg}" ALL_REGS: list[RegChar] = ["A", "B", "C", "D", "E", "F", "G", "H"] -STACK_POINTER_REG = "G" -CSR_SCRATCH_REG = "H" -SPECIAL_REGS: list[RegChar] = [STACK_POINTER_REG, CSR_SCRATCH_REG] +STACK_POINTER_REG = "H" +SPECIAL_REGS: list[RegChar] = [STACK_POINTER_REG] GENERIC_REGS: OrderedDict[RegChar, None] = OrderedDict() for char in ALL_REGS: if char not in SPECIAL_REGS: @@ -84,6 +83,7 @@ class Compiler(ast.NodeVisitor): self.currently_emitting_asm_list = self.program_asm self.frame_stack = FrameStack() + self.tmp_stack_values_n: int = 0 self.unique_name_counter = 0 self.latest_break_target: Label | None = None @@ -113,6 +113,14 @@ class Compiler(ast.NodeVisitor): self.currently_emitting_asm_list.append(asm) + def emit_stack_push(self, reg: str): + self.tmp_stack_values_n += 1 + self.emit(f"spu {reg}") + + def emit_stack_pop(self, reg: str): + self.tmp_stack_values_n -= 1 + self.emit(f"spo {reg}") + def emit_label(self, label_name: str): label_name = label_name.lower() self.emit(f"@label {label_name}") @@ -219,17 +227,15 @@ class Compiler(ast.NodeVisitor): stmts = node.body frame_names = self.collect_local_variables(stmts) - self.emit(f"; stack frame names: {frame_names}") - # Move stack pointer to accommodate local variables - - # TODO instead of self.stack_frame_size, use a proper stack for frames. - # That way, we can restore the top-level stack frame when returning + self.emit("; stack frame with offsets") frame_bindings: dict[str, Label | StackOffset] = {} for idx, name in enumerate(frame_names): offset = self.frame_stack.total_offset() + idx frame_bindings[name] = offset + self.emit(f"; {name} {offset}") + frame = Frame( names = frame_names, bindings = frame_bindings, @@ -238,15 +244,19 @@ class Compiler(ast.NodeVisitor): self.emit(f"addi SP {len(frame.names)} SP") for stmt in stmts: + if type(stmt) == ast.Expr and type(stmt.value) != ast.Call: + self.emit("; NOP top-level expression") + continue + self.visit(stmt) self.frame_stack.pop() self.emit(f"subi SP {len(frame.names)} SP") def visit_Expr(self, expr: ast.Expr): - if self.frame_stack.size == 1 and type(expr.value) != ast.Call: - self.emit("; NOP top-level expression") - return + # if self.frame_stack.size == 1 and type(expr.value) != ast.Call: + # self.emit("; NOP top-level expression") + # return self.visit(expr.value) @@ -381,16 +391,62 @@ class Compiler(ast.NodeVisitor): self.emit(f"bri zero {label_false}") for true_branch_stmt in node.body: + if type(true_branch_stmt) == ast.Expr and type(true_branch_stmt.value) != ast.Call: + self.emit("; NOP top-level expression") + continue + self.visit(true_branch_stmt) self.emit(f"jpi {label_end}") self.emit_label(label_false) for false_branch_stmt in node.orelse: + if type(false_branch_stmt) == ast.Expr and type(false_branch_stmt.value) != ast.Call: + self.emit("; NOP top-level expression") + continue + self.visit(false_branch_stmt) self.emit_label(label_end) + def visit_Compare(self, node: ast.Compare): + if len(node.ops) > 1: + raise Exception("Multiple compare ops not supported") + + if len(node.comparators) > 1: + raise Exception("Multiple comparators not supported") + + op = node.ops[0] + left = node.left + right = node.comparators[0] + + self.visit(left) + self.visit(right) + + label_true = self.get_unique_name("Compare_true") + label_end = self.get_unique_name("Compare_end") + + with self.allocated_reg() as reg_lhs, self.allocated_reg() as reg_rhs: + match op: + case ast.Lt(): # lhs < rhs + self.emit(f"spo {reg_rhs}") + self.emit(f"spo {reg_lhs}") + + self.emit(f"sub {reg_lhs} {reg_rhs} {reg_lhs}") + self.emit(f"bri carry {label_true}") + + # false branch + self.emit(f"ldi 0 {reg_lhs}") + self.emit(f"spu {reg_lhs}") + self.emit(f"jpi {label_end}") + + # true branch + self.emit_label(label_true) + self.emit(f"ldi 1 {reg_lhs}") + self.emit(f"spu {reg_lhs}") + + self.emit_label(label_end) + def visit_While(self, node: ast.While): self.emit(f"; {node}") @@ -409,6 +465,10 @@ class Compiler(ast.NodeVisitor): self.emit(f"bri zero {label_else}") for body_stmt in node.body: + if type(body_stmt) == ast.Expr and type(body_stmt.value) != ast.Call: + self.emit("; NOP top-level expression") + continue + self.visit(body_stmt) self.emit(f"jpi {label_test}") @@ -441,6 +501,7 @@ class Compiler(ast.NodeVisitor): raise Exception("Lambda functions not supported. Consider using a named function instead.") def collect_local_variables(self, stmts: list[ast.stmt]): + result: list[str] = [] symbols: list[str] = [] for stmt in stmts: match stmt: @@ -455,8 +516,11 @@ class Compiler(ast.NodeVisitor): symbols += self.collect_local_variables(fb) case other: pass - # remove duplicates - return list(set(symbols)) + for symbol in symbols: + if symbol not in result: + result.append(symbol) + + return result def visit_FunctionDef(self, node: ast.FunctionDef): prev_currently_emitting_asm_list = self.currently_emitting_asm_list @@ -478,16 +542,19 @@ class Compiler(ast.NodeVisitor): return_address_name = self.get_unique_name("return_address") local_var_names = self.collect_local_variables(fn_stmts) frame_names = [return_address_name] + fn_params + local_var_names - self.emit(f"; stack frame names: {frame_names}") # Move stack pointer to accommodate local variables - self.emit(f"addi SP {len(local_var_names)} SP") + if len(local_var_names) > 0: + self.emit(f"addi SP {len(local_var_names)} SP") + self.emit("; stack frame with offsets") frame_bindings: dict[str, Label | StackOffset] = {} for idx, name in enumerate(frame_names): offset = self.frame_stack.total_offset() + idx frame_bindings[name] = offset + self.emit(f"; {name} {offset}") + frame = Frame( names = frame_names, bindings = frame_bindings @@ -509,21 +576,24 @@ class Compiler(ast.NodeVisitor): frame = self.frame_stack.peek() ret = node.value + if ret is not None: + self.visit(ret) with self.allocated_reg() as reg1, self.allocated_reg() as reg2: - print(frame.names) ret_addr_offset = self.frame_stack.total_offset() - frame.size() self.emit(f"ldi vt_stack_addr {reg1}") # vector table address of stack segment address self.emit(f"ldr {reg1} {reg1}") # stack segment address self.emit(f"ldi {ret_addr_offset} {reg2}") # stack offset self.emit(f"add {reg1} {reg2} {reg1}") # stack address of return address = stack segment start + stack offset + self.emit(f"; stack address of return address is stored in reg {reg1}") if ret is not None: - self.visit(ret) self.emit(f"spo {reg2}") else: self.emit(f"ldi 0 {reg2}") + self.emit(f"; return value is stored in reg {reg2}") + self.emit(f"mov {reg1} SP") # reset stack pointer to return address position (i.e. start of stack frame) self.emit(f"ldr {reg1} {reg1}") # return address @@ -609,10 +679,12 @@ class Compiler(ast.NodeVisitor): if type(offset) != StackOffset: raise Exception(f"Invalid address {offset} for name {name}. Can only assign to stack offsets.") - self.emit(f"; assigning {name} to stack segment + offset {offset}") + self.emit(f"; assigning {name} at stack segment + {offset}") with self.allocated_reg() as reg1, self.allocated_reg() as reg2: + self.emit(f"; evaluating value to be assigned") self.visit(value) + self.emit(f"; assigning value to stack segment + {offset}") self.emit(f"ldi vt_stack_addr {reg1}") self.emit(f"ldr {reg1} {reg1}") self.emit(f"ldi {offset} {reg2}") |
