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

pidgeot at users.sourceforge.net pidgeot at users.sourceforge.net
Sat Aug 7 04:39:11 CEST 2010


Revision: 51824
          http://scummvm.svn.sourceforge.net/scummvm/?rev=51824&view=rev
Author:   pidgeot
Date:     2010-08-07 02:39:11 +0000 (Sat, 07 Aug 2010)

Log Message:
-----------
DECOMPILER: Code generation for KYRA

Modified Paths:
--------------
    tools/branches/gsoc2010-decompiler/Makefile.common
    tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp
    tools/branches/gsoc2010-decompiler/decompiler/codegen.h
    tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp
    tools/branches/gsoc2010-decompiler/decompiler/kyra/disassembler.cpp
    tools/branches/gsoc2010-decompiler/decompiler/kyra/engine.cpp
    tools/branches/gsoc2010-decompiler/decompiler/kyra/engine.h
    tools/branches/gsoc2010-decompiler/decompiler/stack.h

Added Paths:
-----------
    tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.cpp
    tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.h

Modified: tools/branches/gsoc2010-decompiler/Makefile.common
===================================================================
--- tools/branches/gsoc2010-decompiler/Makefile.common	2010-08-07 01:27:14 UTC (rev 51823)
+++ tools/branches/gsoc2010-decompiler/Makefile.common	2010-08-07 02:39:11 UTC (rev 51824)
@@ -282,7 +282,8 @@
 	decompiler/scummv6/engine.o \
 	decompiler/scummv6/codegen.o \
 	decompiler/kyra/disassembler.o \
-	decompiler/kyra/engine.o
+	decompiler/kyra/engine.o \
+	decompiler/kyra/codegen.o
 
 decompile_LIBS := \
 	-lboost_program_options

Modified: tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp	2010-08-07 01:27:14 UTC (rev 51823)
+++ tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp	2010-08-07 02:39:11 UTC (rev 51824)
@@ -34,6 +34,14 @@
 
 static int dupindex = 0;
 
+int32 IntEntry::getValue() {
+	return _val;
+}
+
+bool IntEntry::getSigned() {
+	return _isSigned;
+}
+
 std::ostream &IntEntry::print(std::ostream &output) const {
 	if (_isSigned)
 		output << (int32)_val;
@@ -104,6 +112,10 @@
 	return new IntEntry(_val, _isSigned);
 }
 
+std::string CodeGenerator::constructFuncSignature(const Function &func) {
+	return "";
+}
+
 std::string CodeGenerator::indentString(std::string s) {
 	std::stringstream stream;
 	stream << std::string(kIndentAmount * _indentLevel, ' ') << s;
@@ -120,53 +132,68 @@
 void CodeGenerator::generate(const Graph &g) {
 	_g = g;
 
-	// Find entry point
-	// FIXME: For simplicity, we simply treat the first group as the entry point, because that's how SCUMM works.
-	// This should be changed later to allow for functions etc.
-	VertexRange vr = boost::vertices(_g);
-	GraphVertex entryPoint = *(vr.first);
-	GroupPtr p = GET(entryPoint);
-	while (p->_prev != NULL)
-		p = p->_prev;
-	entryPoint = p->_vertex;
+	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);
+		}
 
-	// DFS from entry point to process each vertex
-	Stack<DFSEntry> dfsStack;
-	std::set<GraphVertex> seen;
-	dfsStack.push(DFSEntry(entryPoint, EntryStack()));
-	seen.insert(entryPoint);
-	while (!dfsStack.empty()) {
-		DFSEntry e = dfsStack.pop();
-		GroupPtr tmp = GET(e.first);
-		_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);
+		GroupPtr lastGroup = GET(entryPoint);
+
+		// DFS from entry point to process each vertex
+		Stack<DFSEntry> dfsStack;
+		std::set<GraphVertex> seen;
+		dfsStack.push(DFSEntry(entryPoint, EntryStack()));
+		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);
+				}
 			}
 		}
-	}
 
-	// Print output
-	// TODO: Proper indenting
-	p = GET(entryPoint);
-	while (p != NULL) {
-		for (std::vector<CodeLine>::iterator it = p->_code.begin(); it != p->_code.end(); ++it) {
-			if (it->_unindentBefore /*&& _indentLevel != 0*/)
-				_indentLevel--;
-			_output << boost::format("%08X: %s") % p->_start->_address % indentString(it->_line) << std::endl;
-			if (it->_indentAfter)
-				_indentLevel++;
+		if (printFuncSignature) {
+			_curGroup = lastGroup;
+			addOutputLine("}", true, false);
 		}
-		p = p->_next;
+
+		// Print output
+		// TODO: Proper indenting
+		GroupPtr p = GET(entryPoint);
+		while (p != NULL) {
+			for (std::vector<CodeLine>::iterator it = p->_code.begin(); it != p->_code.end(); ++it) {
+				if (it->_unindentBefore /*&& _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;
 	}
-
-	if (_indentLevel != 0)
-		std::cerr << "WARNING: Indent level ended at " << _indentLevel << std::endl;
 }
 
 void CodeGenerator::addOutputLine(std::string s, bool unindentBefore, bool indentAfter) {
@@ -320,11 +347,15 @@
 					break;
 				}
 				break;
+			case kReturn:
+				// TODO: Allow specification of return value as part of return statement
+				addOutputLine("return;");
+				break;
 			case kSpecial:
 				{
 					_argList.clear();
 					bool returnsValue = (it->_codeGenData.find("r") == 0);
-					std::string metadata = (!returnsValue ? it->_codeGenData : it->_codeGenData.substr(1) );
+					std::string metadata = (!returnsValue ? it->_codeGenData : it->_codeGenData.substr(1));
 					for (size_t i = 0; i < metadata.length(); i++)
 						processSpecialMetadata(*it, metadata[i]);
 					_stack.push(new CallEntry(it->_name, _argList));

Modified: tools/branches/gsoc2010-decompiler/decompiler/codegen.h
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/codegen.h	2010-08-07 01:27:14 UTC (rev 51823)
+++ tools/branches/gsoc2010-decompiler/decompiler/codegen.h	2010-08-07 02:39:11 UTC (rev 51824)
@@ -33,6 +33,8 @@
 
 class Engine;
 
+class Function;
+
 enum StackEntryType {
 	seInt,
 	seVar,
@@ -150,6 +152,10 @@
 	 */
 	IntEntry(uint32 val, bool isSigned) : StackEntry(seInt), _val(val), _isSigned(isSigned) { }
 
+	int32 getValue();
+
+	bool getSigned();
+
 	virtual std::ostream &print(std::ostream &output) const;
 
 	virtual EntryPtr dup(std::ostream &output);
@@ -336,7 +342,6 @@
  */
 class CodeGenerator {
 private:
-	Engine *_engine;           ///< Pointer to the Engine used for the script.
 	Graph _g;                  ///< The annotated graph of the script.
 	const ArgOrder _binOrder;  ///< Order of operands for binary operations.
 	const ArgOrder _callOrder; ///< Order of operands for call arguments.
@@ -349,6 +354,7 @@
 	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.
 	EntryStack _stack;     ///< The stack currently being processed.
 	uint _indentLevel;     ///< Indentation level.
@@ -402,6 +408,13 @@
 	 */
 	void addArg(EntryPtr p);
 
+	/**
+	 * 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:
 	virtual ~CodeGenerator() { }
 

Modified: tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp	2010-08-07 01:27:14 UTC (rev 51823)
+++ tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp	2010-08-07 02:39:11 UTC (rev 51824)
@@ -168,10 +168,16 @@
 			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())
+				if (fn->second._endIt == _insts.end()) {
 					return;
+				}
+				if (fn->second._startIt == fn->second._endIt) {
+					detectEndPoint = true;
+					break;
+				}
 				nextFunc = fn->second._endIt->_address;
 				functionExists = true;
 			}
@@ -180,12 +186,14 @@
 		if (functionExists)
 			continue;
 
-		InEdgeRange ier = boost::in_edges(v, _g);
 		bool isEntryPoint = true;
-		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 (!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) {
@@ -216,7 +224,14 @@
 			} else {
 				endInst = _insts.end();
 			}
-			Function f(gr->_start, endInst);
+			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)

Added: tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.cpp	                        (rev 0)
+++ tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.cpp	2010-08-07 02:39:11 UTC (rev 51824)
@@ -0,0 +1,209 @@
+/* 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"
+
+std::string Kyra::CodeGenerator::constructFuncSignature(const Function &func) {
+	std::stringstream s;
+	s << func._name << "(";
+	for (uint32 i = 0; i != func._args; ++i) {
+		if (i != 0)
+			s << ", ";
+		s << "param" << (i+1);
+	}
+	s << ") {";
+	return s.str();
+}
+
+void Kyra::CodeGenerator::processInst(const Instruction inst) {
+	switch (inst._type) {
+	case kLoad:
+		switch (inst._opcode) {
+		case 2:
+			_stack.push(new VarEntry("retval"));
+			break;
+		case 3:
+		case 4:
+			_stack.push(new IntEntry(inst._params[0].getSigned(), true));
+			break;
+		case 5:
+			{
+				std::stringstream s;
+				s << boost::format("var%d") % inst._params[0].getSigned();
+				_stack.push(new VarEntry(s.str()));
+			}
+			break;
+		case 6:
+			{
+				std::stringstream s;
+				s << boost::format("localvar%d") % inst._params[0].getSigned();
+				_stack.push(new VarEntry(s.str()));
+			}
+			break;
+		case 7:
+			{
+				std::stringstream s;
+				s << boost::format("param%d") % inst._params[0].getSigned();
+				_stack.push(new VarEntry(s.str()));
+			}
+			break;
+		}
+		break;
+	case kStore:
+		switch (inst._opcode) {
+		case 8:
+			{
+				EntryPtr p = new VarEntry("retval");
+				writeAssignment(p, _stack.pop());
+			}
+			break;
+		case 9:
+			{
+				std::stringstream s;
+				s << boost::format("var%d") % inst._params[0].getSigned();
+				EntryPtr p = new VarEntry(s.str());
+				writeAssignment(p, _stack.pop());
+			}
+			break;
+		case 10:
+			{
+				std::stringstream s;
+				s << boost::format("localvar%d") % inst._params[0].getSigned();
+				EntryPtr p = new VarEntry(s.str());
+				writeAssignment(p, _stack.pop());
+			}
+			break;
+		case 11:
+			{
+				std::stringstream s;
+				s << boost::format("param%d") % inst._params[0].getSigned();
+				EntryPtr p = new VarEntry(s.str());
+				writeAssignment(p, _stack.pop());
+			}
+			break;
+		}
+		break;
+	case kStack:
+		if (inst._opcode == 12) {
+			for (int i = inst._params[0].getSigned(); i != 0; --i) {
+				if (!_stack.empty())
+					_stack.pop();
+			}
+		} else if (inst._opcode == 13) {
+			for (int i = 0; i != inst._params[0].getSigned(); ++i) {
+				std::stringstream s;
+				s << boost::format("localvar%d") % i;
+				_stack.push(new VarEntry(s.str()));
+			}
+		}
+		break;
+	case kCondJump:
+		switch (_curGroup->_type) {
+		case kIfCond:
+		case kWhileCond:
+			break;
+		case kDoWhileCond:
+			_stack.push(new UnaryOpEntry(_stack.pop(), "!"));
+			break;
+		default:
+			{
+				std::stringstream s;
+				s << boost::format("WARNING: Couldn't handle conditional jump at address %08X") % inst._address;
+				addOutputLine(s.str());
+			}
+			break;
+		}
+		break;
+	case kCall:
+		{
+			_argList.clear();
+			Function f = _engine->_functions.find(inst._params[0].getUnsigned())->second;
+			for (size_t i = 0; i < f._metadata.length(); i++)
+				processSpecialMetadata(inst, f._metadata[i]);
+			_stack.push(new CallEntry(f._name, _argList));
+			if (!f._retVal) {
+				std::stringstream stream;
+				stream << _stack.pop() << ";";
+				addOutputLine(stream.str());
+			} else {
+				EntryPtr p = new VarEntry("retval");
+				writeAssignment(p, _stack.pop());
+			}
+			break;
+		}
+	case kSpecial:
+		{
+			if (inst._opcode == 2)
+				return;
+			_argList.clear();
+			bool returnsValue = (inst._codeGenData.find("r") == 1);
+			std::string metadata = (!returnsValue ? inst._codeGenData.substr(1) : inst._codeGenData.substr(2));
+			for (size_t i = 0; i < metadata.length(); i++)
+				processSpecialMetadata(inst, metadata[i]);
+			_stack.push(new CallEntry(inst._name, _argList));
+			if (!returnsValue) {
+				std::stringstream stream;
+				stream << _stack.pop() << ";";
+				addOutputLine(stream.str());
+			} else {
+				EntryPtr p = new VarEntry("retval");
+				writeAssignment(p, _stack.pop());
+			}
+			break;
+		}
+	default:
+		{
+			std::stringstream s;
+			s << boost::format("WARNING: Unknown opcode %X at address %08X") % inst._opcode % inst._address;
+			addOutputLine(s.str());
+		}
+		break;
+	}
+}
+
+void Kyra::CodeGenerator::processSpecialMetadata(const Instruction inst, char c) {
+	switch (c) {
+	case '0':
+		_stackOffset = 0;
+		break;
+	case 'p':
+		addArg(_stack.peekPos(_stackOffset++));
+		break;
+	case 's':
+		{
+			EntryPtr p = _stack.peekPos(_stackOffset++);
+			if (p->_type == seInt) {
+				IntEntry *ie = (IntEntry *)p.get();
+				addArg(new StringEntry(((Kyra::Engine *)_engine)->_textStrings[ie->getValue()]));
+			} else {
+				EntryList idxs;
+				idxs.push_front(p);
+				addArg(new ArrayEntry("strings", idxs));
+			}
+		}
+		break;
+	default:
+		::CodeGenerator::processSpecialMetadata(inst, c);
+		break;
+	}
+}


Property changes on: tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.h
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.h	                        (rev 0)
+++ tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.h	2010-08-07 02:39:11 UTC (rev 51824)
@@ -0,0 +1,52 @@
+/* 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_KYRA_CODEGEN_H
+#define DEC_KYRA_CODEGEN_H
+
+#include "../codegen.h"
+
+namespace Kyra {
+
+/**
+ * KYRA code generator.
+ */
+class CodeGenerator : public ::CodeGenerator {
+private:
+	int _stackOffset; ///< Running count of where in the stack to look for the next argument.
+public:
+	/**
+	 * Constructor for Kyra::CodeGenerator.
+	 *
+	 * @param engine Pointer to the Engine used for the script.
+	 * @param output The std::ostream to output the code to.
+	 */
+	CodeGenerator(Engine *engine, std::ostream &output) : ::CodeGenerator(engine, output, kLIFO, kLIFO) {}
+protected:
+	void processInst(const Instruction inst);
+	virtual void processSpecialMetadata(const Instruction inst, char c);
+	std::string constructFuncSignature(const Function &func);
+};
+
+} // End of namespace Kyra
+
+#endif


Property changes on: tools/branches/gsoc2010-decompiler/decompiler/kyra/codegen.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: tools/branches/gsoc2010-decompiler/decompiler/kyra/disassembler.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/kyra/disassembler.cpp	2010-08-07 01:27:14 UTC (rev 51823)
+++ tools/branches/gsoc2010-decompiler/decompiler/kyra/disassembler.cpp	2010-08-07 02:39:11 UTC (rev 51824)
@@ -33,225 +33,225 @@
 
 static FunctionData kyra2FuncDesc[] = {
 	// 0x00
-	{ "o2_setCharacterFacingRefresh", "0ppp" },
-	{ "o2_setCharacterPos", "0ppp" },
-	{ "o2_defineObject", "0pspppp" },
-	{ "o2_refreshCharacter", "0pppp" },
+	{ "o2_setCharacterFacingRefresh", "\xC0r0ppp" },
+	{ "o2_setCharacterPos", "\xC0r0ppp" },
+	{ "o2_defineObject", "\xC0r0pspppp" },
+	{ "o2_refreshCharacter", "\xC0r0pppp" },
 	// 0x04
-	{ "o2_getCharacterX", "" },
-	{ "o2_getCharacterY", "" },
-	{ "o2_getCharacterFacing", "" },
-	{ "o2_getCharacterScene", "" },
+	{ "o2_getCharacterX", "\xC0r" },
+	{ "o2_getCharacterY", "\xC0r" },
+	{ "o2_getCharacterFacing", "\xC0r" },
+	{ "o2_getCharacterScene", "\xC0r" },
 	// 0x08
-	{ "o2_setSceneComment", "0s" },
-	{ "unk09", "0p" },
-	{ "unk0A", "0p" },
-	{ "o2_setCharacterAnimFrame", "0ppp" },
+	{ "o2_setSceneComment", "\xC0r0s" },
+	{ "unk09", "\xC0r0p" },
+	{ "unk0A", "\xC0r0p" },
+	{ "o2_setCharacterAnimFrame", "\xC0r0ppp" },
 	// 0x0c
-	{ "o2_setCharacterFacingOverwrite", "0p" },
-	{ "o2_trySceneChange", "0pppp" },
-	{ "o2_moveCharacter", "0ppp" },
-	{ "o2_customCharacterChat", "0spppp" },
+	{ "o2_setCharacterFacingOverwrite", "\xC0r0p" },
+	{ "o2_trySceneChange", "\xC0r0pppp" },
+	{ "o2_moveCharacter", "\xC0r0ppp" },
+	{ "o2_customCharacterChat", "\xC0r0spppp" },
 	// 0x10
-	{ "o2_soundFadeOut", "" },
-	{ "o2_showChapterMessage", "0pp" },
-	{ "o2_restoreTalkTextMessageBkgd", "" },
-	{ "o2_printString", "0spppp" },
+	{ "o2_soundFadeOut", "\xC0r" },
+	{ "o2_showChapterMessage", "\xC0r0pp" },
+	{ "o2_restoreTalkTextMessageBkgd", "\xC0r" },
+	{ "o2_printString", "\xC0r0spppp" },
 	// 0x14
-	{ "o2_wsaClose", "0p" },
-	{ "o2_backUpScreen", "0p" },
-	{ "o2_restoreScreen", "0p" },
-	{ "o2_displayWsaFrame", "0ppppppppp" },
+	{ "o2_wsaClose", "\xC0r0p" },
+	{ "o2_backUpScreen", "\xC0r0p" },
+	{ "o2_restoreScreen", "\xC0r0p" },
+	{ "o2_displayWsaFrame", "\xC0r0ppppppppp" },
 	// 0x18
-	{ "o2_displayWsaSequentialFramesLooping", "0pppppppp" },
-	{ "o2_wsaOpen", "0sp" },
-	{ "o2_displayWsaSequentialFrames", "0ppppppp" },
-	{ "o2_displayWsaSequence", "0pppppp" },
+	{ "o2_displayWsaSequentialFramesLooping", "\xC0r0pppppppp" },
+	{ "o2_wsaOpen", "\xC0r0sp" },
+	{ "o2_displayWsaSequentialFrames", "\xC0r0ppppppp" },
+	{ "o2_displayWsaSequence", "\xC0r0pppppp" },
 	// 0x1c
-	{ "o2_addItemToInventory", "0ppp" },
-	{ "o2_drawShape", "0ppppp" },
-	{ "o2_addItemToCurScene", "0ppp" },
-	{ "o2_limitMouseRange", "0pppp" },
+	{ "o2_addItemToInventory", "\xC0r0ppp" },
+	{ "o2_drawShape", "\xC0r0ppppp" },
+	{ "o2_addItemToCurScene", "\xC0r0ppp" },
+	{ "o2_limitMouseRange", "\xC0r0pppp" },
 	// 0x20
-	{ "o2_checkForItem", "0pp" },
-	{ "o2_loadSoundFile", "0p" },
-	{ "o2_removeSlotFromInventory", "0p" },
-	{ "o2_defineItem", "0pppp" },
+	{ "o2_checkForItem", "\xC0r0pp" },
+	{ "o2_loadSoundFile", "\xC0r0p" },
+	{ "o2_removeSlotFromInventory", "\xC0r0p" },
+	{ "o2_defineItem", "\xC0r0pppp" },
 	// 0x24
-	{ "o2_removeItemFromInventory", "0p" },
-	{ "o2_countItemInInventory", "0pp" },
-	{ "o2_countItemsInScene", "0p" },
-	{ "o1_queryGameFlag", "0p" },
+	{ "o2_removeItemFromInventory", "\xC0r0p" },
+	{ "o2_countItemInInventory", "\xC0r0pp" },
+	{ "o2_countItemsInScene", "\xC0r0p" },
+	{ "o1_queryGameFlag", "\xC0r0p" },
 	// 0x28
-	{ "o1_resetGameFlag", "0p" },
-	{ "o1_setGameFlag", "0p" },
-	{ "o1_setHandItem", "0p" },
-	{ "o1_removeHandItem", "" },
+	{ "o1_resetGameFlag", "\xC0r0p" },
+	{ "o1_setGameFlag", "\xC0r0p" },
+	{ "o1_setHandItem", "\xC0r0p" },
+	{ "o1_removeHandItem", "\xC0r" },
 	// 0x2c
-	{ "o1_getMouseState", "" },
-	{ "o1_hideMouse", "" },
-	{ "o2_addSpecialExit", "0ppppp" },
-	{ "o1_setMousePos", "0pp" },
+	{ "o1_getMouseState", "\xC0r" },
+	{ "o1_hideMouse", "\xC0r" },
+	{ "o2_addSpecialExit", "\xC0r0ppppp" },
+	{ "o1_setMousePos", "\xC0r0pp" },
 	// 0x30
-	{ "o1_showMouse", "" },
-	{ "o2_drawBox", "0ppppp" },
-	{ "o2_wipeDownMouseItem", "0ppp" },
-	{ "o2_getElapsedSecs", "" },
+	{ "o1_showMouse", "\xC0r" },
+	{ "o2_drawBox", "\xC0r0ppppp" },
+	{ "o2_wipeDownMouseItem", "\xC0r0ppp" },
+	{ "o2_getElapsedSecs", "\xC0r" },
 	// 0x34
-	{ "o2_getTimerDelay", "0p" },
-	{ "o1_playSoundEffect", "0p" },
-	{ "o2_delaySecs", "0p" },
-	{ "o2_delay", "0pp" },
+	{ "o2_getTimerDelay", "\xC0r0p" },
+	{ "o1_playSoundEffect", "\xC0r0p" },
+	{ "o2_delaySecs", "\xC0r0p" },
+	{ "o2_delay", "\xC0r0pp" },
 	// 0x38
-	{ "o2_dummy38", "" },
-	{ "o2_setTimerDelay", "0pp" },
-	{ "o2_setScaleTableItem", "0pp" },
-	{ "o2_setDrawLayerTableItem", "0pp" },
+	{ "o2_dummy38", "\xC0r" },
+	{ "o2_setTimerDelay", "\xC0r0pp" },
+	{ "o2_setScaleTableItem", "\xC0r0pp" },
+	{ "o2_setDrawLayerTableItem", "\xC0r0pp" },
 	// 0x3c
-	{ "o2_setCharPalEntry", "0pp" },
-	{ "o2_loadZShapes", "0p" },
-	{ "o2_drawSceneShape", "0pppp" },
-	{ "o2_drawSceneShapeOnPage", "0ppppp" },
+	{ "o2_setCharPalEntry", "\xC0r0pp" },
+	{ "o2_loadZShapes", "\xC0r0p" },
+	{ "o2_drawSceneShape", "\xC0r0pppp" },
+	{ "o2_drawSceneShapeOnPage", "\xC0r0ppppp" },
 	// 0x40
-	{ "o2_disableAnimObject", "0p" },
-	{ "o2_enableAnimObject", "0p" },
-	{ "o2_dummy42", "" },
-	{ "o2_loadPalette384", "0s" },
+	{ "o2_disableAnimObject", "\xC0r0p" },
+	{ "o2_enableAnimObject", "\xC0r0p" },
+	{ "o2_dummy42", "\xC0r" },
+	{ "o2_loadPalette384", "\xC0r0s" },
 	// 0x44
-	{ "o2_setPalette384", "" },
-	{ "o2_restoreBackBuffer", "0p" },
-	{ "o2_backUpInventoryGfx", "" },
-	{ "o2_disableSceneAnim", "0p" },
+	{ "o2_setPalette384", "\xC0r" },
+	{ "o2_restoreBackBuffer", "\xC0r0p" },
+	{ "o2_backUpInventoryGfx", "\xC0r" },
+	{ "o2_disableSceneAnim", "\xC0r0p" },
 	// 0x48
-	{ "o2_enableSceneAnim", "0p" },
-	{ "o2_restoreInventoryGfx", "" },
-	{ "o2_setSceneAnimPos2", "0ppp" },
-	{ "o2_update", "0p" },
+	{ "o2_enableSceneAnim", "\xC0r0p" },
+	{ "o2_restoreInventoryGfx", "\xC0r" },
+	{ "o2_setSceneAnimPos2", "\xC0r0ppp" },
+	{ "o2_update", "\xC0r0p" },
 	// 0x4c
-	{ "unk4C_palFade?", "0pp" },
-	{ "o2_fadeScenePal", "0pp" },
-	{ "o2_dummy4E", "" },
-	{ "o2_dummy4F", "" },
+	{ "unk4C_palFade?", "\xC0r0pp" },
+	{ "o2_fadeScenePal", "\xC0r0pp" },
+	{ "o2_dummy4E", "\xC0r" },
+	{ "o2_dummy4F", "\xC0r" },
 	// 0x50
-	{ "o2_enterNewScene", "0ppppp" },
-	{ "o2_switchScene", "0p" },
-	{ "o2_getShapeFlag1", "0pp" },
-	{ "o2_setPathfinderFlag", "0p" },
+	{ "o2_enterNewScene", "\xC0r0ppppp" },
+	{ "o2_switchScene", "\xC0r0p" },
+	{ "o2_getShapeFlag1", "\xC0r0pp" },
+	{ "o2_setPathfinderFlag", "\xC0r0p" },
 	// 0x54
-	{ "o2_getSceneExitToFacing", "0pp" },
-	{ "o2_setLayerFlag", "0p" },
-	{ "o2_setZanthiaPos", "0pp" },
-	{ "o2_loadMusicTrack", "0p" },
+	{ "o2_getSceneExitToFacing", "\xC0r0pp" },
+	{ "o2_setLayerFlag", "\xC0r0p" },
+	{ "o2_setZanthiaPos", "\xC0r0pp" },
+	{ "o2_loadMusicTrack", "\xC0r0p" },
 	// 0x58
-	{ "o1_playWanderScoreViaMap", "0pp" },
-	{ "o1_playSoundEffect", "0p" },
-	{ "o2_setSceneAnimPos", "0ppp" },
-	{ "o1_blockInWalkableRegion", "0pppp" },
+	{ "o1_playWanderScoreViaMap", "\xC0r0pp" },
+	{ "o1_playSoundEffect", "\xC0r0p" },
+	{ "o2_setSceneAnimPos", "\xC0r0ppp" },
+	{ "o1_blockInWalkableRegion", "\xC0r0pppp" },
 	// 0x5c
-	{ "o1_blockOutWalkableRegion", "0pppp" },
-	{ "unk5D", "0ppppp" },
-	{ "o2_setCauldronState", "0pp" },
-	{ "o2_showItemString", "0pp" },
+	{ "o1_blockOutWalkableRegion", "\xC0r0pppp" },
+	{ "unk5D", "\xC0r0ppppp" },
+	{ "o2_setCauldronState", "\xC0r0pp" },
+	{ "o2_showItemString", "\xC0r0pp" },
 	// 0x60
-	{ "o1_getRand", "0pp" },
-	{ "o2_isAnySoundPlaying", "" },
-	{ "o1_setDeathHandler", "0p" },
-	{ "o2_setDrawNoShapeFlag", "0p" },
+	{ "o1_getRand", "\xC0r0pp" },
+	{ "o2_isAnySoundPlaying", "\xC0r" },
+	{ "o1_setDeathHandler", "\xC0r0p" },
+	{ "o2_setDrawNoShapeFlag", "\xC0r0p" },
 	// 0x64
-	{ "o2_setRunFlag", "0p" },
-	{ "o2_showLetter", "0p" },
-	{ "o1_shakeScreen", "0pp" },
-	{ "o1_fillRect", "0pppppp" },
+	{ "o2_setRunFlag", "\xC0r0p" },
+	{ "o2_showLetter", "\xC0r0p" },
+	{ "o1_shakeScreen", "\xC0r0pp" },
+	{ "o1_fillRect", "\xC0r0pppppp" },
 	// 0x68
-	{ "o2_getKey", "" },
-	{ "unk69", "0pppp" },
-	{ "o2_playFireflyScore", "" },
-	{ "o2_waitForConfirmationClick", "0p" },
+	{ "o2_getKey", "\xC0r" },
+	{ "unk69", "\xC0r0pppp" },
+	{ "o2_playFireflyScore", "\xC0r" },
+	{ "o2_waitForConfirmationClick", "\xC0r0p" },
 	// 0x6c
-	{ "o2_encodeShape", "0ppppp" },
-	{ "o2_defineRoomEntrance", "0ppp" },
-	{ "o2_runAnimationScript", "0sppp" },
-	{ "o2_setSpecialSceneScriptRunTime", "0pp" },
+	{ "o2_encodeShape", "\xC0r0ppppp" },
+	{ "o2_defineRoomEntrance", "\xC0r0ppp" },
+	{ "o2_runAnimationScript", "\xC0r0sppp" },
+	{ "o2_setSpecialSceneScriptRunTime", "\xC0r0pp" },
 	// 0x70
-	{ "o2_defineSceneAnim", "0pppppppppppps" },
-	{ "o2_updateSceneAnim", "pp" },
-	{ "o2_updateSceneAnim", "pp" },
-	{ "o2_addToSceneAnimPosAndUpdate", "0ppp" },
+	{ "o2_defineSceneAnim", "\xC0r0pppppppppppps" },
+	{ "o2_updateSceneAnim", "\xC0r0pp" },
+	{ "o2_updateSceneAnim", "\xC0r0pp" },
+	{ "o2_addToSceneAnimPosAndUpdate", "\xC0r0ppp" },
 	// 0x74
-	{ "o2_useItemOnMainChar", "" },
-	{ "o2_startDialogue", "0p" },
-	{ "o2_randomSceneChat", "" },
-	{ "o2_setDlgIndex", "0p" },
+	{ "o2_useItemOnMainChar", "\xC0r" },
+	{ "o2_startDialogue", "\xC0r0p" },
+	{ "o2_randomSceneChat", "\xC0r" },
+	{ "o2_setDlgIndex", "\xC0r0p" },
 	// 0x78
-	{ "o2_getDlgIndex", "" },
-	{ "o2_defineScene", "0pspppppp" },
-	{ "o2_addCauldronStateTableEntry", "0pp" },
-	{ "o2_setCountDown", "0p" },
+	{ "o2_getDlgIndex", "\xC0r" },
+	{ "o2_defineScene", "\xC0r0pspppppp" },
+	{ "o2_addCauldronStateTableEntry", "\xC0r0pp" },
+	{ "o2_setCountDown", "\xC0r0p" },
 	// 0x7c
-	{ "o2_getCountDown", "" },
-	{ "o2_dummy7D", "" },
-	{ "o2_dummy7E", "" },
-	{ "o2_pressColorKey", "0p" },
+	{ "o2_getCountDown", "\xC0r" },
+	{ "o2_dummy7D", "\xC0r" },
+	{ "o2_dummy7E", "\xC0r" },
+	{ "o2_pressColorKey", "\xC0r0p" },
 	// 0x80
-	{ "o2_objectChat", "0sp" },
-	{ "o2_changeChapter", "0pp" },
-	{ "o2_getColorCodeFlag1", "" },
-	{ "o2_setColorCodeFlag1", "0p" },
+	{ "o2_objectChat", "\xC0r0sp" },
+	{ "o2_changeChapter", "\xC0r0pp" },
+	{ "o2_getColorCodeFlag1", "\xC0r" },
+	{ "o2_setColorCodeFlag1", "\xC0r0p" },
 	// 0x84
-	{ "o2_getColorCodeFlag2", "" },
-	{ "o2_setColorCodeFlag2", "0p" },
-	{ "o2_getColorCodeValue", "0p" },
-	{ "o2_setColorCodeValue", "0pp" },
+	{ "o2_getColorCodeFlag2", "\xC0r" },
+	{ "o2_setColorCodeFlag2", "\xC0r0p" },
+	{ "o2_getColorCodeValue", "\xC0r0p" },
+	{ "o2_setColorCodeValue", "\xC0r0pp" },
 	// 0x88
-	{ "o2_countItemInstances", "0p" },
-	{ "o2_removeItemFromScene", "0pp" },
-	{ "o2_initObject", "0p" },
-	{ "o2_npcChat", "0spp" }, // FIXME: Non-talkie metadata; talkie opcode is 0spp
+	{ "o2_countItemInstances", "\xC0r0p" },
+	{ "o2_removeItemFromScene", "\xC0r0pp" },
+	{ "o2_initObject", "\xC0r0p" },
+	{ "o2_npcChat", "\xC0r0spp" }, // FIXME: Non-talkie metadata; talkie opcode is 0spp
 	// 0x8c
-	{ "o2_deinitObject", "0p" },
-	{ "o2_playTimSequence", "0s" },
-	{ "o2_makeBookOrCauldronAppear", "0p" },
-	{ "o2_setSpecialSceneScriptState", "0p" },
+	{ "o2_deinitObject", "\xC0r0p" },
+	{ "o2_playTimSequence", "\xC0r0s" },
+	{ "o2_makeBookOrCauldronAppear", "\xC0r0p" },
+	{ "o2_setSpecialSceneScriptState", "\xC0r0p" },
 	// 0x90
-	{ "o2_clearSpecialSceneScriptState", "0p" },
-	{ "o2_querySpecialSceneScriptState", "0p" },
-	{ "o2_resetInputColorCode", "" },
-	{ "o2_setHiddenItemsEntry", "0pp" },
+	{ "o2_clearSpecialSceneScriptState", "\xC0r0p" },
+	{ "o2_querySpecialSceneScriptState", "\xC0r0p" },
+	{ "o2_resetInputColorCode", "\xC0r" },
+	{ "o2_setHiddenItemsEntry", "\xC0r0pp" },
 	// 0x94
-	{ "o2_getHiddenItemsEntry", "0p" },
-	{ "o2_mushroomEffect", "" },
-	{ "o2_wsaClose", "0p" },
-	{ "o2_meanWhileScene", "0p" },
+	{ "o2_getHiddenItemsEntry", "\xC0r0p" },
+	{ "o2_mushroomEffect", "\xC0r" },
+	{ "o2_wsaClose", "\xC0r0p" },
+	{ "o2_meanWhileScene", "\xC0r0p" },
 	// 0x98
-	{ "o2_customChat", "0spp" },
-	{ "o2_customChatFinish", "" },
-	{ "o2_setupSceneAnimation", "0pppppppppppps" },
-	{ "o2_stopSceneAnimation", "0pp" },
+	{ "o2_customChat", "\xC0r0spp" },
+	{ "o2_customChatFinish", "\xC0r" },
+	{ "o2_setupSceneAnimation", "\xC0r0pppppppppppps" },
+	{ "o2_stopSceneAnimation", "\xC0r0pp" },
 	// 0x9c
-	{ "o2_disableTimer", "0p" },
-	{ "o2_enableTimer", "0p" },
-	{ "o2_setTimerCountdown", "0pp" },
-	{ "o2_processPaletteIndex", "0pppppp" },
+	{ "o2_disableTimer", "\xC0r0p" },
+	{ "o2_enableTimer", "\xC0r0p" },
+	{ "o2_setTimerCountdown", "\xC0r0pp" },
+	{ "o2_processPaletteIndex", "\xC0r0pppppp" },
 	// 0xa0
-	{ "o2_updateTwoSceneAnims", "0pppp" },
-	{ "o2_getRainbowRoomData", "0p" },
-	{ "o2_drawSceneShapeEx", "0pppp" },
-	{ "o2_midiSoundFadeout", "" },
+	{ "o2_updateTwoSceneAnims", "\xC0r0pppp" },
+	{ "o2_getRainbowRoomData", "\xC0r0p" },
+	{ "o2_drawSceneShapeEx", "\xC0r0pppp" },
+	{ "o2_midiSoundFadeout", "\xC0r" },
 	// 0xa4
-	{ "o2_getSfxDriver", "" },
-	{ "o2_getVocSupport", "" },
-	{ "o2_getMusicDriver", "" },
-	{ "o2_setVocHigh", "0p" },
+	{ "o2_getSfxDriver", "\xC0r" },
+	{ "o2_getVocSupport", "\xC0r" },
+	{ "o2_getMusicDriver", "\xC0r" },
+	{ "o2_setVocHigh", "\xC0r0p" },
 	// 0xa8
-	{ "o2_getVocHigh", "" },
-	{ "o2_zanthiaChat", "0sp" },
-	{ "o2_isVoiceEnabled", "" },
-	{ "o2_isVoicePlaying", "" },
+	{ "o2_getVocHigh", "\xC0r" },
+	{ "o2_zanthiaChat", "\xC0r0sp" },
+	{ "o2_isVoiceEnabled", "\xC0r" },
+	{ "o2_isVoicePlaying", "\xC0r" },
 	// 0xac
-	{ "o2_stopVoicePlaying", "" },
-	{ "o2_getGameLanguage", "" },
-	{ "o2_demoFinale", "" },
-	{ "o2_dummyAF", "" }
+	{ "o2_stopVoicePlaying", "\xC0r" },
+	{ "o2_getGameLanguage", "\xC0r" },
+	{ "o2_demoFinale", "\xC0r" },
+	{ "o2_dummyAF", "\xC0r" }
 };
 
 IFFChunk::IFFChunk() {
@@ -326,7 +326,9 @@
 		uint16 numStrings = minTextOffset / 2;
 #define posString(x) (char*)&_textChunk._data[READ_BE_UINT16(&((uint16 *)_textChunk._data)[(x)])]
 		for (uint16 i = 0; i < numStrings; ++i) {
-			_engine->_textStrings.push_back(posString(i));
+			std::stringstream s;
+			s << "\"" << posString(i) << "\"";
+			_engine->_textStrings.push_back(s.str());
 		}
 #undef posString
 	}
@@ -466,7 +468,7 @@
 			break;
 		case 16:
 			if (parameter == 0) {
-				OPCODE_MD("boolCast", kUnaryOp, 0, false, false, "(bool)");
+				OPCODE_MD("boolNegate", kUnaryOp, 0, false, false, "!");
 			} else if (parameter == 1) {
 				OPCODE_MD("arithmeticNegate", kUnaryOp, 0, false, false,"-");
 			} else if (parameter == 2) {
@@ -555,12 +557,10 @@
 		addrMap[it->_address] = it;
 
 	std::sort(funcAddrs.begin(), funcAddrs.end());
-	//Create ranges from entry points
+	// We only have the entry points, but the end points are not known, so create placeholder function entries
 	for (size_t i = 0; i < funcAddrs.size(); i++) {
-		if (i == funcAddrs.size() - 1) // Last function
-			_engine->_functions[funcAddrs[i]] = Function(addrMap[funcAddrs[i]], _insts.end());
-		else
-			_engine->_functions[funcAddrs[i]] = Function(addrMap[funcAddrs[i]], addrMap[funcAddrs[i+1]]);
+		_engine->_functions[funcAddrs[i]] = Function(addrMap[funcAddrs[i]], addrMap[funcAddrs[i]]);
+		_engine->_functions[funcAddrs[i]]._name = "global_";
 	}
 
 	// Correct jumps to functions so they're treated as calls
@@ -574,3 +574,4 @@
 		lastWasPushPos = (it->_name.compare("pushPos") == 0);
 	}
 }
+

Modified: tools/branches/gsoc2010-decompiler/decompiler/kyra/engine.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/kyra/engine.cpp	2010-08-07 01:27:14 UTC (rev 51823)
+++ tools/branches/gsoc2010-decompiler/decompiler/kyra/engine.cpp	2010-08-07 02:39:11 UTC (rev 51824)
@@ -22,6 +22,7 @@
 
 #include "engine.h"
 #include "disassembler.h"
+#include "codegen.h"
 
 #include <iostream>
 #include <sstream>
@@ -36,15 +37,15 @@
 }
 
 ::CodeGenerator *Kyra::Engine::getCodeGenerator(std::ostream &output) {
-	// TODO
-	return NULL;
+	return new CodeGenerator(this, output);
 }
 
 void Kyra::Engine::postCFG(std::vector<Instruction> &insts, Graph g) {
 	// Add metadata to functions
 	for (FuncMap::iterator it = _functions.begin(); it != _functions.end(); ++it) {
 		std::stringstream s;
-		s << boost::format("sub0x%X") % it->second._startIt->_address;
+		s << it->second._name << boost::format("sub0x%X") % it->second._startIt->_address;
+		it->second._name = s.str();
 		int maxArg = 0;
 		for (ConstInstIterator instIt = it->second._startIt; instIt != it->second._endIt; ++instIt) {
 			if (instIt->_name.compare("pushBPAdd") == 0) {
@@ -55,6 +56,9 @@
 		}
 		it->second._args = maxArg;
 		it->second._retVal = true;
+		std::stringstream md;
+		md << "0" << std::string(maxArg, 'p');
+		it->second._metadata = md.str();
 	}
 }
 

Modified: tools/branches/gsoc2010-decompiler/decompiler/kyra/engine.h
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/kyra/engine.h	2010-08-07 01:27:14 UTC (rev 51823)
+++ tools/branches/gsoc2010-decompiler/decompiler/kyra/engine.h	2010-08-07 02:39:11 UTC (rev 51824)
@@ -39,7 +39,6 @@
 	uint32 getDestAddress(ConstInstIterator it) const;
 	::CodeGenerator *getCodeGenerator(std::ostream &output);
 	void postCFG(std::vector<Instruction> &insts, Graph g);
-	bool supportsCodeGen() { return false; }
 	bool detectMoreFuncs();
 
 	std::vector<std::string> _textStrings;

Modified: tools/branches/gsoc2010-decompiler/decompiler/stack.h
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/stack.h	2010-08-07 01:27:14 UTC (rev 51823)
+++ tools/branches/gsoc2010-decompiler/decompiler/stack.h	2010-08-07 02:39:11 UTC (rev 51824)
@@ -79,7 +79,11 @@
 	 * @param pos The number of items to skip on the stack.
 	 * @return The desired item from the stack.
 	 */
-	T &peekPos(size_t pos) { return _stack.at(pos); }
+	T &peekPos(size_t pos) {
+		if (pos >= _stack.size())
+			std::cerr << "WARNING: Looking outside stack\n";
+		return _stack.at(pos);
+	}
 
 	/**
 	 * Return the item on the specificed stack position without removing it.
@@ -87,7 +91,11 @@
 	 * @param pos The number of items to skip on the stack.
 	 * @return The desired item from the stack.
 	 */
-	const T &peekPos(size_t pos) const { return _stack.at(pos); }
+	const T &peekPos(size_t pos) const {
+		if (pos >= _stack.size())
+			std::cerr << "WARNING: Looking outside stack\n";
+		return _stack.at(pos);
+	}
 };
 
 #endif


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