Worked on code generation

This commit is contained in:
Kyler 2024-07-09 15:32:08 -06:00
parent 52225d49df
commit 8dc15cf538
4 changed files with 322 additions and 28 deletions

View File

@ -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):

View File

@ -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())

View File

@ -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:

View File

@ -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):