[Scummvm-cvs-logs] CVS: tools descumm.cpp,1.28,1.29 descumm6.cpp,1.93,1.94
Max Horn
fingolfin at users.sourceforge.net
Thu May 8 18:29:25 CEST 2003
Update of /cvsroot/scummvm/tools
In directory sc8-pr-cvs1:/tmp/cvs-serv30317
Modified Files:
descumm.cpp descumm6.cpp
Log Message:
more descumm/descumm6 unification; made descumm's 'if' output code more similar to the one in descumm6 -> this allowed me to use the 'while' detecion code here, too. Sadly that's of limited use - we need a 'do { ... } while(...)' detector, too!
Index: descumm.cpp
===================================================================
RCS file: /cvsroot/scummvm/tools/descumm.cpp,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -d -r1.28 -r1.29
--- descumm.cpp 8 May 2003 23:44:07 -0000 1.28
+++ descumm.cpp 9 May 2003 00:37:06 -0000 1.29
@@ -31,6 +31,36 @@
#include <process.h>
#endif
+/*
+ Similar to the code that detects "head" while loops like this:
+ while(Condition) {
+ }
+ add code to detect tail while loops, i.e. something of the kind
+ doÊ{
+ } while(Condition);
+ In V2-V5, those are the most frequent type of loops (and in V6-V8 they
+ sometimes occur, too).
+ In some cases it might be preferable to emit a
+ repeat {
+ } until(!Condition)
+ Namely then when the condition has to be negated.
+
+ However, implementing this might be quite tricky, and require us to refactor the
+ code, because unlike a "head if/while", we don't know we are inside a loop until its
+ end. This means a problem for indention, and when outputing the initial "do {".
+ To solve this, we could implement some sort of look ahead; but that would be very
+ complicated, because essentially we have to perform full parsing of the data anyway.
+ Instead of doing multiple look aheads, one could also do a 2 pass descumming:
+ In pass 1, we find all jump statement, and identify all jump targets. From this data
+ we can work backwards to detect all loops (and also if/else/elsif).
+ Yet another approach would be to not emit any lines until we fully descummed the script.
+ Instead, we keep each line in a line buffer, with indention but with an associated
+ "indention" variable. When we discover a do/while loop, we can then insert a "do {"
+ line and increase the indention of all intermediate lines. However this approach
+ needs a lot of memory, and won't output anything until the script is fully descummed,
+ which is annoying when debugging descumm.
+
+*/
#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
@@ -66,6 +96,8 @@
#define TO_LE_32(x) (x)
#endif
+#define MKID(a) (((a&0xff) << 8) | ((a >> 8)&0xff))
+
#define A1B (1<<0)
#define A1W (2<<0)
@@ -100,7 +132,6 @@
#define ANOFIRSTPAREN (1<<29)
#define ASTARTCOMMA (1<<28)
#define AVARSTORE (1<<27)
-#define MKID(a) (((a&0xff) << 8) | ((a >> 8)&0xff))
@@ -115,6 +146,7 @@
char *indentbuf;
struct BlockStack {
+ bool isWhile;
unsigned short from;
unsigned short to;
};
@@ -129,6 +161,8 @@
int pendingElseOpcode;
int pendingElseIndent;
+int offs_of_line;
+
bool alwaysShowOffs = 0;
bool dontOutputIfs = 0;
bool dontOutputWhile = 0;
@@ -146,7 +180,7 @@
bool GF_UNBLOCKED = false;
-bool emit_if(char *before, char *after);
+void emit_if(char *buf, char *condition);
int get_curoffs()
{
@@ -165,10 +199,9 @@
return i;
}
-int get_gotopos()
+int get_signed_word()
{
- int j = get_word();
- return (short)(j + get_curoffs());
+ return (short)get_word();
}
char *strecpy(char *buf, const char *src)
@@ -379,12 +412,9 @@
}
if (args & ATO) {
- char before[256];
- char after[256];
char tmp[256];
strcpy(tmp, buforg);
- emit_if(before, after);
- sprintf(buforg, "%s%s%s", before, tmp, after);
+ emit_if(buforg, tmp);
} else if (!(args & ANOLASTPAREN)) {
buf = strecpy(buf, ")");
}
@@ -414,7 +444,7 @@
-BlockStack *PushBlockStackItem()
+BlockStack *pushBlockStackItem()
{
if (!block_stack)
block_stack = (BlockStack *) malloc(256 * sizeof(BlockStack));
@@ -431,16 +461,23 @@
{
int i;
BlockStack *p;
-
+
if (((to | cur) >> 16) || (to <= cur))
- return 0; /* Invalid jump */
-
+ return false; // Invalid jump
+
for (i = 0, p = block_stack; i < num_block_stack; i++, p++) {
if (to > p->to)
- return 0;
+ return false;
}
+
+ p = pushBlockStackItem();
- p = PushBlockStackItem();
+ // Try to determine if this is a while loop. For this, first check if we
+ // jump right behind a regular jump, then whether that jump is targeting us.
+ p->isWhile = (*(byte*)(org_pos+to-3) == g_jump_opcode);
+ i = TO_LE_16(*(int16*)(org_pos+to-2));
+
+ p->isWhile = p->isWhile && (offs_of_line == (int)to + i);
p->from = cur;
p->to = to;
return 1;
@@ -462,7 +499,7 @@
}
/* Returns 0 or 1 depending if it's ok to add an else */
-int RequestElseAdd(int cur, int to)
+int maybeAddElse(int cur, int to)
{
BlockStack *p;
int i;
@@ -498,6 +535,11 @@
if (!num_block_stack)
return false; /* There are no previous blocks, so an ifelse is not ok */
+ p = &block_stack[num_block_stack - 1];
+
+ if (p->isWhile)
+ return false;
+
k = to - 3;
if (k < 0 || k >= size_of_code)
return false; /* Invalid jump */
@@ -510,7 +552,6 @@
if (k != elseto)
return false; /* Not an ifelse */
- p = &block_stack[num_block_stack - 1];
p->from = cur;
p->to = to;
@@ -1518,40 +1559,68 @@
}
-bool emit_if(char *before, char *after)
+void do_unconditional_jump(char *buf, byte opcode)
{
- int to = get_gotopos();
+ int offset = get_signed_word();
+ int cur = get_curoffs();
+ int to = cur + offset;
- before[0] = 0;
- after[0] = 0;
+ if (offset == 0) {
+ sprintf(buf, "/* goto %.4X; */", to);
+ } else if (!dontOutputElse && maybeAddElse(cur, to)) {
+ pendingElse = 1;
+ pendingElseTo = to;
+ pendingElseOffs = cur - 1;
+ pendingElseOpcode = opcode;
+ pendingElseIndent = num_block_stack;
+ buf[0] = 0;
+ } 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.
+ }
+ sprintf(buf, "goto %.4X;", to);
+ }
+}
+
+void emit_if(char *buf, char *condition)
+{
+ int offset = get_signed_word();
+ int cur = get_curoffs();
+ int to = cur + offset;
if (!dontOutputElseif && pendingElse) {
- if (maybeAddElseIf(get_curoffs(), pendingElseTo, to)) {
+ if (maybeAddElseIf(cur, pendingElseTo, to)) {
pendingElse = false;
haveElse = true;
- sprintf(after, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to);
- strcpy(before, "} else ");
- return true;
+ buf = strecpy(buf, "} else if (");
+ buf = strecpy(buf, condition);
+ sprintf(buf, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to);
+ return;
}
}
- if (!dontOutputIfs && maybeAddIf(get_curoffs(), to)) {
- sprintf(after, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to);
- return true;
+ if (!dontOutputIfs && maybeAddIf(cur, to)) {
+ if (!dontOutputWhile && block_stack[num_block_stack - 1].isWhile) {
+ buf = strecpy(buf, "while (");
+ } else
+ buf = strecpy(buf, "if (");
+ buf = strecpy(buf, condition);
+ sprintf(buf, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to);
+ return;
}
- sprintf(after, ") goto %.4X;", to);
- return false;
+// buf = strecpy(buf, negate ? "if (" : "unless (");
+ buf = strecpy(buf, "unless (");
+ buf = strecpy(buf, condition);
+ sprintf(buf, ") goto %.4X;", to);
}
-
-
void do_if_code(char *buf, byte opcode)
{
- char tmp2[256];
char var[256];
- char before[256], after[256];
- byte neg;
+ char tmp[256], tmp2[256];
int txt;
const char *cmp_texts[8] = {
@@ -1596,16 +1665,14 @@
get_var_or_word(tmp2, opcode & 0x80);
}
- neg = emit_if(before, after) ^ 1;
-
- sprintf(buf, "%sif (%s%s%s%s", before, var, cmp_texts[txt ^ neg], tmp2, after);
+ sprintf(tmp, "%s%s%s", var, cmp_texts[txt], tmp2);
+ emit_if(buf, tmp);
}
void do_if_state_code(char *buf, byte opcode)
{
- char tmp2[256];
char var[256];
- char before[256], after[256];
+ char tmp[256], tmp2[256];
byte neg;
int state = 0;
@@ -1677,34 +1744,13 @@
}
}
- neg = neg ^ emit_if(before, after) ^ 1;
-
if (scriptVersion > 2)
- sprintf(buf, "%sif (getState(%s)%s%s%s", before, var, neg ? " != " : " == ", tmp2, after);
+ sprintf(tmp, "getState(%s)%s%s", var, neg ? " != " : " == ", tmp2);
else
- sprintf(buf, "%sif (%sgetState%02d(%s)%s", before, neg ? "!" : "", state, var, after);
-}
-
-void do_unconditional_jump(char *buf, byte opcode)
-{
- int i = get_gotopos();
- int j = get_curoffs();
-
- if (i == j) {
- sprintf(buf, "/* goto %.4X; */", i);
- } else if (!dontOutputElse && RequestElseAdd(j, i)) {
- pendingElse = 1;
- pendingElseTo = i;
- pendingElseOffs = j - 3;
- pendingElseOpcode = opcode;
- pendingElseIndent = num_block_stack;
- buf[0] = 0;
- } else {
- sprintf(buf, "goto %.4X;", i);
- }
+ sprintf(tmp, "%sgetState%02d(%s)", neg ? "!" : "", state, var);
+ emit_if(buf, tmp);
}
-
void do_varset_code(char *buf, byte opcode)
{
char *s;
@@ -2587,7 +2633,7 @@
case 0x1D:
case 0x9D:
- do_tok(buf, "if ClassOfIs", ((opcode & 0x80) ? A1V : A1W) | A2VARUNTIL0xFF | ATO);
+ do_tok(buf, "classOfIs", ((opcode & 0x80) ? A1V : A1W) | A2VARUNTIL0xFF | ATO);
break; /* arg1=object; vararg=classes to test; arg3=jumpoffs */
case 0x1E:
@@ -3306,7 +3352,7 @@
len -= mem - memorg;
- int offs_of_line = 0;
+ offs_of_line = 0;
do {
byte opcode = *cur_pos;
Index: descumm6.cpp
===================================================================
RCS file: /cvsroot/scummvm/tools/descumm6.cpp,v
retrieving revision 1.93
retrieving revision 1.94
diff -u -d -r1.93 -r1.94
--- descumm6.cpp 8 May 2003 23:44:07 -0000 1.93
+++ descumm6.cpp 9 May 2003 00:37:06 -0000 1.94
@@ -1207,27 +1207,27 @@
{
int i;
BlockStack *p;
-
+
if (((to | cur) >> 16) || (to <= cur))
- return 0; /* Invalid jump */
-
+ return false; // Invalid jump
+
for (i = 0, p = block_stack; i < num_block_stack; i++, p++) {
if (to > p->to)
return false;
}
-
+
p = pushBlockStackItem();
-
+
// Try to determine if this is a while loop. For this, first check if we
// jump right behind a regular jump, then whether that jump is targeting us.
if (scriptVersion == 8) {
- p->isWhile = (*(byte*)(org_pos+to-5) == 0x66);
+ p->isWhile = (*(byte*)(org_pos+to-5) == g_jump_opcode);
i = TO_LE_32(*(int32*)(org_pos+to-4));
} else {
- p->isWhile = (*(byte*)(org_pos+to-3) == 0x73);
+ p->isWhile = (*(byte*)(org_pos+to-3) == g_jump_opcode);
i = TO_LE_16(*(int16*)(org_pos+to-2));
}
-
+
p->isWhile = p->isWhile && (offs_of_line == (int)to + i);
p->from = cur;
p->to = to;
@@ -1302,6 +1302,7 @@
int offset = get_signed_word();
int cur = get_curoffs();
int to = cur + offset;
+
if (!dontOutputElse && maybeAddElse(cur, to)) {
// In order to avoid stray lonely "} else {" from occuring, we check
// for offset = 1. These cases really constitute NOPs, obviously.
@@ -1322,7 +1323,7 @@
}
}
-void jumpif(StackEnt * se, bool when)
+void jumpif(StackEnt * se, bool negate)
{
int offset = get_signed_word();
int cur = get_curoffs();
@@ -1334,7 +1335,7 @@
pendingElse = false;
haveElse = true;
e = strecpy(e, "} else if (");
- if (when)
+ if (negate)
se = se_neg(se);
e = se_astext(se, e, false);
sprintf(e, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to);
@@ -1347,14 +1348,14 @@
e = strecpy(e, "while (");
} else
e = strecpy(e, "if (");
- if (when)
+ if (negate)
se = se_neg(se);
e = se_astext(se, e, false);
sprintf(e, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to);
return;
}
- e = strecpy(e, when ? "if (" : "if (!");
+ e = strecpy(e, negate ? "if (" : "unless (");
e = se_astext(se, e);
sprintf(e, ") goto %x", to);
}
More information about the Scummvm-git-logs
mailing list