157 lines
5.1 KiB
Python
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) |