[Scummvm-cvs-logs] SF.net SVN: scummvm: [28607] tools/branches/gsoc2007-decompiler

brixxie at users.sourceforge.net brixxie at users.sourceforge.net
Tue Aug 14 05:56:28 CEST 2007


Revision: 28607
          http://scummvm.svn.sourceforge.net/scummvm/?rev=28607&view=rev
Author:   brixxie
Date:     2007-08-13 20:56:28 -0700 (Mon, 13 Aug 2007)

Log Message:
-----------
added various bugfixes to scumm frontend, added cfg.py

Modified Paths:
--------------
    tools/branches/gsoc2007-decompiler/finalD/decompiler.py
    tools/branches/gsoc2007-decompiler/finalD/disasm.py
    tools/branches/gsoc2007-decompiler/finalD/iformat.py
    tools/branches/gsoc2007-decompiler/finalD/scumm.py

Added Paths:
-----------
    tools/branches/gsoc2007-decompiler/finalD/cfg.py

Property Changed:
----------------
    tools/branches/gsoc2007-decompiler/


Property changes on: tools/branches/gsoc2007-decompiler
___________________________________________________________________
Name: svk:merge
   - 489ca303-0d3d-4dc1-a57d-017c7912a06a:/local/gsoc2007-decompiler:71
   + 489ca303-0d3d-4dc1-a57d-017c7912a06a:/local/gsoc2007-decompiler:73

Added: tools/branches/gsoc2007-decompiler/finalD/cfg.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/cfg.py	                        (rev 0)
+++ tools/branches/gsoc2007-decompiler/finalD/cfg.py	2007-08-14 03:56:28 UTC (rev 28607)
@@ -0,0 +1,95 @@
+"""Control flow graph module."""
+
+from iformat import *
+from altgraph import Graph
+
+
+class BT:
+    """Block type enumeration."""
+
+    fall = 0
+    """fall-through block"""
+    one_way = 1
+    """one way block"""
+    two_way = 2
+    """two way block"""
+
+
+class BasicBlock:
+    """BasicBlock class."""
+
+    def __init__(self, instrs, btype):
+        """
+        Initialize BasicBlock object.
+
+        Arguments:
+        instrs -- a list of instructions
+        btype -- basic block type (see BT)
+        """
+        self.instrs = instrs
+        self.btype = btype
+
+    def __str__(self):
+        """BasicBlock string representation."""
+        return str(self.instrs)
+
+    def get_first(self):
+        """Return first instruction offset in block."""
+        return self.instrs[0]
+
+    def get_last(self):
+        """Return last instruction offset in block."""
+        return self.instrs[-1]
+
+
+def get_bt(last_instr):
+    """Return block type of block with last instruction last_instr."""
+    return {CondJump : BT.two_way,
+            Jump : BT.one_way}.get(last_instr.__class__, BT.fall)
+
+def gen_basic_blocks(decoded):
+    """Generate basic block from a decoded instruction dictionary."""
+    blocks = []
+    block_instrs = []
+    jump_targets = set(map(lambda jmp: jmp.get_to(),
+                           filter(is_jump, decoded.values())))
+    decoded_tuples = decoded.items()
+    decoded_tuples.sort(key=(lambda t: t[0]))
+    for off, instr in decoded_tuples:
+        if off in jump_targets:
+            if block_instrs:
+                blocks.append(BasicBlock(block_instrs, BT.fall))
+                block_instrs = []
+        block_instrs.append(off)
+        if is_jump(instr):
+            blocks.append(BasicBlock(block_instrs, get_bt(instr)))
+            block_instrs = []
+    if block_instrs:
+        blocks.append(BasicBlock(block_instrs, BT.fall))
+    return blocks
+
+def gen_control_flow_graph(blocks, decoded):
+    """
+    Generate a control flow graph.
+
+    Arguments:
+    blocks -- a list of BasicBlock objects
+    decoded -- a dict of offset : Instr
+    """
+    edges = []
+    def index_key(lst, val, key):
+        for i, e in enumerate(lst):
+            if key(e) == val:
+                return i
+    for i, block in enumerate(blocks):
+        if block.btype == BT.one_way or block.btype == BT.two_way:
+            # we know the last Instr is some kind of Jump instance
+            jump_target = decoded[block.get_last()].get_to()
+            target_index = index_key(blocks, jump_target, BasicBlock.get_first)
+            assert(target_index != None)  # this should be non None
+            edges.append((i, target_index))
+        # a two-way has a fall-through too!
+        if block.btype == BT.fall or block.btype == BT.two_way:
+            if i+1 != len(blocks):
+                edges.append((i, i+1))
+    return Graph.Graph(edges)


Property changes on: tools/branches/gsoc2007-decompiler/finalD/cfg.py
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Modified: tools/branches/gsoc2007-decompiler/finalD/decompiler.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/decompiler.py	2007-08-14 01:57:44 UTC (rev 28606)
+++ tools/branches/gsoc2007-decompiler/finalD/decompiler.py	2007-08-14 03:56:28 UTC (rev 28607)
@@ -3,6 +3,7 @@
 import disasm
 import scumm
 import bytecode
+import cfg
 
 import array
 from optparse import OptionParser
@@ -14,16 +15,28 @@
 if __name__ == '__main__':
     parser = OptionParser()
     parser.add_option("-f", "--file", dest="filename")
+    parser.add_option("-d", "--disassemble", dest="disonly", action="store_true", default=False)
     (options, args) = parser.parse_args()
     f = open(options.filename, 'r')
     sc = scumm.SCUMM345(array.array('B', f.read()),
                         3,
                         indy_flag = True,
                         halt_on_error = False)
-    sc.parse_header()
     try:
-        while 1:
-            print sc.decode_next()
-    except bytecode.IncompleteFetchError:
-        pass
+        sc.parse_header()
+        dis = disasm.Disasm(sc)
+        decoded = dis.decode()
+        if not options.disonly:
+            blocks = cfg.gen_basic_blocks(decoded)
+            graph = cfg.gen_control_flow_graph(blocks, decoded)
+            print "%s" % graph
+        else:
+            decoded_tuples = decoded.items()
+            decoded_tuples.sort(key=lambda t: t[0])
+            for off, instr in decoded_tuples:
+                print "[%.4X] %s;" % (off, instr)
+    except:
+        print "ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOORRRRRRRRRRRRRRR"
+        print options.filename
+        raise
     print "END"

Modified: tools/branches/gsoc2007-decompiler/finalD/disasm.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/disasm.py	2007-08-14 01:57:44 UTC (rev 28606)
+++ tools/branches/gsoc2007-decompiler/finalD/disasm.py	2007-08-14 03:56:28 UTC (rev 28607)
@@ -22,8 +22,8 @@
         Arguments:
         bc -- instance of bytecode.ByteCode class
         """
-        self.decoded = []
-        """Hold decoded instructions."""
+        self.decoded = {}
+        """Hold decoded instructions indexed by script offset."""
         self._bc = bc
         """Hold bytecode.ByteCode instance."""
 
@@ -33,7 +33,8 @@
             # Append results of self.decode_next() to self.decoded until
             # an exception is raised.
             while 1:
-                self.decoded.append(self._bc.decode_next())
+                pos = self._bc.get_pos()
+                self.decoded[pos] = self._bc.decode_next()
         except bytecode.IncompleteFetchError:
             # If an bytecode.IncompleteFetchError was raised, we are done.
             return self.decoded

Modified: tools/branches/gsoc2007-decompiler/finalD/iformat.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/iformat.py	2007-08-14 01:57:44 UTC (rev 28606)
+++ tools/branches/gsoc2007-decompiler/finalD/iformat.py	2007-08-14 03:56:28 UTC (rev 28607)
@@ -26,7 +26,7 @@
 class AssgnInstr(Instr):
     """Assignment Instruction in intermediate format."""
 
-    def __init__(self, op, dst, val):
+    def __init__(self, op,  dst, val):
         Instr.__init__(self, op, (dst, val))
 
     def __str__(self):
@@ -39,6 +39,9 @@
     def __init__(self, to):
         Instr.__init__(self, "goto", (to,))
 
+    def get_to(self):
+        return self.args[0]
+
     def __str__(self):
         return "goto %.4X" % self.args[0]
 
@@ -51,3 +54,8 @@
 
     def __str__(self):
         return "unless(%s) goto %.4X" % (self.condition, self.args[0])
+
+
+def is_jump(instr):
+    """Return true if instr is a Jump."""
+    return instr.__class__ == Jump or instr.__class__ == CondJump

Modified: tools/branches/gsoc2007-decompiler/finalD/scumm.py
===================================================================
--- tools/branches/gsoc2007-decompiler/finalD/scumm.py	2007-08-14 01:57:44 UTC (rev 28606)
+++ tools/branches/gsoc2007-decompiler/finalD/scumm.py	2007-08-14 03:56:28 UTC (rev 28607)
@@ -395,6 +395,10 @@
 
         bytecode.ByteCode.__init__(self, init, SCUMM.get_byte)
 
+    def get_pos(self):
+        """Return self._pos - self.script_start."""
+        return self._pos - self.script_start
+
     def skip_verb_header(self, off, ofetch, cfetch=0):
         min_offset = 255
         offset = off
@@ -709,7 +713,7 @@
         self.register_opcodes(opcodes, handler)
 
     def calc_abs_jump(self, relative):
-        return 0x7fff & (relative + (self.get_pos() - self.script_start))
+        return 0x7fff & (relative + self.get_pos())
 
     def make_jump(self, condition=0):
         offset = self.get_word()
@@ -1112,8 +1116,8 @@
         def mak_state_handler(name):
             def handler(opcode):
                 if opcode & 0x40:
-                    return Instr(name, 0)
-                return Instr(name, self.get_byte())
+                    return Instr(name, [])
+                return Instr(name, [self.get_byte()])
             return handler
         self.register_opcodes([0x0f, 0x4f], mak_state_handler("clearState02"))
         self.register_opcodes([0x37, 0x77], mak_state_handler("clearState04"))
@@ -1201,6 +1205,7 @@
         if self.version == 5:
             self.register_complex_set("getObjectState", 0x0f, self.vow)
         self.register_complex("panCameraTo", 0x12, self.vow)
+        self.register_opcodes([0x14, 0x94, 0xd8], self.do_print_ego)
         self.register_opcodes([0x13, 0x53, 0x93, 0xd3], self.do_actor_ops)
         self.register_complex_set("actorFromPos", 0x15, self.vow, self.vow)
         self.register_opcodes([0x17, 0x97,
@@ -1349,9 +1354,9 @@
         d = self.get_byte()
         if (d & 0x1f) == 3:
             return Instr("oldRoomEffect-set",
-                         self.get_var_or_word(opcode, pmasks[0]))
+                         [self.get_var_or_word(opcode, pmasks[0])])
         return Instr("oldRoomEffect-fadein",
-                     self.get_var_or_word(opcode, pmasks[0]))
+                     [self.get_var_or_word(opcode, pmasks[0])])
 
     def do_begin_override(self, _):
         d = self.get_byte()
@@ -1679,7 +1684,7 @@
                 instr = self.produce_instr("LoadCharset", opc,
                                            self.vob, self.vob)
             else:
-                instr = self.produce_instr("CursorCommand", self.lst)
+                instr = self.produce_instr("CursorCommand", opc, self.lst)
         else:
             raise UnknownSubOpError, \
                 "SCUMM345.do_cursor_command: unknown subop %d" % opcm
@@ -1744,27 +1749,28 @@
                 break
             opcm = opc & 0x1f
             if opcm == 0x0:
-                args.append(self.produce_instr("Pos", self.vow, self.vow))
+                args.append(self.produce_instr("Pos", opc, self.vow, self.vow))
             elif opcm == 0x1:
-                args.append(self.produce_instr("Color", self.vob))
+                args.append(self.produce_instr("Color", opc, self.vob))
             elif opcm == 0x2:
-                args.append(self.produce_instr("Clipped", self.vow))
+                args.append(self.produce_instr("Clipped", opc, self.vow))
             elif opcm == 0x3:
-                args.append(self.produce_instr("RestoreBG", self.vow, self.vow))
+                args.append(self.produce_instr("RestoreBG", opc, self.vow, self.vow))
             elif opcm == 0x4:
                 args.append(Instr("Center", []))
             elif opcm == 0x6:
                 if self.unblocked:
-                    args.append(self.produce_instr("Height", self.vow))
+                    args.append(self.produce_instr("Height", opc, self.vow))
                 else:
                     args.append(Instr("Left", []))
             elif opcm == 0x7:
                 args.append(Instr("Overhead", []))
             elif opcm == 0x8:
                 args.append(self.produce_instr("PlayCDTrack",
+                                               opc,
                                                self.vow, self.vow))
             elif opcm == 0xf:
-                args.append(self.produce_instr("Text", self.asc))
+                args.append(self.produce_instr("Text", opc, self.asc))
                 break
             else:
                 raise UnknownSubOpError, \
@@ -1775,11 +1781,11 @@
         opc = self.get_byte()
         opcm = opc & 0x1f
         if opcm == 0x1:
-            instr = self.produce_instr("setBoxFlags", self.vob, self.vob)
+            instr = self.produce_instr("setBoxFlags", opc, self.vob, self.vob)
         elif opcm == 0x2:
-            instr = self.produce_instr("setBoxScale", self.vob, self.vob)
+            instr = self.produce_instr("setBoxScale", opc, self.vob, self.vob)
         elif opcm == 0x3:
-            instr = self.produce_instr("setBoxSlot", self.vob, self.vob)
+            instr = self.produce_instr("setBoxSlot", opc, self.vob, self.vob)
         elif opcm == 0x4:
             instr = Instr("createBoxMatrix", [])
         else:


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list