From 523ccecbc0fee6aa51d9a613bd37223a4e3e7405 Mon Sep 17 00:00:00 2001 From: SpookyDervish <78246495+SpookyDervish@users.noreply.github.com> Date: Wed, 10 Sep 2025 18:56:45 +1000 Subject: [PATCH] RETURNING WORKSSSSS --- generators/generator.py | 22 +++++++++- generators/x86_64.py | 91 ++++++++++++++++++++++++++++++++-------- out | Bin 8928 -> 8928 bytes out.asm | 6 +++ test2.grnd | 3 +- 5 files changed, 103 insertions(+), 19 deletions(-) diff --git a/generators/generator.py b/generators/generator.py index 49ca48b..eb884db 100644 --- a/generators/generator.py +++ b/generators/generator.py @@ -3,17 +3,37 @@ from typing import Any from ground_ast import * +class SymbolTable: + def __init__(self, parent=None): + self.table = {} # variable name -> info (e.g., stack offset, type) + self.parent = parent + + def define(self, name, value): + self.table[name] = value + + def lookup(self, name): + scope = self + while scope: + if name in scope.table: + return scope.table[name] + scope = scope.parent + return None + #raise KeyError(f"Undefined variable: {name}") + + class Generator: def __init__(self, ast: RootNode, code: str, output_path: str): self.ast = ast self.lines: list[str] = [] self.code = code self.output_path = output_path - self.variables = {} + self.global_scope = SymbolTable() + self.current_var_scope = self.global_scope self.constants = {} self.structs = {} self.functions: dict[str, FunctionNode] = {} self.labels = [] + self.arg_list = [] self.constants_reverse = {} self.constant_counter = 0 diff --git a/generators/x86_64.py b/generators/x86_64.py index 1c97690..da10e6e 100644 --- a/generators/x86_64.py +++ b/generators/x86_64.py @@ -1,4 +1,4 @@ -from generators.generator import Generator +from generators.generator import Generator, SymbolTable from ground_ast import * from error import traceback from optimizers.x86_64 import X86_64Optimizer @@ -26,7 +26,7 @@ class X86_64Generator(Generator): self.stack_size -= 1 def get_variable(self, lines, var_name: str, reg: str, float: bool = False, offset: int = 0, no_stack_pop: bool = True): - var = self.variables.get(var_name, None) + var = self.current_var_scope.lookup(var_name) var_pos = self.get_var_pos(var_name) try: #print(var["type"]) @@ -67,7 +67,7 @@ class X86_64Generator(Generator): def get_var_pos(self, var_name: str): try: - return (self.stack_size - self.variables.get(var_name)['stack_loc'] - 1) * 8 + return (self.stack_size - self.current_var_scope.lookup(var_name)['stack_loc'] - 1) * 8 except TypeError: # not defined traceback(self.code, "TypeError", f"\"{var_name}\" is not defined.") @@ -115,19 +115,19 @@ class X86_64Generator(Generator): self.stack_size += 1 else: self.push(starting_value, lines) - self.variables[var_name] = {"stack_loc": stack_location, "type": var_type} + self.current_var_scope.define(var_name, {"stack_loc": stack_location, "type": var_type}) def change_variable(self, lines, var_name: str, new_value): var_pos = self.get_var_pos(var_name) if type(new_value) == IntNode: # we're changing a variable to a number lines.append(f"mov QWORD [rsp + {var_pos}], {new_value.value}\n\t") - self.variables[var_name]["type"] = IntNode + self.current_var_scope.table[var_name]["type"] = IntNode elif type(new_value) == VarRefNode: # we're changing a variable to the value of another variable var_type = self.get_variable(lines, new_value.var_name, "rax") lines.append(f"mov QWORD [rsp + {var_pos}], rax\n\t") - self.variables[var_name]["type"] = var_type + self.current_var_scope.table[var_name]["type"] = var_type elif type(new_value) == StringNode: # we're changing a variable to a string lines.append(f"mov QWORD [rsp + {var_pos}], 0\n\t") @@ -138,21 +138,21 @@ class X86_64Generator(Generator): #lines.append(f"lea QWORD [rsp + {var_pos}], {string_pointer}\n\t") ##lines.append(f"mov QWORD [rsp + {var_pos + 8}], {string_len[1:-1]}\n\t") - self.variables[var_name]["stack_loc"] = self.stack_size + self.current_var_scope.table[var_name]["stack_loc"] = self.stack_size lines.append(f"lea rax, {string_pointer}\n\t") self.push("rax", lines) lines.append(f"mov rax, {string_len[1:-1]}\n\t") self.push("rax", lines) - self.variables[var_name]["type"] = StringNode + self.current_var_scope.table[var_name]["type"] = StringNode elif type(new_value) == BoolNode: lines.append(f"mov QWORD [rsp + {var_pos}], {'1' if new_value.value else '0'}\n\t") - self.variables[var_name]["type"] = BoolNode + self.current_var_scope.table[var_name]["type"] = BoolNode elif type(new_value) == str: # we're changing a variable to the value of a register lines.append(f"mov QWORD [rsp + {var_pos}], {new_value}\n\t") - self.variables[var_name]["type"] = IntNode + self.current_var_scope.table[var_name]["type"] = IntNode def generate_LabelDecNode(self, node: LabelDecNode, lines): self.labels.append(node.name) @@ -164,9 +164,16 @@ class X86_64Generator(Generator): if node.name == None: traceback(self.code, "SyntaxError", "Functions require a name.") + self.current_var_scope = SymbolTable(self.current_var_scope) + + # function boilerplate self.function_lines.append(node.name + ":") + self.push("rbp", self.function_lines) + self.function_lines.append("mov rbp, rsp\n\t") + for inst in node.statements: self.generate_InstructionNode(inst, self.function_lines) + self.add_function(node) def generate_InstructionNode(self, node: InstructionNode, lines = None): @@ -200,7 +207,7 @@ class X86_64Generator(Generator): if type(node.arguments[1]) not in [IntNode, VarRefNode, FloatNode, StringNode, BoolNode]: traceback(self.code, "TypeError", f"variables can't be of type \"{type(node.arguments[1])}\"") - variable_exists = self.variables.get(node.arguments[0].var_name, None) != None + variable_exists = self.current_var_scope.lookup(node.arguments[0].var_name) != None if not variable_exists: # create a new variable self.create_variable(lines, node.arguments[0].var_name, node.arguments[1]) @@ -265,7 +272,7 @@ class X86_64Generator(Generator): is_integer = number1_type == IntNode and number2_type == IntNode starting_reg = "rax" if is_integer else "xmm0" - if self.variables.get(node.arguments[2].var_name, None) == None: # we need to create a variable for the destination + if self.current_var_scope.lookup(node.arguments[2].var_name) == None: # we need to create a variable for the destination self.create_variable(lines, node.arguments[2].var_name, starting_reg, IntNode if is_integer else FloatNode) else: self.change_variable(lines, node.arguments[2].var_name, starting_reg) @@ -304,7 +311,7 @@ class X86_64Generator(Generator): lines.append(f"divsd xmm0, xmm1\n\t") - if self.variables.get(node.arguments[2].var_name, None) == None: # we need to create a variable for the destination + if self.current_var_scope.lookup(node.arguments[2].var_name) == None: # we need to create a variable for the destination self.create_variable(lines, node.arguments[2].var_name, "xmm0", FloatNode) else: self.change_variable(lines, node.arguments[2].var_name, "xmm0") @@ -413,7 +420,7 @@ class X86_64Generator(Generator): var_name = node.arguments[2].var_name - if self.variables.get(var_name, None) == None: + if self.current_var_scope.lookup(var_name) == None: self.create_variable(lines, var_name, "rax", BoolNode) else: self.change_variable(lines, var_name, "rax") @@ -430,25 +437,75 @@ class X86_64Generator(Generator): lines.append(f"mov rax, {int(node.arguments[0].value)}") elif isinstance(node.arguments[0], FloatNode): lines.append(f"mov xmm0, {node.arguments[0].value}") + #self.get_variable(lines, node.arguments[0].var_name, "rax") else: lines.append("mov rax, 0\n\t") + + self.pop("rbp", lines) lines.append("ret\n\t") + old_scope = self.current_var_scope + self.current_var_scope = self.current_var_scope.parent + del old_scope elif node.instruction == "call": self.clamp_instruction_args(node, 1, 2) if not isinstance(node.arguments[0], FunctionCallNode): traceback(self.code, "TypeError", "Argument 1 of call needs to be a function reference.") - if not isinstance(node.arguments[1], VarPointerNode): - traceback(self.code, "TypeError", "Argument 1 of call needs to be a variable pointer.") + func = self.functions.get(node.arguments[0].func_name, None) + if not func: + traceback(self.code, "TypeError", f"Function \"{node.arguments[0].func_name}\" is not defined.") + if len(self.arg_list) != len(func.args): + traceback(self.code, "TypeError", f"Function \"{node.arguments[0].func_name}\" takes {len(func.args)} arguments, but got {len(self.arg_list)}") + + # stack alignment + if self.stack_size % 2 == 0: + lines.append("sub rsp, 8\n\t") # align the stack to 16 bytes + + for i, arg in enumerate(self.arg_list): + #self.create_variable(lines, func.args[i].name, arg, func.args[i].arg_type) + value = "" + + if isinstance(arg, IntNode): + value = arg.value + elif isinstance(arg, StringNode): + value = self.add_constant(arg.value) + else: + traceback(self.code, "CallError", f"Can't pass {arg} to function.") + + if i == 0: + lines.append(f"mov rdi, {value}") + elif i == 1: + lines.append(f"mov rsi, {value}") + elif i == 2: + lines.append(f"mov rdx, {value}") + elif i == 3: + lines.append(f"mov rcx, {value}") + elif i == 4: + lines.append(f"mov r8, {value}") + elif i == 5: + lines.append(f"mov r9, {value}") + else: + traceback(self.code, "CallError", "Functions with more than 6 args aren't supported yet, sorry...") lines.append(f"call {node.arguments[0].func_name}\n\t") + + self.lines.append(f"add rsp, {len(self.arg_list) * 8}") + self.arg_list.clear() if len(node.arguments) == 2: - if self.variables.get(node.arguments[1].var_name, None): + if not isinstance(node.arguments[1], VarPointerNode): + traceback(self.code, "TypeError", "Argument 1 of call needs to be a variable pointer.") + + if self.current_var_scope.lookup(node.arguments[1].var_name): self.change_variable(lines, node.arguments[1].var_name, "rax") else: self.create_variable(lines, node.arguments[1].var_name, "rax", self.ground_type_to_node(self.functions.get(node.arguments[0].func_name).return_type)) + elif node.instruction == "pusharg": + self.clamp_instruction_args(node, 1, 1) + #if type(node.arguments[0]) not in [IntNode]: + # traceback(self.code, "TypeError", f"A {node.arguments[0]} can't be passed as an argument.") + self.arg_list.append(node.arguments[0]) else: raise NotImplementedError(f"A generate method hasn't been made for the \"{node.instruction}\" instruction.") diff --git a/out b/out index b2d7f9d594c05616b5cc1eb65a62073174a30b96..701552695794a51ca2e41942c64ebff0cf3a4406 100644 GIT binary patch delta 83 zcmaFh`oML<3{DpY2yofBFrHt@qxlWT{$ilW3jrYE(R_p>V22He)or7~&l>8{`E;_N ffC6LeW