From a23bcf78236a45e802a91761d2c34edcaa03b899 Mon Sep 17 00:00:00 2001 From: SpookyDervish <78246495+SpookyDervish@users.noreply.github.com> Date: Wed, 10 Sep 2025 20:25:19 +1000 Subject: [PATCH] IT WORKSSSS, WE'RE ACCESSING THE ARGS!!!!! --- generators/generator.py | 8 ++- generators/x86_64.py | 149 ++++++++++++++++++++++++---------------- out | Bin 8928 -> 8928 bytes out.asm | 4 +- test2.grnd | 2 +- 5 files changed, 101 insertions(+), 62 deletions(-) diff --git a/generators/generator.py b/generators/generator.py index eb884db..4f19f51 100644 --- a/generators/generator.py +++ b/generators/generator.py @@ -31,7 +31,7 @@ class Generator: self.current_var_scope = self.global_scope self.constants = {} self.structs = {} - self.functions: dict[str, FunctionNode] = {} + self.functions: dict[str, dict] = {} self.labels = [] self.arg_list = [] self.constants_reverse = {} @@ -58,7 +58,11 @@ class Generator: return "[.LC" + str(self.constant_counter-1) + "]" def add_function(self, node: FunctionNode): - self.functions[node.name] = node + self.functions[node.name] = { + "func": node, + "scope": SymbolTable(self.current_var_scope) + } + return self.functions[node.name] def clamp_instruction_args(self, instruction: InstructionNode, min_args: int, max_args: int): if len(instruction.arguments) < min_args: diff --git a/generators/x86_64.py b/generators/x86_64.py index da10e6e..a817fa8 100644 --- a/generators/x86_64.py +++ b/generators/x86_64.py @@ -25,55 +25,66 @@ class X86_64Generator(Generator): lines.append("pop " + reg + "\n\t") 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.current_var_scope.lookup(var_name) - var_pos = self.get_var_pos(var_name) - try: - #print(var["type"]) - if var["type"] == FloatNode: - conversion = { - "rax": "xmm0", - "rbx": "xmm1", - "rdi": "xmm0" - # ... - } + def get_variable(self, lines, var_name: str, reg: str, float: bool = False, offset: int = 0, no_stack_pop: bool = True, scope: SymbolTable = None): + scope = scope or self.current_var_scope - lines.append(f"movsd {conversion[reg]}, [rsp + {var_pos + offset}]\n\t") - lines.append("add rsp, 8\n\t") - self.stack_size += 1 - elif var["type"] in [IntNode,StringNode]: - if no_stack_pop: - lines.append(f"mov {reg}, [rsp + {var_pos + offset}]\n\t") - else: - self.push( - f"QWORD [rsp + {var_pos + offset}]", - lines - ) - self.pop(reg, lines) - elif var["type"] == BoolNode: - if no_stack_pop: - lines.append(f"mov {reg}, [rsp + {var_pos + offset}]\n\t") - else: - self.push( - f"QWORD [rsp + {var_pos + offset}]", - lines - ) - self.pop(reg, lines) - - except TypeError: # variable doesnt exist - traceback(self.code, "NameError", f"\"{var_name}\" is not defined.") + var = scope.lookup(var_name) + var_pos = self.get_var_pos(var_name, scope) + + if isinstance(var_pos, str): # in a reg, not on the stack + lines.append(f"mov {reg}, {var_pos}\n\t") + else: + try: + #print(var["type"]) + if var["type"] == FloatNode: + conversion = { + "rax": "xmm0", + "rbx": "xmm1", + "rdi": "xmm0" + # ... + } + + lines.append(f"movsd {conversion[reg]}, [rsp + {var_pos + offset}]\n\t") + lines.append("add rsp, 8\n\t") + self.stack_size += 1 + elif var["type"] in [IntNode,StringNode]: + if no_stack_pop: + lines.append(f"mov {reg}, [rsp + {var_pos + offset}]\n\t") + else: + self.push( + f"QWORD [rsp + {var_pos + offset}]", + lines + ) + self.pop(reg, lines) + elif var["type"] == BoolNode: + if no_stack_pop: + lines.append(f"mov {reg}, [rsp + {var_pos + offset}]\n\t") + else: + self.push( + f"QWORD [rsp + {var_pos + offset}]", + lines + ) + self.pop(reg, lines) + + except TypeError as e: # variable doesnt exist + traceback(self.code, "NameError", f"\"{var_name}\" is not defined.") return var["type"] - def get_var_pos(self, var_name: str): + def get_var_pos(self, var_name: str, scope: SymbolTable = None): + scope = scope or self.current_var_scope try: - return (self.stack_size - self.current_var_scope.lookup(var_name)['stack_loc'] - 1) * 8 - except TypeError: # not defined + stack_loc = scope.lookup(var_name)['stack_loc'] + if isinstance(stack_loc, str): + return stack_loc # its in a reg not on the stack + + return (self.stack_size - stack_loc - 1) * 8 + except TypeError as e: # not defined traceback(self.code, "TypeError", f"\"{var_name}\" is not defined.") - def create_variable(self, lines, var_name: str, starting_value, var_type: Any = None): - if var_type == None: - var_type = type(starting_value) + def create_variable(self, lines, var_name: str, starting_value, var_type: Any = None, scope = None): + var_type = var_type or type(starting_value) + scope = scope or self.current_var_scope stack_location = self.stack_size @@ -81,7 +92,7 @@ class X86_64Generator(Generator): lines.append(f"mov rax, {starting_value.value}\n\t") self.push("rax", lines) elif type(starting_value) == VarRefNode: - var_type = self.get_variable(lines, starting_value.var_name, "rax") + var_type = self.get_variable(lines, starting_value.var_name, "rax", scope=scope) if var_type == FloatNode: lines.append("sub rsp, 8\n\t") @@ -115,19 +126,20 @@ class X86_64Generator(Generator): self.stack_size += 1 else: self.push(starting_value, lines) - self.current_var_scope.define(var_name, {"stack_loc": stack_location, "type": var_type}) + 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) + def change_variable(self, lines, var_name: str, new_value, scope: SymbolTable = None): + scope = scope or self.current_var_scope + var_pos = self.get_var_pos(var_name, scope) 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.current_var_scope.table[var_name]["type"] = IntNode + 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.current_var_scope.table[var_name]["type"] = var_type + 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 +150,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.current_var_scope.table[var_name]["stack_loc"] = self.stack_size + 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.current_var_scope.table[var_name]["type"] = StringNode + 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.current_var_scope.table[var_name]["type"] = BoolNode + 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.current_var_scope.table[var_name]["type"] = IntNode + scope.table[var_name]["type"] = IntNode def generate_LabelDecNode(self, node: LabelDecNode, lines): self.labels.append(node.name) @@ -164,21 +176,27 @@ 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) + func = self.add_function(node) + self.current_var_scope = func["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 i, arg in enumerate(node.args): + try: + stack_loc = ["rdi","rsi","rdx","rcx","r8","r9"][i] # "" + except IndexError: + traceback(self.code, "CallError", "Functions with more than 6 args aren't supported yet, sorry...") + + self.current_var_scope.define(arg.name, {"stack_loc": stack_loc, "type": self.ground_type_to_node(arg.arg_type)}) + for inst in node.statements: self.generate_InstructionNode(inst, self.function_lines) - self.add_function(node) - def generate_InstructionNode(self, node: InstructionNode, lines = None): - if lines == None: - lines = self.lines + lines = lines or self.lines ### MISC ### if node.instruction == "end": @@ -335,9 +353,11 @@ class X86_64Generator(Generator): lines.append(f"mov rsi, {string_pointer}\n\t") lines.append(f"mov rdx, {string_len}\n\t") # length + self.push("rdi", lines) # save rdi lines.append("mov rax, 1\n\t") # sys_write syscall lines.append("mov rdi, 1\n\t") # a file descriptor of 1 is stdout lines.append("syscall\n\t") + self.pop("rdi", lines) # restore rdi elif node.instruction == "jump": self.clamp_instruction_args(node, 1, 1) @@ -429,6 +449,8 @@ class X86_64Generator(Generator): return elif node.instruction == "return": self.clamp_instruction_args(node, 0, 1) + + func = self.functions.get(node.parent.name) # the return statement will be a parent of a function node, so we can get the current scope using that if len(node.arguments) == 1: if isinstance(node.arguments[0], IntNode): @@ -438,6 +460,8 @@ class X86_64Generator(Generator): 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") + elif isinstance(node.arguments[0], VarRefNode): + self.get_variable(self.function_lines, node.arguments[0].var_name, "rax", scope=func["scope"]) else: lines.append("mov rax, 0\n\t") @@ -455,6 +479,8 @@ class X86_64Generator(Generator): 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.") + func_scope: SymbolTable = func["scope"] + func: FunctionNode = func["func"] 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)}") @@ -465,15 +491,22 @@ class X86_64Generator(Generator): for i, arg in enumerate(self.arg_list): #self.create_variable(lines, func.args[i].name, arg, func.args[i].arg_type) value = "" + var_type = "" if isinstance(arg, IntNode): value = arg.value + var_type = IntNode elif isinstance(arg, StringNode): + value = self.add_constant(arg.value) else: traceback(self.code, "CallError", f"Can't pass {arg} to function.") + arg_name = func.args[i].name + #self.change_variable(lines, arg_name, value, func_scope) if i == 0: + #func_scope.define(arg_name, {"stack_loc": "rdi", "type": type(arg)}) + lines.append(f"mov rdi, {value}") elif i == 1: lines.append(f"mov rsi, {value}") @@ -499,7 +532,7 @@ class X86_64Generator(Generator): 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)) + self.create_variable(lines, node.arguments[1].var_name, "rax", self.ground_type_to_node(self.functions.get(node.arguments[0].func_name)["func"].return_type)) elif node.instruction == "pusharg": self.clamp_instruction_args(node, 1, 1) #if type(node.arguments[0]) not in [IntNode]: diff --git a/out b/out index 701552695794a51ca2e41942c64ebff0cf3a4406..11ce66fa0046ff18d5bdd23cadd3a19c4066711e 100644 GIT binary patch delta 39 tcmaFh`oMLAp@4As4n_tBhW#LdpEcg2^GEFA&4B{z`6n^*Zc=!_1OWT<450u3 delta 39 rcmaFh`oMLAp@8rXMg|6k{UCy$bw@RjiaoqJP+&d(Bu3s%3J;h7=C=z~ diff --git a/out.asm b/out.asm index 1d3aedc..8f2a7fc 100644 --- a/out.asm +++ b/out.asm @@ -19,9 +19,11 @@ push rbp mov rbp, rsp mov rsi, .LC0 mov rdx, .LC1 +push rdi mov rax, 1 mov rdi, 1 syscall -mov rax, 123 +pop rdi +mov rax, rdi pop rbp ret diff --git a/test2.grnd b/test2.grnd index b65c263..a53d978 100644 --- a/test2.grnd +++ b/test2.grnd @@ -1,6 +1,6 @@ fun -int !test -int &arg1 stdout "this was called by a function!!!!\n" - return 123 + return $arg1 endfun pusharg 115