/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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$ * */ // Console module #include "sci/sci.h" #include "sci/console.h" #include "sci/debug.h" #include "sci/resource.h" #include "sci/vocabulary.h" #include "sci/engine/savegame.h" #include "sci/engine/state.h" #include "sci/engine/gc.h" #include "sci/engine/kernel_types.h" // for determine_reg_type #include "sci/gfx/gfx_gui.h" // for sciw_set_status_bar #include "sci/gfx/gfx_state_internal.h" #include "sci/gfx/gfx_widgets.h" // for getPort #include "sci/sfx/songlib.h" // for SongLibrary #include "sci/sfx/iterator.h" // for SCI_SONG_ITERATOR_TYPE_SCI0 #include "sci/sfx/sci_midi.h" #include "sci/vocabulary.h" #include "common/savefile.h" namespace Sci { int g_debug_sleeptime_factor = 1; int g_debug_simulated_key = 0; bool g_debug_track_mouse_clicks = false; bool g_debug_weak_validations = true; Console::Console(SciEngine *vm) : GUI::Debugger() { _vm = vm; // Variables DVar_Register("sleeptime_factor", &g_debug_sleeptime_factor, DVAR_INT, 0); DVar_Register("gc_interval", &script_gc_interval, DVAR_INT, 0); DVar_Register("simulated_key", &g_debug_simulated_key, DVAR_INT, 0); DVar_Register("track_mouse_clicks", &g_debug_track_mouse_clicks, DVAR_BOOL, 0); DVar_Register("weak_validations", &g_debug_weak_validations, DVAR_BOOL, 0); DVar_Register("script_abort_flag", &script_abort_flag, DVAR_INT, 0); // General DCmd_Register("help", WRAP_METHOD(Console, cmdHelp)); // Kernel // DCmd_Register("classes", WRAP_METHOD(Console, cmdClasses)); // TODO DCmd_Register("opcodes", WRAP_METHOD(Console, cmdOpcodes)); DCmd_Register("selector", WRAP_METHOD(Console, cmdSelector)); DCmd_Register("selectors", WRAP_METHOD(Console, cmdSelectors)); DCmd_Register("functions", WRAP_METHOD(Console, cmdKernelFunctions)); DCmd_Register("class_table", WRAP_METHOD(Console, cmdClassTable)); // Parser DCmd_Register("suffixes", WRAP_METHOD(Console, cmdSuffixes)); DCmd_Register("parse_grammar", WRAP_METHOD(Console, cmdParseGrammar)); DCmd_Register("parser_nodes", WRAP_METHOD(Console, cmdParserNodes)); DCmd_Register("parser_words", WRAP_METHOD(Console, cmdParserWords)); DCmd_Register("sentence_fragments", WRAP_METHOD(Console, cmdSentenceFragments)); DCmd_Register("parse", WRAP_METHOD(Console, cmdParse)); DCmd_Register("set_parse_nodes", WRAP_METHOD(Console, cmdSetParseNodes)); // Resources DCmd_Register("hexdump", WRAP_METHOD(Console, cmdHexDump)); DCmd_Register("resource_id", WRAP_METHOD(Console, cmdResourceId)); DCmd_Register("resource_size", WRAP_METHOD(Console, cmdResourceSize)); DCmd_Register("resource_types", WRAP_METHOD(Console, cmdResourceTypes)); DCmd_Register("list", WRAP_METHOD(Console, cmdList)); DCmd_Register("hexgrep", WRAP_METHOD(Console, cmdHexgrep)); // Game DCmd_Register("save_game", WRAP_METHOD(Console, cmdSaveGame)); DCmd_Register("restore_game", WRAP_METHOD(Console, cmdRestoreGame)); DCmd_Register("restart_game", WRAP_METHOD(Console, cmdRestartGame)); DCmd_Register("version", WRAP_METHOD(Console, cmdGetVersion)); DCmd_Register("room", WRAP_METHOD(Console, cmdRoomNumber)); DCmd_Register("exit", WRAP_METHOD(Console, cmdExit)); // Screen DCmd_Register("sci0_palette", WRAP_METHOD(Console, cmdSci0Palette)); DCmd_Register("clear_screen", WRAP_METHOD(Console, cmdClearScreen)); DCmd_Register("redraw_screen", WRAP_METHOD(Console, cmdRedrawScreen)); DCmd_Register("fill_screen", WRAP_METHOD(Console, cmdFillScreen)); DCmd_Register("show_map", WRAP_METHOD(Console, cmdShowMap)); DCmd_Register("update_zone", WRAP_METHOD(Console, cmdUpdateZone)); DCmd_Register("propagate_zone", WRAP_METHOD(Console, cmdPropagateZone)); DCmd_Register("priority_bands", WRAP_METHOD(Console, cmdPriorityBands)); // Graphics DCmd_Register("draw_pic", WRAP_METHOD(Console, cmdDrawPic)); DCmd_Register("draw_rect", WRAP_METHOD(Console, cmdDrawRect)); DCmd_Register("draw_cel", WRAP_METHOD(Console, cmdDrawCel)); DCmd_Register("view_info", WRAP_METHOD(Console, cmdViewInfo)); // GUI DCmd_Register("current_port", WRAP_METHOD(Console, cmdCurrentPort)); DCmd_Register("print_port", WRAP_METHOD(Console, cmdPrintPort)); DCmd_Register("visual_state", WRAP_METHOD(Console, cmdVisualState)); DCmd_Register("flush_visual", WRAP_METHOD(Console, cmdFlushPorts)); DCmd_Register("dynamic_views", WRAP_METHOD(Console, cmdDynamicViews)); DCmd_Register("dropped_views", WRAP_METHOD(Console, cmdDroppedViews)); DCmd_Register("status_bar", WRAP_METHOD(Console, cmdStatusBarColors)); #ifdef GFXW_DEBUG_WIDGETS DCmd_Register("print_widget", WRAP_METHOD(Console, cmdPrintWidget)); #endif // Segments DCmd_Register("segment_table", WRAP_METHOD(Console, cmdPrintSegmentTable)); DCmd_Register("segtable", WRAP_METHOD(Console, cmdPrintSegmentTable)); // alias DCmd_Register("segment_info", WRAP_METHOD(Console, cmdSegmentInfo)); DCmd_Register("seginfo", WRAP_METHOD(Console, cmdSegmentInfo)); // alias DCmd_Register("segment_kill", WRAP_METHOD(Console, cmdKillSegment)); DCmd_Register("segkill", WRAP_METHOD(Console, cmdKillSegment)); // alias // Garbage collection DCmd_Register("gc", WRAP_METHOD(Console, cmdGCInvoke)); DCmd_Register("gc_objects", WRAP_METHOD(Console, cmdGCObjects)); DCmd_Register("gc_reachable", WRAP_METHOD(Console, cmdGCShowReachable)); DCmd_Register("gc_freeable", WRAP_METHOD(Console, cmdGCShowFreeable)); DCmd_Register("gc_normalize", WRAP_METHOD(Console, cmdGCNormalize)); // Music/SFX DCmd_Register("songlib", WRAP_METHOD(Console, cmdSongLib)); DCmd_Register("is_sample", WRAP_METHOD(Console, cmdIsSample)); DCmd_Register("sfx01_header", WRAP_METHOD(Console, cmdSfx01Header)); DCmd_Register("sfx01_track", WRAP_METHOD(Console, cmdSfx01Track)); DCmd_Register("stop_sfx", WRAP_METHOD(Console, cmdStopSfx)); // Script DCmd_Register("addresses", WRAP_METHOD(Console, cmdAddresses)); DCmd_Register("registers", WRAP_METHOD(Console, cmdRegisters)); DCmd_Register("dissect_script", WRAP_METHOD(Console, cmdDissectScript)); DCmd_Register("set_acc", WRAP_METHOD(Console, cmdSetAccumulator)); DCmd_Register("backtrace", WRAP_METHOD(Console, cmdBacktrace)); DCmd_Register("bt", WRAP_METHOD(Console, cmdBacktrace)); // alias DCmd_Register("step", WRAP_METHOD(Console, cmdStep)); DCmd_Register("s", WRAP_METHOD(Console, cmdStep)); // alias DCmd_Register("step_event", WRAP_METHOD(Console, cmdStepEvent)); DCmd_Register("se", WRAP_METHOD(Console, cmdStepEvent)); // alias DCmd_Register("step_ret", WRAP_METHOD(Console, cmdStepRet)); DCmd_Register("sret", WRAP_METHOD(Console, cmdStepRet)); // alias DCmd_Register("step_global", WRAP_METHOD(Console, cmdStepGlobal)); DCmd_Register("sg", WRAP_METHOD(Console, cmdStepGlobal)); // alias DCmd_Register("step_callk", WRAP_METHOD(Console, cmdStepCallk)); DCmd_Register("snk", WRAP_METHOD(Console, cmdStepCallk)); // alias DCmd_Register("disasm", WRAP_METHOD(Console, cmdDissassemble)); DCmd_Register("disasm_addr", WRAP_METHOD(Console, cmdDissassembleAddress)); DCmd_Register("send", WRAP_METHOD(Console, cmdSend)); DCmd_Register("go", WRAP_METHOD(Console, cmdGo)); // Breakpoints DCmd_Register("bp_list", WRAP_METHOD(Console, cmdBreakpointList)); DCmd_Register("bplist", WRAP_METHOD(Console, cmdBreakpointList)); // alias DCmd_Register("bp_del", WRAP_METHOD(Console, cmdBreakpointDelete)); DCmd_Register("bpdel", WRAP_METHOD(Console, cmdBreakpointDelete)); // alias DCmd_Register("bp_exec_method", WRAP_METHOD(Console, cmdBreakpointExecMethod)); DCmd_Register("bpx", WRAP_METHOD(Console, cmdBreakpointExecMethod)); // alias DCmd_Register("bp_exec_function", WRAP_METHOD(Console, cmdBreakpointExecFunction)); DCmd_Register("bpe", WRAP_METHOD(Console, cmdBreakpointExecFunction)); // alias // VM DCmd_Register("script_steps", WRAP_METHOD(Console, cmdScriptSteps)); DCmd_Register("vm_varlist", WRAP_METHOD(Console, cmdVMVarlist)); DCmd_Register("vmvarlist", WRAP_METHOD(Console, cmdVMVarlist)); // alias DCmd_Register("vm_vars", WRAP_METHOD(Console, cmdVMVars)); DCmd_Register("vmvars", WRAP_METHOD(Console, cmdVMVars)); // alias DCmd_Register("stack", WRAP_METHOD(Console, cmdStack)); DCmd_Register("value_type", WRAP_METHOD(Console, cmdValueType)); DCmd_Register("view_listnode", WRAP_METHOD(Console, cmdViewListNode)); DCmd_Register("view_reference", WRAP_METHOD(Console, cmdViewReference)); DCmd_Register("vr", WRAP_METHOD(Console, cmdViewReference)); // alias DCmd_Register("view_object", WRAP_METHOD(Console, cmdViewObject)); DCmd_Register("vo", WRAP_METHOD(Console, cmdViewObject)); // alias DCmd_Register("active_object", WRAP_METHOD(Console, cmdViewActiveObject)); DCmd_Register("acc_object", WRAP_METHOD(Console, cmdViewAccumulatorObject)); scriptState.seeking = kDebugSeekNothing; scriptState.seekLevel = 0; scriptState.runningStep = 0; scriptState.stopOnEvent = false; scriptState.debugging = false; } Console::~Console() { } void Console::preEnter() { if (_vm->_gamestate) _vm->_gamestate->_sound.sfx_suspend(true); _vm->_mixer->pauseAll(true); } void Console::postEnter() { if (_vm->_gamestate) _vm->_gamestate->_sound.sfx_suspend(false); _vm->_mixer->pauseAll(false); } #if 0 // Unused #define LOOKUP_SPECIES(species) (\ (species >= 1000) ? species : *(s->_classtable[species].scriptposp) \ + s->_classtable[species].class_offset) #endif bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf("\n"); DebugPrintf("Variables\n"); DebugPrintf("---------\n"); DebugPrintf("sleeptime_factor: Factor to multiply with wait times in kWait()\n"); DebugPrintf("gc_interval: Number of kernel calls in between garbage collections\n"); DebugPrintf("simulated_key: Add a key with the specified scan code to the event list\n"); DebugPrintf("track_mouse_clicks: Toggles mouse click tracking to the console\n"); DebugPrintf("weak_validations: Turns some validation errors into warnings\n"); DebugPrintf("script_abort_flag: Set to 1 to abort script execution. Set to 2 to force a replay afterwards\n"); DebugPrintf("\n"); DebugPrintf("Debug flags\n"); DebugPrintf("-----------\n"); DebugPrintf("debugflag_list - Lists the available debug flags and their status\n"); DebugPrintf("debugflag_enable - Enables a debug flag\n"); DebugPrintf("debugflag_disable - Disables a debug flag\n"); DebugPrintf("\n"); DebugPrintf("Commands\n"); DebugPrintf("--------\n"); DebugPrintf("Kernel:\n"); DebugPrintf(" opcodes - Lists the opcode names\n"); DebugPrintf(" selectors - Lists the selector names\n"); DebugPrintf(" selector - Attempts to find the requested selector by name\n"); DebugPrintf(" functions - Lists the kernel functions\n"); DebugPrintf(" class_table - Shows the available classes\n"); DebugPrintf("\n"); DebugPrintf("Parser:\n"); DebugPrintf(" suffixes - Lists the vocabulary suffixes\n"); DebugPrintf(" parse_grammar - Shows the parse grammar, in strict GNF\n"); DebugPrintf(" parser_nodes - Shows the specified number of nodes from the parse node tree\n"); DebugPrintf(" parser_words - Shows the words from the parse node tree\n"); DebugPrintf(" sentence_fragments - Shows the sentence fragments (used to build Parse trees)\n"); DebugPrintf(" parse - Parses a sequence of words and prints the resulting parse tree\n"); DebugPrintf(" set_parse_nodes - Sets the contents of all parse nodes\n"); DebugPrintf("\n"); DebugPrintf("Resources:\n"); DebugPrintf(" hexdump - Dumps the specified resource to standard output\n"); DebugPrintf(" resource_id - Identifies a resource number by splitting it up in resource type and resource number\n"); DebugPrintf(" resource_size - Shows the size of a resource\n"); DebugPrintf(" resource_types - Shows the valid resource types\n"); DebugPrintf(" list - Lists all the resources of a given type\n"); DebugPrintf(" hexgrep - Searches some resources for a particular sequence of bytes, represented as hexadecimal numbers\n"); DebugPrintf("\n"); DebugPrintf("Game:\n"); DebugPrintf(" save_game - Saves the current game state to the hard disk\n"); DebugPrintf(" restore_game - Restores a saved game from the hard disk\n"); DebugPrintf(" restart_game - Restarts the game\n"); DebugPrintf(" version - Shows the resource and interpreter versions\n"); DebugPrintf(" room - Shows the current room number\n"); DebugPrintf(" exit - Exits the game\n"); DebugPrintf("\n"); DebugPrintf("Screen:\n"); DebugPrintf(" sci0_palette - Sets the SCI0 palette to use (EGA, Amiga or grayscale)\n"); DebugPrintf(" clear_screen - Clears the screen\n"); DebugPrintf(" redraw_screen - Redraws the screen\n"); DebugPrintf(" fill_screen - Fills the screen with one of the EGA colors\n"); DebugPrintf(" show_map - Shows one of the screen maps (visual, priority or control)\n"); DebugPrintf(" update_zone - Propagates a rectangular area from the back buffer to the front buffer\n"); DebugPrintf(" propagate_zone - Propagates a rectangular area from a lower graphics buffer to a higher one\n"); DebugPrintf(" priority_bands - Shows information about priority bands\n"); DebugPrintf("\n"); DebugPrintf("Graphics:\n"); DebugPrintf(" draw_pic - Draws a pic resource\n"); DebugPrintf(" draw_rect - Draws a rectangle to the screen with one of the EGA colors\n"); DebugPrintf(" draw_cel - Draws a single view cel to the center of the screen\n"); DebugPrintf(" view_info - Displays information for the specified view\n"); DebugPrintf("\n"); DebugPrintf("GUI:\n"); DebugPrintf(" current_port - Shows the ID of the currently active port\n"); DebugPrintf(" print_port - Prints information about a port\n"); DebugPrintf(" visual_state - Shows the state of the current visual widget\n"); DebugPrintf(" flush_visual - Flushes dynamically allocated ports (for memory profiling)\n"); DebugPrintf(" dynamic_views - Lists active dynamic views\n"); DebugPrintf(" dropped_views - Lists dropped dynamic views\n"); DebugPrintf(" status_bar - Sets the colors of the status bar\n"); #ifdef GFXW_DEBUG_WIDGETS DebugPrintf(" print_widget - Shows active widgets (no params) or information on the specified widget indices\n"); #endif DebugPrintf("\n"); DebugPrintf("Segments:\n"); DebugPrintf(" segment_table / segtable - Lists all segments\n"); DebugPrintf(" segment_info / seginfo - Provides information on the specified segment\n"); DebugPrintf(" segment_kill / segkill - Deletes the specified segment\n"); DebugPrintf("\n"); DebugPrintf("Garbage collection:\n"); DebugPrintf(" gc - Invokes the garbage collector\n"); DebugPrintf(" gc_objects - Lists all reachable objects, normalized\n"); DebugPrintf(" gc_reachable - Lists all addresses directly reachable from a given memory object\n"); DebugPrintf(" gc_freeable - Lists all addresses freeable in a given segment\n"); DebugPrintf(" gc_normalize - Prints the \"normal\" address of a given address\n"); DebugPrintf("\n"); DebugPrintf("Music/SFX:\n"); DebugPrintf(" songlib - Shows the song library\n"); DebugPrintf(" is_sample - Shows information on a given sound resource, if it's a PCM sample\n"); DebugPrintf(" sfx01_header - Dumps the header of a SCI01 song\n"); DebugPrintf(" sfx01_track - Dumps a track of a SCI01 song\n"); DebugPrintf(" stop_sfx - Stops a playing sound\n"); DebugPrintf("\n"); DebugPrintf("Script:\n"); DebugPrintf(" addresses - Provides information on how to pass addresses\n"); DebugPrintf(" registers - Shows the current register values\n"); DebugPrintf(" dissect_script - Examines a script\n"); DebugPrintf(" set_acc - Sets the accumulator\n"); DebugPrintf(" backtrace / bt - Dumps the send/self/super/call/calle/callb stack\n"); DebugPrintf(" step / s - Executes one operation (no parameters) or several operations (specified as a parameter) \n"); DebugPrintf(" step_event / se - Steps forward until a SCI event is received.\n"); DebugPrintf(" step_ret / sret - Steps forward until ret is called on the current execution stack level.\n"); DebugPrintf(" step_global / sg - Steps until the global variable with the specified index is modified.\n"); DebugPrintf(" step_callk / snk - Steps forward until it hits the next callk operation, or a specific callk (specified as a parameter)\n"); DebugPrintf(" disasm - Disassembles a method by name\n"); DebugPrintf(" disasm_addr - Disassembles one or more commands\n"); DebugPrintf(" send - Sends a message to an object\n"); DebugPrintf(" go - Executes the script\n"); DebugPrintf("\n"); DebugPrintf("Breakpoints:\n"); DebugPrintf(" bp_list / bplist - Lists the current breakpoints\n"); DebugPrintf(" bp_del / bpdel - Deletes a breakpoint with the specified index\n"); DebugPrintf(" bp_exec_method / bpx - Sets a breakpoint on the execution of the specified method\n"); DebugPrintf(" bp_exec_function / bpe - Sets a breakpoint on the execution of the specified exported function\n"); DebugPrintf("\n"); DebugPrintf("VM:\n"); DebugPrintf(" script_steps - Shows the number of executed SCI operations\n"); DebugPrintf(" vm_varlist / vmvarlist - Shows the addresses of variables in the VM\n"); DebugPrintf(" vm_vars / vmvars - Displays or changes variables in the VM\n"); DebugPrintf(" stack - Lists the specified number of stack elements\n"); DebugPrintf(" value_type - Determines the type of a value\n"); DebugPrintf(" view_listnode - Examines the list node at the given address\n"); DebugPrintf(" view_reference / vr - Examines an arbitrary reference\n"); DebugPrintf(" view_object / vo - Examines the object at the given address\n"); DebugPrintf(" active_object - Shows information on the currently active object or class\n"); DebugPrintf(" acc_object - Shows information on the object or class at the address indexed by the accumulator\n"); DebugPrintf("\n"); return true; } ResourceType parseResourceType(const char *resid) { // Gets the resource number of a resource string, or returns -1 ResourceType res = kResourceTypeInvalid; for (int i = 0; i < kResourceTypeInvalid; i++) if (strcmp(getResourceTypeName((ResourceType)i), resid) == 0) res = (ResourceType)i; return res; } const char *selector_name(EngineState *s, int selector) { if (selector >= 0 && selector < (int)((SciEngine*)g_engine)->getKernel()->getSelectorNamesSize()) return ((SciEngine*)g_engine)->getKernel()->getSelectorName(selector).c_str(); else return "--INVALID--"; } bool Console::cmdGetVersion(int argc, const char **argv) { DebugPrintf("Emulated interpreter version: %s\n", ((SciEngine *)g_engine)->getSciVersionDesc(_vm->getVersion()).c_str()); return true; } bool Console::cmdOpcodes(int argc, const char **argv) { // Load the opcode table from vocab.998 if it exists, to obtain the opcode names Resource* r = _vm->getResourceManager()->findResource(ResourceId(kResourceTypeVocab, 998), 0); // If the resource couldn't be loaded, leave if (!r) { DebugPrintf("unable to load vocab.998"); return true; } int count = READ_LE_UINT16(r->data); DebugPrintf("Opcode names in numeric order [index: type name]:\n"); for (int i = 0; i < count; i++) { int offset = READ_LE_UINT16(r->data + 2 + i * 2); int len = READ_LE_UINT16(r->data + offset) - 2; int type = READ_LE_UINT16(r->data + offset + 2); // QFG3 has empty opcodes Common::String name = len > 0 ? Common::String((char *)r->data + offset + 4, len) : "Dummy"; DebugPrintf("%03x: %03x %20s | ", i, type, name.c_str()); if ((i % 3) == 2) DebugPrintf("\n"); } DebugPrintf("\n"); return true; } bool Console::cmdSelector(int argc, const char **argv) { if (argc < 2) { DebugPrintf("Attempts to find the requested selector by name.\n"); DebugPrintf("Usage: %s \n", argv[0]); return true; } for (uint seeker = 0; seeker < _vm->getKernel()->getSelectorNamesSize(); seeker++) { if (!scumm_stricmp(_vm->getKernel()->getSelectorName(seeker).c_str(), argv[1])) { DebugPrintf("Selector %s found at %03x (%d)\n", _vm->getKernel()->getSelectorName(seeker).c_str(), seeker, seeker); return true; } } DebugPrintf("Selector %s wasn't found\n", argv[1]); return true; } bool Console::cmdSelectors(int argc, const char **argv) { DebugPrintf("Selector names in numeric order:\n"); Common::String selectorName; for (uint seeker = 0; seeker < _vm->getKernel()->getSelectorNamesSize(); seeker++) { selectorName = _vm->getKernel()->getSelectorName(seeker); if (selectorName != "BAD SELECTOR") DebugPrintf("%03x: %20s | ", seeker, selectorName.c_str()); else continue; if ((seeker % 3) == 2) DebugPrintf("\n"); } DebugPrintf("\n"); return true; } bool Console::cmdKernelFunctions(int argc, const char **argv) { DebugPrintf("Kernel function names in numeric order:\n"); for (uint seeker = 0; seeker < _vm->getKernel()->getKernelNamesSize(); seeker++) { DebugPrintf("%03x: %20s | ", seeker, _vm->getKernel()->getKernelName(seeker).c_str()); if ((seeker % 3) == 2) DebugPrintf("\n"); } DebugPrintf("\n"); return true; } bool Console::cmdSuffixes(int argc, const char **argv) { _vm->getVocabulary()->printSuffixes(); return true; } bool Console::cmdParserWords(int argc, const char **argv) { _vm->getVocabulary()->printParserWords(); return true; } enum { kParseEndOfInput = 0, kParseOpeningParenthesis = 1, kParseClosingParenthesis = 2, kParseNil = 3, kParseNumber = 4 }; int parseNodes(EngineState *s, int *i, int *pos, int type, int nr, int argc, const char **argv) { int nextToken = 0, nextValue = 0, newPos = 0, oldPos = 0; Console *con = ((SciEngine *)g_engine)->getSciDebugger(); if (type == kParseNil) return 0; if (type == kParseNumber) { s->parser_nodes[*pos += 1].type = kParseTreeLeafNode; s->parser_nodes[*pos].content.value = nr; return *pos; } if (type == kParseEndOfInput) { con->DebugPrintf("Unbalanced parentheses\n"); return -1; } if (type == kParseClosingParenthesis) { con->DebugPrintf("Syntax error at token %d\n", *i); return -1; } s->parser_nodes[oldPos = ++(*pos)].type = kParseTreeBranchNode; for (int j = 0; j <= 1; j++) { if (*i == argc) { nextToken = kParseEndOfInput; } else { const char *token = argv[(*i)++]; if (!strcmp(token, "(")) { nextToken = kParseOpeningParenthesis; } else if (!strcmp(token, ")")) { nextToken = kParseClosingParenthesis; } else if (!strcmp(token, "nil")) { nextToken = kParseNil; } else { nextValue = strtol(token, NULL, 0); nextToken = kParseNumber; } } if ((newPos = s->parser_nodes[oldPos].content.branches[j] = parseNodes(s, i, pos, nextToken, nextValue, argc, argv)) == -1) return -1; } const char *token = argv[(*i)++]; if (strcmp(token, ")")) con->DebugPrintf("Expected ')' at token %d\n", *i); return oldPos; } bool Console::cmdSetParseNodes(int argc, const char **argv) { if (argc < 2) { DebugPrintf("Sets the contents of all parse nodes.\n"); DebugPrintf("Usage: %s ... \n", argv[0]); DebugPrintf("Tokens should be separated by blanks and enclosed in parentheses\n"); return true; } int i = 0; int pos = -1; int nextToken = 0, nextValue = 0; const char *token = argv[i++]; if (!strcmp(token, "(")) { nextToken = kParseOpeningParenthesis; } else if (!strcmp(token, ")")) { nextToken = kParseClosingParenthesis; } else if (!strcmp(token, "nil")) { nextToken = kParseNil; } else { nextValue = strtol(token, NULL, 0); nextToken = kParseNumber; } if (parseNodes(_vm->_gamestate, &i, &pos, nextToken, nextValue, argc, argv) == -1) return 1; vocab_dump_parse_tree("debug-parse-tree", _vm->_gamestate->parser_nodes); return true; } bool Console::cmdRegisters(int argc, const char **argv) { DebugPrintf("Current register values:\n"); DebugPrintf("acc=%04x:%04x prev=%04x:%04x &rest=%x\n", PRINT_REG(_vm->_gamestate->r_acc), PRINT_REG(_vm->_gamestate->r_prev), scriptState.restAdjust); if (!_vm->_gamestate->_executionStack.empty()) { EngineState *s = _vm->_gamestate; // for PRINT_STK DebugPrintf("pc=%04x:%04x obj=%04x:%04x fp=ST:%04x sp=ST:%04x\n", PRINT_REG(scriptState.xs->addr.pc), PRINT_REG(scriptState.xs->objp), PRINT_STK(scriptState.xs->fp), PRINT_STK(scriptState.xs->sp)); } else DebugPrintf("\n"); return true; } bool Console::cmdHexDump(int argc, const char **argv) { if (argc != 3) { DebugPrintf("Dumps the specified resource to standard output\n"); DebugPrintf("Usage: %s \n", argv[0]); cmdResourceTypes(argc, argv); return true; } int resNum = atoi(argv[2]); ResourceType res = parseResourceType(argv[1]); if (res == kResourceTypeInvalid) DebugPrintf("Resource type '%s' is not valid\n", argv[1]); else { Resource *resource = _vm->getResourceManager()->findResource(ResourceId(res, resNum), 0); if (resource) { Common::hexdump(resource->data, resource->size, 16, 0); DebugPrintf("Resource %s.%03d has been dumped to standard output\n", argv[1], resNum); } else { DebugPrintf("Resource %s.%03d not found\n", argv[1], resNum); } } return true; } bool Console::cmdResourceId(int argc, const char **argv) { if (argc != 2) { DebugPrintf("Identifies a resource number by splitting it up in resource type and resource number\n"); DebugPrintf("Usage: %s \n", argv[0]); return true; } int id = atoi(argv[1]); DebugPrintf("%s.%d (0x%x)\n", getResourceTypeName((ResourceType)(id >> 11)), id & 0x7ff, id & 0x7ff); return true; } bool Console::cmdDissectScript(int argc, const char **argv) { if (argc != 2) { DebugPrintf("Examines a script\n"); DebugPrintf("Usage: %s