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 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 unknownDependencySet():
    return DependencySet(ALL_REGS - set(['FZ', 'FC', 'FN', 'FH']), ALL_REGS - set(['ROMBANK'])) def parse(text):
    try:
        lexer = shlex.shlex(text)
        lexer.commenters = ''
        lexer.wordchars += '#'
        return expression(lexer)
    except ExpressionError as e:
        print('ERROR:', e.msg, 'in', text) class JumpTable(object):
    def __init__(self, proj, addr):
        self.addr = addr
        self.targets = []

        for i in range(256):
            a = addr.offset(i*2)
            lo = proj.rom.get(a)
            hi = proj.rom.get(a.offset(1))
            value = address.fromVirtualAndCurrent((hi<<8) | lo, addr)

            if not value.inPhysicalMem():
                break

            self.targets.append(ProcAddress(value))

    def render(self, renderer):
        with renderer.lineAddress(self.addr):
            with renderer.comment():
                renderer.hline()
                renderer.startNewLine()
                renderer.write('jumptable ')
                renderer.writeSymbol(self.addr, 'jumptable')
                renderer.hline()
        with renderer.indent():
            i = 0
            for t in self.targets:
                with renderer.lineAddress(self.addr.offset(i*2)):
                    renderer.startNewLine()
                    renderer.write(str(i) + ' -> ')
                    t.render(renderer)
                i += 1 class ComplexValue(Operand):
    def __init__(self, hint='complex', deps=None):
        self.hint = hint
        if deps:
            self.deps = deps
        else:
            self.deps = set()

    def isComplex(self):
        return True

    def getDependencies(self):
        return self.deps

    def __str__(self):
        return '#'+self.hint+':'+(','.join(str(dep) for dep in self.deps if not isinstance(dep, address.Address)))+'#' class ComputedProcAddress(Operand):
    bits = 24

    def __init__(self, bank, addr):
        self.bank = bank
        self.addr = addr
        self.childs = (self.bank, self.addr)

    def __str__(self):
        return '[L {0}:{1}]'.format(self.bank, self.addr)

    def render(self, renderer):
        renderer.add('[L ')
        self.bank.render(renderer)
        renderer.add(':')
        self.addr.render(renderer)
        renderer.add(']')

    def optimizedWithContext(self, ctx):
        bank = self.bank.optimizedWithContext(ctx)
        addr = self.addr.optimizedWithContext(ctx)

        if hasattr(addr, 'value') and addr.value is not None and hasattr(bank, 'value') and bank.value is not None:
            return ProcAddress(address.fromVirtualAndBank(addr.value, bank.value))

        return ComputedProcAddress(bank, addr)

    def getDependencies(self):
        return self.addr.getDependencies() | self.bank.getDependencies()

    def __hash__(self):
        return hash((ComputedProcAddress, self.bank, self.addr))

    def __eq__(self, other):
        return isinstance(other, ComputedProcAddress) and self.addr == other.addr and self.bank == other.bank class JumpTableAddress(AddressConstant):
    link_prefix = "/jump/"
    html_class = "jumptable-addr" class ProcAddress(AddressConstant):
    link_prefix = "/proc/"
    html_class = "proc-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 def splitRegister(name):
    if name in ('BC', 'DE', 'HL'):
        return set([name[0], name[1]])
    elif name == 'AF':
        #return set(['A', 'FZ', 'FC', 'FN', 'FH'])
        return set(['A'])
    elif name == 'FNZ':
        return set(['FZ'])
    elif name == 'FNC':
        return set(['FC'])
    elif name == 'FF00+C':
        return set(['C'])
    return set([name]) def splitRegisters(regs):
    out = set()
    for x in regs:
        out |= splitRegister(x)
    return out
from awake import address, placeholders
from awake.depend import DependencySet, unknownDependencySet
from awake.expression import parse
from awake.jumptable import JumpTable
from awake.operand import ComplexValue, ComputedProcAddress, JumpTableAddress, ProcAddress
from awake.regutil import ALL_REGS, joinRegisters, splitRegister, splitRegisters
# 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 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 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 ExpressionOp(BaseOp):
    def __init__(self, name, operands, addr, reads, writes, values, loads):
        super(ExpressionOp, self).__init__(name, operands, addr)
        self._reads = reads
        self._writes = writes
        self._values = values
        self._loads = loads

    def optimizedWithContext(self, ctx):
        for w in self._writes:
            if w not in self._values:

                ctx.setValue(w, ComplexValue(self.name))