RETURNING WORKSSSSS

This commit is contained in:
SpookyDervish
2025-09-10 18:56:45 +10:00
parent 3103d17026
commit 523ccecbc0
5 changed files with 103 additions and 19 deletions

View File

@@ -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

View File

@@ -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.")

BIN
out

Binary file not shown.

View File

@@ -6,16 +6,22 @@ section .data
section .text
global _start
_start:
sub rsp, 8
mov rdi, 115
call test
add rsp, 8
push rax
mov rax, 60
mov rdi, [rsp + 0]
syscall
test:
push rbp
mov rbp, rsp
mov rsi, .LC0
mov rdx, .LC1
mov rax, 1
mov rdi, 1
syscall
mov rax, 123
pop rbp
ret

View File

@@ -1,7 +1,8 @@
fun -int !test
fun -int !test -int &arg1
stdout "this was called by a function!!!!\n"
return 123
endfun
pusharg 115
call !test &var
end $var