home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Elysian Archive
/
AmigaElysianArchive.iso
/
games
/
utils
/
ztools.lha
/
ztools
/
src
/
txd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-17
|
35KB
|
1,014 lines
/* txd.c V1.3
*
* Z code disassembler.
*
* No switches, no nothing, just give it a story file name, and you're off.
* Requires txio.c and tx.h. To reduce some CPU cost define NO_LOW_SCAN, but
* some low address routines may be skipped.
*
* Currently only works for type 3, 4 and 5 games.
*
* Usage: txd story-file-name
*
* Mark Howell 25 August 1992 howell_ma@movies.enet.dec.com
*
* History:
* Merge separate disassemblers for each type into one program
* Fix logic error in low routine scan
* Force PC past start PC in middle routine scan
*/
#include "tx.h"
#define MAX_PCS 100
#ifdef __STDC__
static int decode_code (void);
static int decode_inputs (void);
static int decode_opcode (void);
static int decode_operands (const char *, int, int, int);
static int decode_outputs (void);
static int decode_routine (void);
static void decode_operand (int, int);
static void decode_program (void);
static void decode_strings (unsigned long);
static void scan_strings (unsigned long);
static int lookup_string (unsigned long);
static void scan_words (void);
static unsigned long lookup_word (unsigned long);
#else
static int decode_code ();
static int decode_inputs ();
static int decode_opcode ();
static int decode_operands ();
static int decode_outputs ();
static int decode_routine ();
static void decode_operand ();
static void decode_program ();
static void decode_strings ();
static void scan_strings ();
static int lookup_string ();
static void scan_words ();
static unsigned long lookup_word ();
#endif
static unsigned long pctable[MAX_PCS];
static int pcindex = 0;
static unsigned long start_data_pc, end_data_pc;
static decode_t decode;
static opcode_t opcode;
#ifdef __STDC__
int main (int argc, char *argv [])
#else
int main (argc, argv)
int argc;
char *argv [];
#endif
{
if (argc != 2) {
fprintf (stderr, "Usage: %s data-file\n", argv [0]);
exit (EXIT_FAILURE);
}
open_story (argv [1]);
configure (V3, V5);
load_cache ();
decode.pc = (unsigned long) h_data_size;
decode.initial_pc = (unsigned long) h_start_pc;
printf ("Resident data ends at %lx, program starts at %lx, file ends at %lx\n",
(unsigned long) h_data_size, (unsigned long) h_start_pc, (unsigned long) h_file_size * story_scaler);
printf ("\nStarting analysis pass at address %lx\n", decode.pc);
decode.first_pass = 1;
decode_program ();
scan_strings (decode.pc);
scan_words ();
printf ("\nEnd of analysis pass, low address = %lx, high address = %lx\n",
decode.low_address, decode.high_address);
if (start_data_pc)
printf ("\nData PC range = %lx to %lx\n", start_data_pc, end_data_pc);
decode.first_pass = 0;
decode_program ();
decode_strings (decode.pc);
close_story ();
exit (EXIT_SUCCESS);
return (0);
}/* main */
/* decode_program - Decode Z code in two passes */
#ifdef __STDC__
static void decode_program (void)
#else
static void decode_program ()
#endif
{
unsigned long pc, low_pc, high_pc, prev_low_pc, prev_high_pc;
int flag, vars;
if (decode.first_pass) {
#if !defined(NO_LOW_SCAN)
/* Scan for low routines */
decode.pc = (decode.pc + (story_scaler - 1)) & ~(story_scaler - 1);
for (pc = decode.pc, flag = 0; pc < (decode.initial_pc - 1) && !flag; pc += story_scaler) {
decode.pc = pc;
while (decode.pc < (decode.initial_pc - 1) && (decode_routine () == END_OF_ROUTINE) && pcindex == 0)
decode.pc = (decode.pc + (story_scaler - 1)) & ~(story_scaler - 1);
if (decode.pc == (decode.initial_pc - 1)) {
decode.pc = pc;
flag = 1;
}
pcindex = 0;
}
if (!flag)
#endif /* !defined(NO_LOW_SCAN) */
decode.pc = decode.initial_pc - 1;
/* Fill in middle routines */
decode.low_address = decode.pc;
decode.high_address = decode.pc;
start_data_pc = 0;
end_data_pc = 0;
do {
prev_low_pc = decode.low_address;
prev_high_pc = decode.high_address;
flag = 0;
pcindex = 0;
low_pc = decode.low_address;
high_pc = decode.high_address;
pc = decode.pc = decode.low_address;
while (decode.pc <= high_pc || decode.pc <= (decode.initial_pc - 1)) {
if (start_data_pc == decode.pc)
decode.pc = end_data_pc;
if (decode_routine () != END_OF_ROUTINE) {
if (start_data_pc == 0)
start_data_pc = decode.pc;
flag = 1;
end_data_pc = 0;
pcindex = 0;
pc = (pc + (story_scaler - 1)) & ~(story_scaler - 1);
do {
pc += story_scaler;
vars = (char) read_data_byte (&pc);
pc--;
} while (vars < 0 || vars > 15);
decode.pc = pc;
} else {
if (start_data_pc && end_data_pc == 0)
end_data_pc = pc;
pc = (decode.pc + (story_scaler - 1)) & ~(story_scaler - 1);
if (!flag) {
low_pc = decode.low_address;
high_pc = decode.high_address;
}
}
}
decode.low_address = low_pc;
decode.high_address = high_pc;
} while (low_pc < prev_low_pc || high_pc > prev_high_pc);
/* Scan for high routines */
pc = decode.pc;
while (decode_routine () == END_OF_ROUTINE) {
decode.high_address = pc;
pc = decode.pc;
}
} else {
printf ("\n[start of code at %lx]\n", decode.low_address);
for (decode.pc = decode.low_address;
decode.pc <= decode.high_address; )
decode_routine ();
printf ("\n[end of code at %lx]\n", decode.pc);
}
}/* decode_program */
/* decode_routine - Decode a routine from start address to last instruction */
#ifdef __STDC__
static int decode_routine (void)
#else
static int decode_routine ()
#endif
{
unsigned long old_pc;
int vars, status, count, i;
if (decode.first_pass) {
old_pc = decode.pc;
decode.pc = (decode.pc + (story_scaler - 1)) & ~(story_scaler - 1);
vars = read_data_byte (&decode.pc);
if (vars >= 0 && vars <= 15) {
if (h_type == V3 || h_type == V4)
for (; vars; vars--)
read_data_word (&decode.pc);
if (decode_code () == END_OF_ROUTINE)
return (END_OF_ROUTINE);
}
decode.pc = old_pc;
if ((status = decode_code ()) != END_OF_ROUTINE) {
decode.pc = old_pc;
return (status);
}
pctable[pcindex++] = old_pc;
if (pcindex == MAX_PCS) {
fprintf (stderr, "\nFatal: too many orphan code fragments\n");
exit (EXIT_FAILURE);
}
} else {
if (decode.pc == start_data_pc) {
printf ("\n[start of data at %lx]\n\n", decode.pc);
count = 0;
while (decode.pc < end_data_pc) {
printf ("[%04x]", (unsigned int) read_data_word (&decode.pc));
if (++count == 13) {
printf ("\n");
count = 0;
}
}
printf ("\n\n[end of data at %lx]\n", decode.pc);
decode.pc = end_data_pc;
}
for (i = 0; i < pcindex && decode.pc != pctable[i]; i++)
;
if (i == pcindex) {
decode.pc = (decode.pc + (story_scaler - 1)) & ~(story_scaler - 1);
vars = read_data_byte (&decode.pc);
printf ("%soutine %lx, %d local",
(decode.pc == decode.initial_pc) ? "\nMain r" : "\nR",
(unsigned long) decode.pc - 1,
vars);
if (vars != 1)
printf ("s");
if (h_type == V3 || h_type == V4) {
printf (" (");
for (; vars; vars--) {
printf ("%04x", (unsigned int) read_data_word (&decode.pc));
if (vars > 1)
printf (",");
}
printf (")");
}
printf ("\n\n");
} else
printf ("\norphan code fragment:\n\n");
status = decode_code ();
}
return (status);
}/* decode_routine */
/* decode_code - grab opcode and determine the class */
#ifdef __STDC__
static int decode_code (void)
#else
static int decode_code ()
#endif
{
int status;
decode.high_pc = decode.pc;
do {
if (!decode.first_pass)
printf ("%5lx: ", decode.pc);
opcode.opcode = read_data_byte (&decode.pc);
if (h_type == V5 && opcode.opcode == 0xbe) {
opcode.opcode = read_data_byte (&decode.pc);
opcode.class = EXTENDED_OPERAND;
} else if (opcode.opcode < 0x80)
opcode.class = TWO_OPERAND;
else
if (opcode.opcode < 0xb0)
opcode.class = ONE_OPERAND;
else
if (opcode.opcode < 0xc0)
opcode.class = ZERO_OPERAND;
else
opcode.class = VARIABLE_OPERAND;
status = decode_opcode ();
} while (status == END_OF_INSTRUCTION);
return (status);
}/* decode_code */
/* decode_opcode - Check and decode the opcode itself */
#define caseline(opc, text, operands, type1, type2) \
case opc: return (decode_operands (text, operands, type1, type2))
#ifdef __STDC__
static int decode_opcode (void)
#else
static int decode_opcode ()
#endif
{
int code;
code = opcode.opcode;
switch (opcode.class) {
case EXTENDED_OPERAND:
code &= 0x3f;
switch (code) {
caseline (0x00, "SAVE", 0, STORE, NONE);
caseline (0x01, "RESTORE", 0, STORE, NONE);
caseline (0x02, "SHIFT", 2, STORE, NONE);
caseline (0x04, "GRAPHICS", 1, STORE, NONE);
caseline (0x09, "SAVE UNDO", 0, STORE, NONE);
caseline (0x0A, "RESTORE UNDO", 0, STORE, NONE);
default:
return (decode_operands ("ILLEGAL", 0, ILLEGAL, NONE));
}
case TWO_OPERAND:
code &= 0x1f;
case VARIABLE_OPERAND:
code &= 0x3f;
switch (code) {
caseline (0x01, "JE", -4, BRANCH, NONE);
caseline (0x02, "JLE", 2, BRANCH, NONE);
caseline (0x03, "JGE", 2, BRANCH, NONE);
caseline (0x04, "DEC_CHK", 2, BRANCH, VAR);
caseline (0x05, "INC_CHK", 2, BRANCH, VAR);
caseline (0x06, "COMPARE_POBJ", 2, BRANCH, NONE);
caseline (0x07, "TEST", 2, BRANCH, NONE);
caseline (0x08, "OR", 2, STORE, NONE);
caseline (0x09, "AND", 2, STORE, NONE);
caseline (0x0A, "TEST_ATTR", 2, BRANCH, NONE);
caseline (0x0B, "SET_ATTR", 2, NONE, NONE);
caseline (0x0C, "CLEAR_ATTR", 2, NONE, NONE);
caseline (0x0D, "STORE", 2, NONE, VAR);
caseline (0x0E, "INSERT_OBJ", 2, NONE, NONE);
caseline (0x0F, "LOADW", 2, STORE, NONE);
caseline (0x10, "LOADB", 2, STORE, NONE);
caseline (0x11, "GET_PROP", 2, STORE, NONE);
caseline (0x12, "GET_PROP_ADDR", 2, STORE, NONE);
caseline (0x13, "GET_NEXT_PROP", 2, STORE, NONE);
caseline (0x14, "ADD", 2, STORE, NONE);
caseline (0x15, "SUB", 2, STORE, NONE);
caseline (0x16, "MUL", 2, STORE, NONE);
caseline (0x17, "DIV", 2, STORE, NONE);
caseline (0x18, "MOD", 2, STORE, NONE);
caseline (0x20, "CALL", -4, CALL, NONE);
caseline (0x21, "STOREW", 3, NONE, NONE);
caseline (0x22, "STOREB", 3, NONE, NONE);
caseline (0x23, "PUT_PROP", 3, NONE, NONE);
caseline (0x25, "PRINT_CHAR", 1, PCHAR, NONE);
caseline (0x26, "PRINT_NUM", 1, NONE, NONE);
caseline (0x27, "RANDOM", 1, STORE, NONE);
caseline (0x28, "PUSH", 1, NONE, NONE);
caseline (0x29, "POP", 1, NONE, VAR);
caseline (0x2A, "STATUS_SIZE", 1, NONE, NONE);
caseline (0x2B, "SET_WINDOW", 1, NONE, NONE);
caseline (0x33, "SET_PRINT", -2, NONE, NONE);
caseline (0x34, "#RECORD_MODE", 1, NONE, NONE);
caseline (0x35, "SOUND", -4, NONE, NONE);
default:
switch (h_type) {
case V3:
switch (code) {
caseline (0x24, "READ", 2, NONE, NONE);
}
case V4:
switch (code) {
caseline (0x19, "CALL", 2, CALL, NONE);
caseline (0x24, "READ", -4, NONE, NONE);
caseline (0x2C, "CALL", -8, CALL, NONE);
caseline (0x2D, "ERASE_WINDOW", 1, NONE, NONE);
caseline (0x2E, "ERASE_LINE", 1, NONE, NONE);
caseline (0x2F, "SET_CURSOR", 2, NONE, NONE);
caseline (0x31, "VIDEO_ATTR", 1, VATTR, NONE);
caseline (0x32, "SET_FORMAT", 1, NONE, NONE);
caseline (0x36, "READ_CHAR", -3, STORE, NONE);
caseline (0x37, "SCANW", -4, STORE, OBJECT);
}
case V5:
switch (code) {
caseline (0x19, "CALL", 2, CALL, NONE);
caseline (0x1A, "CALL", 2, NCALL, NONE);
caseline (0x1B, "OPCODE 0x1B", 2, NONE, NONE);
caseline (0x24, "READ", -4, STORE, NONE);
caseline (0x2C, "CALL", -8, CALL, NONE);
caseline (0x2D, "ERASE_WINDOW", 1, NONE, NONE);
caseline (0x2E, "ERASE_LINE", 1, NONE, NONE);
caseline (0x2F, "SET_CURSOR", 2, NONE, NONE);
caseline (0x31, "VIDEO_ATTR", 1, VATTR, NONE);
caseline (0x32, "SET_FORMAT", 1, NONE, NONE);
caseline (0x36, "READ_CHAR", -3, STORE, NONE);
caseline (0x37, "SCANW", -4, STORE, OBJECT);
caseline (0x39, "CALL", -4, NCALL, NONE);
caseline (0x3A, "CALL", -8, NCALL, NONE);
caseline (0x3B, "PARSE", -4, NONE, NONE);
caseline (0x3C, "ENCRYPT", 4, NONE, NONE);
caseline (0x3D, "BLOCK_COPY", 3, NONE, NONE);
caseline (0x3E, "PRINT_TEXT", -3, NONE, NONE);
caseline (0x3F, "CHECK_VA_ARG", 1, BRANCH, NONE);
}
}
return (decode_operands ("ILLEGAL", 0, ILLEGAL, NONE));
}
case ONE_OPERAND:
code &= 0x0f;
switch (code) {
caseline (0x00, "JZ", 1, BRANCH, NONE);
caseline (0x01, "GET_SIBLING", 1, STORE, OBJECT);
caseline (0x02, "GET_CHILD", 1, STORE, OBJECT);
caseline (0x03, "GET_PARENT", 1, STORE, NONE);
caseline (0x04, "GET_PROP_LEN", 1, STORE, NONE);
caseline (0x05, "INC", 1, NONE, VAR);
caseline (0x06, "DEC", 1, NONE, VAR);
caseline (0x07, "PRINT_ADDR", 1, NONE, NONE);
caseline (0x09, "REMOVE_OBJ", 1, NONE, NONE);
caseline (0x0A, "PRINT_OBJ", 1, NONE, NONE);
caseline (0x0B, "RET", 1, RETURN, NONE);
caseline (0x0C, "JUMP", 1, JUMP, NONE);
caseline (0x0D, "PRINT_PADDR", 1, NONE, NONE);
caseline (0x0E, "LOAD", 1, STORE, VAR);
default:
switch (h_type) {
case V3:
switch (code) {
caseline (0x0F, "NOT", 1, STORE, NONE);
}
case V4:
switch (code) {
caseline (0x08, "CALL", 1, CALL, NONE);
caseline (0x0F, "NOT", 1, STORE, NONE);
}
case V5:
switch (code) {
caseline (0x08, "CALL", 1, CALL, NONE);
caseline (0x0F, "CALL", 1, NCALL, NONE);
}
}
return (decode_operands ("ILLEGAL", 0, ILLEGAL, NONE));
}
case ZERO_OPERAND:
code &= 0x0f;
switch (code) {
caseline (0x00, "RET #TRUE", 0, RETURN, NONE);
caseline (0x01, "RET #FALSE", 0, RETURN, NONE);
caseline (0x02, "PRINT", 0, NONE, TEXT);
caseline (0x03, "PRINT_RET", 0, RETURN, TEXT);
caseline (0x07, "RESTART", 0, NONE, NONE);
caseline (0x08, "RET (SP)+", 0, RETURN, NONE);
caseline (0x09, "POP", 0, NONE, NONE);
caseline (0x0A, "QUIT", 0, NONE, NONE);
caseline (0x0B, "NEW_LINE", 0, NONE, NONE);
caseline (0x0D, "VERIFY", 0, BRANCH, NONE);
default:
switch (h_type) {
case V3:
switch (code) {
caseline (0x05, "SAVE", 0, BRANCH, NONE);
caseline (0x06, "RESTORE", 0, BRANCH, NONE);
caseline (0x0C, "SHOW_SCORE", 0, NONE, NONE);
}
case V4:
switch (code) {
caseline (0x05, "SAVE", 0, STORE, NONE);
caseline (0x06, "RESTORE", 0, STORE, NONE);
}
case V5:
switch (code) {
/* From a bug in Wishbringer V23 */
caseline (0x0C, "SHOW_SCORE", 0, NONE, NONE);
}
}
return (decode_operands ("ILLEGAL", 0, ILLEGAL, NONE));
}
default:
fprintf (stderr, "\nFatal: bad class (%d)\n", opcode.class);
exit (EXIT_FAILURE);
}
return (0);
}/* decode_opcode */
#undef caseline
/* decode_operands - Decode operands of opcode */
#ifdef __STDC__
static int decode_operands (const char *opcode_name, int input_opers, int type, int special)
#else
static int decode_operands (opcode_name, input_opers, type, special)
const char *opcode_name;
int input_opers;
int type;
int special;
#endif
{
size_t len;
int opers, status;
opcode.type = type;
opcode.special = special;
if (opcode.type == ILLEGAL)
return (BAD_OPCODE);
if (decode.first_pass) {
opers = decode_inputs ();
if (input_opers < 0) {
if (opers > abs (input_opers))
return (BAD_OPCODE);
} else
if (opers != input_opers)
return (BAD_OPCODE);
status = decode_outputs ();
} else {
printf (opcode_name);
for (len = strlen (opcode_name); len < 14; len++)
printf (" ");
opers = decode_inputs ();
if (opers > 0 && ((opcode.type == CALL) || (opcode.type == BRANCH) || (opcode.type == STORE)))
printf (" -> ");
status = decode_outputs ();
printf ("\n");
}
if (decode.pc > decode.high_pc)
decode.high_pc = decode.pc;
return (status);
}/* decode_operands */
/* decode_inputs - Decode input operands */
#ifdef __STDC__
static int decode_inputs (void)
#else
static int decode_inputs ()
#endif
{
int modes, addr_mode, maxopers, opers = 0;
switch (opcode.class) {
case ONE_OPERAND:
decode_operand ((opcode.opcode >> 4) & 0x03, 1);
opers = 1;
break;
case TWO_OPERAND:
decode_operand ((opcode.opcode & 0x40) ? VARIABLE : BYTE_IMMED, 1);
if (!decode.first_pass)
printf (",");
decode_operand ((opcode.opcode & 0x20) ? VARIABLE : BYTE_IMMED, 0);
opers = 2;
break;
case VARIABLE_OPERAND:
case EXTENDED_OPERAND:
if ((opcode.opcode & 0x3f) == 0x2c ||
(opcode.opcode & 0x3f) == 0x3a) {
modes = read_data_word (&decode.pc);
maxopers = 8;
} else {
modes = read_data_byte (&decode.pc);
maxopers = 4;
}
for (addr_mode = 0, opers = 0;
(addr_mode != NO_OPERAND) && maxopers; maxopers--) {
addr_mode = (modes >> ((maxopers - 1) * 2)) & 0x03;
if (addr_mode != NO_OPERAND) {
if (!decode.first_pass && opers) {
if ((opcode.type == CALL || opcode.type == NCALL) && opers == 1)
printf (" (");
else
printf (",");
}
decode_operand (addr_mode, opers == 0);
opers++;
}
}
if (!decode.first_pass && (opcode.type == CALL || opcode.type == NCALL) && opers > 1)
printf (")");
break;
case ZERO_OPERAND:
if (opcode.special == TEXT) {
if (decode.first_pass) {
while ((short) read_data_word (&decode.pc) >= 0)
;
} else {
printf ("\"");
decode_text (&decode.pc);
printf ("\"");
}
}
break;
default:
fprintf (stderr, "\nFatal: bad class (%d)\n", opcode.class);
exit (EXIT_FAILURE);
}
return (opers);
}/* decode_inputs */
/* decode_operand - Decode one operand */
#ifdef __STDC__
static void decode_operand (int addr_mode, int flag)
#else
static void decode_operand (addr_mode, flag)
int addr_mode;
int flag;
#endif
{
unsigned long addr = 0;
int vars, type, special;
if (flag) {
type = opcode.type;
special = opcode.special;
} else {
type = NONE;
special = NONE;
}
if (special == VAR)
addr_mode = VARIABLE;
switch (addr_mode) {
case WORD_IMMED:
addr = (zword_t) read_data_word (&decode.pc);
break;
case BYTE_IMMED:
addr = (zbyte_t) read_data_byte (&decode.pc);
break;
case VARIABLE:
addr = read_data_byte (&decode.pc);
if (!decode.first_pass) {
if (addr == 0)
printf ("(SP)+");
else
if (addr < 16)
printf ("L%02lx", (unsigned long) (addr - 1));
else
printf ("G%02lx", (unsigned long) (addr - 16));
}
case NO_OPERAND:
return;
default:
fprintf (stderr, "\nFatal: bad addressing mode (%d)\n", addr_mode);
exit (EXIT_FAILURE);
}
switch (type) {
case NCALL:
case CALL:
addr *= story_scaler;
if (!decode.first_pass)
printf ("%lx", addr);
if (addr < decode.low_address &&
addr >= (unsigned long) h_data_size) {
vars = read_data_byte (&addr);
if (vars >= 0 && vars <= 15)
decode.low_address = addr - 1;
}
if (addr > decode.high_address &&
addr < ((unsigned long) h_file_size * story_scaler)) {
vars = read_data_byte (&addr);
if (vars >= 0 && vars <= 15)
decode.high_address = addr - 1;
}
break;
case JUMP:
addr = decode.pc + (short) addr - 2;
if (!decode.first_pass)
printf ("%lx", addr);
if (addr > decode.high_pc)
decode.high_pc = addr;
break;
case PCHAR:
if (!decode.first_pass)
if (isprint ((char) addr)) {
printf ("\'%c\'", (char) addr);
break;
}
case VATTR:
if (!decode.first_pass) {
switch ((char) addr) {
case NORMAL:
printf ("NORMAL");
break;
case REVERSE:
printf ("REVERSE");
break;
case BOLD:
printf ("BOLD");
break;
case BLINK:
printf ("BLINK");
break;
case UNDERSCORE:
printf ("UNDERSCORE");
break;
}
if (addr >= 0 && addr <= 4)
break;
}
default:
if (!decode.first_pass)
if (addr_mode == WORD_IMMED) {
printf ("#%04lx", addr);
if (special = lookup_string (addr * story_scaler))
printf ("[s%d]", special);
if (addr = lookup_word (addr)) {
printf ("[w\"");
decode_text (&addr);
printf ("\"]");
}
} else
printf ("#%02lx", addr);
}
}/* decode_operand */
/* decode_outputs - Decode output operand */
#ifdef __STDC__
static int decode_outputs (void)
#else
static int decode_outputs ()
#endif
{
unsigned long addr;
switch (opcode.type) {
case CALL:
case STORE:
addr = (zbyte_t) read_data_byte (&decode.pc);
if (!decode.first_pass) {
if (addr == 0)
printf ("-(SP)");
else
if (addr < 16)
printf ("L%02lx", (unsigned long) (addr - 1));
else
printf ("G%02lx", (unsigned long) (addr - 16));
}
if (opcode.special != OBJECT)
break;
else
if (!decode.first_pass)
printf (", ");
case BRANCH:
addr = (zbyte_t) read_data_byte (&decode.pc);
if (!decode.first_pass) {
if (addr & 0x80)
printf ("[TRUE]");
else
printf ("[FALSE]");
}
addr &= 0x7f;
if (addr & 0x40)
addr &= 0x3f;
else {
addr = (addr << 8) | (zbyte_t) read_data_byte (&decode.pc);
if (addr & 0x2000) {
addr &= 0x1fff;
addr |= ~0x1fff;
}
}
if (addr == 0) {
if (!decode.first_pass)
printf (" RET #FALSE");
} else if (addr == 1) {
if (!decode.first_pass)
printf (" RET #TRUE");
} else {
addr = decode.pc + addr - 2;
if (!decode.first_pass)
printf (" %lx", addr);
if (addr > decode.high_pc)
decode.high_pc = addr;
}
break;
case RETURN:
case JUMP:
if (decode.pc > decode.high_pc)
return (END_OF_ROUTINE);
case NCALL:
case NONE:
case PCHAR:
case VATTR:
break;
default:
fprintf (stderr, "\nFatal: bad type (%d)\n", opcode.type);
exit (EXIT_FAILURE);
}
return (END_OF_INSTRUCTION);
}/* decode_outputs */
/* decode_strings - Dump text after end of code */
#ifdef __STDC__
static void decode_strings (unsigned long pc)
#else
static void decode_strings (pc)
unsigned long pc;
#endif
{
int count = 1;
pc = (pc + (story_scaler - 1)) & ~(story_scaler - 1);
printf ("\n[start of text at %lx]\n\n", pc);
while (pc < ((unsigned long) h_file_size * story_scaler)) {
printf ("%5lx: [s%d] \"", pc, count++);
decode_text (&pc);
printf ("\"\n");
pc = (pc + (story_scaler - 1)) & ~(story_scaler - 1);
}
printf ("\n[end of text at %lx]\n\n[End of file]\n", pc);
}/* decode_strings */
typedef struct string_item {
struct string_item *next;
unsigned long text_addr;
int text_num;
} string_item_t;
static string_item_t *strings_base = NULL;
/* scan_strings - build string address table */
#ifdef __STDC__
static void scan_strings (unsigned long pc)
#else
static void scan_strings (pc)
unsigned long pc;
#endif
{
int count = 1;
string_item_t *string_item;
zword_t data;
pc = (pc + (story_scaler - 1)) & ~(story_scaler - 1);
while (pc < ((unsigned long) h_file_size * story_scaler)) {
string_item = (string_item_t *) malloc (sizeof (string_item_t));
if (string_item == NULL) {
fprintf (stderr, "Insufficient memory\n");
exit (EXIT_FAILURE);
}
string_item->text_addr = pc;
string_item->text_num = count++;
string_item->next = strings_base;
strings_base = string_item;
do
data = (zword_t) read_data_word (&pc);
while ((data & 0x8000) == 0);
pc = (pc + (story_scaler - 1)) & ~(story_scaler - 1);
}
}/* scan_strings */
/* lookup_string - lookup a string address */
#ifdef __STDC__
static int lookup_string (unsigned long addr)
#else
static int lookup_string (addr)
unsigned long addr;
#endif
{
string_item_t *string_item;
for (string_item = strings_base; string_item->next != NULL; string_item = string_item->next)
if (string_item->text_addr == addr)
return (string_item->text_num);
return (0);
}/* lookup_string */
typedef struct word_item {
struct word_item *next;
unsigned long word_addr;
} word_item_t;
static word_item_t *words_base = NULL;
/* scan_words - build dictionary address table */
#ifdef __STDC__
static void scan_words (void)
#else
static void scan_words ()
#endif
{
unsigned long offset;
int separator_count, word_size, word_count, i;
word_item_t *word_item;
offset = (unsigned long) h_words_offset;
separator_count = (int) read_data_byte (&offset);
offset += separator_count;
word_size = (int) read_data_byte (&offset);
word_count = (int) read_data_word (&offset);
for (i = 0; i < word_count; i++) {
if ((offset + 4) < (unsigned long) h_data_size)
if (h_type == V3)
set_byte (offset + 2, get_byte (offset + 2) | 0x80);
else
set_byte (offset + 4, get_byte (offset + 4) | 0x80);
word_item = (word_item_t *) malloc (sizeof (word_item_t));
if (word_item == NULL) {
fprintf (stderr, "Insufficient memory\n");
exit (EXIT_FAILURE);
}
word_item->word_addr = offset;
word_item->next = words_base;
words_base = word_item;
offset += word_size;
}
}/* scan_words */
/* lookup_word - lookup a word address */
#ifdef __STDC__
static unsigned long lookup_word (unsigned long addr)
#else
static unsigned long lookup_word (addr)
unsigned long addr;
#endif
{
word_item_t *word_item;
for (word_item = words_base; word_item->next != NULL; word_item = word_item->next)
if (word_item->word_addr == addr)
return (word_item->word_addr);
return (0);
}/* lookup_word */