From 8dc15cf53816ff39cb6f593b70b3f51bfc7b2e1c Mon Sep 17 00:00:00 2001 From: Kyler <59854022+KylerOlsen@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:32:08 -0600 Subject: [PATCH] Worked on code generation --- pytd12dk/compiler/code_generator.py | 330 ++++++++++++++++++++-- pytd12dk/compiler/main.py | 5 + pytd12dk/compiler/semantical_analyzer.py | 12 + pytd12dk/compiler/syntactical_analyzer.py | 3 + 4 files changed, 322 insertions(+), 28 deletions(-) diff --git a/pytd12dk/compiler/code_generator.py b/pytd12dk/compiler/code_generator.py index e1384e0..3801c98 100644 --- a/pytd12dk/compiler/code_generator.py +++ b/pytd12dk/compiler/code_generator.py @@ -24,24 +24,27 @@ class _State: memory: dict[sma.Symbol, int] local: dict[sma.Symbol, int] - registers: dict[str, sma.Symbol | None] + registers: dict[str, sma.Symbol | bool] _register_rotation: int + _loop_index: int def __init__(self): self.memory = dict() self.local = dict() self.registers = { - 'D0': None, - 'D1': None, - 'D2': None, - 'D3': None, + 'D0': False, + 'D1': False, + 'D2': False, + 'D3': False, } self._register_rotation = 0 + self._loop_index = 0 @property def register_rotation(self) -> str: for reg in self.registers: - if self.registers[reg] is None: + if self.registers[reg] is False: + self._register_rotation = (int(reg[1]) + 1) % 4 return reg else: try: return f"D{self._register_rotation}" @@ -49,24 +52,32 @@ class _State: self._register_rotation += 1 self._register_rotation %= 4 + @property + def loop_index(self) -> str: + self._loop_index += 1 + return f"`loop{self._loop_index - 1}" + def store_symbol(self, reg: str) -> str: code = "" - symbol = self.registers[reg] - if symbol in self.local: - code += f"ldi {self.local[symbol]}\n" - code += "add MP SP MP\n" - code += f"str {reg}\n" - elif symbol in self.memory: - code += f"ldi {self.memory[symbol]}\n" - code += f"str {reg}\n" + if isinstance(self.registers[reg], sma.Symbol): + symbol = self.registers[reg] + if symbol in self.local: + code += f"ldi {self.local[symbol]}\n" + code += "add MP SP MP\n" + code += f"str {reg}\n" + elif symbol in self.memory: + code += f"ldi {self.memory[symbol]}\n" + code += f"str {reg}\n" + self.registers[reg] = False return code def load_symbol(self, symbol: sma.Symbol, reg: str | None = None) -> str: code = "" if reg is None: reg = self.register_rotation - if self.registers[reg] is not None: + if isinstance(self.registers[reg], sma.Symbol): self.store_symbol(reg) + self.registers[reg] = symbol if symbol in self.local: code += f"ldi {self.local[symbol]}\n" code += "add MP SP MP\n" @@ -78,18 +89,277 @@ class _State: f"Can not find memory of symbol: {symbol.name} ({hash(symbol)})") return code - def gen_binary_exprs(self, expression: sya.BinaryExpression) -> str: - pass + def get_symbol(self, symbol: sma.Symbol) -> str: + for sym in self.registers.values(): + if sym == symbol: + return "" + else: + return self.load_symbol(symbol) - def gen_block(self, block: sma.CodeBlock) -> str: + def get_register(self, symbol: sma.Symbol) -> str: + for reg, sym in self.registers.items(): + if sym == symbol: + return reg + return "NN" + + def load_immediate(self, value: int) -> str: + if value >= 64: + valuea = value // 64 + valueb = value % 64 + return f"liu {valuea}\nlil {valueb}\n" + else: + return f"ldi {value}\n" + + def gen_binary_exprs( + self, + expression: sya.BinaryExpression, + symbols: sma.SymbolTable, + reg: str | None = None, + ) -> str: code = "" - # for statement in block.code: - # if isinstance(statement, sya.BinaryExpression): - # code += self.gen_binary_exprs(statement) + if expression.operator == sya.BinaryOperatorEnum.Addition: + if reg: + if isinstance(expression.operand1, sya.Identifier): + code += self.get_symbol( + symbols.get(expression.operand1.content)) + rega = self.get_register( + symbols.get(expression.operand1.content)) + elif isinstance(expression.operand1, ( + sya.BuiltInConst, + sya.CharLiteral, + sya.NumberLiteral, + )): + rega = self.register_rotation + code += f"ldi {expression.operand1.value}\n" + code += f"or {rega} MP ZR\n" + + if isinstance(expression.operand2, sya.Identifier): + code += self.get_symbol( + symbols.get(expression.operand2.content)) + regb = self.get_register( + symbols.get(expression.operand2.content)) + elif isinstance(expression.operand2, ( + sya.BuiltInConst, + sya.CharLiteral, + sya.NumberLiteral, + )): + regb = self.register_rotation + code += self.load_immediate(expression.operand2.value) + code += f"or {regb} MP ZR\n" + + code += f"add {reg} {rega} {regb}\n" + elif expression.operator == sya.BinaryOperatorEnum.Subtraction: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for Subtraction", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.Multiplication: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for Multiplication", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.Division: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for Division", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.Modulus: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for Modulus", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.BitwiseAND: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for BitwiseAND", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.BitwiseOR: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for BitwiseOR", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.BitwiseXOR: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for BitwiseXOR", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.LeftShift: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for LeftShift", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.RightShift: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for RightShift", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.MemberOf: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for MemberOf", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.Assignment: + code += self.get_symbol( + symbols.get(expression.operand1.content)) # type: ignore + reg = self.get_register( + symbols.get(expression.operand1.content)) # type: ignore + if isinstance(expression.operand2, sya.BinaryExpression): + code += self.gen_binary_exprs(expression.operand2, symbols, reg) + elif isinstance(expression.operand2, sya.Identifier): + code += self.get_symbol( + symbols.get(expression.operand2.content)) + rega = self.get_register( + symbols.get(expression.operand2.content)) + code += f"or {reg} {rega} ZR\n" + elif isinstance(expression.operand2, ( + sya.BuiltInConst, + sya.CharLiteral, + sya.NumberLiteral, + )): + regb = self.register_rotation + code += self.load_immediate(expression.operand2.value) + code += f"or {reg} MP ZR\n" + elif expression.operator == sya.BinaryOperatorEnum.AdditionAssignment: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for AdditionAssignment", + expression.file_info + ) + elif ( + expression.operator == + sya.BinaryOperatorEnum.SubtractionAssignment + ): + raise CodeGenerationNotImplemented( + "Code Generation not implemented for SubtractionAssignment", + expression.file_info + ) + elif ( + expression.operator == + sya.BinaryOperatorEnum.MultiplicationAssignment + ): + raise CodeGenerationNotImplemented( + "Code Generation not implemented for MultiplicationAssignment", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.DivisionAssignment: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for DivisionAssignment", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.ModulusAssignment: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for ModulusAssignment", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.BitwiseANDAssignment: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for BitwiseANDAssignment", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.BitwiseORAssignment: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for BitwiseORAssignment", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.BitwiseXORAssignment: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for BitwiseXORAssignment", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.LeftShiftAssignment: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for LeftShiftAssignment", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.RightShiftAssignment: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for RightShiftAssignment", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.BooleanAND: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for BooleanAND", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.BooleanOR: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for BooleanOR", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.BooleanXOR: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for BooleanXOR", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.EqualityComparison: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for EqualityComparison", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.InequalityComparison: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for InequalityComparison", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.LessThan: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for LessThan", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.LessOrEqualToThan: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for LessOrEqualToThan", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.GreaterThan: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for GreaterThan", + expression.file_info + ) + elif expression.operator == sya.BinaryOperatorEnum.GreaterOrEqualToThan: + raise CodeGenerationNotImplemented( + "Code Generation not implemented for GreaterOrEqualToThan", + expression.file_info + ) return code - def gen_while(self, func: sma.WhileBlock) -> str: - pass + def gen_block(self, block: sma.CodeBlock, symbols: sma.SymbolTable) -> str: + code = "" + for statement in block.code: + if isinstance(statement, sya.LetStatement): pass + elif isinstance(statement, sya.BinaryExpression): + code += self.gen_binary_exprs(statement, symbols) + elif isinstance(statement, sma.WhileBlock): + code += self.gen_while(statement, symbols) + else: + raise CodeGenerationNotImplemented( + "Code Generation not yet implemented for: " + f"{statement.__class__.__name__}.", + statement.file_info, # type: ignore + ) + return code + + def gen_while(self, loop: sma.WhileBlock, symbols: sma.SymbolTable) -> str: + start_label = self.loop_index + end_label = self.loop_index + break_label = self.loop_index + code = f"{start_label}:\n" + if not ( + loop.condition.code and + isinstance(loop.condition.code[0], sya.BuiltInConst) and + loop.condition.code[0].content == sya.BuiltInConstEnum.ConstTrue + ): + raise CodeGenerationNotImplemented( + "Code Generation not yet implemented for: " + "while loop non-true conditions.", + loop.file_info, + ) + code += self.gen_block(loop.code, symbols) + code += f"ldi :{start_label}\nor PC MP ZR\n{end_label}:\n" + if loop.else_block is not None: + code += self.gen_block(loop.else_block.code, symbols) + code += f"{break_label}:\n" + + return code def gen_func(self, func: sma.FunctionBlock) -> str: self.local = dict() @@ -115,10 +385,14 @@ class _State: ) else: code += f"; Loading initial value for {symbol.name}\n" - code += f"ldi {symbol.definition.assignment.value}\n" - code += "sub SP SP MP\n" + code += self.load_immediate( + symbol.definition.assignment.value) + code += "or D0 MP ZR\n" + code += f"ldi {self.local[symbol]}\n" + code += "add MP SP MP\n" + code += "str D0\n" - code += self.gen_block(func.code) + code += self.gen_block(func.code, func.symbol_table) code += "\n; Uninitializing stack for function:" code += f" {func.identifier.content}\nldi {memory}\n" @@ -138,8 +412,8 @@ class _State: code += "; Global variables use " code += f"{memory - RAM[0]}/{RAM[1] - RAM[0]} bytes\n" code += "\n.0x0\n" - code += f"ldi {RAM[1]}\nor SP MP ZR\n" - code += f"ldi :{entry_name}\nor PC MP ZR\n" + code += self.load_immediate(RAM[1]) + code += f"or SP MP ZR\nldi :{entry_name}\nor PC MP ZR\n" for child in syntax_tree.children: if isinstance(child, sma.FunctionBlock): diff --git a/pytd12dk/compiler/main.py b/pytd12dk/compiler/main.py index a52bd4c..d2febb4 100644 --- a/pytd12dk/compiler/main.py +++ b/pytd12dk/compiler/main.py @@ -9,6 +9,7 @@ from .lexer import lexer from .syntactical_analyzer import syntactical_analyzer from .semantical_analyzer import semantical_analyzer from .code_generator import code_generator +from ..assembler import Program def _compile(args: argparse.Namespace): tokens = lexer(args.input_file.read(), args.input_file.name) @@ -32,6 +33,10 @@ def _compile(args: argparse.Namespace): if args.assembly_file: args.assembly_file.write(assembly_code) + if args.output_file: + machine_code = Program(assembly_code) + args.output_file.write(bytes(machine_code)) + def compile(args: argparse.Namespace): try: _compile(args) except CompilerError as e: print(e.compiler_error()) diff --git a/pytd12dk/compiler/semantical_analyzer.py b/pytd12dk/compiler/semantical_analyzer.py index f5b8b47..207b1b9 100644 --- a/pytd12dk/compiler/semantical_analyzer.py +++ b/pytd12dk/compiler/semantical_analyzer.py @@ -651,6 +651,9 @@ class ElseBlock: @property def file_info(self) -> FileInfo: return self._file_info + @property + def code(self) -> CodeBlock: return self._code + def tree_str(self, pre: str = "", pre_cont: str = "") -> str: return self._code.tree_str(pre + " Else", pre_cont + "") @@ -817,6 +820,15 @@ class WhileBlock: @property def file_info(self) -> FileInfo: return self._file_info + @property + def condition(self) -> CodeBlock: return self._condition + + @property + def code(self) -> CodeBlock: return self._code + + @property + def else_block(self) -> ElseBlock | None: return self._else + def tree_str(self, pre: str = "", pre_cont: str = "") -> str: s: str = f"{pre} While Loop\n" if self._code or self._else is not None: diff --git a/pytd12dk/compiler/syntactical_analyzer.py b/pytd12dk/compiler/syntactical_analyzer.py index 92ce560..07a9071 100644 --- a/pytd12dk/compiler/syntactical_analyzer.py +++ b/pytd12dk/compiler/syntactical_analyzer.py @@ -177,6 +177,9 @@ class BuiltInConst: @property def file_info(self) -> FileInfo: return self._file_info + @property + def content(self) -> BuiltInConstEnum: return self._content + @property def value(self) -> int: match (self._content):