ytd_12-bit_computer/pytd12dk/compiler/code_generator.py

157 lines
5.1 KiB
Python

# Kyler Olsen
# Jul 2024
from datetime import datetime
from .compiler_types import CompilerError
from . import syntactical_analyzer as sya
from . import semantical_analyzer as sma
CODE = (0x000, 0x6ff)
IO = (0x700, 0x7ff)
RAM = (0x800, 0xfff)
class CodeGenerationError(Exception): pass
class CodeGenerationNotImplemented(CompilerError):
_compiler_error_type = "Code Generation"
class _State:
memory: dict[sma.Symbol, int]
local: dict[sma.Symbol, int]
registers: dict[str, sma.Symbol | None]
_register_rotation: int
def __init__(self):
self.memory = dict()
self.local = dict()
self.registers = {
'D0': None,
'D1': None,
'D2': None,
'D3': None,
}
self._register_rotation = 0
@property
def register_rotation(self) -> str:
for reg in self.registers:
if self.registers[reg] is None:
return reg
else:
try: return f"D{self._register_rotation}"
finally:
self._register_rotation += 1
self._register_rotation %= 4
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"
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:
self.store_symbol(reg)
if symbol in self.local:
code += f"ldi {self.local[symbol]}\n"
code += "add MP SP MP\n"
code += f"lod {reg}\n"
elif symbol in self.memory:
code += f"ldi {self.memory[symbol]}\n"
code += f"lod {reg}\n"
else: raise CodeGenerationError(
f"Can not find memory of symbol: {symbol.name} ({hash(symbol)})")
return code
def gen_binary_exprs(self, expression: sya.BinaryExpression) -> str:
pass
def gen_block(self, block: sma.CodeBlock) -> str:
code = ""
# for statement in block.code:
# if isinstance(statement, sya.BinaryExpression):
# code += self.gen_binary_exprs(statement)
return code
def gen_while(self, func: sma.WhileBlock) -> str:
pass
def gen_func(self, func: sma.FunctionBlock) -> str:
self.local = dict()
memory = 0
for symbol in func.symbol_table.symbols:
self.local[symbol] = memory
memory += 1
code = f"{func.identifier.content}:\n"
code += f"\n; Initializing stack for function:"
code += f" {func.identifier.content}\nldi {memory}\n"
code += "sub SP SP MP\n\n"
for symbol in func.symbol_table.symbols:
if (
isinstance(symbol.definition, sya.LetStatement) and
symbol.definition.assignment is not None
):
if isinstance(symbol.definition.assignment, sya.StringLiteral):
raise CodeGenerationNotImplemented(
"Code Generation not yet implemented for "
"loading string literals",
symbol.definition.assignment.file_info,
)
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.gen_block(func.code)
code += "\n; Uninitializing stack for function:"
code += f" {func.identifier.content}\nldi {memory}\n"
code += "add SP SP MP\n"
return code
def code_generator(self, syntax_tree: sma.File, entry_name: str) -> str:
memory = RAM[0]
for symbol in syntax_tree.symbol_table.symbols:
if symbol.symbol_type == sma.SymbolType.variable:
self.memory[symbol] = memory
memory += 1 #symbol.definition.size
code = "; Generated by `pytd12dk` compiler\n"
code += f"; {datetime.now().isoformat()}\n"
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"
for child in syntax_tree.children:
if isinstance(child, sma.FunctionBlock):
code += f"\n{self.gen_func(child)}\n"
else:
raise CodeGenerationNotImplemented(
"Code Generation not yet implemented for: "
f"{child.__class__.__name__}.",
child.file_info,
)
return code
def code_generator(syntax_tree: sma.File, entry_name: str = 'main') -> str:
return _State().code_generator(syntax_tree, entry_name)