view python/target/basetarget.py @ 318:e84047f29c78

Add burg and yacc initial attempts
author Windel Bouwman
date Tue, 31 Dec 2013 12:38:15 +0100
parents b145f8e6050b
children 6f4753202b9a
line wrap: on
line source

from asmnodes import ASymbol, AInstruction, ANumber
from ppci import CompilerError

"""
  Base classes for defining a target
"""

# Machine code interface:
class Operand:
   """ Single machine operand """
   pass

# standard immediates:

class ImmBase:
    def __init__(self, imm):
        assert type(imm) is int
        assert imm < self.Max()
        self.imm = imm

    @classmethod
    def Max(cls):
        return 2**cls.bits

    @classmethod
    def Create(cls, vop):
        if type(vop) is ANumber and vop.number < cls.Max():
            return cls(vop.number)


class Imm3(ImmBase):
    bits = 3


class Imm7(ImmBase):
    bits = 7


class Imm8(ImmBase):
    bits = 8


class Imm32(ImmBase):
    bits = 32


class LabelRef:
    def __init__(self, name):
        assert type(name) is str
        self.name = name

    @classmethod
    def Create(cls, vop):
        if type(vop) is ASymbol:
            return cls(vop.name)


class Instruction:
    """ Base instruction class """
    def encode(self):
        raise NotImplementedError('Instruction {0} has no encode yet, TODO'.format(type(self)))

    def resolve(self, f):
        pass


class Nop(Instruction):
    """ Instruction that does nothing and has zero size """
    def encode(self):
        return bytes()


class PseudoInstruction(Instruction):
    pass


class Label(PseudoInstruction):
    def __init__(self, name):
        self.name = name
        self.address = 0

    def __repr__(self):
        return '{}:'.format(self.name)

    def encode(self):
        return bytes()

    @classmethod
    def Create(cls, vop):
        if type(vop) is ASymbol:
            name = vop.name
            return cls(name)


class Comment(PseudoInstruction):
    def __init__(self, txt):
        self.txt = txt

    def encode(self):
        return bytes()

    def __repr__(self):
        return '; {}'.format(self.txt)


class Alignment(PseudoInstruction):
    def __init__(self, a):
        self.align = a

    def __repr__(self):
        return 'ALIGN({})'.format(self.align)

    def encode(self):
        pad = []
        address = self.address
        while (address % self.align) != 0:
            address += 1
            pad.append(0)
        return bytes(pad)


class DebugInfo(PseudoInstruction):
    def __init__(self, i):
        self.info = i

    def __repr__(self):
        return 'DebugInfo: {}'.format(self.info)

    def encode(self):
        return bytes()


class Register(Operand):
    def __init__(self, name):
        self.name = name


class Target:
    def __init__(self, name, desc=''):
        self.name = name
        self.desc = desc
        self.registers = []
        self.instructions = []
        self.byte_sizes = {'int':4}  # For front end!

    def instruction(self, cls):
        """ Decorator function that registers an instruction to this target """
        self.addInstruction(cls)
        return cls

    def check(self):
        """ Check target """
        for i in self.instructions:
            assert hasattr(i, 'mnemonic')
            assert hasattr(i, 'operands'), str(i)
            assert type(i.mnemonic) is str
            assert type(i.operands) is tuple, str(i)

    def addInstruction(self, ins_class):
        self.instructions.append(ins_class)

    def mapOperand(self, operand):
        """ Try to map an operand to a target type """
        if type(operand) is ASymbol:
            # Try to map to register:
            regs = {}
            for r in self.registers:
                regs[r.name] = r
            if operand.name in regs:
                return regs[operand.name]
        raise CompilerError('Cannot map {0}'.format(operand))

    def mapInstruction(self, vi):
        assert type(vi) is AInstruction
        """ Map ast tree to real instruction for this target """

        # map to real operands:
        if vi.mnemonic.upper() == 'ALIGN' and len(vi.operands) == 1:
            if type(vi.operands[0]) == ANumber:
                return Alignment(vi.operands[0].number)

        # look for a suitable instruction
        for ic in self.instructions:
            if ic.mnemonic.upper() == vi.mnemonic.upper() and len(ic.operands) == len(vi.operands):
                # Try to map operands to the correct operand types:
                rops = [roptype.Create(vop) for roptype, vop in zip(ic.operands, vi.operands)]

                # Check if we succeeded:
                if all(isinstance(rop, optype) for rop, optype in zip(rops, ic.operands)):
                    return ic(*rops)
        raise CompilerError('No suitable instruction found for "{0}"'.format(vi))