From be2cfdf9c803d4b50d3c8961661967406284c421 Mon Sep 17 00:00:00 2001 From: SpookyDervish <78246495+SpookyDervish@users.noreply.github.com> Date: Sun, 7 Sep 2025 20:00:35 +1000 Subject: [PATCH] doing a bit of cleaning up --- generators/generator.py | 7 ++ generators/x86_64.py | 139 ++++++---------------------------------- ground_ast.py | 3 +- test.o | 33 ++++++++++ 4 files changed, 59 insertions(+), 123 deletions(-) create mode 100644 test.o diff --git a/generators/generator.py b/generators/generator.py index bc8c980..f9526ba 100644 --- a/generators/generator.py +++ b/generators/generator.py @@ -1,5 +1,6 @@ from ground_ast import RootNode from typing import Any +from ground_ast import * class Generator: @@ -21,6 +22,12 @@ class Generator: self.constants_reverse[value] = "LC" + str(self.constant_counter) self.constant_counter += 1 return "[.LC" + str(self.constant_counter-1) + "]" + + def clamp_instruction_args(self, instruction: InstructionNode, min_args: int, max_args: int): + if len(instruction.arguments) < min_args: + traceback(self.code, "TypeError", f"{instruction.instruction} expects at least {min_args} arguments.") + elif len(instruction.arguments) > max_args: + traceback(self.code, "TypeError", f"{instruction.instruction} expects at most {max_args} arguments.") def init(self): pass diff --git a/generators/x86_64.py b/generators/x86_64.py index db3d5e9..f1ec526 100644 --- a/generators/x86_64.py +++ b/generators/x86_64.py @@ -179,10 +179,7 @@ class X86_64Generator(Generator): ### VARIABLE INSTRUCTIONS ### elif node.instruction == "set": - if len(node.arguments) < 2: # example: "set" or "set &hi" - traceback(self.code, "TypeError", "set expects atleast 2 arguments.") - elif len(node.arguments) > 2: # example: "set &hi 0 123" - traceback(self.code, "TypeError", "set expects only 2 arguments.") + self.clamp_instruction_args(node, 2, 2) if not isinstance(node.arguments[0], VarPointerNode): traceback(self.code, "TypeError", f"the first argument of set should be a variable pointer, not \"{node.arguments[0]}\"") if type(node.arguments[1]) not in [IntNode, VarRefNode, FloatNode, StringNode, BoolNode]: @@ -196,13 +193,10 @@ class X86_64Generator(Generator): self.change_variable(node.arguments[0].var_name, node.arguments[1]) ### MATH INSTRUCTIONS ### - elif node.instruction == "add": - if len(node.arguments) < 3: # example: "add" or "add 1" or "add 1 2" - traceback(self.code, "TypeError", "add expects atleast 3 arguments.") - elif len(node.arguments) > 3: # example: "add 1 2 3 4" - traceback(self.code, "TypeError", "add expects only 3 arguments.") - elif type(node.arguments[2]) != VarPointerNode: - traceback(self.code, "TypeError", f"the destination of the add command must be a variable pointer, not \"{node.arguments[2]}\"") + elif node.instruction in ["add", "subtract", "multiply"]: + self.clamp_instruction_args(node, 3, 3) + if type(node.arguments[2]) != VarPointerNode: + traceback(self.code, "TypeError", f"the destination of the {node.instruction} command must be a variable pointer, not \"{node.arguments[2]}\"") # bro this entire god damn instruction is just error handling 😔 number1_type = None @@ -236,66 +230,22 @@ class X86_64Generator(Generator): # TODO: numbers can be added to numbers, but numbers cant be added to strings. but strings can be added to strings, etc... if number1_type not in [IntNode, FloatNode] or number2_type not in [IntNode, FloatNode]: - traceback(self.code, "TypeError", f"Unsupported operation \"add\" for \"{node.arguments[0]}\" and \"{node.arguments[1]}\".") - - if number1_type == IntNode and number2_type == IntNode: - self.lines.append(f"add rax, {arg2}\n\t") - else: - self.lines.append(f"addsd xmm0, xmm1\n\t") - - 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 - self.create_variable(node.arguments[2].var_name, starting_reg, IntNode if is_integer else FloatNode) - else: - self.change_variable(node.arguments[2].var_name, starting_reg) - elif node.instruction == "subtract": - if len(node.arguments) < 3: # example: "subtract" or "subtract 1" or "subtract 1 2" - traceback(self.code, "TypeError", "subtract expects atleast 3 arguments.") - elif len(node.arguments) > 3: # example: "subtract 1 2 3 4" - traceback(self.code, "TypeError", "subtract expects only 3 arguments.") - elif type(node.arguments[2]) != VarPointerNode: - traceback(self.code, "TypeError", f"the destination of the subtract command must be a variable pointer, not \"{node.arguments[2]}\"") + traceback(self.code, "TypeError", f"Unsupported operation \"f{node.instruction}\" for \"{node.arguments[0]}\" and \"{node.arguments[1]}\".") - # bro this entire god damn instruction is just error handling 😔 - number1_type = None - number2_type = None - arg2 = "rbx" - if isinstance(node.arguments[0], VarRefNode): - number1_type = self.get_variable(node.arguments[0].var_name, "rax", isinstance(node.arguments[1], FloatNode)) - elif isinstance(node.arguments[0], FloatNode) or isinstance(node.arguments[1], FloatNode): - number1_type = FloatNode - constant_name = self.add_constant(node.arguments[0].value) - self.lines.append(f"movsd xmm0, {constant_name}\n\t") - elif isinstance(node.arguments[0], IntNode): - number1_type = IntNode - #arg1 = node.arguments[0].value - self.lines.append(f"mov rax, {node.arguments[0].value}\n\t") - else: - traceback(self.code, "TypeError", f"expected a variable reference or number for argument 1 of subtract, got {node.arguments[0]}") - - if isinstance(node.arguments[1], VarRefNode): - number2_type = self.get_variable(node.arguments[1].var_name, "rbx", number1_type == FloatNode) - elif number1_type == FloatNode or isinstance(node.arguments[1], FloatNode): - number2_type = FloatNode - constant_name = self.add_constant(node.arguments[1].value) - self.lines.append(f"movsd xmm1, {constant_name}\n\t") - elif isinstance(node.arguments[1], IntNode): - number2_type = IntNode - arg2 = node.arguments[1].value - #self.lines.append(f"mov rbx, {node.arguments[1].value}\n\t") - else: - traceback(self.code, "TypeError", f"expected a variable reference or number for argument 2 of subtract, got {node.arguments[1]}") - - # TODO: numbers can be added to numbers, but numbers cant be added to strings. but strings can be added to strings, etc... - if number1_type not in [IntNode, FloatNode] or number2_type not in [IntNode, FloatNode]: - traceback(self.code, "TypeError", f"Unsupported operation \"subtract\" for \"{node.arguments[0]}\" and \"{node.arguments[1]}\".") - if number1_type == IntNode and number2_type == IntNode: - self.lines.append(f"sub rax, {arg2}\n\t") + if node.instruction == "add": + self.lines.append(f"add rax, {arg2}\n\t") + elif node.instruction == "subtract": + self.lines.append(f"sub rax, {arg2}\n\t") + elif node.instruction == "multiply": + self.lines.append(f"imul rax, {arg2}\n\t") else: - self.lines.append(f"subsd xmm0, xmm1\n\t") + if node.instruction == "add": + self.lines.append(f"addsd xmm0, xmm1\n\t") + elif node.instruction == "subtract": + self.lines.append(f"subsd xmm0, xmm1\n\t") + elif node.instruction == "multiply": + self.lines.append(f"mulsd xmm0, xmm1\n\t") is_integer = number1_type == IntNode and number2_type == IntNode starting_reg = "rax" if is_integer else "xmm0" @@ -304,60 +254,7 @@ class X86_64Generator(Generator): self.create_variable(node.arguments[2].var_name, starting_reg, IntNode if is_integer else FloatNode) else: self.change_variable(node.arguments[2].var_name, starting_reg) - elif node.instruction == "multiply": - if len(node.arguments) < 3: # example: "multiply" or "multiply 1" or "multiply 1 2" - traceback(self.code, "TypeError", "multiply expects atleast 3 arguments.") - elif len(node.arguments) > 3: # example: "multiply 1 2 3 4" - traceback(self.code, "TypeError", "multiply expects only 3 arguments.") - elif type(node.arguments[2]) != VarPointerNode: - traceback(self.code, "TypeError", f"the destination of the multiply command must be a variable pointer, not \"{node.arguments[2]}\"") - - # bro this entire god damn instruction is just error handling 😔 - number1_type = None - number2_type = None - arg2 = "rbx" - if isinstance(node.arguments[0], VarRefNode): - number1_type = self.get_variable(node.arguments[0].var_name, "rax", isinstance(node.arguments[1], FloatNode)) - elif isinstance(node.arguments[0], FloatNode) or isinstance(node.arguments[1], FloatNode): - number1_type = FloatNode - constant_name = self.add_constant(node.arguments[0].value) - self.lines.append(f"movsd xmm0, {constant_name}\n\t") - elif isinstance(node.arguments[0], IntNode): - number1_type = IntNode - #arg1 = node.arguments[0].value - self.lines.append(f"mov rax, {node.arguments[0].value}\n\t") - else: - traceback(self.code, "TypeError", f"expected a variable reference or number for argument 1 of multiply, got {node.arguments[0]}") - if isinstance(node.arguments[1], VarRefNode): - number2_type = self.get_variable(node.arguments[1].var_name, "rbx", number1_type == FloatNode) - elif number1_type == FloatNode or isinstance(node.arguments[1], FloatNode): - number2_type = FloatNode - constant_name = self.add_constant(node.arguments[1].value) - self.lines.append(f"movsd xmm1, {constant_name}\n\t") - elif isinstance(node.arguments[1], IntNode): - number2_type = IntNode - arg2 = node.arguments[1].value - #self.lines.append(f"mov rbx, {node.arguments[1].value}\n\t") - else: - traceback(self.code, "TypeError", f"expected a variable reference or number for argument 2 of multiply, got {node.arguments[1]}") - - # TODO: numbers can be added to numbers, but numbers cant be added to strings. but strings can be added to strings, etc... - if number1_type not in [IntNode, FloatNode] or number2_type not in [IntNode, FloatNode]: - traceback(self.code, "TypeError", f"Unsupported operation \"multiply\" for \"{node.arguments[0]}\" and \"{node.arguments[1]}\".") - - if number1_type == IntNode and number2_type == IntNode: - self.lines.append(f"imul rax, {arg2}\n\t") - else: - self.lines.append(f"mulsd xmm0, xmm1\n\t") - - 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 - self.create_variable(node.arguments[2].var_name, starting_reg, IntNode if is_integer else FloatNode) - else: - self.change_variable(node.arguments[2].var_name, starting_reg) elif node.instruction == "divide": if len(node.arguments) < 3: # example: "divide" or "divide 1" or "divide 1 2" traceback(self.code, "TypeError", "divide expects atleast 3 arguments.") diff --git a/ground_ast.py b/ground_ast.py index 8365373..4cb66ce 100644 --- a/ground_ast.py +++ b/ground_ast.py @@ -98,8 +98,7 @@ def generate_ast(tokens: list[Token], code: str) -> RootNode: current_node_type = None scope = root_node - # todo: this is the absolute WORST way i could do this, but i could not care less lmao - # its not even performant...... + # todo: this is the absolute WORST way i could do this, but i could not care less lmao, its not even performant...... for token in tokens: if token.type == TokenType.INSTRUCTION: diff --git a/test.o b/test.o new file mode 100644 index 0000000..ef74e3d --- /dev/null +++ b/test.o @@ -0,0 +1,33 @@ + .file "test.c" + .text + .section .text.startup,"ax",@progbits + .p2align 4 + .globl main + .type main, @function +main: +.LFB0: + .cfi_startproc + endbr64 + movl $100000000, %eax + ret + .cfi_endproc +.LFE0: + .size main, .-main + .ident "GCC: (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0" + .section .note.GNU-stack,"",@progbits + .section .note.gnu.property,"a" + .align 8 + .long 1f - 0f + .long 4f - 1f + .long 5 +0: + .string "GNU" +1: + .align 8 + .long 0xc0000002 + .long 3f - 2f +2: + .long 0x3 +3: + .align 8 +4: