BANK_SIZE = 0x4000
class BadAddressException(Exception):
class Address(object):
    def __init__(self, addr):
    def __str__(self):
def fromVirtual(virtual):
def fromVirtualAndBank(virtual, bank):
def fromVirtualAndCurrent(virtual, current):
def fromPhysical(physical):
def fromConventional(conventional):
    def __init__(self, address):
    def virtual(self):
    def bank(self):
    def isAmbiguous(self):
    def inBankedSpace(self):
    def inPhysicalMem(self):
    def physical(self):
    def offset(self, offset):
    def withBankSpecified(self, bank):
    def __lt__(self, other):
    def __eq__(self, other):
    def __ne__(self, other):
    def __hash__(self):
    def __str__(self):
    def __repr__(self):
 BC = Register("BC")
DE = Register("DE")
HL = Register("HL")
SP = Register("SP")
AF = Register("AF")
B = Register("B")
C = Register("C")
D = Register("D")
E = Register("E")
H = Register("H")
L = Register("L")
A = Register("A")
FNZ = Condition("FNZ")
FZ = Condition("FZ")
FNC = Condition("FNC")
FC = Condition("FC")
ALWAYS = Condition("ALWAYS")
ROMBANK = Register('ROMBANK')
def get(name, value): class Context:
    def __init__(self, values=None):
        if not values:
            self.values = dict()
        else:
            self.values = dict(values)

    def setValueComplex(self, register):
        if register in ('BC', 'DE', 'HL'):
            self.setValueComplex(register[0])
            self.setValueComplex(register[1])
        else:
            self.invalidate(register)
            self.values[register] = ComplexValue('ctx')

    def setValue(self, register, value):
        assert not isinstance(value, int)  # detect common errors

        if register in ('BC', 'DE', 'HL'):
            self.setValue(register[0], HighByte(value))
            self.setValue(register[1], LowByte(value))
        elif register == 'AF':
            self.setValue('A', HighByte(value))
            self.setValueComplex('FZ')
            self.setValueComplex('FC')
            self.setValueComplex('FN')
            self.setValueComplex('FH')
        else:
            self.invalidate(register)

            if register in value.getDependencies():
                self.setValueComplex(register)
            else:
                self.values[register] = value

    def invalidate(self, register):
        delete = set()

        for x in self.values:
            if self.values[x] and register in self.values[x].getDependencies():
                delete.add(x)

        for x in delete:
            del(self.values[x])

    def hasValue(self, register):
        if register in ('BC', 'DE', 'HL'):
            return self.hasValue(register[0]) and self.hasValue(register[1])
        if register == 'FNZ':
            return self.hasValue('FZ')
        if register == 'FNC':
            return self.hasValue('FC')
        if register not in self.values:
            return False
        value = self.values[register]
        try:
            return not value.isComplex()
        except AttributeError:
            return True

    def hasConstantValue(self, register):
        return self.hasValue(register) and self.getValue(register).value is not None

    def getValue(self, register):
        if register in ('BC', 'DE', 'HL'):
            return Word(self.getValue(register[0]), self.getValue(register[1])).optimizedWithContext(Context())
        if register == 'FNZ':
            return LogicalNot(self.getValue('FZ')).optimizedWithContext(Context())
        if register == 'FNC':
            return LogicalNot(self.getValue('FC')).optimizedWithContext(Context())
        else:
            return self.values[register].optimizedWithContext(Context())

    def invalidateAll(self):
        self.values = dict()

    def invalidateComplex(self):
        values = set(self.values)
        for v in values:
            if not self.hasConstantValue(v):
                del self.values[v]

    def clone(self):
        return Context(self.values) class DependencySet:
    def __init__(self, reads=None, writes=None):
        if reads:
            self.reads = reads
        else:
            self.reads = set()
        if writes:
            self.writes = writes
        else:
            self.writes = set()

    def __str__(self):
        return 'DependencySet({0}, {1})'.format(joinRegisters(self.reads), joinRegisters(self.writes))

    def onlyRegisters(self):
        return DependencySet(self.reads & ALL_REGS, self.writes & ALL_REGS) def dependParallel(a, b):
    reads = a.reads | b.reads
    writes = a.writes | b.writes
    return DependencySet(reads, writes) def joinDependencies(first, second):
    reads = second.reads - first.writes | first.reads
    writes = first.writes | second.writes
    return DependencySet(reads, writes) def unknownDependencySet():
    return DependencySet(ALL_REGS - set(['FZ', 'FC', 'FN', 'FH']), ALL_REGS - set(['ROMBANK'])) class BaseOp(Instruction):
    def __init__(self, name, operands, addr=None):
        super(BaseOp, self).__init__(name, addr)
        self._operands = operands

    def operands(self):
        return self._operands class Instruction(object):
    def __init__(self, name, addr=None):
        self.name = name
        self.addr = addr
        if not self.addr:
            self.addr = address.fromVirtual(0)

    def __str__(self):
        out = self.name
        if self.operands():
            out += '\t'
            out += ', '.join(str(op) for op in self.operands())
        return out

    def calls(self):
        return set()

    def jumps(self):
        return []

    def allJumps(self):
        return self.jumps()

    def operands(self):
        return []

    def signature(self):
        return ''  #'...' + (', '.join(str(x) for x in self.getDependencySet().reads))

    def optimizedWithContext(self, ctx):
        ctx.invalidateAll()
        return self

    def getDependencies(self, needed):
        return needed | ALL_REGS

    def getDependencySet(self):
        return unknownDependencySet()

    def optimizeDependencies(self, needed):
        return self

    def splitToSimple(self):
        return [self]

    def render(self, renderer):
        renderer.newInstruction(self.addr)
        renderer.instructionName(self.name)
        renderer.add('    ')
        renderer.renderList(self.operands())
        renderer.instructionSignature(self.signature())

    def hasContinue(self):
        return True

    def getMemreads(self):
        return set()

    def getMemwrites(self):
        return set() class AddressConstant(Constant):
    def __init__(self, addr):
        if not hasattr(addr, 'virtual'):
            if isinstance(addr, int):                       #If addr is an int,
                addr = address.fromVirtual(addr)            #   code path is unchanged.
            else:                                           #Else, addr is a string,
                addr = address.fromConventional(addr)       #   so it should be processed by fromConventional.
        super(AddressConstant, self).__init__(addr.virtual())
        self.addr = addr
        self.value = addr.virtual()

    def getAddress(self):
        return self.addr

    def __str__(self):
        return str(self.addr)

    def optimizedWithContext(self, ctx):
        if self.addr.isAmbiguous() and ctx.hasConstantValue('ROMBANK'):
            bank = ctx.getValue('ROMBANK').value
            addr = self.addr.withBankSpecified(bank)
            return self.__class__(addr)
        return self

    def render(self, renderer):
        addr = self.getAddress()
        renderer.writeSymbol(addr, self.html_class, self.link_prefix + str(addr)) class Constant(Operand):
    def __init__(self, value):
        assert isinstance(value, int)
        self.value = value

    def __str__(self):
        if 0 <= self.value <= 9:
            return str(self.value)
        return hex(self.value)

    def render(self, renderer):
        renderer.add(str(self), 'constant')

    def __hash__(self):
        return hash(self.value)

    def __eq__(self, other):
        try:
            return self.value == other.value
        except AttributeError:
            return False

    @property
    def bits(self):
        if self.value > 0xFF:
            return 16
        else:
            return 8 class JumpTableAddress(AddressConstant):
    link_prefix = "/jump/"
    html_class = "jumptable-addr" class LabelAddress(AddressConstant):
    link_prefix = "#"
    html_class = "label-addr" ALL_REGS = set(['B', 'C', 'D', 'E', 'H', 'L', 'SP', 'A', 'mem', 'ROMBANK', 'FZ', 'FC', 'FN', 'FH']) def joinRegisters(regs):
    out = set(regs)
    for big in ('BC', 'DE', 'HL'):
        if splitRegister(big) <= out:
            out -= splitRegister(big)
            out.add(big)
    return out
from awake import address, placeholders
from awake.context import Context
from awake.depend import DependencySet, dependParallel, joinDependencies, unknownDependencySet
from awake.instruction import BaseOp, Instruction
from awake.operand import AddressConstant, Constant, JumpTableAddress, LabelAddress
from awake.regutil import ALL_REGS, joinRegisters
        from . import operator
# This file is part of Awake - GB decompiler.
# Copyright (C) 2012  Wojciech Marczenko (devdri) <wojtek.marczenko@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


class Label(BaseOp):
    def __init__(self, addr):
        super(Label, self).__init__('label', [AddressConstant(addr)])
        self.addr = addr
        self.gotos = set()
        self.breaks = set()
        self.continues = set()
        self.needed = ALL_REGS - set(['FZ', 'FC', 'FN', 'FH'])
        self.depset = unknownDependencySet()

    def addGoto(self, x):
        self.gotos.add(x)

    def addBreak(self, x):
        self.breaks.add(x)

    def addContinue(self, x):
        self.continues.add(x)

    def optimizedWithContext(self, ctx):
        if self.gotos or self.breaks or self.continues:
            for w in self.depset.writes:
                ctx.setValueComplex(w)
        return self

    def setContextWrites(self, writes):
        self.depset.writes = writes

    def getDependencies(self, needed):
        return needed

    def getDependencySet(self):
        return DependencySet()

    def optimizeDependencies(self, needed):
        if self.gotos or self.breaks or self.continues:
            self.needed = set(needed)
            self.depset.reads = needed
            return self
        else:
            return None

    def signature(self):
        ins = joinRegisters(self.needed & ALL_REGS)
        return ' @ ' + ', '.join(sorted(str(x) for x in ins if not isinstance(x, address.Address)))

    def render(self, renderer, labels=None):
        if not self.gotos:
            return
        renderer.label(self.addr, self.signature())

class FlowTerminator(BaseOp):
    def __init__(self, name, target=None):
        if target:
            operands = [LabelAddress(target)]
        else:
            operands = []
        super(FlowTerminator, self).__init__(name, operands)
        self.target = target

    def hasContinue(self):
        return False

    def optimizeDependencies(self, needed):
        return self

class Goto(FlowTerminator):
    def __init__(self, label):
        super(Goto, self).__init__("goto", label.addr)
        self.target_label = label
        label.addGoto(self)

    def getDependencies(self, needed):
        return self.target_label.needed

    def getDependencySet(self):
        return DependencySet(self.target_label.depset.reads, set())

    def signature(self):

        ins = joinRegisters(self.target_label.needed & ALL_REGS)