You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.3 KiB
135 lines
3.3 KiB
from dataclasses import dataclass
|
|
|
|
from .consts import binary_op_inverses, binary_ops, condition_ops, unary_ops
|
|
from .instruction_definition import FUNCS
|
|
|
|
class Instruction:
|
|
pass
|
|
|
|
class Noop(Instruction):
|
|
def __str__(self):
|
|
return "noop"
|
|
|
|
class Set(Instruction):
|
|
def __init__(self, dest: str, src: str):
|
|
self.src = src
|
|
self.dest = dest
|
|
|
|
def __str__(self):
|
|
return f"set {self.dest} {self.src}"
|
|
|
|
class BinaryOp(Instruction):
|
|
def __init__(self, dest: str, left: str, right: str, op: str):
|
|
self.left = left
|
|
self.right = right
|
|
self.op = op
|
|
self.dest = dest
|
|
|
|
def inverse(self):
|
|
return BinaryOp(self.dest, self.left, self.right, binary_op_inverses[self.op])
|
|
|
|
def __str__(self):
|
|
return f"op {binary_ops[self.op]} {self.dest} {self.left} {self.right}"
|
|
|
|
class UnaryOp(Instruction):
|
|
def __init__(self, dest: str, src: str, op: str):
|
|
self.src = src
|
|
self.dest = dest
|
|
self.op = op
|
|
|
|
def __str__(self):
|
|
return f"op {unary_ops[self.op]} {self.dest} {self.src} 0"
|
|
|
|
@dataclass
|
|
class JumpCondition:
|
|
op: str
|
|
left: str
|
|
right: str
|
|
|
|
@classmethod
|
|
def from_binaryop(cls, binop: BinaryOp):
|
|
return cls(binop.op, binop.left, binop.right)
|
|
|
|
always: "JumpCondition" = None
|
|
|
|
def __str__(self):
|
|
return f"{condition_ops[self.op]} {self.left} {self.right}"
|
|
|
|
JumpCondition.always = JumpCondition("==", "0", "0")
|
|
|
|
class RelativeJump(Instruction):
|
|
def __init__(self, offset: int, cond: JumpCondition):
|
|
self.offset = offset
|
|
self.func_start: int = None
|
|
self.cond = cond
|
|
|
|
def __str__(self):
|
|
return f"jump {self.func_start + self.offset} {self.cond}"
|
|
|
|
class FunctionCall(Instruction):
|
|
def __init__(self, func_name: str):
|
|
self.func_name = func_name
|
|
self.func_start: int = None
|
|
|
|
def __str__(self):
|
|
return f"jump {self.func_start} {JumpCondition.always}"
|
|
|
|
class Return(Instruction):
|
|
def __init__(self, func_name: str):
|
|
self.func_name = func_name
|
|
|
|
def __str__(self):
|
|
return f"set @counter __retaddr_{self.func_name}"
|
|
|
|
class Goto(Instruction):
|
|
def __init__(self, label: str):
|
|
self.label = label
|
|
self.offset: int = None
|
|
self.func_start: int = None
|
|
|
|
def __str__(self):
|
|
return f"jump {self.func_start + self.offset} {JumpCondition.always}"
|
|
|
|
class End(Instruction):
|
|
def __str__(self):
|
|
return "end"
|
|
|
|
class RawAsm(Instruction):
|
|
def __init__(self, code: str):
|
|
self.code = code
|
|
|
|
def __str__(self):
|
|
return self.code
|
|
|
|
class ParsedInstruction(Instruction):
|
|
def __str__(self):
|
|
unescaped = self.assembly_string.replace('\\', '')
|
|
return unescaped.format(**self.__dict__)
|
|
|
|
class ParsedInstructionFactory():
|
|
def __init__(self, name, argn, argt, assembly_string):
|
|
self.argn = argn
|
|
self.argt = argt
|
|
self.name = name
|
|
self.assembly_string = assembly_string
|
|
|
|
def __call__(self, *args):
|
|
ret_instruction = ParsedInstruction()
|
|
ret_instruction.argt = self.argt
|
|
ret_instruction.assembly_string = self.assembly_string
|
|
if "{dest}" in self.assembly_string:
|
|
ret_instruction.__setattr__('dest', args[0])
|
|
args = args[1:]
|
|
ret_instruction.name = self.name
|
|
for arg, argn in zip(args, self.argn):
|
|
ret_instruction.__setattr__(argn, arg)
|
|
return ret_instruction
|
|
|
|
parsed_instructions = {}
|
|
for func_name, func in FUNCS.items():
|
|
argn = [arg_desc[0] for arg_desc in func['args']]
|
|
argt = [arg_desc[1] for arg_desc in func['args']]
|
|
assembly_string = func['asm']
|
|
parsed_instructions[func_name] = ParsedInstructionFactory(
|
|
func_name, argn, argt, assembly_string
|
|
)
|