diff --git a/generators/generator.py b/generators/generator.py index 9208b1e..a4d699b 100644 --- a/generators/generator.py +++ b/generators/generator.py @@ -7,6 +7,7 @@ class Generator: self.lines: list[str] = [] self.code = code self.output_path = output_path + self.variables = {} def init(self): pass @@ -15,12 +16,13 @@ class Generator: self.lines.append(f"; {node}\n\t") node_type = str(type(node))[19:-2] if not hasattr(self, f"generate_{node_type}"): - raise Exception(f"Generator has no generate method for {node_type}.") + raise NotImplementedError(f"Generator has no generate method for {node_type}.") getattr(self, f"generate_{node_type}")(node) def generate(self): for statement in self.ast.statements: self.generate_node(statement) + def write(self): with open(self.output_path + ".asm", "w") as f: f.writelines(self.lines) \ No newline at end of file diff --git a/generators/x86_64.py b/generators/x86_64.py index e152fbd..09d7f82 100644 --- a/generators/x86_64.py +++ b/generators/x86_64.py @@ -3,20 +3,64 @@ from ground_ast import * from error import traceback class X86_64Generator(Generator): + def __init__(self, ast, code, output_path): + super().__init__(ast, code, output_path) + self.stack_size = 0 + def init(self): self.lines.append("global _start\n\n") self.lines.append("_start:\n\t") + + # generate code self.generate() + self.write() + + def push(self, reg: str): + self.lines.append("push " + reg + "\n\t") + self.stack_size += 1 + + def pop(self, reg: str): + self.lines.append("pop " + reg + "\n\t") + self.stack_size -= 1 + + def get_variable(self, var_name: str, reg: str): + self.push( + f"QWORD [rsp + {(self.stack_size - self.variables.get(var_name)["stack_loc"] - 1) * 8}]" + ) + self.pop(reg) def generate_InstructionNode(self, node: InstructionNode): if node.instruction == "end": - if len(node.arguments) == 0: + if len(node.arguments) == 0: # example: "end" traceback(self.code, "TypeError", "end expects atleast 1 argument.") - elif len(node.arguments) > 1: + elif len(node.arguments) > 1: # example: "end 1 1" traceback(self.code, "TypeError", "end expects only 1 argument.") - if not isinstance(node.arguments[0], NumberNode): + if not type(node.arguments[0]) in [NumberNode, VarRefNode]: # example: "end true" traceback(self.code, "TypeError", f"end expects an integer, not {type(node.arguments[0])}") self.lines.append("mov rax, 60\n\t") - self.lines.append("mov rdi, " + str(node.arguments[0].value) + "\n\t") - self.lines.append("syscall\n\n\t") \ No newline at end of file + if isinstance(node.arguments[0], NumberNode): + self.lines.append("mov rdi, " + str(node.arguments[0].value) + "\n\t") + elif isinstance(node.arguments[0], VarRefNode): + self.get_variable(node.arguments[0].var_name, "rdi") + #self.lines.append("mov rdi, " + str(self.get_variable(node.arguments[0].var_name)) + "\n\t") + self.lines.append("syscall\n\t") + + 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.") + if not isinstance(node.arguments[0], VarPointerNode): + traceback(self.code, "TypeError", f"the first argument of set should be a variable pointer, not \"{type(node.arguments[0])}\"") + if type(node.arguments[1]) not in [NumberNode]: + traceback(self.code, "TypeError", f"variables can't be of type \"{type(node.arguments[1])}\"") + + self.variables[node.arguments[0].var_name] = {"stack_loc": self.stack_size} + if type(node.arguments[1]) == NumberNode: + self.lines.append(f"mov rax, {node.arguments[1].value}\n\t") + self.push("rax") + + else: + self.lines.append("; FUCK\n\t") + #raise NotImplementedError(f"A generate method hasn't been made for the \"{node.instruction}\" instruction.") \ No newline at end of file diff --git a/ground_ast.py b/ground_ast.py index 79641ab..eb2209c 100644 --- a/ground_ast.py +++ b/ground_ast.py @@ -16,21 +16,33 @@ class InstructionNode: @dataclass class StringNode: value: str + def __repr__(self): + return "String" @dataclass class NumberNode: value: float + def __repr__(self): + return "Number" @dataclass class VarRefNode: var_name: str + def __repr__(self): + return "VariableReference" @dataclass class VarPointerNode: var_name: str + def __repr__(self): + return "VariablePointer" @dataclass class FunctionCallNode: func_name: str + def __repr__(self): + return "FunctionCall" @dataclass class TypeNode: value: str + def __repr__(self): + return "Type" @dataclass class ArgNode: arg_type: str @@ -46,15 +58,23 @@ class FunctionNode: @dataclass class LabelDecNode: name: str + def __repr__(self): + return "LabelDecleration" @dataclass class LabelRefNode: name: str + def __repr__(self): + return "LabelReference" @dataclass class LineRefNode: line: int + def __repr__(self): + return "LineReference" @dataclass class BoolNode: value: bool + def __repr__(self): + return "Boolean" def generate_ast(tokens: list[Token], code: str) -> RootNode: root_node = RootNode([]) diff --git a/main.py b/main.py index 9b32859..dadc5ef 100644 --- a/main.py +++ b/main.py @@ -27,14 +27,13 @@ def main(): traceback(code, "fatal error", f"unkown architecture \"{arch}\"") generator.init() + compile_time = time()-start + print(f"Compiled in {round(compile_time, 1)} seconds.") system(f"nasm -felf64 {out_path}.asm") system(f"ld -o {out_path} {out_path}.o -m elf_{arch}") remove(out_path + ".o") - remove(out_path + ".asm") - - compile_time = time()-start - print(f"Compiled in {round(compile_time, 1)} seconds.") + #remove(out_path + ".asm") if __name__ == "__main__": diff --git a/out b/out index e63e2e0..c73a515 100644 Binary files a/out and b/out differ diff --git a/out.asm b/out.asm new file mode 100644 index 0000000..11e323b --- /dev/null +++ b/out.asm @@ -0,0 +1,15 @@ +global _start + +_start: + ; InstructionNode(instruction='set', parent=RootNode(statements=[..., InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Number]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), arguments=[VariablePointer, Number]) + mov rax, 6 + push rax + ; InstructionNode(instruction='set', parent=RootNode(statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Number]), ..., InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), arguments=[VariablePointer, Number]) + mov rax, 7 + push rax + ; InstructionNode(instruction='end', parent=RootNode(statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Number]), InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Number]), ...]), arguments=[VariableReference]) + mov rax, 60 + push QWORD [rsp + 0] + pop rdi + syscall + \ No newline at end of file diff --git a/test2.grnd b/test2.grnd index 53e4707..e3bd493 100644 --- a/test2.grnd +++ b/test2.grnd @@ -1 +1,3 @@ -end 123 \ No newline at end of file +set &x 6 +set &y 7 +end $y \ No newline at end of file