[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