[Scummvm-cvs-logs] SF.net SVN: scummvm:[54955] tools/trunk
pidgeot at users.sourceforge.net
pidgeot at users.sourceforge.net
Sat Dec 18 14:38:27 CET 2010
Revision: 54955
http://scummvm.svn.sourceforge.net/scummvm/?rev=54955&view=rev
Author: pidgeot
Date: 2010-12-18 13:38:26 +0000 (Sat, 18 Dec 2010)
Log Message:
-----------
TOOLS: Merge the gsoc2010-decompiler branch
Modified Paths:
--------------
tools/trunk/Makefile.common
tools/trunk/configure
Added Paths:
-----------
tools/trunk/decompiler/
tools/trunk/decompiler/codegen.cpp
tools/trunk/decompiler/codegen.h
tools/trunk/decompiler/control_flow.cpp
tools/trunk/decompiler/control_flow.h
tools/trunk/decompiler/decompiler.cpp
tools/trunk/decompiler/disassembler.cpp
tools/trunk/decompiler/disassembler.h
tools/trunk/decompiler/doc/
tools/trunk/decompiler/doc/Makefile
tools/trunk/decompiler/doc/cfg.tex
tools/trunk/decompiler/doc/codegen.tex
tools/trunk/decompiler/doc/disassembler.tex
tools/trunk/decompiler/doc/doc.tex
tools/trunk/decompiler/doc/engine.tex
tools/trunk/decompiler/doc/overview.tex
tools/trunk/decompiler/doc/preamble.tex
tools/trunk/decompiler/doc/restrictions.tex
tools/trunk/decompiler/doc/todo.tex
tools/trunk/decompiler/engine.h
tools/trunk/decompiler/graph.cpp
tools/trunk/decompiler/graph.h
tools/trunk/decompiler/instruction.cpp
tools/trunk/decompiler/instruction.h
tools/trunk/decompiler/kyra/
tools/trunk/decompiler/kyra/codegen.cpp
tools/trunk/decompiler/kyra/codegen.h
tools/trunk/decompiler/kyra/disassembler.cpp
tools/trunk/decompiler/kyra/disassembler.h
tools/trunk/decompiler/kyra/engine.cpp
tools/trunk/decompiler/kyra/engine.h
tools/trunk/decompiler/objectFactory.h
tools/trunk/decompiler/refcounted.h
tools/trunk/decompiler/scummv6/
tools/trunk/decompiler/scummv6/codegen.cpp
tools/trunk/decompiler/scummv6/codegen.h
tools/trunk/decompiler/scummv6/disassembler.cpp
tools/trunk/decompiler/scummv6/disassembler.h
tools/trunk/decompiler/scummv6/engine.cpp
tools/trunk/decompiler/scummv6/engine.h
tools/trunk/decompiler/simple_disassembler.cpp
tools/trunk/decompiler/simple_disassembler.h
tools/trunk/decompiler/stack.h
tools/trunk/decompiler/test/
tools/trunk/decompiler/test/branches.dmp
tools/trunk/decompiler/test/branches.txt
tools/trunk/decompiler/test/break-do-while.dmp
tools/trunk/decompiler/test/break-do-while.txt
tools/trunk/decompiler/test/break-do-while2.dmp
tools/trunk/decompiler/test/break-do-while2.txt
tools/trunk/decompiler/test/break-while.dmp
tools/trunk/decompiler/test/break-while.txt
tools/trunk/decompiler/test/cfg_test.h
tools/trunk/decompiler/test/codegen.h
tools/trunk/decompiler/test/continue-do-while.dmp
tools/trunk/decompiler/test/continue-do-while.txt
tools/trunk/decompiler/test/continue-do-while2.dmp
tools/trunk/decompiler/test/continue-do-while2.txt
tools/trunk/decompiler/test/continue-while.dmp
tools/trunk/decompiler/test/continue-while.txt
tools/trunk/decompiler/test/disassembler/
tools/trunk/decompiler/test/disassembler/pasc.cpp
tools/trunk/decompiler/test/disassembler/pasc.h
tools/trunk/decompiler/test/disassembler/subopcode.cpp
tools/trunk/decompiler/test/disassembler/subopcode.h
tools/trunk/decompiler/test/disassembler_test.h
tools/trunk/decompiler/test/do-while-in-while.dmp
tools/trunk/decompiler/test/do-while-in-while.txt
tools/trunk/decompiler/test/do-while.dmp
tools/trunk/decompiler/test/do-while.txt
tools/trunk/decompiler/test/hanoi20.pasb
tools/trunk/decompiler/test/if-else.dmp
tools/trunk/decompiler/test/if-else.txt
tools/trunk/decompiler/test/if-no-else.dmp
tools/trunk/decompiler/test/if-no-else.txt
tools/trunk/decompiler/test/if.dmp
tools/trunk/decompiler/test/if.txt
tools/trunk/decompiler/test/module.mk
tools/trunk/decompiler/test/nested-do-while.dmp
tools/trunk/decompiler/test/nested-do-while.txt
tools/trunk/decompiler/test/nested-while.dmp
tools/trunk/decompiler/test/nested-while.txt
tools/trunk/decompiler/test/nested-while2.dmp
tools/trunk/decompiler/test/nested-while2.txt
tools/trunk/decompiler/test/short-circuit.dmp
tools/trunk/decompiler/test/short-circuit.txt
tools/trunk/decompiler/test/subopcode_test.bin
tools/trunk/decompiler/test/unknownopcode_test.bin
tools/trunk/decompiler/test/unreachable.dmp
tools/trunk/decompiler/test/unreachable.txt
tools/trunk/decompiler/test/while-in-do-while.dmp
tools/trunk/decompiler/test/while-in-do-while.txt
tools/trunk/decompiler/test/while-in-do-while2.dmp
tools/trunk/decompiler/test/while-in-do-while2.txt
tools/trunk/decompiler/test/while.dmp
tools/trunk/decompiler/test/while.txt
tools/trunk/decompiler/unknown_opcode.cpp
tools/trunk/decompiler/unknown_opcode.h
tools/trunk/decompiler/value.cpp
tools/trunk/decompiler/value.h
tools/trunk/decompiler/wrongtype.h
Removed Paths:
-------------
tools/trunk/decompiler/codegen.cpp
tools/trunk/decompiler/codegen.h
tools/trunk/decompiler/control_flow.cpp
tools/trunk/decompiler/control_flow.h
tools/trunk/decompiler/decompiler.cpp
tools/trunk/decompiler/disassembler.cpp
tools/trunk/decompiler/disassembler.h
tools/trunk/decompiler/doc/
tools/trunk/decompiler/doc/Makefile
tools/trunk/decompiler/doc/cfg.tex
tools/trunk/decompiler/doc/codegen.tex
tools/trunk/decompiler/doc/disassembler.tex
tools/trunk/decompiler/doc/doc.tex
tools/trunk/decompiler/doc/engine.tex
tools/trunk/decompiler/doc/overview.tex
tools/trunk/decompiler/doc/preamble.tex
tools/trunk/decompiler/doc/restrictions.tex
tools/trunk/decompiler/doc/todo.tex
tools/trunk/decompiler/engine.h
tools/trunk/decompiler/graph.cpp
tools/trunk/decompiler/graph.h
tools/trunk/decompiler/instruction.cpp
tools/trunk/decompiler/instruction.h
tools/trunk/decompiler/kyra/
tools/trunk/decompiler/kyra/codegen.cpp
tools/trunk/decompiler/kyra/codegen.h
tools/trunk/decompiler/kyra/disassembler.cpp
tools/trunk/decompiler/kyra/disassembler.h
tools/trunk/decompiler/kyra/engine.cpp
tools/trunk/decompiler/kyra/engine.h
tools/trunk/decompiler/objectFactory.h
tools/trunk/decompiler/refcounted.h
tools/trunk/decompiler/scummv6/
tools/trunk/decompiler/scummv6/codegen.cpp
tools/trunk/decompiler/scummv6/codegen.h
tools/trunk/decompiler/scummv6/disassembler.cpp
tools/trunk/decompiler/scummv6/disassembler.h
tools/trunk/decompiler/scummv6/engine.cpp
tools/trunk/decompiler/scummv6/engine.h
tools/trunk/decompiler/simple_disassembler.cpp
tools/trunk/decompiler/simple_disassembler.h
tools/trunk/decompiler/stack.h
tools/trunk/decompiler/test/
tools/trunk/decompiler/test/branches.dmp
tools/trunk/decompiler/test/branches.txt
tools/trunk/decompiler/test/break-do-while.dmp
tools/trunk/decompiler/test/break-do-while.txt
tools/trunk/decompiler/test/break-do-while2.dmp
tools/trunk/decompiler/test/break-do-while2.txt
tools/trunk/decompiler/test/break-while.dmp
tools/trunk/decompiler/test/break-while.txt
tools/trunk/decompiler/test/cfg_test.h
tools/trunk/decompiler/test/codegen.h
tools/trunk/decompiler/test/continue-do-while.dmp
tools/trunk/decompiler/test/continue-do-while.txt
tools/trunk/decompiler/test/continue-do-while2.dmp
tools/trunk/decompiler/test/continue-do-while2.txt
tools/trunk/decompiler/test/continue-while.dmp
tools/trunk/decompiler/test/continue-while.txt
tools/trunk/decompiler/test/disassembler/
tools/trunk/decompiler/test/disassembler/pasc.cpp
tools/trunk/decompiler/test/disassembler/pasc.h
tools/trunk/decompiler/test/disassembler/subopcode.cpp
tools/trunk/decompiler/test/disassembler/subopcode.h
tools/trunk/decompiler/test/disassembler_test.h
tools/trunk/decompiler/test/do-while-in-while.dmp
tools/trunk/decompiler/test/do-while-in-while.txt
tools/trunk/decompiler/test/do-while.dmp
tools/trunk/decompiler/test/do-while.txt
tools/trunk/decompiler/test/hanoi20.pasb
tools/trunk/decompiler/test/if-else.dmp
tools/trunk/decompiler/test/if-else.txt
tools/trunk/decompiler/test/if-no-else.dmp
tools/trunk/decompiler/test/if-no-else.txt
tools/trunk/decompiler/test/if.dmp
tools/trunk/decompiler/test/if.txt
tools/trunk/decompiler/test/module.mk
tools/trunk/decompiler/test/nested-do-while.dmp
tools/trunk/decompiler/test/nested-do-while.txt
tools/trunk/decompiler/test/nested-while.dmp
tools/trunk/decompiler/test/nested-while.txt
tools/trunk/decompiler/test/nested-while2.dmp
tools/trunk/decompiler/test/nested-while2.txt
tools/trunk/decompiler/test/short-circuit.dmp
tools/trunk/decompiler/test/short-circuit.txt
tools/trunk/decompiler/test/subopcode_test.bin
tools/trunk/decompiler/test/unknownopcode_test.bin
tools/trunk/decompiler/test/unreachable.dmp
tools/trunk/decompiler/test/unreachable.txt
tools/trunk/decompiler/test/while-in-do-while.dmp
tools/trunk/decompiler/test/while-in-do-while.txt
tools/trunk/decompiler/test/while-in-do-while2.dmp
tools/trunk/decompiler/test/while-in-do-while2.txt
tools/trunk/decompiler/test/while.dmp
tools/trunk/decompiler/test/while.txt
tools/trunk/decompiler/unknown_opcode.cpp
tools/trunk/decompiler/unknown_opcode.h
tools/trunk/decompiler/value.cpp
tools/trunk/decompiler/value.h
tools/trunk/decompiler/wrongtype.h
Property Changed:
----------------
tools/trunk/
Property changes on: tools/trunk
___________________________________________________________________
Modified: svn:ignore
- .deps
.gdb_history
construct_mohawk
create_sjisfnt
decine
degob
dekyra
deriven
descumm
desword2
extract_mohawk
gob_loadcalc
ScummVM Tools.app
scummvm-tools
scummvm-tools-cli
config.mk
config.h
config.log
+ .deps
.gdb_history
construct_mohawk
create_sjisfnt
decine
decompile
degob
dekyra
deriven
descumm
desword2
extract_mohawk
gob_loadcalc
ScummVM Tools.app
scummvm-tools
scummvm-tools-cli
config.mk
config.h
config.log
Modified: svn:mergeinfo
- /tools/trunk:41370-43135
+ /tools/branches/gsoc2010-decompiler:48926-54952
/tools/trunk:41370-43135
Modified: tools/trunk/Makefile.common
===================================================================
--- tools/trunk/Makefile.common 2010-12-18 13:13:49 UTC (rev 54954)
+++ tools/trunk/Makefile.common 2010-12-18 13:38:26 UTC (rev 54955)
@@ -27,16 +27,20 @@
PROGRAMS = \
decine \
+ degob \
dekyra \
deriven \
descumm \
desword2 \
- degob \
gob_loadcalc \
extract_mohawk \
construct_mohawk \
scummvm-tools-cli
+ifdef USE_BOOST
+PROGRAMS += \
+ decompile
+endif
ifdef USE_FREETYPE
ifdef USE_ICONV
@@ -85,6 +89,21 @@
decine_OBJS := engines/cine/decine.o
+degob_OBJS := \
+ engines/gob/degob.o \
+ engines/gob/degob_script.o \
+ engines/gob/degob_script_v1.o \
+ engines/gob/degob_script_v2.o \
+ engines/gob/degob_script_v3.o \
+ engines/gob/degob_script_v4.o \
+ engines/gob/degob_script_v5.o \
+ engines/gob/degob_script_v6.o \
+ engines/gob/degob_script_bargon.o \
+ engines/gob/degob_script_fascin.o \
+ tool.o \
+ version.o \
+ $(UTILS)
+
dekyra_OBJS := \
engines/kyra/dekyra.o \
engines/kyra/dekyra_v1.o \
@@ -93,18 +112,18 @@
deriven_OBJS := \
engines/mohawk/archive.o \
engines/mohawk/deriven.o \
+ engines/mohawk/utils/file.o \
common/hashmap.o \
+ common/md5.o \
common/memorypool.o \
common/str.o \
- engines/mohawk/utils/file.o \
- common/md5.o \
common/util.o
descumm_OBJS := \
- engines/scumm/descumm-tool.o \
engines/scumm/descumm.o \
engines/scumm/descumm6.o \
engines/scumm/descumm-common.o \
+ engines/scumm/descumm-tool.o \
tool.o \
version.o \
$(UTILS)
@@ -137,11 +156,11 @@
extract_mohawk_OBJS := \
engines/mohawk/archive.o \
engines/mohawk/extract_mohawk.o \
+ engines/mohawk/utils/file.o \
common/hashmap.o \
+ common/md5.o \
common/memorypool.o \
common/str.o \
- engines/mohawk/utils/file.o \
- common/md5.o \
common/util.o
construct_mohawk_OBJS := \
@@ -167,29 +186,29 @@
engines/kyra/compress_kyra.o \
engines/queen/compress_queen.o \
engines/saga/compress_saga.o \
+ engines/sci/compress_sci.o \
engines/scumm/compress_scumm_bun.o \
engines/scumm/compress_scumm_san.o \
engines/scumm/compress_scumm_sou.o \
- engines/sci/compress_sci.o \
engines/sword1/compress_sword1.o \
engines/sword2/compress_sword2.o \
+ engines/tinsel/compress_tinsel.o \
engines/touche/compress_touche.o \
engines/tucker/compress_tucker.o \
- engines/tinsel/compress_tinsel.o \
engines/agos/extract_agos.o \
engines/cine/extract_cine.o \
engines/cruise/extract_cruise_pc.o \
engines/gob/extract_gob_stk.o \
engines/kyra/extract_kyra.o \
+ engines/parallaction/extract_parallaction.o \
engines/scumm/extract_loom_tg16.o \
engines/scumm/extract_mm_apple.o \
engines/scumm/extract_mm_c64.o \
engines/scumm/extract_mm_nes.o \
- engines/parallaction/extract_parallaction.o \
engines/scumm/extract_scumm_mac.o \
engines/scumm/extract_zak_c64.o \
+ engines/kyra/kyra_ins.o \
engines/kyra/kyra_pak.o \
- engines/kyra/kyra_ins.o \
compress.o \
tool.o \
tools.o \
@@ -202,10 +221,10 @@
endif
scummvm-tools_OBJS := \
+ gui/configuration.o \
+ gui/gui_tools.o \
gui/main.o \
- gui/configuration.o \
gui/pages.o \
- gui/gui_tools.o \
$(tools_OBJS)
scummvm-tools_LIBS := $(WXLIBS) $(LIBS)
@@ -223,7 +242,36 @@
$(tools_OBJS)
scummvm-tools-cli_LIBS := $(LIBS)
+ifdef USE_BOOST
+decompile_OBJS := \
+ common/file.o \
+ decompiler/codegen.o \
+ decompiler/control_flow.o \
+ decompiler/decompiler.o \
+ decompiler/disassembler.o \
+ decompiler/graph.o \
+ decompiler/instruction.o \
+ decompiler/simple_disassembler.o \
+ decompiler/unknown_opcode.o \
+ decompiler/value.o \
+ decompiler/kyra/codegen.o \
+ decompiler/kyra/disassembler.o \
+ decompiler/kyra/engine.o \
+ decompiler/scummv6/codegen.o \
+ decompiler/scummv6/disassembler.o \
+ decompiler/scummv6/engine.o
+decompile_LIBS := \
+ -lboost_program_options$(BOOST_SUFFIX)
+
+# Decompiler tests
+-include decompiler/test/module.mk
+endif
+
+# Decompiler documentation
+doc:
+ make -C decompiler/doc all
+
# Make base/version.o depend on all other object files. This way if anything is
# changed, it causes version.cpp to be recompiled. This in turn ensures that
# the build date in gScummVMBuildDate is correct.
Modified: tools/trunk/configure
===================================================================
--- tools/trunk/configure 2010-12-18 13:13:49 UTC (rev 54954)
+++ tools/trunk/configure 2010-12-18 13:38:26 UTC (rev 54955)
@@ -78,6 +78,7 @@
_wxwidgets=auto
_freetype=auto
_iconv=auto
+_boost=auto
_endian=unknown
_need_memalign=no
# Default option behaviour yes/no
@@ -321,6 +322,9 @@
--disable-freetype disable freetype (Japanese font) support [autodetect]
+ --with-boost-prefix=DIR Prefix where Boost is installed (optional)
+ --disable-boost disable Boost support [autodetect]
+
Some influential environment variables:
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir>
@@ -354,6 +358,8 @@
--disable-freetype) _freetype=no ;;
--enable-iconv) _iconv=yes ;;
--disable-iconv) _iconv=no ;;
+ --enable-boost) _boost=yes ;;
+ --disable-boost) _boost=no ;;
--enable-verbose-build) _verbose_build=yes ;;
--with-ogg-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
@@ -394,6 +400,11 @@
arg=`echo $ac_option | cut -d '=' -f 2`
_wxpath="$arg:$arg/bin"
;;
+ --with-boost-prefix=*)
+ arg=`echo $ac_option | cut -d '=' -f 2`
+ BOOST_CFLAGS="-I$arg/include"
+ BOOST_LIBS="-L$arg/lib"
+ ;;
--enable-debug)
_debug_build=yes
;;
@@ -991,6 +1002,40 @@
echo "$freetype_version"
#
+# Check for Boost
+#
+echocheck "Boost => 1.32.0"
+if test "$_boost" = auto ; then
+ _boost=no
+ cat > $TMPC << EOF
+#include <iostream>
+#include <boost/version.hpp>
+int main(void) { if (BOOST_VERSION < 103200) return 1; return 0; }
+EOF
+ cc_check $BOOST_CFLAGS $BOOST_LIBS && _boost=yes
+fi
+echo "$_boost"
+
+if test "$_boost" = yes ; then
+ _boost=no
+ echo_n "Checking whether Boost.ProgramOptions has been compiled... "
+ cat > $TMPC << EOF
+#include <boost/program_options.hpp>
+int main(void) { boost::program_options::options_description generic("Generic options"); return 0; }
+EOF
+ cc_check $BOOST_CFLAGS $BOOST_LIBS -lboost_program_options && _boost=yes
+ add_to_config_mk_if_yes "$_boost" 'BOOST_SUFFIX = '
+
+ # If not working without suffix, try -mt suffix
+ if test "$_boost" = no ; then
+ cc_check $BOOST_CFLAGS $BOOST_LIBS -lboost_program_options-mt && _boost=yes
+ add_to_config_mk_if_yes "$_boost" 'BOOST_SUFFIX = -mt'
+ fi
+ add_to_config_mk_if_yes "$_boost" 'USE_BOOST = 1'
+ echo "$_boost"
+fi
+
+#
# Check for iconv
#
echo_n "Checking whether iconv.h is present... "
Property changes on: tools/trunk/decompiler
___________________________________________________________________
Added: svn:ignore
+ .deps
Deleted: tools/trunk/decompiler/codegen.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp 2010-12-18 12:49:08 UTC (rev 54952)
+++ tools/trunk/decompiler/codegen.cpp 2010-12-18 13:38:26 UTC (rev 54955)
@@ -1,268 +0,0 @@
-/* ScummVM Tools
- * Copyright (C) 2010 The ScummVM project
- *
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "codegen.h"
-#include "engine.h"
-
-#include <algorithm>
-#include <iostream>
-#include <set>
-#include <boost/format.hpp>
-
-#define GET(vertex) (boost::get(boost::vertex_name, _g, vertex))
-#define GET_EDGE(edge) (boost::get(boost::edge_attribute, _g, edge))
-
-std::string CodeGenerator::constructFuncSignature(const Function &func) {
- return "";
-}
-
-std::string CodeGenerator::indentString(std::string s) {
- std::stringstream stream;
- stream << std::string(kIndentAmount * _indentLevel, ' ') << s;
- return stream.str();
-}
-
-CodeGenerator::CodeGenerator(Engine *engine, std::ostream &output, ArgOrder binOrder, ArgOrder callOrder) : _output(output), _binOrder(binOrder), _callOrder(callOrder) {
- _engine = engine;
- _indentLevel = 0;
-}
-
-typedef std::pair<GraphVertex, ValueStack> DFSEntry;
-
-void CodeGenerator::generate(const Graph &g) {
- _g = g;
-
- for (FuncMap::iterator fn = _engine->_functions.begin(); fn != _engine->_functions.end(); ++fn) {
- _indentLevel = 0;
- while (!_stack.empty())
- _stack.pop();
- GraphVertex entryPoint = fn->second._v;
- std::string funcSignature = constructFuncSignature(fn->second);
- bool printFuncSignature = !funcSignature.empty();
- if (printFuncSignature) {
- _curGroup = GET(entryPoint);
- if (!(fn == _engine->_functions.begin()))
- addOutputLine("");
- addOutputLine(funcSignature, false, true);
- }
-
- GroupPtr lastGroup = GET(entryPoint);
-
- // DFS from entry point to process each vertex
- Stack<DFSEntry> dfsStack;
- std::set<GraphVertex> seen;
- dfsStack.push(DFSEntry(entryPoint, ValueStack()));
- seen.insert(entryPoint);
- while (!dfsStack.empty()) {
- DFSEntry e = dfsStack.pop();
- GroupPtr tmp = GET(e.first);
- if ((*tmp->_start)->_address > (*lastGroup->_start)->_address)
- lastGroup = tmp;
- _stack = e.second;
- GraphVertex v = e.first;
- process(v);
- OutEdgeRange r = boost::out_edges(v, _g);
- for (OutEdgeIterator i = r.first; i != r.second; ++i) {
- GraphVertex target = boost::target(*i, _g);
- if (seen.find(target) == seen.end()) {
- dfsStack.push(DFSEntry(target, _stack));
- seen.insert(target);
- }
- }
- }
-
- if (printFuncSignature) {
- _curGroup = lastGroup;
- addOutputLine("}", true, false);
- }
-
- // Print output
- GroupPtr p = GET(entryPoint);
- while (p != NULL) {
- for (std::vector<CodeLine>::iterator it = p->_code.begin(); it != p->_code.end(); ++it) {
- if (it->_unindentBefore) {
- assert(_indentLevel > 0);
- _indentLevel--;
- }
- _output << boost::format("%08X: %s") % (*p->_start)->_address % indentString(it->_line) << std::endl;
- if (it->_indentAfter)
- _indentLevel++;
- }
- p = p->_next;
- }
-
- if (_indentLevel != 0)
- std::cerr << boost::format("WARNING: Indent level for function at %d ended at %d\n") % fn->first % _indentLevel;
- }
-}
-
-void CodeGenerator::addOutputLine(std::string s, bool unindentBefore, bool indentAfter) {
- _curGroup->_code.push_back(CodeLine(s, unindentBefore, indentAfter));
-}
-
-void CodeGenerator::writeAssignment(ValuePtr dst, ValuePtr src) {
- std::stringstream s;
- s << dst << " = " << src << ";";
- addOutputLine(s.str());
-}
-
-void CodeGenerator::process(GraphVertex v) {
- _curVertex = v;
- _curGroup = GET(v);
-
- // Check if we should add else start
- if (_curGroup->_startElse)
- addOutputLine("} else {", true, true);
-
- // Check ingoing edges to see if we want to add any extra output
- InEdgeRange ier = boost::in_edges(v, _g);
- for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
- GraphVertex in = boost::source(*ie, _g);
- GroupPtr inGroup = GET(in);
-
- if (!boost::get(boost::edge_attribute, _g, *ie)._isJump || inGroup->_stackLevel == -1)
- continue;
-
- switch (inGroup->_type) {
- case kDoWhileCondGroupType:
- addOutputLine("do {", false, true);
- break;
- case kIfCondGroupType:
- if (!_curGroup->_startElse)
- addOutputLine("}", true, false);
- break;
- case kWhileCondGroupType:
- addOutputLine("}", true, false);
- break;
- default:
- break;
- }
- }
-
- ConstInstIterator it = _curGroup->_start;
- do {
- processInst(*it);
- } while (it++ != _curGroup->_end);
-
- // Add else end if necessary
- for (ElseEndIterator elseIt = _curGroup->_endElse.begin(); elseIt != _curGroup->_endElse.end(); ++elseIt) {
- if (!(*elseIt)->_coalescedElse)
- addOutputLine("}", true, false);
- }
-}
-
-void CodeGenerator::processInst(const InstPtr inst) {
- inst->processInst(_stack, _engine, this);
- if (inst->isCondJump()) {
- std::stringstream s;
- switch (_curGroup->_type) {
- case kIfCondGroupType:
- if (_curGroup->_startElse && _curGroup->_code.size() == 1) {
- OutEdgeRange oer = boost::out_edges(_curVertex, _g);
- bool coalesceElse = false;
- for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
- GroupPtr oGr = GET(boost::target(*oe, _g))->_prev;
- if (std::find(oGr->_endElse.begin(), oGr->_endElse.end(), _curGroup.get()) != oGr->_endElse.end())
- coalesceElse = true;
- }
- if (coalesceElse) {
- _curGroup->_code.clear();
- _curGroup->_coalescedElse = true;
- s << "} else ";
- }
- }
- s << "if (" << _stack.pop()->negate() << ") {";
- addOutputLine(s.str(), _curGroup->_coalescedElse, true);
- break;
- case kWhileCondGroupType:
- s << "while (" << _stack.pop()->negate() << ") {";
- addOutputLine(s.str(), false, true);
- break;
- case kDoWhileCondGroupType:
- s << "} while (" << _stack.pop() << ")";
- addOutputLine(s.str(), true, false);
- break;
- default:
- break;
- }
- } else if (inst->isUncondJump()) {
- switch (_curGroup->_type) {
- case kBreakGroupType:
- addOutputLine("break;");
- break;
- case kContinueGroupType:
- addOutputLine("continue;");
- break;
- default:
- {
- bool printJump = true;
- OutEdgeRange r = boost::out_edges(_curVertex, _g);
- for (OutEdgeIterator e = r.first; e != r.second && printJump; ++e) {
- // Don't output jump to next vertex
- if (boost::target(*e, _g) == _curGroup->_next->_vertex) {
- printJump = false;
- break;
- }
-
- // Don't output jump if next vertex starts an else block
- if (_curGroup->_next->_startElse) {
- printJump = false;
- break;
- }
-
-
- OutEdgeRange targetR = boost::out_edges(boost::target(*e, _g), _g);
- for (OutEdgeIterator targetE = targetR.first; targetE != targetR.second; ++targetE) {
- // Don't output jump to while loop that has jump to next vertex
- if (boost::target(*targetE, _g) == _curGroup->_next->_vertex)
- printJump = false;
- }
- }
- if (printJump) {
- std::stringstream s;
- s << boost::format("jump 0x%X;") % inst->getDestAddress();
- addOutputLine(s.str());
- }
- }
- break;
- }
- }
-}
-
-void CodeGenerator::addArg(ValuePtr p) {
- if (_callOrder == kFIFOArgOrder)
- _argList.push_front(p);
- else if (_callOrder == kLIFOArgOrder)
- _argList.push_back(p);
-}
-
-void CodeGenerator::processSpecialMetadata(const InstPtr inst, char c, int pos) {
- switch (c) {
- case 'p':
- addArg(_stack.pop());
- break;
- default:
- std::cerr << boost::format("WARNING: Unknown character in metadata: %c\n") % c ;
- break;
- }
-}
-
Copied: tools/trunk/decompiler/codegen.cpp (from rev 54952, tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp)
===================================================================
--- tools/trunk/decompiler/codegen.cpp (rev 0)
+++ tools/trunk/decompiler/codegen.cpp 2010-12-18 13:38:26 UTC (rev 54955)
@@ -0,0 +1,268 @@
+/* ScummVM Tools
+ * Copyright (C) 2010 The ScummVM project
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "codegen.h"
+#include "engine.h"
+
+#include <algorithm>
+#include <iostream>
+#include <set>
+#include <boost/format.hpp>
+
+#define GET(vertex) (boost::get(boost::vertex_name, _g, vertex))
+#define GET_EDGE(edge) (boost::get(boost::edge_attribute, _g, edge))
+
+std::string CodeGenerator::constructFuncSignature(const Function &func) {
+ return "";
+}
+
+std::string CodeGenerator::indentString(std::string s) {
+ std::stringstream stream;
+ stream << std::string(kIndentAmount * _indentLevel, ' ') << s;
+ return stream.str();
+}
+
+CodeGenerator::CodeGenerator(Engine *engine, std::ostream &output, ArgOrder binOrder, ArgOrder callOrder) : _output(output), _binOrder(binOrder), _callOrder(callOrder) {
+ _engine = engine;
+ _indentLevel = 0;
+}
+
+typedef std::pair<GraphVertex, ValueStack> DFSEntry;
+
+void CodeGenerator::generate(const Graph &g) {
+ _g = g;
+
+ for (FuncMap::iterator fn = _engine->_functions.begin(); fn != _engine->_functions.end(); ++fn) {
+ _indentLevel = 0;
+ while (!_stack.empty())
+ _stack.pop();
+ GraphVertex entryPoint = fn->second._v;
+ std::string funcSignature = constructFuncSignature(fn->second);
+ bool printFuncSignature = !funcSignature.empty();
+ if (printFuncSignature) {
+ _curGroup = GET(entryPoint);
+ if (!(fn == _engine->_functions.begin()))
+ addOutputLine("");
+ addOutputLine(funcSignature, false, true);
+ }
+
+ GroupPtr lastGroup = GET(entryPoint);
+
+ // DFS from entry point to process each vertex
+ Stack<DFSEntry> dfsStack;
+ std::set<GraphVertex> seen;
+ dfsStack.push(DFSEntry(entryPoint, ValueStack()));
+ seen.insert(entryPoint);
+ while (!dfsStack.empty()) {
+ DFSEntry e = dfsStack.pop();
+ GroupPtr tmp = GET(e.first);
+ if ((*tmp->_start)->_address > (*lastGroup->_start)->_address)
+ lastGroup = tmp;
+ _stack = e.second;
+ GraphVertex v = e.first;
+ process(v);
+ OutEdgeRange r = boost::out_edges(v, _g);
+ for (OutEdgeIterator i = r.first; i != r.second; ++i) {
+ GraphVertex target = boost::target(*i, _g);
+ if (seen.find(target) == seen.end()) {
+ dfsStack.push(DFSEntry(target, _stack));
+ seen.insert(target);
+ }
+ }
+ }
+
+ if (printFuncSignature) {
+ _curGroup = lastGroup;
+ addOutputLine("}", true, false);
+ }
+
+ // Print output
+ GroupPtr p = GET(entryPoint);
+ while (p != NULL) {
+ for (std::vector<CodeLine>::iterator it = p->_code.begin(); it != p->_code.end(); ++it) {
+ if (it->_unindentBefore) {
+ assert(_indentLevel > 0);
+ _indentLevel--;
+ }
+ _output << boost::format("%08X: %s") % (*p->_start)->_address % indentString(it->_line) << std::endl;
+ if (it->_indentAfter)
+ _indentLevel++;
+ }
+ p = p->_next;
+ }
+
+ if (_indentLevel != 0)
+ std::cerr << boost::format("WARNING: Indent level for function at %d ended at %d\n") % fn->first % _indentLevel;
+ }
+}
+
+void CodeGenerator::addOutputLine(std::string s, bool unindentBefore, bool indentAfter) {
+ _curGroup->_code.push_back(CodeLine(s, unindentBefore, indentAfter));
+}
+
+void CodeGenerator::writeAssignment(ValuePtr dst, ValuePtr src) {
+ std::stringstream s;
+ s << dst << " = " << src << ";";
+ addOutputLine(s.str());
+}
+
+void CodeGenerator::process(GraphVertex v) {
+ _curVertex = v;
+ _curGroup = GET(v);
+
+ // Check if we should add else start
+ if (_curGroup->_startElse)
+ addOutputLine("} else {", true, true);
+
+ // Check ingoing edges to see if we want to add any extra output
+ InEdgeRange ier = boost::in_edges(v, _g);
+ for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
+ GraphVertex in = boost::source(*ie, _g);
+ GroupPtr inGroup = GET(in);
+
+ if (!boost::get(boost::edge_attribute, _g, *ie)._isJump || inGroup->_stackLevel == -1)
+ continue;
+
+ switch (inGroup->_type) {
+ case kDoWhileCondGroupType:
+ addOutputLine("do {", false, true);
+ break;
+ case kIfCondGroupType:
+ if (!_curGroup->_startElse)
+ addOutputLine("}", true, false);
+ break;
+ case kWhileCondGroupType:
+ addOutputLine("}", true, false);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ConstInstIterator it = _curGroup->_start;
+ do {
+ processInst(*it);
+ } while (it++ != _curGroup->_end);
+
+ // Add else end if necessary
+ for (ElseEndIterator elseIt = _curGroup->_endElse.begin(); elseIt != _curGroup->_endElse.end(); ++elseIt) {
+ if (!(*elseIt)->_coalescedElse)
+ addOutputLine("}", true, false);
+ }
+}
+
+void CodeGenerator::processInst(const InstPtr inst) {
+ inst->processInst(_stack, _engine, this);
+ if (inst->isCondJump()) {
+ std::stringstream s;
+ switch (_curGroup->_type) {
+ case kIfCondGroupType:
+ if (_curGroup->_startElse && _curGroup->_code.size() == 1) {
+ OutEdgeRange oer = boost::out_edges(_curVertex, _g);
+ bool coalesceElse = false;
+ for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
+ GroupPtr oGr = GET(boost::target(*oe, _g))->_prev;
+ if (std::find(oGr->_endElse.begin(), oGr->_endElse.end(), _curGroup.get()) != oGr->_endElse.end())
+ coalesceElse = true;
+ }
+ if (coalesceElse) {
+ _curGroup->_code.clear();
+ _curGroup->_coalescedElse = true;
+ s << "} else ";
+ }
+ }
+ s << "if (" << _stack.pop()->negate() << ") {";
+ addOutputLine(s.str(), _curGroup->_coalescedElse, true);
+ break;
+ case kWhileCondGroupType:
+ s << "while (" << _stack.pop()->negate() << ") {";
+ addOutputLine(s.str(), false, true);
+ break;
+ case kDoWhileCondGroupType:
+ s << "} while (" << _stack.pop() << ")";
+ addOutputLine(s.str(), true, false);
+ break;
+ default:
+ break;
+ }
+ } else if (inst->isUncondJump()) {
+ switch (_curGroup->_type) {
+ case kBreakGroupType:
+ addOutputLine("break;");
+ break;
+ case kContinueGroupType:
+ addOutputLine("continue;");
+ break;
+ default:
+ {
+ bool printJump = true;
+ OutEdgeRange r = boost::out_edges(_curVertex, _g);
+ for (OutEdgeIterator e = r.first; e != r.second && printJump; ++e) {
+ // Don't output jump to next vertex
+ if (boost::target(*e, _g) == _curGroup->_next->_vertex) {
+ printJump = false;
+ break;
+ }
+
+ // Don't output jump if next vertex starts an else block
+ if (_curGroup->_next->_startElse) {
+ printJump = false;
+ break;
+ }
+
+
+ OutEdgeRange targetR = boost::out_edges(boost::target(*e, _g), _g);
+ for (OutEdgeIterator targetE = targetR.first; targetE != targetR.second; ++targetE) {
+ // Don't output jump to while loop that has jump to next vertex
+ if (boost::target(*targetE, _g) == _curGroup->_next->_vertex)
+ printJump = false;
+ }
+ }
+ if (printJump) {
+ std::stringstream s;
+ s << boost::format("jump 0x%X;") % inst->getDestAddress();
+ addOutputLine(s.str());
+ }
+ }
+ break;
+ }
+ }
+}
+
+void CodeGenerator::addArg(ValuePtr p) {
+ if (_callOrder == kFIFOArgOrder)
+ _argList.push_front(p);
+ else if (_callOrder == kLIFOArgOrder)
+ _argList.push_back(p);
+}
+
+void CodeGenerator::processSpecialMetadata(const InstPtr inst, char c, int pos) {
+ switch (c) {
+ case 'p':
+ addArg(_stack.pop());
+ break;
+ default:
+ std::cerr << boost::format("WARNING: Unknown character in metadata: %c\n") % c ;
+ break;
+ }
+}
+
Deleted: tools/trunk/decompiler/codegen.h
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/codegen.h 2010-12-18 12:49:08 UTC (rev 54952)
+++ tools/trunk/decompiler/codegen.h 2010-12-18 13:38:26 UTC (rev 54955)
@@ -1,153 +0,0 @@
-/* ScummVM Tools
- * Copyright (C) 2010 The ScummVM project
- *
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "graph.h"
-#include "value.h"
-
-#include <ostream>
-#include <utility>
-
-#include <boost/intrusive_ptr.hpp>
-
-#ifndef DEC_CODEGEN_H
-#define DEC_CODEGEN_H
-
-class Engine;
-
-class Function;
-
-const int kIndentAmount = 2; ///< How many spaces to use for each indent.
-
-/**
- * Enumeration for the different argument/operand orderings.
- */
-enum ArgOrder {
- kFIFOArgOrder, ///< First argument is pushed to stack first.
- kLIFOArgOrder ///< First argument is pushed to stack last.
-};
-
-/**
- * Base class for code generators.
- */
-class CodeGenerator {
-private:
- Graph _g; ///< The annotated graph of the script.
-
- /**
- * Processes a GraphVertex.
- *
- * @param v The vertex to process.
- */
- void process(GraphVertex v);
-
-protected:
- Engine *_engine; ///< Pointer to the Engine used for the script.
- std::ostream &_output; ///< The std::ostream to output the code to.
- ValueStack _stack; ///< The stack currently being processed.
- uint _indentLevel; ///< Indentation level.
- GraphVertex _curVertex; ///< Graph vertex currently being processed.
-
- /**
- * Processes an instruction. Called by process() for each instruction.
- * Call the base class implementation for opcodes you cannot handle yourself,
- * or where the base class implementation is preferable.
- *
- * @param inst The instruction to process.
- */
- void processInst(const InstPtr inst);
-
- /**
- * Indents a string according to the current indentation level.
- *
- * @param s The string to indent.
- * @result The indented string.
- */
- std::string indentString(std::string s);
-
- /**
- * Construct the signature for a function.
- *
- * @param func Reference to the function to construct the signature for.
- */
- virtual std::string constructFuncSignature(const Function &func);
-
-public:
- const ArgOrder _binOrder; ///< Order of operands for binary operations.
- const ArgOrder _callOrder; ///< Order of operands for call arguments.
- ValueList _argList; ///< Storage for lists of arguments to be built when processing function calls.
- GroupPtr _curGroup; ///< Pointer to the group currently being processed.
-
- virtual ~CodeGenerator() { }
-
- /**
- * Constructor for CodeGenerator.
- *
- * @param engine Pointer to the Engine used for the script.
- * @param output The std::ostream to output the code to.
- * @param binOrder Order of arguments for binary operators.
- * @param callOrder Order of arguments for function calls.
- */
- CodeGenerator(Engine *engine, std::ostream &output, ArgOrder binOrder, ArgOrder callOrder);
-
- /**
- * Generates code from the provided graph and outputs it to stdout.
- *
- * @param g The annotated graph of the script.
- */
- void generate(const Graph &g);
-
- /**
- * Adds a line of code to the current group.
- *
- * @param s The line to add.
- * @param unindentBefore Whether or not to remove an indentation level before the line. Defaults to false.
- * @param indentAfter Whether or not to add an indentation level after the line. Defaults to false.
- */
- void addOutputLine(std::string s, bool unindentBefore = false, bool indentAfter = false);
-
- /**
- * Generate an assignment statement.
- *
- * @param dst The variable being assigned to.
- * @param src The value being assigned.
- */
- void writeAssignment(ValuePtr dst, ValuePtr src);
-
- /**
- * Add an argument to the argument list.
- *
- * @param p The argument to add.
- */
- void addArg(ValuePtr p);
-
- /**
- * Process a single character of metadata.
- *
- * @param inst The instruction being processed.
- * @param c The character signifying the action to be taken.
- * @param pos The position at which c occurred in the metadata.
- */
- virtual void processSpecialMetadata(const InstPtr inst, char c, int pos);
-
-};
-
-#endif
Copied: tools/trunk/decompiler/codegen.h (from rev 54952, tools/branches/gsoc2010-decompiler/decompiler/codegen.h)
===================================================================
--- tools/trunk/decompiler/codegen.h (rev 0)
+++ tools/trunk/decompiler/codegen.h 2010-12-18 13:38:26 UTC (rev 54955)
@@ -0,0 +1,153 @@
+/* ScummVM Tools
+ * Copyright (C) 2010 The ScummVM project
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "graph.h"
+#include "value.h"
+
+#include <ostream>
+#include <utility>
+
+#include <boost/intrusive_ptr.hpp>
+
+#ifndef DEC_CODEGEN_H
+#define DEC_CODEGEN_H
+
+class Engine;
+
+class Function;
+
+const int kIndentAmount = 2; ///< How many spaces to use for each indent.
+
+/**
+ * Enumeration for the different argument/operand orderings.
+ */
+enum ArgOrder {
+ kFIFOArgOrder, ///< First argument is pushed to stack first.
+ kLIFOArgOrder ///< First argument is pushed to stack last.
+};
+
+/**
+ * Base class for code generators.
+ */
+class CodeGenerator {
+private:
+ Graph _g; ///< The annotated graph of the script.
+
+ /**
+ * Processes a GraphVertex.
+ *
+ * @param v The vertex to process.
+ */
+ void process(GraphVertex v);
+
+protected:
+ Engine *_engine; ///< Pointer to the Engine used for the script.
+ std::ostream &_output; ///< The std::ostream to output the code to.
+ ValueStack _stack; ///< The stack currently being processed.
+ uint _indentLevel; ///< Indentation level.
+ GraphVertex _curVertex; ///< Graph vertex currently being processed.
+
+ /**
+ * Processes an instruction. Called by process() for each instruction.
+ * Call the base class implementation for opcodes you cannot handle yourself,
+ * or where the base class implementation is preferable.
+ *
+ * @param inst The instruction to process.
+ */
+ void processInst(const InstPtr inst);
+
+ /**
+ * Indents a string according to the current indentation level.
+ *
+ * @param s The string to indent.
+ * @result The indented string.
+ */
+ std::string indentString(std::string s);
+
+ /**
+ * Construct the signature for a function.
+ *
+ * @param func Reference to the function to construct the signature for.
+ */
+ virtual std::string constructFuncSignature(const Function &func);
+
+public:
+ const ArgOrder _binOrder; ///< Order of operands for binary operations.
+ const ArgOrder _callOrder; ///< Order of operands for call arguments.
+ ValueList _argList; ///< Storage for lists of arguments to be built when processing function calls.
+ GroupPtr _curGroup; ///< Pointer to the group currently being processed.
+
+ virtual ~CodeGenerator() { }
+
+ /**
+ * Constructor for CodeGenerator.
+ *
+ * @param engine Pointer to the Engine used for the script.
+ * @param output The std::ostream to output the code to.
+ * @param binOrder Order of arguments for binary operators.
+ * @param callOrder Order of arguments for function calls.
+ */
+ CodeGenerator(Engine *engine, std::ostream &output, ArgOrder binOrder, ArgOrder callOrder);
+
+ /**
+ * Generates code from the provided graph and outputs it to stdout.
+ *
+ * @param g The annotated graph of the script.
+ */
+ void generate(const Graph &g);
+
+ /**
+ * Adds a line of code to the current group.
+ *
+ * @param s The line to add.
+ * @param unindentBefore Whether or not to remove an indentation level before the line. Defaults to false.
+ * @param indentAfter Whether or not to add an indentation level after the line. Defaults to false.
+ */
+ void addOutputLine(std::string s, bool unindentBefore = false, bool indentAfter = false);
+
+ /**
+ * Generate an assignment statement.
+ *
+ * @param dst The variable being assigned to.
+ * @param src The value being assigned.
+ */
+ void writeAssignment(ValuePtr dst, ValuePtr src);
+
+ /**
+ * Add an argument to the argument list.
+ *
+ * @param p The argument to add.
+ */
+ void addArg(ValuePtr p);
+
+ /**
+ * Process a single character of metadata.
+ *
+ * @param inst The instruction being processed.
+ * @param c The character signifying the action to be taken.
+ * @param pos The position at which c occurred in the metadata.
+ */
+ virtual void processSpecialMetadata(const InstPtr inst, char c, int pos);
+
+};
+
+#endif
Deleted: tools/trunk/decompiler/control_flow.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp 2010-12-18 12:49:08 UTC (rev 54952)
+++ tools/trunk/decompiler/control_flow.cpp 2010-12-18 13:38:26 UTC (rev 54955)
@@ -1,612 +0,0 @@
-/* ScummVM Tools
- * Copyright (C) 2010 The ScummVM project
- *
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "control_flow.h"
-#include "stack.h"
-
-#include <algorithm>
-#include <iostream>
-#include <set>
-
-#include <boost/format.hpp>
-
-#define PUT(vertex, group) boost::put(boost::vertex_name, _g, vertex, group);
-#define PUT_EDGE(edge, isJump) boost::put(boost::edge_attribute, _g, edge, isJump);
-#define PUT_ID(vertex, id) boost::put(boost::vertex_index, _g, vertex, id);
-#define GET(vertex) (boost::get(boost::vertex_name, _g, vertex))
-#define GET_EDGE(edge) (boost::get(boost::edge_attribute, _g, edge))
-
-ControlFlow::ControlFlow(const InstVec &insts, Engine *engine) : _insts(insts) {
- _engine = engine;
-
- // Automatically add a function if we're not supposed to look for more functions and no functions are defined
- // This avoids a special case for when no real functions exist in the script
- if (engine->_functions.empty() && !_engine->detectMoreFuncs())
- engine->_functions[(*insts.begin())->_address] = Function(insts.begin(), insts.end());
-
- GroupPtr prev = NULL;
- int id = 0;
- // Create vertices
- for (ConstInstIterator it = insts.begin(); it != insts.end(); ++it) {
- GraphVertex cur = boost::add_vertex(_g);
- _addrMap[(*it)->_address] = cur;
- PUT(cur, new Group(cur, it, it, prev));
- PUT_ID(cur, id);
- id++;
-
- // Add reference to vertex if function starts here
- if (_engine->_functions.find((*it)->_address) != _engine->_functions.end())
- _engine->_functions[(*it)->_address]._v = cur;
-
- prev = GET(cur);
- }
-
- // Add regular edges
- FuncMap::iterator fn;
- GraphVertex last;
- bool addEdge = false;
- prev = NULL;
- for (ConstInstIterator it = insts.begin(); it != insts.end(); ++it) {
- if (_engine->_functions.find((*it)->_address) != _engine->_functions.end()) {
- addEdge = false;
- }
-
- GraphVertex cur = find(it);
- if (addEdge) {
- GraphEdge e = boost::add_edge(last, cur, _g).first;
- PUT_EDGE(e, false);
- }
-
- last = cur;
- addEdge = !((*it)->isUncondJump() || (*it)->isReturn());
- prev = GET(cur);
-
- }
-
- // Add jump edges
- for (ConstInstIterator it = insts.begin(); it != insts.end(); ++it) {
- if ((*it)->isJump()) {
- GraphEdge e = boost::add_edge(find(it), find((*it)->getDestAddress()), _g).first;
- PUT_EDGE(e, true);
- }
- }
-}
-
-GraphVertex ControlFlow::find(const InstPtr inst) {
- return _addrMap[inst->_address];
-}
-
-GraphVertex ControlFlow::find(ConstInstIterator it) {
- return _addrMap[(*it)->_address];
-}
-
-GraphVertex ControlFlow::find(uint32 address) {
- std::map<uint32, GraphVertex>::iterator it = _addrMap.find(address);
- if (it == _addrMap.end())
- std::cerr << "Request for instruction at unknown address" << boost::format("0x%08x") % address;
- return it->second;
-}
-
-void ControlFlow::merge(GraphVertex g1, GraphVertex g2) {
- // Update property
- GroupPtr gr1 = GET(g1);
- GroupPtr gr2 = GET(g2);
- gr1->_end = gr2->_end;
- PUT(g1, gr1);
-
- // Update address map
- ConstInstIterator it = gr2->_start;
- do {
- _addrMap[(*it)->_address] = g1;
- ++it;
- } while (gr2->_start != gr2->_end && it != gr2->_end);
-
- // Add outgoing edges from g2
- OutEdgeRange r = boost::out_edges(g2, _g);
- for (OutEdgeIterator e = r.first; e != r.second; ++e) {
- GraphEdge newE = boost::add_edge(g1, boost::target(*e, _g), _g).first;
- PUT_EDGE(newE, GET_EDGE(*e));
- }
-
- // Update _next pointer
- gr1->_next = gr2->_next;
- if (gr2->_next != NULL)
- gr2->_next->_prev = gr2->_prev;
-
- // Remove edges to/from g2
- boost::clear_vertex(g2, _g);
- // Remove vertex
- boost::remove_vertex(g2, _g);
-}
-
-typedef std::pair<GraphVertex, int> LevelEntry;
-
-void ControlFlow::setStackLevel(GraphVertex g, int level) {
- Stack<LevelEntry> levelStack;
- std::set<GraphVertex> seen;
- levelStack.push(LevelEntry(g, level));
- seen.insert(g);
- while (!levelStack.empty()) {
- LevelEntry e = levelStack.pop();
- GroupPtr gr = GET(e.first);
- if (gr->_stackLevel != -1) {
- if (gr->_stackLevel != e.second)
- std::cerr << boost::format("WARNING: Inconsistency in expected stack level for instruction at address 0x%08x (current: %d, requested: %d)\n") % (*gr->_start)->_address % gr->_stackLevel % e.second;
- continue;
- }
- gr->_stackLevel = e.second;
-
- OutEdgeRange r = boost::out_edges(e.first, _g);
- for (OutEdgeIterator oe = r.first; oe != r.second; ++oe) {
- GraphVertex target = boost::target(*oe, _g);
- if (seen.find(target) == seen.end()) {
- levelStack.push(LevelEntry(target, e.second + (*gr->_start)->_stackChange));
- seen.insert(target);
- }
- }
- }
-}
-
-void ControlFlow::detectFunctions() {
- uint32 nextFunc = 0;
- for (ConstInstIterator it = _insts.begin(); it != _insts.end(); ++it) {
- GraphVertex v = find(it);
- GroupPtr gr = GET(v);
-
- if ((*it)->_address < nextFunc)
- continue;
-
- bool functionExists = false;
- bool detectEndPoint = false;
- for (FuncMap::iterator fn = _engine->_functions.begin(); fn != _engine->_functions.end(); ++fn) {
- if (fn->first == (*it)->_address) {
- if (fn->second._endIt == _insts.end()) {
- return;
- }
- if (fn->second._startIt == fn->second._endIt) {
- // We already know this is an entry point, we only need to detect the end point
- detectEndPoint = true;
- break;
- }
- nextFunc = (*fn->second._endIt)->_address;
- functionExists = true;
- }
- }
-
- if (functionExists)
- continue;
-
- bool isEntryPoint = true;
- if (!detectEndPoint) {
- InEdgeRange ier = boost::in_edges(v, _g);
- for (InEdgeIterator e = ier.first; e != ier.second; ++e) {
- // If an ingoing edge exists from earlier in the code, this is not a function entry point
- if ((*GET(boost::source(*e, _g))->_start)->_address < (*gr->_start)->_address)
- isEntryPoint = false;
- }
- }
-
- if (isEntryPoint) {
- // Detect end point
- Stack<GraphVertex> stack;
- std::set<GraphVertex> seen;
- stack.push(v);
- GroupPtr endPoint = gr;
- while (!stack.empty()) {
- v = stack.pop();
- GroupPtr tmp = GET(v);
- if ((*tmp->_start)->_address > (*endPoint->_start)->_address)
- endPoint = tmp;
- OutEdgeRange r = boost::out_edges(v, _g);
- for (OutEdgeIterator i = r.first; i != r.second; ++i) {
- GraphVertex target = boost::target(*i, _g);
- if (seen.find(target) == seen.end()) {
- stack.push(target);
- seen.insert(target);
- }
- }
- }
-
- ConstInstIterator endInst;
- if (endPoint->_next) {
- endInst = endPoint->_next->_start;
- nextFunc = (*endInst)->_address;
- } else {
- endInst = _insts.end();
- }
- Function f;
- if (detectEndPoint) {
- f = _engine->_functions[(*gr->_start)->_address];
- f._endIt = endInst;
- } else {
- f = Function(gr->_start, endInst);
- f._name = "auto_";
- }
- f._v = find(it);
- _engine->_functions[(*gr->_start)->_address] = f;
- if (!endPoint->_next)
- return;
- }
- }
-}
-
-void ControlFlow::createGroups() {
- if (!_engine->_functions.empty() && GET(_engine->_functions.begin()->second._v)->_stackLevel != -1)
- return;
-
- // Detect more functions
- if (_engine->detectMoreFuncs())
- detectFunctions();
-
- for (FuncMap::iterator fn = _engine->_functions.begin(); fn != _engine->_functions.end(); ++fn)
- setStackLevel(fn->second._v, 0);
- ConstInstIterator curInst, nextInst;
- nextInst = _insts.begin();
- nextInst++;
- int stackLevel = 0;
- int expectedStackLevel = 0;
- for (curInst = _insts.begin(); nextInst != _insts.end(); ++curInst, ++nextInst) {
- GraphVertex cur = find(curInst);
- GraphVertex next = find(nextInst);
-
- GroupPtr grCur = GET(cur);
- GroupPtr grNext = GET(next);
-
- // Don't process unreachable code
- if (grCur->_stackLevel < 0) {
- stackLevel = grNext->_stackLevel;
- continue;
- }
-
- expectedStackLevel = grCur->_stackLevel;
- // If expected stack level decreases in next vertex, then use next vertex level as expected level
- if (expectedStackLevel > grNext->_stackLevel && grNext->_stackLevel >= 0) {
- expectedStackLevel = grNext->_stackLevel;
- // Also set the stack level of the current group to remember that we expect it to be lower
- grCur->_stackLevel = expectedStackLevel;
- }
-
- stackLevel += (*curInst)->_stackChange;
-
- // For stack operations, the new stack level becomes the expected stack level starting from the next group
- if ((*curInst)->isStackOp()) {
- expectedStackLevel = stackLevel;
- grNext->_stackLevel = stackLevel;
- }
-
- // Group ends after a jump
- if ((*curInst)->isJump()) {
- stackLevel = grNext->_stackLevel;
- continue;
- }
-
- // Group ends with a return
- if ((*curInst)->isReturn()) {
- stackLevel = grNext->_stackLevel;
- continue;
- }
-
- // Group ends before target of a jump
- if (in_degree(next, _g) != 1) {
- stackLevel = grNext->_stackLevel;
- continue;
- }
-
- // If group has no instructions with stack effect >= 0, don't merge on balanced stack
- bool forceMerge = true;
- ConstInstIterator it = grCur->_start;
- do {
- if ((*it)->_stackChange >= 0)
- forceMerge = false;
- ++it;
- } while (grCur->_start != grCur->_end && it != grCur->_end);
-
- // Group ends when stack is balanced, unless just before conditional jump
- if (stackLevel == expectedStackLevel && !forceMerge && !(*nextInst)->isCondJump()) {
- continue;
- }
-
- // All checks passed, merge groups
- merge(cur, next);
- }
-
- // FIXME: The short-circuit detection is disabled because short-circuited groups require some special handling
- // in the code generation. It's not entirely clear how to handle it properly, though: you need to deduce which
- // effect is created by the conditional jumps in the middle of a block, which seems to get fairly complex when
- // you have multiple groups that are merged by the short-circuit detection.
- //detectShortCircuit();
-}
-
-void ControlFlow::detectShortCircuit() {
- ConstInstIterator lastInst = _insts.end();
- --lastInst;
- GraphVertex cur = find(lastInst);
- GroupPtr gr = GET(cur);
- while (gr->_prev != NULL) {
- bool doMerge = false;
- cur = find(gr->_start);
- GraphVertex prev = find(gr->_prev->_start);
- // Block is candidate for short-circuit merging if it and the preceding block both end with conditional jumps
- if (out_degree(cur, _g) == 2 && out_degree(prev, _g) == 2) {
- doMerge = true;
- OutEdgeRange rCur = boost::out_edges(cur, _g);
- std::vector<GraphVertex> succs;
-
- // Find possible target vertices
- for (OutEdgeIterator it = rCur.first; it != rCur.second; ++it) {
- succs.push_back(boost::target(*it, _g));
- }
-
- // Check if vertex would add new targets - if yes, don't merge
- OutEdgeRange rPrev = boost::out_edges(prev, _g);
- for (OutEdgeIterator it = rPrev.first; it != rPrev.second; ++it) {
- GraphVertex target = boost::target(*it, _g);
- doMerge &= (std::find(succs.begin(), succs.end(), target) != succs.end() || target == cur);
- }
-
- if (doMerge) {
- gr = gr->_prev;
- merge(prev, cur);
- continue;
- }
- }
- gr = gr->_prev;
- }
-}
-
-const Graph &ControlFlow::analyze() {
- detectDoWhile();
- detectWhile();
- detectBreak();
- detectContinue();
- detectIf();
- detectElse();
- return _g;
-}
-
-void ControlFlow::detectWhile() {
- VertexRange vr = boost::vertices(_g);
- for (VertexIterator v = vr.first; v != vr.second; ++v) {
- GroupPtr gr = GET(*v);
- // Undetermined block that ends with conditional jump
- if (out_degree(*v, _g) == 2 && gr->_type == kNormalGroupType) {
- InEdgeRange ier = boost::in_edges(*v, _g);
- bool isWhile = false;
- for (InEdgeIterator e = ier.first; e != ier.second; ++e) {
- GroupPtr sourceGr = GET(boost::source(*e, _g));
- // Block has ingoing edge from block later in the code that isn't a do-while condition
- if ((*sourceGr->_start)->_address > (*gr->_start)->_address && sourceGr->_type != kDoWhileCondGroupType)
- isWhile = true;
- }
- if (isWhile)
- gr->_type = kWhileCondGroupType;
- }
- }
-}
-
-void ControlFlow::detectDoWhile() {
- VertexRange vr = boost::vertices(_g);
- for (VertexIterator v = vr.first; v != vr.second; ++v) {
- GroupPtr gr = GET(*v);
- // Undetermined block that ends with conditional jump...
- if (out_degree(*v, _g) == 2 && gr->_type == kNormalGroupType) {
- OutEdgeRange oer = boost::out_edges(*v, _g);
- for (OutEdgeIterator e = oer.first; e != oer.second; ++e) {
- GroupPtr targetGr = GET(boost::target(*e, _g));
- // ...to earlier in code
- if ((*targetGr->_start)->_address < (*gr->_start)->_address)
- gr->_type = kDoWhileCondGroupType;
- }
- }
- }
-}
-
-void ControlFlow::detectBreak() {
- VertexRange vr = boost::vertices(_g);
- for (VertexIterator v = vr.first; v != vr.second; ++v) {
- GroupPtr gr = GET(*v);
- // Undetermined block with unconditional jump...
- if (gr->_type == kNormalGroupType && ((*gr->_end)->isUncondJump()) && out_degree(*v, _g) == 1) {
- OutEdgeIterator oe = boost::out_edges(*v, _g).first;
- GraphVertex target = boost::target(*oe, _g);
- GroupPtr targetGr = GET(target);
- // ...to somewhere later in the code...
- if ((*gr->_start)->_address >= (*targetGr->_start)->_address)
- continue;
- InEdgeRange ier = boost::in_edges(target, _g);
- for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
- GroupPtr sourceGr = GET(boost::source(*ie, _g));
- // ...to block immediately after a do-while condition, or to jump target of a while condition
- if ((targetGr->_prev == sourceGr && sourceGr->_type == kDoWhileCondGroupType) || sourceGr->_type == kWhileCondGroupType) {
- if (validateBreakOrContinue(gr, sourceGr))
- gr->_type = kBreakGroupType;
- }
- }
- }
- }
-}
-
-void ControlFlow::detectContinue() {
- VertexRange vr = boost::vertices(_g);
- for (VertexIterator v = vr.first; v != vr.second; ++v) {
- GroupPtr gr = GET(*v);
- // Undetermined block with unconditional jump...
- if (gr->_type == kNormalGroupType && ((*gr->_end)->isUncondJump()) && out_degree(*v, _g) == 1) {
- OutEdgeIterator oe = boost::out_edges(*v, _g).first;
- GraphVertex target = boost::target(*oe, _g);
- GroupPtr targetGr = GET(target);
- // ...to a while or do-while condition...
- if (targetGr->_type == kWhileCondGroupType || targetGr->_type == kDoWhileCondGroupType) {
- bool isContinue = true;
- // ...unless...
- OutEdgeRange toer = boost::out_edges(target, _g);
- bool afterJumpTargets = true;
- for (OutEdgeIterator toe = toer.first; toe != toer.second; ++toe) {
- // ...it is targeting a while condition which jumps to the next sequential group
- if (targetGr->_type == kWhileCondGroupType && GET(boost::target(*toe, _g)) == gr->_next)
- isContinue = false;
- // ...or the instruction is placed after all jump targets from condition
- if ((*GET(boost::target(*toe, _g))->_start)->_address > (*gr->_start)->_address)
- afterJumpTargets = false;
- }
- if (afterJumpTargets)
- isContinue = false;
-
- if (isContinue && validateBreakOrContinue(gr, targetGr))
- gr->_type = kContinueGroupType;
- }
- }
- }
-}
-
-bool ControlFlow::validateBreakOrContinue(GroupPtr gr, GroupPtr condGr) {
- GroupPtr from, to, cursor;
-
- if (condGr->_type == kDoWhileCondGroupType) {
- to = condGr;
- from = gr;
- } else {
- to = gr;
- from = condGr->_next;
- }
-
- GroupType ogt = (condGr->_type == kDoWhileCondGroupType ? kWhileCondGroupType : kDoWhileCondGroupType);
- // Verify that destination deals with innermost while/do-while
- for (cursor = from; cursor->_next != NULL && cursor != to; cursor = cursor->_next) {
- if (cursor->_type == condGr->_type) {
- OutEdgeRange oerValidate = boost::out_edges(find(cursor->_start), _g);
- for (OutEdgeIterator oeValidate = oerValidate.first; oeValidate != oerValidate.second; ++oeValidate) {
- GraphVertex vValidate = boost::target(*oeValidate, _g);
- GroupPtr gValidate = GET(vValidate);
- // For all other loops of same type found in range, all targets must fall within that range
- if ((*gValidate->_start)->_address < (*from->_start)->_address || (*gValidate->_start)->_address > (*to->_start)->_address )
- return false;
-
- InEdgeRange ierValidate = boost::in_edges(vValidate, _g);
- for (InEdgeIterator ieValidate = ierValidate.first; ieValidate != ierValidate.second; ++ieValidate) {
- GroupPtr igValidate = GET(boost::source(*ieValidate, _g));
- // All loops of other type going into range must be placed within range
- if (igValidate->_type == ogt && ((*igValidate->_start)->_address < (*from->_start)->_address || (*igValidate->_start)->_address > (*to->_start)->_address ))
- return false;
- }
- }
- }
- }
- return true;
-}
-
-void ControlFlow::detectIf() {
- VertexRange vr = boost::vertices(_g);
- for (VertexIterator v = vr.first; v != vr.second; ++v) {
- GroupPtr gr = GET(*v);
- // if: Undetermined block with conditional jump
- if (gr->_type == kNormalGroupType && ((*gr->_end)->isCondJump())) {
- gr->_type = kIfCondGroupType;
- }
- }
-}
-
-void ControlFlow::detectElse() {
- VertexRange vr = boost::vertices(_g);
- for (VertexIterator v = vr.first; v != vr.second; ++v) {
- GroupPtr gr = GET(*v);
- if (gr->_type == kIfCondGroupType) {
- OutEdgeRange oer = boost::out_edges(*v, _g);
- GraphVertex target;
- uint32 maxAddress = 0;
- GroupPtr targetGr;
- // Find jump target
- for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
- targetGr = GET(boost::target(*oe, _g));
- if ((*targetGr->_start)->_address > maxAddress) {
- target = boost::target(*oe, _g);
- maxAddress = (*targetGr->_start)->_address;
- }
- }
- targetGr = GET(target);
- // else: Jump target of if immediately preceded by an unconditional jump...
- if (!(*targetGr->_prev->_end)->isUncondJump())
- continue;
- // ...which is not a break or a continue...
- if (targetGr->_prev->_type == kContinueGroupType || targetGr->_prev->_type == kBreakGroupType)
- continue;
- // ...to later in the code
- OutEdgeIterator toe = boost::out_edges(find((*targetGr->_prev->_start)->_address), _g).first;
- GroupPtr targetTargetGr = GET(boost::target(*toe, _g));
- if ((*targetTargetGr->_start)->_address > (*targetGr->_end)->_address) {
- if (validateElseBlock(gr, targetGr, targetTargetGr)) {
- targetGr->_startElse = true;
- targetTargetGr->_prev->_endElse.push_back(targetGr.get());
- }
- }
- }
- }
-}
-
-bool ControlFlow::validateElseBlock(GroupPtr ifGroup, GroupPtr start, GroupPtr end) {
- for (GroupPtr cursor = start; cursor != end; cursor = cursor->_next) {
- if (cursor->_type == kIfCondGroupType || cursor->_type == kWhileCondGroupType || cursor->_type == kDoWhileCondGroupType) {
- // Validate outgoing edges of conditions
- OutEdgeRange oer = boost::out_edges(find(cursor->_start), _g);
- for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
- GraphVertex target = boost::target(*oe, _g);
- GroupPtr targetGr = GET(target);
- // Each edge from condition must not leave the range [start, end]
- if ((*start->_start)->_address > (*targetGr->_start)->_address || (*targetGr->_start)->_address > (*end->_start)->_address)
- return false;
- }
- }
-
- // If previous group ends an else, that else must start inside the range
- for (ElseEndIterator it = cursor->_prev->_endElse.begin(); it != cursor->_prev->_endElse.end(); ++it)
- {
- if ((*(*it)->_start)->_address < (*start->_start)->_address)
- return false;
- }
-
- // Unless group is a simple unconditional jump...
- if ((*cursor->_start)->isUncondJump())
- continue;
-
- // ...validate ingoing edges
- InEdgeRange ier = boost::in_edges(find(cursor->_start), _g);
- for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
- GraphVertex source = boost::source(*ie, _g);
- GroupPtr sourceGr = GET(source);
-
- // Edges going to conditions...
- if (sourceGr->_type == kIfCondGroupType || sourceGr->_type == kWhileCondGroupType || sourceGr->_type == kDoWhileCondGroupType) {
- // ...must not come from outside the range [start, end]...
- if ((*start->_start)->_address > (*sourceGr->_start)->_address || (*sourceGr->_start)->_address > (*end->_start)->_address) {
- // ...unless source is simple unconditional jump...
- if ((*sourceGr->_start)->isUncondJump())
- continue;
- // ...or the edge is from the if condition associated with this else
- if (ifGroup == sourceGr)
- continue;
- return false;
- }
- }
- }
- }
- return true;
-}
Copied: tools/trunk/decompiler/control_flow.cpp (from rev 54952, tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp)
===================================================================
--- tools/trunk/decompiler/control_flow.cpp (rev 0)
+++ tools/trunk/decompiler/control_flow.cpp 2010-12-18 13:38:26 UTC (rev 54955)
@@ -0,0 +1,612 @@
+/* ScummVM Tools
+ * Copyright (C) 2010 The ScummVM project
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "control_flow.h"
+#include "stack.h"
+
+#include <algorithm>
+#include <iostream>
+#include <set>
+
+#include <boost/format.hpp>
+
+#define PUT(vertex, group) boost::put(boost::vertex_name, _g, vertex, group);
+#define PUT_EDGE(edge, isJump) boost::put(boost::edge_attribute, _g, edge, isJump);
+#define PUT_ID(vertex, id) boost::put(boost::vertex_index, _g, vertex, id);
+#define GET(vertex) (boost::get(boost::vertex_name, _g, vertex))
+#define GET_EDGE(edge) (boost::get(boost::edge_attribute, _g, edge))
+
+ControlFlow::ControlFlow(const InstVec &insts, Engine *engine) : _insts(insts) {
+ _engine = engine;
+
+ // Automatically add a function if we're not supposed to look for more functions and no functions are defined
+ // This avoids a special case for when no real functions exist in the script
+ if (engine->_functions.empty() && !_engine->detectMoreFuncs())
+ engine->_functions[(*insts.begin())->_address] = Function(insts.begin(), insts.end());
+
+ GroupPtr prev = NULL;
+ int id = 0;
+ // Create vertices
+ for (ConstInstIterator it = insts.begin(); it != insts.end(); ++it) {
+ GraphVertex cur = boost::add_vertex(_g);
+ _addrMap[(*it)->_address] = cur;
+ PUT(cur, new Group(cur, it, it, prev));
+ PUT_ID(cur, id);
+ id++;
+
+ // Add reference to vertex if function starts here
+ if (_engine->_functions.find((*it)->_address) != _engine->_functions.end())
+ _engine->_functions[(*it)->_address]._v = cur;
+
+ prev = GET(cur);
+ }
+
+ // Add regular edges
+ FuncMap::iterator fn;
+ GraphVertex last;
+ bool addEdge = false;
+ prev = NULL;
+ for (ConstInstIterator it = insts.begin(); it != insts.end(); ++it) {
+ if (_engine->_functions.find((*it)->_address) != _engine->_functions.end()) {
+ addEdge = false;
+ }
+
+ GraphVertex cur = find(it);
+ if (addEdge) {
+ GraphEdge e = boost::add_edge(last, cur, _g).first;
+ PUT_EDGE(e, false);
+ }
+
+ last = cur;
+ addEdge = !((*it)->isUncondJump() || (*it)->isReturn());
+ prev = GET(cur);
+
+ }
+
+ // Add jump edges
+ for (ConstInstIterator it = insts.begin(); it != insts.end(); ++it) {
+ if ((*it)->isJump()) {
+ GraphEdge e = boost::add_edge(find(it), find((*it)->getDestAddress()), _g).first;
+ PUT_EDGE(e, true);
+ }
+ }
+}
+
+GraphVertex ControlFlow::find(const InstPtr inst) {
+ return _addrMap[inst->_address];
+}
+
+GraphVertex ControlFlow::find(ConstInstIterator it) {
+ return _addrMap[(*it)->_address];
+}
+
+GraphVertex ControlFlow::find(uint32 address) {
+ std::map<uint32, GraphVertex>::iterator it = _addrMap.find(address);
+ if (it == _addrMap.end())
+ std::cerr << "Request for instruction at unknown address" << boost::format("0x%08x") % address;
+ return it->second;
+}
+
+void ControlFlow::merge(GraphVertex g1, GraphVertex g2) {
+ // Update property
+ GroupPtr gr1 = GET(g1);
+ GroupPtr gr2 = GET(g2);
+ gr1->_end = gr2->_end;
+ PUT(g1, gr1);
+
+ // Update address map
+ ConstInstIterator it = gr2->_start;
+ do {
+ _addrMap[(*it)->_address] = g1;
+ ++it;
+ } while (gr2->_start != gr2->_end && it != gr2->_end);
+
+ // Add outgoing edges from g2
+ OutEdgeRange r = boost::out_edges(g2, _g);
+ for (OutEdgeIterator e = r.first; e != r.second; ++e) {
+ GraphEdge newE = boost::add_edge(g1, boost::target(*e, _g), _g).first;
+ PUT_EDGE(newE, GET_EDGE(*e));
+ }
+
+ // Update _next pointer
+ gr1->_next = gr2->_next;
+ if (gr2->_next != NULL)
+ gr2->_next->_prev = gr2->_prev;
+
+ // Remove edges to/from g2
+ boost::clear_vertex(g2, _g);
+ // Remove vertex
+ boost::remove_vertex(g2, _g);
+}
+
+typedef std::pair<GraphVertex, int> LevelEntry;
+
+void ControlFlow::setStackLevel(GraphVertex g, int level) {
+ Stack<LevelEntry> levelStack;
+ std::set<GraphVertex> seen;
+ levelStack.push(LevelEntry(g, level));
+ seen.insert(g);
+ while (!levelStack.empty()) {
+ LevelEntry e = levelStack.pop();
+ GroupPtr gr = GET(e.first);
+ if (gr->_stackLevel != -1) {
+ if (gr->_stackLevel != e.second)
+ std::cerr << boost::format("WARNING: Inconsistency in expected stack level for instruction at address 0x%08x (current: %d, requested: %d)\n") % (*gr->_start)->_address % gr->_stackLevel % e.second;
+ continue;
+ }
+ gr->_stackLevel = e.second;
+
+ OutEdgeRange r = boost::out_edges(e.first, _g);
+ for (OutEdgeIterator oe = r.first; oe != r.second; ++oe) {
+ GraphVertex target = boost::target(*oe, _g);
+ if (seen.find(target) == seen.end()) {
+ levelStack.push(LevelEntry(target, e.second + (*gr->_start)->_stackChange));
+ seen.insert(target);
+ }
+ }
+ }
+}
+
+void ControlFlow::detectFunctions() {
+ uint32 nextFunc = 0;
+ for (ConstInstIterator it = _insts.begin(); it != _insts.end(); ++it) {
+ GraphVertex v = find(it);
+ GroupPtr gr = GET(v);
+
+ if ((*it)->_address < nextFunc)
+ continue;
+
+ bool functionExists = false;
+ bool detectEndPoint = false;
+ for (FuncMap::iterator fn = _engine->_functions.begin(); fn != _engine->_functions.end(); ++fn) {
+ if (fn->first == (*it)->_address) {
+ if (fn->second._endIt == _insts.end()) {
+ return;
+ }
+ if (fn->second._startIt == fn->second._endIt) {
+ // We already know this is an entry point, we only need to detect the end point
+ detectEndPoint = true;
+ break;
+ }
+ nextFunc = (*fn->second._endIt)->_address;
+ functionExists = true;
+ }
+ }
+
+ if (functionExists)
+ continue;
+
+ bool isEntryPoint = true;
+ if (!detectEndPoint) {
+ InEdgeRange ier = boost::in_edges(v, _g);
+ for (InEdgeIterator e = ier.first; e != ier.second; ++e) {
+ // If an ingoing edge exists from earlier in the code, this is not a function entry point
+ if ((*GET(boost::source(*e, _g))->_start)->_address < (*gr->_start)->_address)
+ isEntryPoint = false;
+ }
+ }
+
+ if (isEntryPoint) {
+ // Detect end point
+ Stack<GraphVertex> stack;
+ std::set<GraphVertex> seen;
+ stack.push(v);
+ GroupPtr endPoint = gr;
+ while (!stack.empty()) {
+ v = stack.pop();
+ GroupPtr tmp = GET(v);
+ if ((*tmp->_start)->_address > (*endPoint->_start)->_address)
+ endPoint = tmp;
+ OutEdgeRange r = boost::out_edges(v, _g);
+ for (OutEdgeIterator i = r.first; i != r.second; ++i) {
+ GraphVertex target = boost::target(*i, _g);
+ if (seen.find(target) == seen.end()) {
+ stack.push(target);
+ seen.insert(target);
+ }
+ }
+ }
+
+ ConstInstIterator endInst;
+ if (endPoint->_next) {
+ endInst = endPoint->_next->_start;
+ nextFunc = (*endInst)->_address;
+ } else {
+ endInst = _insts.end();
+ }
+ Function f;
+ if (detectEndPoint) {
+ f = _engine->_functions[(*gr->_start)->_address];
+ f._endIt = endInst;
+ } else {
+ f = Function(gr->_start, endInst);
+ f._name = "auto_";
+ }
+ f._v = find(it);
+ _engine->_functions[(*gr->_start)->_address] = f;
+ if (!endPoint->_next)
+ return;
+ }
+ }
+}
+
+void ControlFlow::createGroups() {
+ if (!_engine->_functions.empty() && GET(_engine->_functions.begin()->second._v)->_stackLevel != -1)
+ return;
+
+ // Detect more functions
+ if (_engine->detectMoreFuncs())
+ detectFunctions();
+
+ for (FuncMap::iterator fn = _engine->_functions.begin(); fn != _engine->_functions.end(); ++fn)
+ setStackLevel(fn->second._v, 0);
+ ConstInstIterator curInst, nextInst;
+ nextInst = _insts.begin();
+ nextInst++;
+ int stackLevel = 0;
+ int expectedStackLevel = 0;
+ for (curInst = _insts.begin(); nextInst != _insts.end(); ++curInst, ++nextInst) {
+ GraphVertex cur = find(curInst);
+ GraphVertex next = find(nextInst);
+
+ GroupPtr grCur = GET(cur);
+ GroupPtr grNext = GET(next);
+
+ // Don't process unreachable code
+ if (grCur->_stackLevel < 0) {
+ stackLevel = grNext->_stackLevel;
+ continue;
+ }
+
+ expectedStackLevel = grCur->_stackLevel;
+ // If expected stack level decreases in next vertex, then use next vertex level as expected level
+ if (expectedStackLevel > grNext->_stackLevel && grNext->_stackLevel >= 0) {
+ expectedStackLevel = grNext->_stackLevel;
+ // Also set the stack level of the current group to remember that we expect it to be lower
+ grCur->_stackLevel = expectedStackLevel;
+ }
+
+ stackLevel += (*curInst)->_stackChange;
+
+ // For stack operations, the new stack level becomes the expected stack level starting from the next group
+ if ((*curInst)->isStackOp()) {
+ expectedStackLevel = stackLevel;
+ grNext->_stackLevel = stackLevel;
+ }
+
+ // Group ends after a jump
+ if ((*curInst)->isJump()) {
+ stackLevel = grNext->_stackLevel;
+ continue;
+ }
+
+ // Group ends with a return
+ if ((*curInst)->isReturn()) {
+ stackLevel = grNext->_stackLevel;
+ continue;
+ }
+
+ // Group ends before target of a jump
+ if (in_degree(next, _g) != 1) {
+ stackLevel = grNext->_stackLevel;
+ continue;
+ }
+
+ // If group has no instructions with stack effect >= 0, don't merge on balanced stack
+ bool forceMerge = true;
+ ConstInstIterator it = grCur->_start;
+ do {
+ if ((*it)->_stackChange >= 0)
+ forceMerge = false;
+ ++it;
+ } while (grCur->_start != grCur->_end && it != grCur->_end);
+
+ // Group ends when stack is balanced, unless just before conditional jump
+ if (stackLevel == expectedStackLevel && !forceMerge && !(*nextInst)->isCondJump()) {
+ continue;
+ }
+
+ // All checks passed, merge groups
+ merge(cur, next);
+ }
+
+ // FIXME: The short-circuit detection is disabled because short-circuited groups require some special handling
+ // in the code generation. It's not entirely clear how to handle it properly, though: you need to deduce which
+ // effect is created by the conditional jumps in the middle of a block, which seems to get fairly complex when
+ // you have multiple groups that are merged by the short-circuit detection.
+ //detectShortCircuit();
+}
+
+void ControlFlow::detectShortCircuit() {
+ ConstInstIterator lastInst = _insts.end();
+ --lastInst;
+ GraphVertex cur = find(lastInst);
+ GroupPtr gr = GET(cur);
+ while (gr->_prev != NULL) {
+ bool doMerge = false;
+ cur = find(gr->_start);
+ GraphVertex prev = find(gr->_prev->_start);
+ // Block is candidate for short-circuit merging if it and the preceding block both end with conditional jumps
+ if (out_degree(cur, _g) == 2 && out_degree(prev, _g) == 2) {
+ doMerge = true;
+ OutEdgeRange rCur = boost::out_edges(cur, _g);
+ std::vector<GraphVertex> succs;
+
+ // Find possible target vertices
+ for (OutEdgeIterator it = rCur.first; it != rCur.second; ++it) {
+ succs.push_back(boost::target(*it, _g));
+ }
+
+ // Check if vertex would add new targets - if yes, don't merge
+ OutEdgeRange rPrev = boost::out_edges(prev, _g);
+ for (OutEdgeIterator it = rPrev.first; it != rPrev.second; ++it) {
+ GraphVertex target = boost::target(*it, _g);
+ doMerge &= (std::find(succs.begin(), succs.end(), target) != succs.end() || target == cur);
+ }
+
+ if (doMerge) {
+ gr = gr->_prev;
+ merge(prev, cur);
+ continue;
+ }
+ }
+ gr = gr->_prev;
+ }
+}
+
+const Graph &ControlFlow::analyze() {
+ detectDoWhile();
+ detectWhile();
+ detectBreak();
+ detectContinue();
+ detectIf();
+ detectElse();
+ return _g;
+}
+
+void ControlFlow::detectWhile() {
+ VertexRange vr = boost::vertices(_g);
+ for (VertexIterator v = vr.first; v != vr.second; ++v) {
+ GroupPtr gr = GET(*v);
+ // Undetermined block that ends with conditional jump
+ if (out_degree(*v, _g) == 2 && gr->_type == kNormalGroupType) {
+ InEdgeRange ier = boost::in_edges(*v, _g);
+ bool isWhile = false;
+ for (InEdgeIterator e = ier.first; e != ier.second; ++e) {
+ GroupPtr sourceGr = GET(boost::source(*e, _g));
+ // Block has ingoing edge from block later in the code that isn't a do-while condition
+ if ((*sourceGr->_start)->_address > (*gr->_start)->_address && sourceGr->_type != kDoWhileCondGroupType)
+ isWhile = true;
+ }
+ if (isWhile)
+ gr->_type = kWhileCondGroupType;
+ }
+ }
+}
+
+void ControlFlow::detectDoWhile() {
+ VertexRange vr = boost::vertices(_g);
+ for (VertexIterator v = vr.first; v != vr.second; ++v) {
+ GroupPtr gr = GET(*v);
+ // Undetermined block that ends with conditional jump...
+ if (out_degree(*v, _g) == 2 && gr->_type == kNormalGroupType) {
+ OutEdgeRange oer = boost::out_edges(*v, _g);
+ for (OutEdgeIterator e = oer.first; e != oer.second; ++e) {
+ GroupPtr targetGr = GET(boost::target(*e, _g));
+ // ...to earlier in code
+ if ((*targetGr->_start)->_address < (*gr->_start)->_address)
+ gr->_type = kDoWhileCondGroupType;
+ }
+ }
+ }
+}
+
+void ControlFlow::detectBreak() {
+ VertexRange vr = boost::vertices(_g);
+ for (VertexIterator v = vr.first; v != vr.second; ++v) {
+ GroupPtr gr = GET(*v);
+ // Undetermined block with unconditional jump...
+ if (gr->_type == kNormalGroupType && ((*gr->_end)->isUncondJump()) && out_degree(*v, _g) == 1) {
+ OutEdgeIterator oe = boost::out_edges(*v, _g).first;
+ GraphVertex target = boost::target(*oe, _g);
+ GroupPtr targetGr = GET(target);
+ // ...to somewhere later in the code...
+ if ((*gr->_start)->_address >= (*targetGr->_start)->_address)
+ continue;
+ InEdgeRange ier = boost::in_edges(target, _g);
+ for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
+ GroupPtr sourceGr = GET(boost::source(*ie, _g));
+ // ...to block immediately after a do-while condition, or to jump target of a while condition
+ if ((targetGr->_prev == sourceGr && sourceGr->_type == kDoWhileCondGroupType) || sourceGr->_type == kWhileCondGroupType) {
+ if (validateBreakOrContinue(gr, sourceGr))
+ gr->_type = kBreakGroupType;
+ }
+ }
+ }
+ }
+}
+
+void ControlFlow::detectContinue() {
+ VertexRange vr = boost::vertices(_g);
+ for (VertexIterator v = vr.first; v != vr.second; ++v) {
+ GroupPtr gr = GET(*v);
+ // Undetermined block with unconditional jump...
+ if (gr->_type == kNormalGroupType && ((*gr->_end)->isUncondJump()) && out_degree(*v, _g) == 1) {
+ OutEdgeIterator oe = boost::out_edges(*v, _g).first;
+ GraphVertex target = boost::target(*oe, _g);
+ GroupPtr targetGr = GET(target);
+ // ...to a while or do-while condition...
+ if (targetGr->_type == kWhileCondGroupType || targetGr->_type == kDoWhileCondGroupType) {
+ bool isContinue = true;
+ // ...unless...
+ OutEdgeRange toer = boost::out_edges(target, _g);
+ bool afterJumpTargets = true;
+ for (OutEdgeIterator toe = toer.first; toe != toer.second; ++toe) {
+ // ...it is targeting a while condition which jumps to the next sequential group
+ if (targetGr->_type == kWhileCondGroupType && GET(boost::target(*toe, _g)) == gr->_next)
+ isContinue = false;
+ // ...or the instruction is placed after all jump targets from condition
+ if ((*GET(boost::target(*toe, _g))->_start)->_address > (*gr->_start)->_address)
+ afterJumpTargets = false;
+ }
+ if (afterJumpTargets)
+ isContinue = false;
+
+ if (isContinue && validateBreakOrContinue(gr, targetGr))
+ gr->_type = kContinueGroupType;
+ }
+ }
+ }
+}
+
+bool ControlFlow::validateBreakOrContinue(GroupPtr gr, GroupPtr condGr) {
+ GroupPtr from, to, cursor;
+
+ if (condGr->_type == kDoWhileCondGroupType) {
+ to = condGr;
+ from = gr;
+ } else {
+ to = gr;
+ from = condGr->_next;
+ }
+
+ GroupType ogt = (condGr->_type == kDoWhileCondGroupType ? kWhileCondGroupType : kDoWhileCondGroupType);
+ // Verify that destination deals with innermost while/do-while
+ for (cursor = from; cursor->_next != NULL && cursor != to; cursor = cursor->_next) {
+ if (cursor->_type == condGr->_type) {
+ OutEdgeRange oerValidate = boost::out_edges(find(cursor->_start), _g);
+ for (OutEdgeIterator oeValidate = oerValidate.first; oeValidate != oerValidate.second; ++oeValidate) {
+ GraphVertex vValidate = boost::target(*oeValidate, _g);
+ GroupPtr gValidate = GET(vValidate);
+ // For all other loops of same type found in range, all targets must fall within that range
+ if ((*gValidate->_start)->_address < (*from->_start)->_address || (*gValidate->_start)->_address > (*to->_start)->_address )
+ return false;
+
+ InEdgeRange ierValidate = boost::in_edges(vValidate, _g);
+ for (InEdgeIterator ieValidate = ierValidate.first; ieValidate != ierValidate.second; ++ieValidate) {
+ GroupPtr igValidate = GET(boost::source(*ieValidate, _g));
+ // All loops of other type going into range must be placed within range
+ if (igValidate->_type == ogt && ((*igValidate->_start)->_address < (*from->_start)->_address || (*igValidate->_start)->_address > (*to->_start)->_address ))
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void ControlFlow::detectIf() {
+ VertexRange vr = boost::vertices(_g);
+ for (VertexIterator v = vr.first; v != vr.second; ++v) {
+ GroupPtr gr = GET(*v);
+ // if: Undetermined block with conditional jump
+ if (gr->_type == kNormalGroupType && ((*gr->_end)->isCondJump())) {
+ gr->_type = kIfCondGroupType;
+ }
+ }
+}
+
+void ControlFlow::detectElse() {
+ VertexRange vr = boost::vertices(_g);
+ for (VertexIterator v = vr.first; v != vr.second; ++v) {
+ GroupPtr gr = GET(*v);
+ if (gr->_type == kIfCondGroupType) {
+ OutEdgeRange oer = boost::out_edges(*v, _g);
+ GraphVertex target;
+ uint32 maxAddress = 0;
+ GroupPtr targetGr;
+ // Find jump target
+ for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
+ targetGr = GET(boost::target(*oe, _g));
+ if ((*targetGr->_start)->_address > maxAddress) {
+ target = boost::target(*oe, _g);
+ maxAddress = (*targetGr->_start)->_address;
+ }
+ }
+ targetGr = GET(target);
+ // else: Jump target of if immediately preceded by an unconditional jump...
+ if (!(*targetGr->_prev->_end)->isUncondJump())
+ continue;
+ // ...which is not a break or a continue...
+ if (targetGr->_prev->_type == kContinueGroupType || targetGr->_prev->_type == kBreakGroupType)
+ continue;
+ // ...to later in the code
+ OutEdgeIterator toe = boost::out_edges(find((*targetGr->_prev->_start)->_address), _g).first;
+ GroupPtr targetTargetGr = GET(boost::target(*toe, _g));
+ if ((*targetTargetGr->_start)->_address > (*targetGr->_end)->_address) {
+ if (validateElseBlock(gr, targetGr, targetTargetGr)) {
+ targetGr->_startElse = true;
+ targetTargetGr->_prev->_endElse.push_back(targetGr.get());
+ }
+ }
+ }
+ }
+}
+
+bool ControlFlow::validateElseBlock(GroupPtr ifGroup, GroupPtr start, GroupPtr end) {
+ for (GroupPtr cursor = start; cursor != end; cursor = cursor->_next) {
+ if (cursor->_type == kIfCondGroupType || cursor->_type == kWhileCondGroupType || cursor->_type == kDoWhileCondGroupType) {
+ // Validate outgoing edges of conditions
+ OutEdgeRange oer = boost::out_edges(find(cursor->_start), _g);
+ for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
+ GraphVertex target = boost::target(*oe, _g);
+ GroupPtr targetGr = GET(target);
+ // Each edge from condition must not leave the range [start, end]
+ if ((*start->_start)->_address > (*targetGr->_start)->_address || (*targetGr->_start)->_address > (*end->_start)->_address)
+ return false;
+ }
+ }
+
+ // If previous group ends an else, that else must start inside the range
+ for (ElseEndIterator it = cursor->_prev->_endElse.begin(); it != cursor->_prev->_endElse.end(); ++it)
+ {
+ if ((*(*it)->_start)->_address < (*start->_start)->_address)
+ return false;
+ }
+
+ // Unless group is a simple unconditional jump...
+ if ((*cursor->_start)->isUncondJump())
+ continue;
+
+ // ...validate ingoing edges
+ InEdgeRange ier = boost::in_edges(find(cursor->_start), _g);
+ for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
+ GraphVertex source = boost::source(*ie, _g);
+ GroupPtr sourceGr = GET(source);
+
+ // Edges going to conditions...
+ if (sourceGr->_type == kIfCondGroupType || sourceGr->_type == kWhileCondGroupType || sourceGr->_type == kDoWhileCondGroupType) {
+ // ...must not come from outside the range [start, end]...
+ if ((*start->_start)->_address > (*sourceGr->_start)->_address || (*sourceGr->_start)->_address > (*end->_start)->_address) {
+ // ...unless source is simple unconditional jump...
+ if ((*sourceGr->_start)->isUncondJump())
+ continue;
+ // ...or the edge is from the if condition associated with this else
+ if (ifGroup == sourceGr)
+ continue;
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
Deleted: tools/trunk/decompiler/control_flow.h
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/control_flow.h 2010-12-18 12:49:08 UTC (rev 54952)
+++ tools/trunk/decompiler/control_flow.h 2010-12-18 13:38:26 UTC (rev 54955)
@@ -1,172 +0,0 @@
-/* ScummVM Tools
- * Copyright (C) 2010 The ScummVM project
- *
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef DEC_CONTROL_FLOW_H
-#define DEC_CONTROL_FLOW_H
-
-#include "graph.h"
-#include "engine.h"
-
-/**
- * Class for doing code flow analysis.
- */
-class ControlFlow {
-private:
- Graph _g; ///< The control flow graph.
- Engine *_engine; ///< Pointer to the Engine used for the script.
- const InstVec &_insts; ///< The instructions being analyzed
- std::map<uint32, GraphVertex> _addrMap; ///< Map between addresses and vertices.
-
- /**
- * Finds a graph vertex through an instruction.
- *
- * @param inst The instruction to find the vertex for.
- */
- GraphVertex find(const InstPtr inst);
-
- /**
- * Finds a graph vertex through an instruction iterator.
- *
- * @param it The iterator to find the vertex for.
- */
- GraphVertex find(ConstInstIterator it);
-
- /**
- * Finds a graph vertex through an address.
- *
- * @param address The address to find the vertex for.
- */
- GraphVertex find(uint32 address);
-
- /**
- * Merges two graph vertices. g2 will be merged into g1.
- *
- * @param g1 The first vertex to merge.
- * @param g2 The second vertex to merge.
- */
- void merge(GraphVertex g1, GraphVertex g2);
-
- /**
- * Sets the stack level for all instructions, using depth-first search.
- *
- * @param g The GraphVertex to search from.
- * @param level The stack level when g is reached.
- */
- void setStackLevel(GraphVertex g, int level);
-
- /**
- * Merged groups that are part of the same short-circuited condition check.
- */
- void detectShortCircuit();
-
- /**
- * Detects while blocks.
- * Do-while detection must be completed before running this method.
- */
- void detectWhile();
-
- /**
- * Detects do-while blocks.
- */
- void detectDoWhile();
-
- /**
- * Detects break statements.
- * Do-while and while detection must be completed before running this method.
- */
- void detectBreak();
-
- /**
- * Detects continue statements.
- * Do-while and while detection must be completed before running this method.
- */
- void detectContinue();
-
- /**
- * Checks if a candidate break/continue goes to the closest loop.
- *
- * @param gr The group containing the candidate break/continue.
- * @param condGr The group containing the respective loop condition.
- * @returns True if the validation succeeded, false if it did not.
- */
- bool validateBreakOrContinue(GroupPtr gr, GroupPtr condGr);
-
- /**
- * Detects if blocks.
- * Must be performed after break and continue detection.
- */
- void detectIf();
-
- /**
- * Detects else blocks.
- * Must be performed after if detection.
- */
- void detectElse();
-
- /**
- * Checks if a candidate else block will cross block boundaries.
- *
- * @param ifGroup The group containing the if this else candidate is associated with.
- * @param start The group containing the start of the else.
- * @param end The group immediately after the group ending the else.
- * @returns True if the validation succeeded, false if it did not.
- */
- bool validateElseBlock(GroupPtr ifGroup, GroupPtr start, GroupPtr end);
-
-public:
- /**
- * Gets the current control flow graph.
- *
- * @returns The current control flow graph.
- */
- const Graph &getGraph() const { return _g; };
-
- /**
- * Constructor for the control flow graph.
- *
- * @param insts std::vector containing the instructions to analyze control flow for.
- * @param engine Pointer to the Engine used for the script.
- */
- ControlFlow(const InstVec &insts, Engine *engine);
-
- /**
- * Creates groups suitable for a stack-based machine.
- * Before group creation, the expected stack level for each instruction is determined.
- * After group creation, short-circuit detection is applied to the groups.
- */
- void createGroups();
-
- /**
- * Auto-detects functions from unreachable code.
- */
- void detectFunctions();
-
- /**
- * Performs control flow analysis.
- * The constructs are detected in the following order: do-while, while, break, continue, if/else.
- *
- * @returns The control flow graph after analysis.
- */
- const Graph &analyze();
-};
-
-#endif
Copied: tools/trunk/decompiler/control_flow.h (from rev 54952, tools/branches/gsoc2010-decompiler/decompiler/control_flow.h)
===================================================================
--- tools/trunk/decompiler/control_flow.h (rev 0)
+++ tools/trunk/decompiler/control_flow.h 2010-12-18 13:38:26 UTC (rev 54955)
@@ -0,0 +1,172 @@
+/* ScummVM Tools
+ * Copyright (C) 2010 The ScummVM project
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef DEC_CONTROL_FLOW_H
+#define DEC_CONTROL_FLOW_H
+
+#include "graph.h"
+#include "engine.h"
+
+/**
+ * Class for doing code flow analysis.
+ */
+class ControlFlow {
+private:
+ Graph _g; ///< The control flow graph.
+ Engine *_engine; ///< Pointer to the Engine used for the script.
+ const InstVec &_insts; ///< The instructions being analyzed
+ std::map<uint32, GraphVertex> _addrMap; ///< Map between addresses and vertices.
+
+ /**
+ * Finds a graph vertex through an instruction.
+ *
+ * @param inst The instruction to find the vertex for.
+ */
+ GraphVertex find(const InstPtr inst);
+
+ /**
+ * Finds a graph vertex through an instruction iterator.
+ *
+ * @param it The iterator to find the vertex for.
+ */
+ GraphVertex find(ConstInstIterator it);
+
+ /**
+ * Finds a graph vertex through an address.
+ *
+ * @param address The address to find the vertex for.
+ */
+ GraphVertex find(uint32 address);
+
+ /**
+ * Merges two graph vertices. g2 will be merged into g1.
+ *
+ * @param g1 The first vertex to merge.
+ * @param g2 The second vertex to merge.
+ */
+ void merge(GraphVertex g1, GraphVertex g2);
+
+ /**
+ * Sets the stack level for all instructions, using depth-first search.
+ *
+ * @param g The GraphVertex to search from.
+ * @param level The stack level when g is reached.
+ */
+ void setStackLevel(GraphVertex g, int level);
+
+ /**
+ * Merged groups that are part of the same short-circuited condition check.
+ */
+ void detectShortCircuit();
+
+ /**
+ * Detects while blocks.
+ * Do-while detection must be completed before running this method.
+ */
+ void detectWhile();
+
+ /**
+ * Detects do-while blocks.
+ */
+ void detectDoWhile();
+
+ /**
+ * Detects break statements.
+ * Do-while and while detection must be completed before running this method.
+ */
+ void detectBreak();
+
+ /**
+ * Detects continue statements.
+ * Do-while and while detection must be completed before running this method.
+ */
+ void detectContinue();
+
+ /**
+ * Checks if a candidate break/continue goes to the closest loop.
+ *
+ * @param gr The group containing the candidate break/continue.
+ * @param condGr The group containing the respective loop condition.
+ * @returns True if the validation succeeded, false if it did not.
+ */
+ bool validateBreakOrContinue(GroupPtr gr, GroupPtr condGr);
+
+ /**
+ * Detects if blocks.
+ * Must be performed after break and continue detection.
+ */
+ void detectIf();
+
+ /**
+ * Detects else blocks.
+ * Must be performed after if detection.
+ */
+ void detectElse();
+
+ /**
+ * Checks if a candidate else block will cross block boundaries.
+ *
+ * @param ifGroup The group containing the if this else candidate is associated with.
+ * @param start The group containing the start of the else.
+ * @param end The group immediately after the group ending the else.
+ * @returns True if the validation succeeded, false if it did not.
+ */
+ bool validateElseBlock(GroupPtr ifGroup, GroupPtr start, GroupPtr end);
+
+public:
+ /**
+ * Gets the current control flow graph.
+ *
+ * @returns The current control flow graph.
+ */
+ const Graph &getGraph() const { return _g; };
+
+ /**
+ * Constructor for the control flow graph.
+ *
+ * @param insts std::vector containing the instructions to analyze control flow for.
+ * @param engine Pointer to the Engine used for the script.
+ */
+ ControlFlow(const InstVec &insts, Engine *engine);
+
+ /**
+ * Creates groups suitable for a stack-based machine.
+ * Before group creation, the expected stack level for each instruction is determined.
+ * After group creation, short-circuit detection is applied to the groups.
+ */
+ void createGroups();
+
+ /**
+ * Auto-detects functions from unreachable code.
+ */
+ void detectFunctions();
+
+ /**
+ * Performs control flow analysis.
+ * The constructs are detected in the following order: do-while, while, break, continue, if/else.
+ *
+ * @returns The control flow graph after analysis.
+ */
+ const Graph &analyze();
+};
+
+#endif
Deleted: tools/trunk/decompiler/decompiler.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/decompiler.cpp 2010-12-18 12:49:08 UTC (rev 54952)
+++ tools/trunk/decompiler/decompiler.cpp 2010-12-18 13:38:26 UTC (rev 54955)
@@ -1,237 +0,0 @@
-/* ScummVM Tools
- * Copyright (C) 2010 The ScummVM project
- *
- * 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "objectFactory.h"
-
-#include "disassembler.h"
-#include "engine.h"
-#include "instruction.h"
-
-#include "control_flow.h"
-
-#include "kyra/engine.h"
-#include "scummv6/engine.h"
-
-#include <fstream>
-#include <iostream>
-#include <map>
-#include <string>
-#include <vector>
-#include <boost/program_options.hpp>
-#include <boost/graph/graphviz.hpp>
-
-namespace po = boost::program_options;
-
-#define ENGINE(id, description, engineClass) engines[std::string(id)] = description; engineFactory.addEntry<engineClass>(std::string(id));
-
-int main(int argc, char** argv) {
- try {
- std::map<std::string, std::string> engines;
- ObjectFactory<std::string, Engine> engineFactory;
-
- ENGINE("kyra2", "Legend of Kyrandia: Hand of Fate", Kyra::Kyra2Engine);
- ENGINE("scummv6", "SCUMM v6", Scumm::v6::Scummv6Engine);
-
- po::options_description visible("Options");
- visible.add_options()
- ("help,h", "Produce this help message.")
- ("engine,e", po::value<std::string>(), "Engine the script originates from.")
- ("list,l", "List the supported engines.")
- ("dump-disassembly,d", po::value<std::string>()->implicit_value(""), "Dump the disassembly to a file. Leave out filename to output to stdout.")
- ("dump-graph,g", po::value<std::string>()->implicit_value(""), "Output the control flow graph in dot format to a file. Leave out filename to output to stdout.")
- ("only-disassembly,D", "Stops after disassembly. Implies -d.")
- ("only-graph,G", "Stops after control flow graph has been generated. Implies -g.")
- ("show-unreachable,u", "Show the address and contents of unreachable groups in the script.")
- ("variant,v", po::value<std::string>()->default_value(""), "Tell the engine that the script is from a specific variant. To see a list of variants supported by a specific engine, use the -h option and the -e option together.")
- ("no-stack-effect,s", "Leave out the stack effect when printing raw instructions.");
-
- po::options_description args("");
- args.add(visible).add_options()
- ("input-file", po::value<std::string>(), "Input file");
-
- po::positional_options_description fileArg;
- fileArg.add("input-file", -1);
-
- po::variables_map vm;
- try {
- // FIXME: If specified as the last parameter before the input file name, -d currently requires a filename to specified. -d must be specified earlier than that if outputting to stdout.
- po::store(po::command_line_parser(argc, argv).options(args).positional(fileArg).run(), vm);
- po::notify(vm);
- } catch (std::exception& e) {
- std::cout << e.what() << std::endl;
- }
-
- if (vm.count("list")) {
- std::cout << "Available engines:" << "\n";
-
- std::map<std::string, std::string>::iterator it;
- for (it = engines.begin(); it != engines.end(); it++)
- std::cout << (*it).first << " " << (*it).second << "\n";
-
- return 0;
- }
-
- if (vm.count("help") || !vm.count("input-file")) {
- std::cout << "Usage: " << argv[0] << " [option...] file" << "\n";
- std::cout << visible << "\n";
- if (vm.count("engine") && engines.find(vm["engine"].as<std::string>()) != engines.end()) {
- Engine *engine = engineFactory.create(vm["engine"].as<std::string>());
- std::vector<std::string> variants;
- engine->getVariants(variants);
- if (variants.empty()) {
- std::cout << engines[vm["engine"].as<std::string>()] << " does not use variants.\n";
- } else {
- std::cout << "Supported variants for " << engines[vm["engine"].as<std::string>()] << ":\n";
- for (std::vector<std::string>::iterator i = variants.begin(); i != variants.end(); ++i) {
- std::cout << " " << *i << "\n";
- }
- }
- delete engine;
- std::cout << "\n";
- }
- std::cout << "Note: If outputting to stdout, -d or -g must NOT be specified immediately before the input file.\n";
- return 1;
- }
-
- if (!vm.count("engine")) {
- std::cout << "Engine must be specified.\n";
- return 2;
- } else if (engines.find(vm["engine"].as<std::string>()) == engines.end()) {
- std::cout << "Unknown engine.\n";
- return 2;
- }
-
- if (vm.count("no-stack-effect")) {
- setOutputStackEffect(false);
- }
-
- Engine *engine = engineFactory.create(vm["engine"].as<std::string>());
- engine->_variant = vm["variant"].as<std::string>();
- std::string inputFile = vm["input-file"].as<std::string>();
-
- // Disassembly
- InstVec insts;
- Disassembler *disassembler = engine->getDisassembler(insts);
- disassembler->open(inputFile.c_str());
-
- disassembler->disassemble();
- if (vm.count("dump-disassembly")) {
- std::streambuf *buf;
- std::ofstream of;
-
- if (vm["dump-disassembly"].as<std::string>() != "") {
- of.open(vm["dump-disassembly"].as<std::string>().c_str());
- buf = of.rdbuf();
- } else {
- buf = std::cout.rdbuf();
- }
- std::ostream out(buf);
- disassembler->dumpDisassembly(out);
- }
-
- if (!engine->supportsCodeFlow() || vm.count("only-disassembly") || insts.empty()) {
- if (!vm.count("dump-disassembly")) {
- disassembler->dumpDisassembly(std::cout);
- }
- delete disassembler;
- delete engine;
- return 0;
- }
-
- delete disassembler;
-
- // Control flow analysis
- ControlFlow *cf = new ControlFlow(insts, engine);
- cf->createGroups();
- Graph g = cf->analyze();
-
- if (vm.count("dump-graph")) {
- std::streambuf *buf;
- std::ofstream of;
-
- if (vm["dump-graph"].as<std::string>() != "") {
- of.open(vm["dump-graph"].as<std::string>().c_str());
- buf = of.rdbuf();
- } else {
- buf = std::cout.rdbuf();
- }
- std::ostream out(buf);
- boost::write_graphviz(out, g, boost::make_label_writer(get(boost::vertex_name, g)), boost::makeArrowheadWriter(get(boost::edge_attribute, g)), GraphProperties(engine, g));
- }
-
- if (!engine->supportsCodeGen() || vm.count("only-graph")) {
- if (!vm.count("dump-graph")) {
- boost::write_graphviz(std::cout, g, boost::make_label_writer(get(boost::vertex_name, g)), boost::makeArrowheadWriter(get(boost::edge_attribute, g)), GraphProperties(engine, g));
- }
- delete cf;
- delete engine;
- return 0;
- }
-
- // Post-processing of CFG
- engine->postCFG(insts, g);
-
- // Code generation
- CodeGenerator *cg = engine->getCodeGenerator(std::cout);
- cg->generate(g);
-
- if (vm.count("show-unreachable")) {
- std::vector<GroupPtr> unreachable;
- VertexRange vr = boost::vertices(g);
- for (VertexIterator v = vr.first; v != vr.second; ++v)
- {
- GroupPtr gr = boost::get(boost::vertex_name, g, *v);
- if (gr->_stackLevel == -1)
- unreachable.push_back(gr);
- }
- if (!unreachable.empty()) {
- for (size_t i = 0; i < unreachable.size(); i++) {
- if (i == 0) {
- if (unreachable.size() == 1)
- std::cout << boost::format("\n%d unreachable group detected.\n") % unreachable.size();
- else
- std::cout << boost::format("\n%d unreachable groups detected.\n") % unreachable.size();
- }
- std::cout << "Group " << (i+1) << ":\n";
- ConstInstIterator inst = unreachable[i]->_start;
- do {
- std::cout << *inst;
- } while (inst++ != unreachable[i]->_end);
- std::cout << "----------\n";
- }
- }
- }
-
- // Free memory
- delete cf;
- delete cg;
- delete engine;
- } catch (UnknownOpcodeException &e) {
- std::cerr << "ERROR: " << e.what() << "\n";
- return 3;
- } catch (std::exception &e) {
- std::cerr << "ERROR: " << e.what() << "\n";
- return 4;
- }
-
- return 0;
-}
Copied: tools/trunk/decompiler/decompiler.cpp (from rev 54952, tools/branches/gsoc2010-decompiler/decompiler/decompiler.cpp)
===================================================================
--- tools/trunk/decompiler/decompiler.cpp (rev 0)
+++ tools/trunk/decompiler/decompiler.cpp 2010-12-18 13:38:26 UTC (rev 54955)
@@ -0,0 +1,237 @@
+/* ScummVM Tools
+ * Copyright (C) 2010 The ScummVM project
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "objectFactory.h"
+
+#include "disassembler.h"
+#include "engine.h"
+#include "instruction.h"
+
+#include "control_flow.h"
+
+#include "kyra/engine.h"
+#include "scummv6/engine.h"
+
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <string>
+#include <vector>
+#include <boost/program_options.hpp>
+#include <boost/graph/graphviz.hpp>
+
+namespace po = boost::program_options;
+
+#define ENGINE(id, description, engineClass) engines[std::string(id)] = description; engineFactory.addEntry<engineClass>(std::string(id));
+
+int main(int argc, char** argv) {
+ try {
+ std::map<std::string, std::string> engines;
+ ObjectFactory<std::string, Engine> engineFactory;
+
+ ENGINE("kyra2", "Legend of Kyrandia: Hand of Fate", Kyra::Kyra2Engine);
+ ENGINE("scummv6", "SCUMM v6", Scumm::v6::Scummv6Engine);
+
+ po::options_description visible("Options");
+ visible.add_options()
+ ("help,h", "Produce this help message.")
+ ("engine,e", po::value<std::string>(), "Engine the script originates from.")
+ ("list,l", "List the supported engines.")
+ ("dump-disassembly,d", po::value<std::string>()->implicit_value(""), "Dump the disassembly to a file. Leave out filename to output to stdout.")
+ ("dump-graph,g", po::value<std::string>()->implicit_value(""), "Output the control flow graph in dot format to a file. Leave out filename to output to stdout.")
+ ("only-disassembly,D", "Stops after disassembly. Implies -d.")
+ ("only-graph,G", "Stops after control flow graph has been generated. Implies -g.")
+ ("show-unreachable,u", "Show the address and contents of unreachable groups in the script.")
+ ("variant,v", po::value<std::string>()->default_value(""), "Tell the engine that the script is from a specific variant. To see a list of variants supported by a specific engine, use the -h option and the -e option together.")
+ ("no-stack-effect,s", "Leave out the stack effect when printing raw instructions.");
+
+ po::options_description args("");
+ args.add(visible).add_options()
+ ("input-file", po::value<std::string>(), "Input file");
+
+ po::positional_options_description fileArg;
+ fileArg.add("input-file", -1);
+
+ po::variables_map vm;
+ try {
+ // FIXME: If specified as the last parameter before the input file name, -d currently requires a filename to specified. -d must be specified earlier than that if outputting to stdout.
+ po::store(po::command_line_parser(argc, argv).options(args).positional(fileArg).run(), vm);
+ po::notify(vm);
+ } catch (std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+
+ if (vm.count("list")) {
+ std::cout << "Available engines:" << "\n";
+
+ std::map<std::string, std::string>::iterator it;
+ for (it = engines.begin(); it != engines.end(); it++)
+ std::cout << (*it).first << " " << (*it).second << "\n";
+
+ return 0;
+ }
+
+ if (vm.count("help") || !vm.count("input-file")) {
+ std::cout << "Usage: " << argv[0] << " [option...] file" << "\n";
+ std::cout << visible << "\n";
+ if (vm.count("engine") && engines.find(vm["engine"].as<std::string>()) != engines.end()) {
+ Engine *engine = engineFactory.create(vm["engine"].as<std::string>());
+ std::vector<std::string> variants;
+ engine->getVariants(variants);
+ if (variants.empty()) {
+ std::cout << engines[vm["engine"].as<std::string>()] << " does not use variants.\n";
+ } else {
+ std::cout << "Supported variants for " << engines[vm["engine"].as<std::string>()] << ":\n";
+ for (std::vector<std::string>::iterator i = variants.begin(); i != variants.end(); ++i) {
+ std::cout << " " << *i << "\n";
+ }
+ }
+ delete engine;
+ std::cout << "\n";
+ }
+ std::cout << "Note: If outputting to stdout, -d or -g must NOT be specified immediately before the input file.\n";
+ return 1;
+ }
+
+ if (!vm.count("engine")) {
+ std::cout << "Engine must be specified.\n";
+ return 2;
+ } else if (engines.find(vm["engine"].as<std::string>()) == engines.end()) {
+ std::cout << "Unknown engine.\n";
+ return 2;
+ }
+
+ if (vm.count("no-stack-effect")) {
+ setOutputStackEffect(false);
+ }
+
+ Engine *engine = engineFactory.create(vm["engine"].as<std::string>());
+ engine->_variant = vm["variant"].as<std::string>();
+ std::string inputFile = vm["input-file"].as<std::string>();
+
+ // Disassembly
+ InstVec insts;
+ Disassembler *disassembler = engine->getDisassembler(insts);
+ disassembler->open(inputFile.c_str());
+
+ disassembler->disassemble();
+ if (vm.count("dump-disassembly")) {
+ std::streambuf *buf;
+ std::ofstream of;
+
+ if (vm["dump-disassembly"].as<std::string>() != "") {
+ of.open(vm["dump-disassembly"].as<std::string>().c_str());
+ buf = of.rdbuf();
+ } else {
+ buf = std::cout.rdbuf();
+ }
+ std::ostream out(buf);
+ disassembler->dumpDisassembly(out);
+ }
+
+ if (!engine->supportsCodeFlow() || vm.count("only-disassembly") || insts.empty()) {
+ if (!vm.count("dump-disassembly")) {
+ disassembler->dumpDisassembly(std::cout);
+ }
+ delete disassembler;
+ delete engine;
+ return 0;
+ }
+
+ delete disassembler;
+
@@ Diff output truncated at 100000 characters. @@
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