RETURNING WORKSSSSS
This commit is contained in:
@@ -3,17 +3,37 @@ from typing import Any
|
|||||||
from ground_ast import *
|
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:
|
class Generator:
|
||||||
def __init__(self, ast: RootNode, code: str, output_path: str):
|
def __init__(self, ast: RootNode, code: str, output_path: str):
|
||||||
self.ast = ast
|
self.ast = ast
|
||||||
self.lines: list[str] = []
|
self.lines: list[str] = []
|
||||||
self.code = code
|
self.code = code
|
||||||
self.output_path = output_path
|
self.output_path = output_path
|
||||||
self.variables = {}
|
self.global_scope = SymbolTable()
|
||||||
|
self.current_var_scope = self.global_scope
|
||||||
self.constants = {}
|
self.constants = {}
|
||||||
self.structs = {}
|
self.structs = {}
|
||||||
self.functions: dict[str, FunctionNode] = {}
|
self.functions: dict[str, FunctionNode] = {}
|
||||||
self.labels = []
|
self.labels = []
|
||||||
|
self.arg_list = []
|
||||||
self.constants_reverse = {}
|
self.constants_reverse = {}
|
||||||
self.constant_counter = 0
|
self.constant_counter = 0
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
from generators.generator import Generator
|
from generators.generator import Generator, SymbolTable
|
||||||
from ground_ast import *
|
from ground_ast import *
|
||||||
from error import traceback
|
from error import traceback
|
||||||
from optimizers.x86_64 import X86_64Optimizer
|
from optimizers.x86_64 import X86_64Optimizer
|
||||||
@@ -26,7 +26,7 @@ class X86_64Generator(Generator):
|
|||||||
self.stack_size -= 1
|
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):
|
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)
|
var_pos = self.get_var_pos(var_name)
|
||||||
try:
|
try:
|
||||||
#print(var["type"])
|
#print(var["type"])
|
||||||
@@ -67,7 +67,7 @@ class X86_64Generator(Generator):
|
|||||||
|
|
||||||
def get_var_pos(self, var_name: str):
|
def get_var_pos(self, var_name: str):
|
||||||
try:
|
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
|
except TypeError: # not defined
|
||||||
traceback(self.code, "TypeError", f"\"{var_name}\" is not defined.")
|
traceback(self.code, "TypeError", f"\"{var_name}\" is not defined.")
|
||||||
|
|
||||||
@@ -115,19 +115,19 @@ class X86_64Generator(Generator):
|
|||||||
self.stack_size += 1
|
self.stack_size += 1
|
||||||
else:
|
else:
|
||||||
self.push(starting_value, lines)
|
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):
|
def change_variable(self, lines, var_name: str, new_value):
|
||||||
var_pos = self.get_var_pos(var_name)
|
var_pos = self.get_var_pos(var_name)
|
||||||
|
|
||||||
if type(new_value) == IntNode: # we're changing a variable to a number
|
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")
|
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
|
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")
|
var_type = self.get_variable(lines, new_value.var_name, "rax")
|
||||||
lines.append(f"mov QWORD [rsp + {var_pos}], rax\n\t")
|
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
|
elif type(new_value) == StringNode: # we're changing a variable to a string
|
||||||
lines.append(f"mov QWORD [rsp + {var_pos}], 0\n\t")
|
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"lea QWORD [rsp + {var_pos}], {string_pointer}\n\t")
|
||||||
##lines.append(f"mov QWORD [rsp + {var_pos + 8}], {string_len[1:-1]}\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")
|
lines.append(f"lea rax, {string_pointer}\n\t")
|
||||||
self.push("rax", lines)
|
self.push("rax", lines)
|
||||||
lines.append(f"mov rax, {string_len[1:-1]}\n\t")
|
lines.append(f"mov rax, {string_len[1:-1]}\n\t")
|
||||||
self.push("rax", lines)
|
self.push("rax", lines)
|
||||||
|
|
||||||
self.variables[var_name]["type"] = StringNode
|
self.current_var_scope.table[var_name]["type"] = StringNode
|
||||||
|
|
||||||
elif type(new_value) == BoolNode:
|
elif type(new_value) == BoolNode:
|
||||||
lines.append(f"mov QWORD [rsp + {var_pos}], {'1' if new_value.value else '0'}\n\t")
|
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
|
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")
|
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):
|
def generate_LabelDecNode(self, node: LabelDecNode, lines):
|
||||||
self.labels.append(node.name)
|
self.labels.append(node.name)
|
||||||
@@ -164,9 +164,16 @@ class X86_64Generator(Generator):
|
|||||||
if node.name == None:
|
if node.name == None:
|
||||||
traceback(self.code, "SyntaxError", "Functions require a name.")
|
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.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:
|
for inst in node.statements:
|
||||||
self.generate_InstructionNode(inst, self.function_lines)
|
self.generate_InstructionNode(inst, self.function_lines)
|
||||||
|
|
||||||
self.add_function(node)
|
self.add_function(node)
|
||||||
|
|
||||||
def generate_InstructionNode(self, node: InstructionNode, lines = None):
|
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]:
|
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])}\"")
|
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
|
if not variable_exists: # create a new variable
|
||||||
self.create_variable(lines, node.arguments[0].var_name, node.arguments[1])
|
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
|
is_integer = number1_type == IntNode and number2_type == IntNode
|
||||||
starting_reg = "rax" if is_integer else "xmm0"
|
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)
|
self.create_variable(lines, node.arguments[2].var_name, starting_reg, IntNode if is_integer else FloatNode)
|
||||||
else:
|
else:
|
||||||
self.change_variable(lines, node.arguments[2].var_name, starting_reg)
|
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")
|
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)
|
self.create_variable(lines, node.arguments[2].var_name, "xmm0", FloatNode)
|
||||||
else:
|
else:
|
||||||
self.change_variable(lines, node.arguments[2].var_name, "xmm0")
|
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
|
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)
|
self.create_variable(lines, var_name, "rax", BoolNode)
|
||||||
else:
|
else:
|
||||||
self.change_variable(lines, var_name, "rax")
|
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)}")
|
lines.append(f"mov rax, {int(node.arguments[0].value)}")
|
||||||
elif isinstance(node.arguments[0], FloatNode):
|
elif isinstance(node.arguments[0], FloatNode):
|
||||||
lines.append(f"mov xmm0, {node.arguments[0].value}")
|
lines.append(f"mov xmm0, {node.arguments[0].value}")
|
||||||
|
#self.get_variable(lines, node.arguments[0].var_name, "rax")
|
||||||
else:
|
else:
|
||||||
lines.append("mov rax, 0\n\t")
|
lines.append("mov rax, 0\n\t")
|
||||||
|
|
||||||
|
|
||||||
|
self.pop("rbp", lines)
|
||||||
lines.append("ret\n\t")
|
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":
|
elif node.instruction == "call":
|
||||||
self.clamp_instruction_args(node, 1, 2)
|
self.clamp_instruction_args(node, 1, 2)
|
||||||
if not isinstance(node.arguments[0], FunctionCallNode):
|
if not isinstance(node.arguments[0], FunctionCallNode):
|
||||||
traceback(self.code, "TypeError", "Argument 1 of call needs to be a function reference.")
|
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")
|
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 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")
|
self.change_variable(lines, node.arguments[1].var_name, "rax")
|
||||||
else:
|
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).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:
|
else:
|
||||||
raise NotImplementedError(f"A generate method hasn't been made for the \"{node.instruction}\" instruction.")
|
raise NotImplementedError(f"A generate method hasn't been made for the \"{node.instruction}\" instruction.")
|
||||||
|
|
||||||
|
6
out.asm
6
out.asm
@@ -6,16 +6,22 @@ section .data
|
|||||||
section .text
|
section .text
|
||||||
global _start
|
global _start
|
||||||
_start:
|
_start:
|
||||||
|
sub rsp, 8
|
||||||
|
mov rdi, 115
|
||||||
call test
|
call test
|
||||||
|
add rsp, 8
|
||||||
push rax
|
push rax
|
||||||
mov rax, 60
|
mov rax, 60
|
||||||
mov rdi, [rsp + 0]
|
mov rdi, [rsp + 0]
|
||||||
syscall
|
syscall
|
||||||
test:
|
test:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
mov rsi, .LC0
|
mov rsi, .LC0
|
||||||
mov rdx, .LC1
|
mov rdx, .LC1
|
||||||
mov rax, 1
|
mov rax, 1
|
||||||
mov rdi, 1
|
mov rdi, 1
|
||||||
syscall
|
syscall
|
||||||
mov rax, 123
|
mov rax, 123
|
||||||
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
fun -int !test
|
fun -int !test -int &arg1
|
||||||
stdout "this was called by a function!!!!\n"
|
stdout "this was called by a function!!!!\n"
|
||||||
return 123
|
return 123
|
||||||
endfun
|
endfun
|
||||||
|
|
||||||
|
pusharg 115
|
||||||
call !test &var
|
call !test &var
|
||||||
end $var
|
end $var
|
Reference in New Issue
Block a user