aboutsummaryrefslogtreecommitdiff
path: root/engines/made/script.cpp
diff options
context:
space:
mode:
authorBenjamin Haisch2008-05-20 20:00:10 +0000
committerBenjamin Haisch2008-05-20 20:00:10 +0000
commit828a217a03038673dfbd0f88a80f78832b55d872 (patch)
treeccd7503b1f376dd87e4c1b1051137a384b5405ce /engines/made/script.cpp
parent11697c0eb24aed6c6997c1d6282b69ed3448b1e9 (diff)
downloadscummvm-rg350-828a217a03038673dfbd0f88a80f78832b55d872.tar.gz
scummvm-rg350-828a217a03038673dfbd0f88a80f78832b55d872.tar.bz2
scummvm-rg350-828a217a03038673dfbd0f88a80f78832b55d872.zip
- Implemented "stand-alone" script dumper/disassembler; it can be enabled by defining DUMP_SCRIPTS in script.h and starting with at least debug level 1.
- Commented which script opcodes and extended functions are actually used or not. svn-id: r32202
Diffstat (limited to 'engines/made/script.cpp')
-rw-r--r--engines/made/script.cpp281
1 files changed, 199 insertions, 82 deletions
diff --git a/engines/made/script.cpp b/engines/made/script.cpp
index 7d7ebc83cd..6b736e321b 100644
--- a/engines/made/script.cpp
+++ b/engines/made/script.cpp
@@ -91,83 +91,87 @@ int16 *ScriptStack::getStackPtr() {
/* ScriptInterpreter */
ScriptInterpreter::ScriptInterpreter(MadeEngine *vm) : _vm(vm) {
-#define COMMAND(x) { &ScriptInterpreter::x, #x }
+#ifdef DUMP_SCRIPTS
+#define COMMAND(x, sig) { &ScriptInterpreter::x, #x, sig }
+#else
+#define COMMAND(x, sig) { &ScriptInterpreter::x, #x}
+#endif
static CommandEntry commandProcs[] = {
/* 01 */
- COMMAND(cmd_branchTrue),
- COMMAND(cmd_branchFalse),
- COMMAND(cmd_branch),
- COMMAND(cmd_true),
+ COMMAND(cmd_branchTrue, "W"),
+ COMMAND(cmd_branchFalse, "W"),
+ COMMAND(cmd_branch, "W"),
+ COMMAND(cmd_true, ""),
/* 05 */
- COMMAND(cmd_false),
- COMMAND(cmd_push),
- COMMAND(cmd_not),
- COMMAND(cmd_add),
+ COMMAND(cmd_false, ""),
+ COMMAND(cmd_push, ""),
+ COMMAND(cmd_not, ""),
+ COMMAND(cmd_add, ""),
/* 09 */
- COMMAND(cmd_sub),
- COMMAND(cmd_mul),
- COMMAND(cmd_div),
- COMMAND(cmd_mod),
+ COMMAND(cmd_sub, ""),
+ COMMAND(cmd_mul, ""),
+ COMMAND(cmd_div, ""),
+ COMMAND(cmd_mod, ""),
/* 13 */
- COMMAND(cmd_band),
- COMMAND(cmd_bor),
- COMMAND(cmd_bnot),
- COMMAND(cmd_lt),
+ COMMAND(cmd_band, ""),
+ COMMAND(cmd_bor, ""),
+ COMMAND(cmd_bnot, ""),
+ COMMAND(cmd_lt, ""),
/* 17 */
- COMMAND(cmd_eq),
- COMMAND(cmd_gt),
- COMMAND(cmd_loadConstant),
- COMMAND(cmd_loadVariable),
+ COMMAND(cmd_eq, ""),
+ COMMAND(cmd_gt, ""),
+ COMMAND(cmd_loadConstant, "w"),
+ COMMAND(cmd_loadVariable, "w"),
/* 21 */
- COMMAND(cmd_getObjectProperty),
- COMMAND(cmd_setObjectProperty),
- COMMAND(cmd_set),
- COMMAND(cmd_print),
+ COMMAND(cmd_getObjectProperty, ""),
+ COMMAND(cmd_setObjectProperty, ""),
+ COMMAND(cmd_set, "w"),
+ COMMAND(cmd_print, ""),
/* 25 */
- COMMAND(cmd_terpri),
- COMMAND(cmd_printNumber),
- COMMAND(cmd_vref),
- COMMAND(cmd_vset),
+ COMMAND(cmd_terpri, ""),
+ COMMAND(cmd_printNumber, ""),
+ COMMAND(cmd_vref, ""),
+ COMMAND(cmd_vset, ""),
/* 29 */
- COMMAND(cmd_vsize),
- COMMAND(cmd_exit),
- COMMAND(cmd_return),
- COMMAND(cmd_call),
+ COMMAND(cmd_vsize, ""),
+ COMMAND(cmd_exit, ""),
+ COMMAND(cmd_return, ""),
+ COMMAND(cmd_call, "b"),
/* 33 */
- COMMAND(cmd_svar),
- COMMAND(cmd_sset),
- COMMAND(cmd_split),
- COMMAND(cmd_snlit),
+ COMMAND(cmd_svar, ""),
+ COMMAND(cmd_sset, ""),
+ COMMAND(cmd_split, ""),
+ COMMAND(cmd_snlit, ""),
/* 37 */
- COMMAND(cmd_yorn),
- COMMAND(cmd_save),
- COMMAND(cmd_restore),
- COMMAND(cmd_arg),
+ COMMAND(cmd_yorn, ""),
+ COMMAND(cmd_save, ""),
+ COMMAND(cmd_restore, ""),
+ COMMAND(cmd_arg, "b"),
/* 41 */
- COMMAND(cmd_aset),
- COMMAND(cmd_tmp),
- COMMAND(cmd_tset),
- COMMAND(cmd_tspace),
+ COMMAND(cmd_aset, "b"),
+ COMMAND(cmd_tmp, "b"),
+ COMMAND(cmd_tset, "b"),
+ COMMAND(cmd_tspace, "b"),
/* 45 */
- COMMAND(cmd_class),
- COMMAND(cmd_objectp),
- COMMAND(cmd_vectorp),
- COMMAND(cmd_restart),
+ COMMAND(cmd_class, ""),
+ COMMAND(cmd_objectp, ""),
+ COMMAND(cmd_vectorp, ""),
+ COMMAND(cmd_restart, ""),
/* 49 */
- COMMAND(cmd_rand),
- COMMAND(cmd_randomize),
- COMMAND(cmd_send),
- COMMAND(cmd_extend),
+ COMMAND(cmd_rand, ""),
+ COMMAND(cmd_randomize, ""),
+ COMMAND(cmd_send, "b"),
+ COMMAND(cmd_extend, "Eb"),
/* 53 */
- COMMAND(cmd_catch),
- COMMAND(cmd_cdone),
- COMMAND(cmd_throw),
- COMMAND(cmd_functionp),
+ COMMAND(cmd_catch, ""),
+ COMMAND(cmd_cdone, ""),
+ COMMAND(cmd_throw, ""),
+ COMMAND(cmd_functionp, ""),
/* 57 */
- COMMAND(cmd_le),
- COMMAND(cmd_ge),
- COMMAND(cmd_varx),
- COMMAND(cmd_setx)
+ COMMAND(cmd_le, ""),
+ COMMAND(cmd_ge, ""),
+ COMMAND(cmd_varx, ""),
+ COMMAND(cmd_setx, "")
};
_commands = commandProcs;
_commandsMax = ARRAYSIZE(commandProcs) + 1;
@@ -175,9 +179,6 @@ ScriptInterpreter::ScriptInterpreter(MadeEngine *vm) : _vm(vm) {
_functions = new ScriptFunctions(_vm);
_functions->setupExternalsTable();
- // set to true to dump scripts instead of parsing them
- _dumpScripts = false;
-
#undef COMMAND
}
@@ -217,27 +218,18 @@ int16 ScriptInterpreter::readInt16() {
}
void ScriptInterpreter::cmd_branchTrue() {
- if (_dumpScripts)
- return;
-
int16 ofs = readInt16();
if (_stack.top() != 0)
_codeIp = _codeBase + ofs;
}
void ScriptInterpreter::cmd_branchFalse() {
- if (_dumpScripts)
- return;
-
int16 ofs = readInt16();
if (_stack.top() == 0)
_codeIp = _codeBase + ofs;
}
void ScriptInterpreter::cmd_branch() {
- if (_dumpScripts)
- return;
-
int16 ofs = readInt16();
_codeIp = _codeBase + ofs;
}
@@ -459,29 +451,31 @@ void ScriptInterpreter::cmd_call() {
}
void ScriptInterpreter::cmd_svar() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_svar");
}
void ScriptInterpreter::cmd_sset() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_sset");
}
void ScriptInterpreter::cmd_split() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_split");
}
void ScriptInterpreter::cmd_snlit() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_snlit");
}
void ScriptInterpreter::cmd_yorn() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_yorn");
}
void ScriptInterpreter::cmd_save() {
- if (_dumpScripts)
- return;
-
int16 result = 0;
int16 stringOfs = _stack.top();
const char *filename = _vm->_dat->getString(stringOfs);
@@ -490,9 +484,6 @@ void ScriptInterpreter::cmd_save() {
}
void ScriptInterpreter::cmd_restore() {
- if (_dumpScripts)
- return;
-
int16 result = 0;
int16 stringOfs = _stack.top();
const char *filename = _vm->_dat->getString(stringOfs);
@@ -531,6 +522,7 @@ void ScriptInterpreter::cmd_tspace() {
}
void ScriptInterpreter::cmd_class() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_class");
}
@@ -543,10 +535,12 @@ void ScriptInterpreter::cmd_objectp() {
}
void ScriptInterpreter::cmd_vectorp() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_vectorp");
}
void ScriptInterpreter::cmd_restart() {
+ // TODO: Used in RTZ
warning("Unimplemented command: cmd_restart");
}
@@ -613,9 +607,6 @@ void ScriptInterpreter::cmd_extend() {
for (int i = 0; i < argc; i++)
debug(2, "argv[%02d] = %04X (%d)", i, argv[i], argv[i]);
- if (_dumpScripts)
- return;
-
int16 result = _functions->callFunction(func, argc, argv);
debug(2, "result = %04X (%d)", result, result);
@@ -626,18 +617,22 @@ void ScriptInterpreter::cmd_extend() {
}
void ScriptInterpreter::cmd_catch() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_catch");
}
void ScriptInterpreter::cmd_cdone() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_cdone");
}
void ScriptInterpreter::cmd_throw() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_throw");
}
void ScriptInterpreter::cmd_functionp() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_functionp");
}
@@ -658,11 +653,133 @@ void ScriptInterpreter::cmd_ge() {
}
void ScriptInterpreter::cmd_varx() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_varx");
}
void ScriptInterpreter::cmd_setx() {
+ // Never used in LGOP2, RTZ, Manhole:NE
warning("Unimplemented command: cmd_setx");
}
+#ifdef DUMP_SCRIPTS
+void ScriptInterpreter::dumpScript(int16 objectIndex, int *opcodeStats, int *externStats) {
+
+ debug(1, "Dumping code for object %04X", objectIndex);
+
+ Object *obj = _vm->_dat->getObject(objectIndex);
+ byte *code = obj->getData(), *codeEnd = code + obj->getSize();
+
+ while (code < codeEnd) {
+ byte opcode = *code++;
+ if (opcode >= 1 && opcode <= _commandsMax) {
+ Common::String codeLine;
+ const char *desc = _commands[opcode - 1].desc;
+ const char *sig = _commands[opcode - 1].sig;
+ int valueType; /* 0: dec; 1: hex; 2: extended function */
+ int16 value;
+ char tempStr[32];
+ if (opcodeStats)
+ opcodeStats[opcode - 1]++;
+ codeLine += desc;
+ for (; *sig != '\0'; sig++) {
+ codeLine += " ";
+ // Fallthroughs are intended
+ switch (*sig) {
+ case 'b':
+ valueType = 0;
+ value = *code++;
+ break;
+ case 'B':
+ valueType = 1;
+ value = *code++;
+ break;
+ case 'w':
+ valueType = 0;
+ value = READ_LE_UINT16(code);
+ code += 2;
+ break;
+ case 'W':
+ valueType = 1;
+ value = READ_LE_UINT16(code);
+ code += 2;
+ break;
+ case 'E':
+ valueType = 2;
+ value = *code++;
+ break;
+ }
+ switch (valueType) {
+ case 0:
+ snprintf(tempStr, 32, "%d", value);
+ break;
+ case 1:
+ snprintf(tempStr, 32, "0x%X", value);
+ break;
+ case 2:
+ if (value < _functions->getCount()) {
+ snprintf(tempStr, 32, "%s", _functions->getFuncName(value));
+ externStats[value]++;
+ } else {
+ snprintf(tempStr, 32, "invalid: %d", value);
+ }
+ break;
+ }
+ codeLine += tempStr;
+ }
+ debug(1, "%s", codeLine.c_str());
+ } else {
+ error("ScriptInterpreter::dumpScript(%d) Unknown opcode %02X", objectIndex, opcode);
+ }
+ }
+ debug(1, "-------------------------------------------");
+}
+
+void ScriptInterpreter::dumpAllScripts() {
+ int *opcodeStats = new int[_commandsMax - 1];
+ int *externStats = new int[_functions->getCount()];
+
+ for (int i = 0; i < _commandsMax; i++)
+ opcodeStats[i] = 0;
+ for (int i = 0; i < _functions->getCount(); i++)
+ externStats[i] = 0;
+
+ for (uint objectIndex = 1; objectIndex <= _vm->_dat->getObjectCount(); objectIndex++) {
+ Object *obj = _vm->_dat->getObject(objectIndex);
+ // Check if it's a byte array which might contain code
+ if (obj->getClass() != 0x7FFF)
+ continue;
+ // Code objects aren't excplicitly marked as such, we need to check if
+ // the last byte is a cmd_return opcode.
+ byte *retByte = obj->getData() + obj->getSize() - 1;
+ if (*retByte == 0x1F) {
+ dumpScript(objectIndex, opcodeStats, externStats);
+ }
+ }
+
+ debug(1, "OPCODE statistics:");
+ for (int i = 0; i < _commandsMax - 1; i++)
+ if (opcodeStats[i] > 0)
+ debug(1, "%-30s: %d", _commands[i].desc, opcodeStats[i]);
+ debug(1, "UNUSED OPCODE statistics:");
+ for (int i = 0; i < _commandsMax - 1; i++)
+ if (opcodeStats[i] == 0)
+ debug(1, "%-30s: %d", _commands[i].desc, opcodeStats[i]);
+ debug(1, ".");
+
+ debug(1, "EXTERN statistics (%d):", _functions->getCount());
+ for (int i = 0; i < _functions->getCount(); i++)
+ if (externStats[i] > 0)
+ debug(1, "%-30s: %d", _functions->getFuncName(i), externStats[i]);
+ debug(1, "UNUSED EXTERN statistics (%d):", _functions->getCount());
+ for (int i = 0; i < _functions->getCount(); i++)
+ if (externStats[i] == 0)
+ debug(1, "%-30s: %d", _functions->getFuncName(i), externStats[i]);
+ debug(1, ".");
+
+ delete[] opcodeStats;
+ delete[] externStats;
+}
+#endif
+
} // End of namespace Made