Index: tools/descumm-common.cpp =================================================================== RCS file: /cvsroot/scummvm/tools/descumm-common.cpp,v retrieving revision 1.10 diff -U8 -d -r1.10 descumm-common.cpp --- tools/descumm-common.cpp 21 Sep 2004 15:17:34 -0000 1.10 +++ tools/descumm-common.cpp 30 Sep 2004 01:06:54 -0000 @@ -34,16 +34,17 @@ int g_jump_opcode; bool alwaysShowOffs = false; bool dontOutputIfs = false; bool dontOutputElse = false; bool dontOutputElseif = false; bool dontOutputWhile = false; +bool dontOutputBreaks = false; bool dontShowOpcode = false; bool dontShowOffsets = false; bool haltOnError; byte scriptVersion; byte heVersion; byte *cur_pos, *org_pos; @@ -198,28 +199,36 @@ p->from = cur; p->to = to; return true; } // Returns 0 or 1 depending if it's ok to add an else bool maybeAddElse(uint cur, uint to) { + int i; BlockStack *p; if (((to | cur) >> 16) || (to <= cur)) return false; /* Invalid jump */ if (!num_block_stack) return false; /* There are no previous blocks, so an else is not ok */ p = &block_stack[num_block_stack - 1]; if (cur != p->to) return false; /* We have no prevoius if that is exiting right at the end of this goto */ + /* Don't jump out of previous blocks. This test is stronger than the one in + maybeAddIf. ( >= vs > ) */ + for (i = 0, p = block_stack; i < num_block_stack - 1; i++, p++) { + if (to >= p->to) + return false; + } + num_block_stack--; if (maybeAddIf(cur, to)) return true; /* We can add an else */ num_block_stack++; return false; /* An else is not OK here :( */ } bool maybeAddElseIf(uint cur, uint elseto, uint to) @@ -241,33 +250,58 @@ if (scriptVersion == 8) k = to - 5; else k = to - 3; if (k >= size_of_code) return false; /* Invalid jump */ - if (org_pos[k] != g_jump_opcode) - return false; /* Invalid jump */ - - if (scriptVersion == 8) - k = to + TO_LE_32(*(int32*)(org_pos + k + 1)); - else - k = to + TO_LE_16(*(int16*)(org_pos + k + 1)); - - if (k != elseto) - return false; /* Not an ifelse */ - + if (elseto != to) { + if (org_pos[k] != g_jump_opcode) + return false; /* Invalid jump */ + + if (scriptVersion == 8) + k = to + TO_LE_32(*(int32*)(org_pos + k + 1)); + else + k = to + TO_LE_16(*(int16*)(org_pos + k + 1)); + + if (k != elseto) + return false; /* Not an ifelse */ + } p->from = cur; p->to = to; return true; } +bool maybeAddBreak(uint cur, uint to) +{ + BlockStack *p; + + if (((to | cur) >> 16) || (to <= cur)) + return false; /* Invalid jump */ + + if (!num_block_stack) + return false; /* There are no previous blocks, so a break is not ok */ + + /* Find the first parent block that is a while and if we're jumping to the end of that, we use a break */ + for (int i = num_block_stack - 1; i >= 0; i--) { + p = &block_stack[i]; + if (p->isWhile) { + if (to == p->to) + return true; + else + return false; + } + } + + return false; +} + void writePendingElse() { if (pendingElse) { char buf[32]; sprintf(buf, alwaysShowOffs ? "} else /*%.4X*/ {" : "} else {", pendingElseTo); outputLine(buf, offs_of_line, pendingElseOpcode, pendingElseIndent - 1); offs_of_line = pendingElseOffs; pendingElse = false; Index: tools/descumm-tool.cpp =================================================================== RCS file: /cvsroot/scummvm/tools/descumm-tool.cpp,v retrieving revision 1.8 diff -U8 -d -r1.8 descumm-tool.cpp --- tools/descumm-tool.cpp 28 Sep 2004 19:09:16 -0000 1.8 +++ tools/descumm-tool.cpp 30 Sep 2004 01:06:54 -0000 @@ -41,16 +41,17 @@ "\t-n\tUse Indy3-256 specific hacks\n" "\t-z\tUse Zak256 specific hacks\n" "\t-u\tScript is Unblocked/has no header\n" "\t-o\tAlways Show offsets\n" "\t-i\tDon't output ifs\n" "\t-e\tDon't output else\n" "\t-f\tDon't output else-if\n" "\t-w\tDon't output while\n" + "\t-b\tDon't output breaks\n" "\t-c\tDon't show opcode\n" "\t-x\tDon't show offsets\n" "\t-h\tHalt on error\n"); exit(0); } int skipVerbHeader_V12(byte *p) { @@ -215,16 +216,19 @@ dontOutputElse = true; break; case 'f': dontOutputElseif = true; break; case 'w': dontOutputWhile = true; break; + case 'b': + dontOutputBreaks = true; + break; case 'c': dontShowOpcode = true; break; case 'x': dontShowOffsets = true; break; case 'h': haltOnError = true; @@ -380,17 +384,18 @@ if (haveElse) { haveElse = false; j--; } outputLine(buf, offs_of_line, opcode, j); offs_of_line = get_curoffs(); } while (indentBlock(get_curoffs())) { - outputLine("}", -1, -1, -1); + outputLine("}", offs_of_line, -1, -1); + offs_of_line = get_curoffs(); } fflush(stdout); } printf("END\n"); /* if (scriptVersion >= 6 && num_stack != 0) { Index: tools/descumm.h =================================================================== RCS file: /cvsroot/scummvm/tools/descumm.h,v retrieving revision 1.13 diff -U8 -d -r1.13 descumm.h --- tools/descumm.h 28 Sep 2004 19:09:16 -0000 1.13 +++ tools/descumm.h 30 Sep 2004 01:06:54 -0000 @@ -57,16 +57,17 @@ // // Command line options // extern bool alwaysShowOffs; extern bool dontOutputIfs; extern bool dontOutputElse; extern bool dontOutputElseif; extern bool dontOutputWhile; +extern bool dontOutputBreaks; extern bool dontShowOpcode; extern bool dontShowOffsets; extern bool haltOnError; // // The SCUMM version used for the script we are descumming. // extern byte scriptVersion; @@ -93,16 +94,17 @@ extern char *strecpy(char *buf, const char *src); extern int get_curoffs(); extern int get_byte(); extern int get_word(); extern bool maybeAddIf(uint cur, uint to); extern bool maybeAddElse(uint cur, uint to); extern bool maybeAddElseIf(uint cur, uint elseto, uint to); +extern bool maybeAddBreak(uint cur, uint to); extern void writePendingElse(); // // Entry points for the descumming // extern void next_line_V12(char *buf); // For V1 and V2 extern void next_line_V345(char *buf); // For V3, V4, V5 extern void next_line_V67(char *buf); Index: tools/descumm6.cpp =================================================================== RCS file: /cvsroot/scummvm/tools/descumm6.cpp,v retrieving revision 1.180 diff -U8 -d -r1.180 descumm6.cpp --- tools/descumm6.cpp 28 Sep 2004 19:09:16 -0000 1.180 +++ tools/descumm6.cpp 30 Sep 2004 01:06:55 -0000 @@ -52,61 +52,16 @@ Anyway, the fixed key pattern here seems to be for each case: dup - push - eq - jumpFalse - kill And of course a push before the first of these. Note that there doesn't have to be a jump before each case: after all, "fall through" is possible with C(++) switch/case statements, too, so it's possible they used that in Scumm, too. */ -/* - FIXME: The current "while" and "else" detection code interfer. There simply are case - which they can't decode correctly, leading to completely wrong output. An example - can be seen by looking at script 52 of Sam&Max. It gets descummed to this: - - [002E] (43) localvar1 = 6 - [0037] (5D) while (localvar1 <= 80) { - [0041] (5D) if (array-178[localvar1] == 0) { - [004E] (47) array-178[localvar0] = localvar1 - [0057] (4F) var179 += 1 - [005A] (73) } else { - [005D] (4F) localvar1 += 1 - [0060] (73) jump 37 - [0063] (**) } - [0063] (**) } - [0063] (**) } - [0063] (66) stopObjectCodeB() - - Using "-e" we get the correct result: - [002E] (43) localvar1 = 6 - [0037] (5D) while (localvar1 <= 80) { - [0041] (5D) if (array-178[localvar1] == 0) { - [004E] (47) array-178[localvar0] = localvar1 - [0057] (4F) var179 += 1 - [005A] (73) jump 63 - [005D] (**) } - [005D] (4F) localvar1 += 1 - [0063] (**) } - [0063] (**) } - [0060] (66) stopObjectCodeB() -(but note the wrong offset in the last line!) - -When doing raw output, we get this: - [0031] (43) localvar1 = 6 - [0037] (5D) unless ((localvar1 <= 80)) jump 63 - [0041] (5D) unless ((array-178[localvar1] == 0)) jump 5d - [004E] (47) array-178[localvar0] = localvar1 - [0057] (4F) var179 += 1 - [005A] (73) jump 63 - [005D] (4F) localvar1 += 1 - [0060] (73) jump 37 - [0063] (66) stopObjectCodeB() - -*/ - struct StackEnt { byte type; long data; StackEnt *left, *right; char *str; StackEnt **list; }; @@ -949,23 +904,23 @@ where += sprintf(where, "localvar%ld", se->data & 0xFFF); } else { where += sprintf(where, "?var?%ld", se->data); } } break; case seArray: if (se->left) { - where += sprintf(where, "array-%ld[", se->data); + where += sprintf(where, "array%ld[", se->data); where = se_astext(se->left, where); where = strecpy(where, "]["); where = se_astext(se->right, where); where = strecpy(where, "]"); } else { - where += sprintf(where, "array-%ld[", se->data); + where += sprintf(where, "array%ld[", se->data); where = se_astext(se->right, where); where = strecpy(where, "]"); } break; case seUnary: where += sprintf(where, "%s", oper_list[se->data]); where = se_astext(se->left, where); break; @@ -1037,17 +992,24 @@ char *e = se_astext(dst, output); e = strecpy(e, " = "); se_astext(src, e); } void doAdd(char *output, StackEnt * se, int val) { char *e = se_astext(se, output); - sprintf(e, " += %d", val); + if (val == 1) { + sprintf(e, "++"); + } else if (val == -1) { + sprintf(e, "--"); + } else { + /* SCUMM doesn't support this */ + sprintf(e, " += %d", val); + } } StackEnt *dup(char *output, StackEnt * se) { static int dupindex = 0; if (se->type == seInt) return se; @@ -1314,16 +1276,20 @@ pendingElseOffs = cur; pendingElseOpcode = g_jump_opcode; pendingElseIndent = num_block_stack; } else { if (num_block_stack && !dontOutputWhile) { BlockStack *p = &block_stack[num_block_stack - 1]; if (p->isWhile && cur == p->to) return; // A 'while' ends here. + if (!dontOutputBreaks && maybeAddBreak(cur, to)) { + sprintf(output, "break"); + return; + } } sprintf(output, "jump %x", to); } } void jumpif(char *output, StackEnt * se, bool negate) { int offset = get_word(); @@ -1331,31 +1297,27 @@ int to = cur + offset; char *e = output; if (!dontOutputElseif && pendingElse) { if (maybeAddElseIf(cur, pendingElseTo, to)) { pendingElse = false; haveElse = true; e = strecpy(e, "} else if ("); - if (negate) - se = se_neg(se); e = se_astext(se, e, false); sprintf(e, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to); return; } } if (!dontOutputIfs && maybeAddIf(cur, to)) { - if (!dontOutputWhile && block_stack[num_block_stack - 1].isWhile) { - e = strecpy(e, "while ("); - } else - e = strecpy(e, "if ("); - if (negate) - se = se_neg(se); + if (!dontOutputWhile && block_stack[num_block_stack - 1].isWhile) + e = strecpy(e, negate ? "until (" : "while ("); + else + e = strecpy(e, negate ? "unless (" : "if ("); e = se_astext(se, e, false); sprintf(e, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to); return; } e = strecpy(e, negate ? "if (" : "unless ("); e = se_astext(se, e); sprintf(e, ") jump %x", to); @@ -1518,17 +1480,17 @@ "\x97|softUserputOff," "\x99z|setCursorImg," "\x9App|setCursorHotspot," "\x9Cp|initCharset," "\x9Dl|charsetColors," "\xD6p|makeCursorColorTransparent"); break; case 0x6C: - ext(output, "|break"); + ext(output, "|breakHere"); break; case 0x6D: ext(output, "rlp|ifClassOfIs"); break; case 0x6E: ext(output, "lp|setClass"); break; case 0x6F: @@ -2910,17 +2872,17 @@ "\x97|softUserputOff," "\x99z|setCursorImg," "\x9App|setCursorHotspot," "\x9Cp|initCharset," "\x9Dl|charsetColors," "\xD6p|makeCursorColorTransparent"); break; case 0x6C: - ext(output, "|break"); + ext(output, "|breakHere"); break; case 0x6D: ext(output, "rlp|ifClassOfIs"); break; case 0x6E: ext(output, "lp|setClass"); break; case 0x6F: