diff options
author | Benjamin Haisch | 2008-05-20 20:00:10 +0000 |
---|---|---|
committer | Benjamin Haisch | 2008-05-20 20:00:10 +0000 |
commit | 828a217a03038673dfbd0f88a80f78832b55d872 (patch) | |
tree | ccd7503b1f376dd87e4c1b1051137a384b5405ce /engines/made/script.cpp | |
parent | 11697c0eb24aed6c6997c1d6282b69ed3448b1e9 (diff) | |
download | scummvm-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.cpp | 281 |
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 |