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

pidgeot at users.sourceforge.net pidgeot at users.sourceforge.net
Tue Jul 20 00:50:06 CEST 2010


Revision: 51040
          http://scummvm.svn.sourceforge.net/scummvm/?rev=51040&view=rev
Author:   pidgeot
Date:     2010-07-19 22:50:06 +0000 (Mon, 19 Jul 2010)

Log Message:
-----------
Prototype of actual SCUMMv6 code generation
Currently crashes, committing to do valgrind testing on Linux

Modified Paths:
--------------
    tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp
    tools/branches/gsoc2010-decompiler/decompiler/codegen.h
    tools/branches/gsoc2010-decompiler/decompiler/scummv6/codegen.cpp
    tools/branches/gsoc2010-decompiler/decompiler/scummv6/codegen.h

Modified: tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp	2010-07-19 22:11:06 UTC (rev 51039)
+++ tools/branches/gsoc2010-decompiler/decompiler/codegen.cpp	2010-07-19 22:50:06 UTC (rev 51040)
@@ -37,10 +37,19 @@
 		return this;
 
 	EntryPtr dupEntry = new DupEntry(++dupindex);
-	output << this << " = " << dupEntry;
+	output << dupEntry << " = " << this;
 	return dupEntry;
 }
 
+std::string CodeGenerator::indentString(std::string s) {
+	std::stringstream stream;
+	std::string indent(kIndentAmount, ' ');
+	for (uint i = 0; i < _indentLevel; i++)
+		stream << indent;
+	stream << s;
+	return stream.str();
+}
+
 CodeGenerator::CodeGenerator(Engine *engine, std::ostream &output) : _output(output) {
 	_engine = engine;
 }
@@ -91,6 +100,36 @@
 	}
 }
 
+void CodeGenerator::addOutputLine(std::string s) {
+	_curGroup->_code.push_back(indentString(s));
+}
+
+void CodeGenerator::writeAssignment(EntryPtr dst, EntryPtr src) {
+	std::stringstream s;
+	s << dst << " = " << src << ";";
+	addOutputLine(s.str());
+}
+
 void CodeGenerator::process(GraphVertex v) {
-	// TODO
+	// TODO: Add keyword output
+	_curGroup = GET(v);
+	ConstInstIterator it = _curGroup->_start;
+	do {
+		switch (it->_type) {
+		// We handle plain dups here because their behavior should be identical across instruction sets and this prevents implementation error.
+		case kDup:
+		{
+			std::stringstream s;
+			EntryPtr p = _stack.top()->dup(s);
+			if (s.str().length() > 0)
+				addOutputLine(s.str());
+			_stack.pop();
+			_stack.push(p);
+			_stack.push(p);
+			break;
+		}
+		default:
+			processInst(*it);
+		}
+	} while (++it != _curGroup->_end);
 }

Modified: tools/branches/gsoc2010-decompiler/decompiler/codegen.h
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/codegen.h	2010-07-19 22:11:06 UTC (rev 51039)
+++ tools/branches/gsoc2010-decompiler/decompiler/codegen.h	2010-07-19 22:50:06 UTC (rev 51040)
@@ -102,7 +102,6 @@
 	}
 };
 
-
 namespace boost {
 
 /**
@@ -122,7 +121,6 @@
 
 } // End of namespace boost
 
-
 /**
  * Stack entry containing an integer.
  */
@@ -257,6 +255,8 @@
  */
 typedef std::stack<EntryPtr> Stack;
 
+const int kIndentAmount = 2; ///< How many spaces to use for each indent.
+
 /**
  * Base class for code generators.
  */
@@ -275,14 +275,39 @@
 protected:
 	std::ostream &_output; ///< The std::ostream to output the code to.
 	Stack _stack;          ///< The stack currently being processed.
+	uint _indentLevel;     ///< Indentation level.
+	GroupPtr _curGroup;    ///< Pointer to the group currently being processed.
 
 	/**
 	 * Processes an instruction.
 	 *
 	 * @param inst The instruction to process.
 	 */
-	virtual void processInst(Instruction inst) = 0;
+	virtual void processInst(const Instruction inst) = 0;
 
+	/**
+	 * 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);
+
+	/**
+	 * Indents a line and adds it to the current group.
+	 *
+	 * @param s The string to add.
+	 */
+	void addOutputLine(std::string s);
+
+	/**
+	 * Generate an assignment statement.
+	 *
+	 * @param dst The variable being assigned to.
+	 * @param src The value being assigned.
+	 */
+	void writeAssignment(EntryPtr dst, EntryPtr src);
+
 public:
 	virtual ~CodeGenerator() {};
 

Modified: tools/branches/gsoc2010-decompiler/decompiler/scummv6/codegen.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/scummv6/codegen.cpp	2010-07-19 22:11:06 UTC (rev 51039)
+++ tools/branches/gsoc2010-decompiler/decompiler/scummv6/codegen.cpp	2010-07-19 22:50:06 UTC (rev 51040)
@@ -22,6 +22,249 @@
 
 #include "codegen.h"
 
-void Scumm::v6::CodeGenerator::processInst(Instruction inst) {
+void Scumm::v6::CodeGenerator::processInst(const Instruction inst) {
 	// TODO
+
+	// This is just to keep some order in this code and have related opcodes near each other.
+	// It's not strictly necessary, because we can just look directly at the opcode, but this should be easier to read.
+	switch (inst._type) {
+	case kLoad:
+		switch (inst._opcode) {
+		case 0x00: // pushByte
+			_stack.push(new IntEntry(inst._params[0].getUnsigned(), true));
+			break;
+		case 0x01: // pushWord
+			_stack.push(new IntEntry(inst._params[0].getSigned(), false));
+			break;
+		case 0x02: // pushByteVar
+		case 0x03: // pushWordVar
+			_stack.push(new VarEntry(decodeVarName(inst._params[0].getUnsigned())));
+			break;
+		case 0x06: // byteArrayRead
+			// TODO
+			break;
+		case 0x07: // wordArrayRead
+			// TODO
+			break;
+		case 0x0A: // byteArrayIndexedRead
+			// TODO
+			break;
+		case 0x0B: // wordArrayIndexedRead
+			// TODO
+			break;
+		}
+		break;
+	case kStore:
+		switch (inst._opcode) {
+			case 0x42:
+			case 0x43:
+			{
+				EntryPtr p = new VarEntry(decodeVarName(inst._params[0].getUnsigned()));
+				writeAssignment(p, _stack.top());
+				_stack.pop();
+				break;
+			}
+			case 0x46:
+				break;
+			case 0x47:
+				break;
+			case 0x4A:
+				break;
+			case 0x4B:
+				break;
+		}
+	default:
+		{
+			std::stringstream s;
+			s << boost::format("Unknown opcode %X at address %08X") % inst._opcode % inst._address;
+			_curGroup->_code.push_back(indentString(s.str()));
+			break;
+		}
+	}
 }
+
+const char *var_names[] = {
+	/* 0 */
+	NULL,
+	"VAR_EGO",
+	"VAR_CAMERA_POS_X",
+	"VAR_HAVE_MSG",
+	/* 4 */
+	"VAR_ROOM",
+	"VAR_OVERRIDE",
+	"VAR_MACHINE_SPEED",
+	NULL,
+	/* 8 */
+	"VAR_NUM_ACTOR",
+	"VAR_V6_SOUNDMODE",
+	"VAR_CURRENTDRIVE",
+	"VAR_TMR_1",
+	/* 12 */
+	"VAR_TMR_2",
+	"VAR_TMR_3",
+	NULL,
+	NULL,
+	/* 16 */
+	NULL,
+	"VAR_CAMERA_MIN_X",
+	"VAR_CAMERA_MAX_X",
+	"VAR_TIMER_NEXT",
+	/* 20 */
+	"VAR_VIRT_MOUSE_X",
+	"VAR_VIRT_MOUSE_Y",
+	"VAR_ROOM_RESOURCE",
+	"VAR_LAST_SOUND",
+	/* 24 */
+	"VAR_CUTSCENEEXIT_KEY",
+	"VAR_TALK_ACTOR",
+	"VAR_CAMERA_FAST_X",
+	"VAR_SCROLL_SCRIPT",
+	/* 28 */
+	"VAR_ENTRY_SCRIPT",
+	"VAR_ENTRY_SCRIPT2",
+	"VAR_EXIT_SCRIPT",
+	"VAR_EXIT_SCRIPT2",
+	/* 32 */
+	"VAR_VERB_SCRIPT",
+	"VAR_SENTENCE_SCRIPT",
+	"VAR_INVENTORY_SCRIPT",
+	"VAR_CUTSCENE_START_SCRIPT",
+	/* 36 */
+	"VAR_CUTSCENE_END_SCRIPT",
+	"VAR_CHARINC",
+	"VAR_WALKTO_OBJ",
+	"VAR_DEBUGMODE",
+	/* 40 */
+	"VAR_HEAPSPACE",
+	"VAR_ROOM_WIDTH",
+	"VAR_RESTART_KEY",
+	"VAR_PAUSE_KEY",
+	/* 44 */
+	"VAR_MOUSE_X",
+	"VAR_MOUSE_Y",
+	"VAR_TIMER",
+	"VAR_TMR_4",
+	/* 48 */
+	NULL,
+	"VAR_VIDEOMODE",
+	"VAR_MAINMENU_KEY",
+	"VAR_FIXEDDISK",
+	/* 52 */
+	"VAR_CURSORSTATE",
+	"VAR_USERPUT",
+	"VAR_ROOM_HEIGHT",
+	NULL,
+	/* 56 */
+	"VAR_SOUNDRESULT",
+	"VAR_TALKSTOP_KEY",
+	NULL,
+	"VAR_FADE_DELAY",
+	/* 60 */
+	"VAR_NOSUBTITLES",
+	"VAR_SAVELOAD_SCRIPT",
+	"VAR_SAVELOAD_SCRIPT2",
+	NULL,
+	/* 64 */
+	"VAR_SOUNDPARAM",
+	"VAR_SOUNDPARAM2",
+	"VAR_SOUNDPARAM3",
+	"VAR_INPUTMODE",
+	/* 68 */
+	"VAR_MEMORY_PERFORMANCE",
+	"VAR_VIDEO_PERFORMANCE",
+	"VAR_ROOM_FLAG",
+	"VAR_GAME_LOADED",
+	/* 72 */
+	"VAR_NEW_ROOM",
+	NULL,
+	"VAR_LEFTBTN_DOWN",
+	"VAR_RIGHTBTN_DOWN",
+	/* 76 */
+	"VAR_V6_EMSSPACE",
+	NULL,
+	NULL,
+	NULL,
+	/* 80 */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	/* 84 */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	/* 88 */
+	NULL,
+	NULL,
+	"VAR_GAME_DISK_MSG",
+	"VAR_OPEN_FAILED_MSG",
+	/* 92 */
+	"VAR_READ_ERROR_MSG",
+	"VAR_PAUSE_MSG",
+	"VAR_RESTART_MSG",
+	"VAR_QUIT_MSG",
+	/* 96 */
+	"VAR_SAVE_BTN",
+	"VAR_LOAD_BTN",
+	"VAR_PLAY_BTN",
+	"VAR_CANCEL_BTN",
+	/* 100 */
+	"VAR_QUIT_BTN",
+	"VAR_OK_BTN",
+	"VAR_SAVE_DISK_MSG",
+	"VAR_ENTER_NAME_MSG",
+	/* 104 */
+	"VAR_NOT_SAVED_MSG",
+	"VAR_NOT_LOADED_MSG",
+	"VAR_SAVE_MSG",
+	"VAR_LOAD_MSG",
+	/* 108 */
+	"VAR_SAVE_MENU_TITLE",
+	"VAR_LOAD_MENU_TITLE",
+	"VAR_GUI_COLORS",
+	"VAR_DEBUG_PASSWORD",
+	/* 112 */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	/* 116 */
+	NULL,
+	"VAR_MAIN_MENU_TITLE",
+	"VAR_RANDOM_NR",
+	"VAR_TIMEDATE_YEAR",
+	/* 120 */
+	NULL,
+	"VAR_GAME_VERSION",
+	NULL,
+	"VAR_CHARSET_MASK",
+	/* 124 */
+	NULL,
+	"VAR_TIMEDATE_HOUR",
+	"VAR_TIMEDATE_MINUTE",
+	NULL,
+	/* 128 */
+	"VAR_TIMEDATE_DAY",
+	"VAR_TIMEDATE_MONTH",
+	NULL,
+	NULL,
+};
+
+std::string Scumm::v6::CodeGenerator::decodeVarName(uint16 varID) {
+	std::stringstream s;
+	if (!(varID & 0xF000)) {
+		uint16 var = varID & 0xFFF;
+		if (var < (sizeof(var_names) / sizeof(var_names[0])) && var_names[var] != NULL)
+			return var_names[var];
+		else
+			s << boost::format("var%d") % (varID & 0xFFF);
+	} else if (varID & 0x8000) {
+		s << boost::format("bitvar%d") % (varID & 0x7FFF);
+	} else if (varID & 0x4000) {
+		s << boost::format("localvar%d") % (varID & 0xFFF);
+	} else {
+		s << boost::format("?var?%d") % varID;
+	}
+	return s.str();
+}

Modified: tools/branches/gsoc2010-decompiler/decompiler/scummv6/codegen.h
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/scummv6/codegen.h	2010-07-19 22:11:06 UTC (rev 51039)
+++ tools/branches/gsoc2010-decompiler/decompiler/scummv6/codegen.h	2010-07-19 22:50:06 UTC (rev 51040)
@@ -33,10 +33,18 @@
  * SCUMMv6 code generator.
  */
 class CodeGenerator : public ::CodeGenerator {
+private:
+	/**
+	 * Decode a variable ID to a name.
+	 *
+	 * @param varID The ID to decode.
+	 * @return The decoded variable name.
+	 */
+	std::string decodeVarName(uint16 varID);
 public:
 	CodeGenerator(Engine *engine, std::ostream &output) : ::CodeGenerator(engine, output) {}
 protected:
-	void processInst(Instruction inst);
+	void processInst(const Instruction inst);
 };
 
 } // End of namespace v6


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