#ifdef RCSID
static char RCSid[] =
"$Header: d:/cvsroot/tads/tads3/TCT3UNAS.CPP,v 1.3 1999/07/11 00:46:57 MJRoberts Exp $";
#endif

/* 
 *   Copyright (c) 1999, 2002 Michael J. Roberts.  All Rights Reserved.
 *   
 *   Please see the accompanying license file, LICENSE.TXT, for information
 *   on using and copying this software.  
 */
/*
Name
  tct3unas.cpp - TADS 3 Compiler - T3 Unassembler
Function
  
Notes
  
Modified
  05/10/99 MJRoberts  - Creation
*/

#include "t3std.h"
#include "vmop.h"
#include "tcunas.h"
#include "tct3unas.h"
#include "vmtype.h"


/* ------------------------------------------------------------------------ */
/*
 *   disassemble a code stream 
 */
void CTcT3Unasm::disasm(CTcUnasSrc *src, CTcUnasOut *out)
{
    /* keep going until we run out of source material */
    for (;;)
    {
        char ch;
        
        /* get the next byte; stop if we've reached the end of the source */
        if (src->next_byte(&ch))
            break;

        /* disassemble this instruction */
        disasm_instr(src, out, ch);
    }
}

/* ------------------------------------------------------------------------ */
/*
 *   T3 Instruction Information Array 
 */
t3_instr_info_t CTcT3Unasm::instr_info[] =
{
	/* 0x00 */ { "db 0",       0, { } },
	/* 0x01 */ { "push_0",     0, { } },
	/* 0x02 */ { "push_1",     0, { } },
    /* 0x03 */ { "pushint8",   1, { T3OP_TYPE_8S }},
    /* 0x04 */ { "pushint",    1, { T3OP_TYPE_32S }},
    /* 0x05 */ { "pushstr",    1, { T3OP_TYPE_STR }},
    /* 0x06 */ { "pushlst",    1, { T3OP_TYPE_LIST }},
    /* 0x07 */ { "pushobj",    1, { T3OP_TYPE_OBJ }},
	/* 0x08 */ { "pushnil",    0, { } },
	/* 0x09 */ { "pushtrue",   0, { } },
    /* 0x0a */ { "pushpropid", 1, { T3OP_TYPE_PROP }},
    /* 0x0b */ { "pushfnptr",  1, { T3OP_TYPE_CODE_ABS }},
    /* 0x0c */ { "pushstri",   1, { T3OP_TYPE_INLINE_STR }},
    /* 0x0d */ { "pushparlst", 1, { T3OP_TYPE_8U }},
	/* 0x0e */ { "makelstpar", 0, { } },
    /* 0x0f */ { "pushenum",   1, { T3OP_TYPE_ENUM }},
    /* 0x10 */ { "pushbifptr", 2, { T3OP_TYPE_16U, T3OP_TYPE_16U }},
	/* 0x11 */ { "db 0x11",    0, { } },
	/* 0x12 */ { "db 0x12",    0, { } },
	/* 0x13 */ { "db 0x13",    0, { } },
	/* 0x14 */ { "db 0x14",    0, { } },
	/* 0x15 */ { "db 0x15",    0, { } },
	/* 0x16 */ { "db 0x16",    0, { } },
	/* 0x17 */ { "db 0x17",    0, { } },
	/* 0x18 */ { "db 0x18",    0, { } },
	/* 0x19 */ { "db 0x19",    0, { } },
	/* 0x1a */ { "db 0x1a",    0, { } },
	/* 0x1b */ { "db 0x1b",    0, { } },
	/* 0x1c */ { "db 0x1c",    0, { } },
	/* 0x1d */ { "db 0x1d",    0, { } },
	/* 0x1e */ { "db 0x1e",    0, { } },
	/* 0x1f */ { "db 0x1f",    0, { } },
	/* 0x20 */ { "neg",        0, { } },
	/* 0x21 */ { "bnot",       0, { } },
	/* 0x22 */ { "add",        0, { } },
	/* 0x23 */ { "sub",        0, { } },
	/* 0x24 */ { "mul",        0, { } },
	/* 0x25 */ { "band",       0, { } },
	/* 0x26 */ { "bor",        0, { } },
	/* 0x27 */ { "shl",        0, { } },
	/* 0x28 */ { "shr",        0, { } },
	/* 0x29 */ { "xor",        0, { } },
	/* 0x2a */ { "div",        0, { } },
	/* 0x2b */ { "mod",        0, { } },
	/* 0x2c */ { "not",        0, { } },
	/* 0x2d */ { "boolize",    0, { } },
	/* 0x2e */ { "inc",        0, { } },
	/* 0x2f */ { "dec",        0, { } },
	/* 0x30 */ { "db 0x30",    0, { } },
	/* 0x31 */ { "db 0x31",    0, { } },
	/* 0x32 */ { "db 0x32",    0, { } },
	/* 0x33 */ { "db 0x33",    0, { } },
	/* 0x34 */ { "db 0x34",    0, { } },
	/* 0x35 */ { "db 0x35",    0, { } },
	/* 0x36 */ { "db 0x36",    0, { } },
	/* 0x37 */ { "db 0x37",    0, { } },
	/* 0x38 */ { "db 0x38",    0, { } },
	/* 0x39 */ { "db 0x39",    0, { } },
	/* 0x3a */ { "db 0x3a",    0, { } },
	/* 0x3b */ { "db 0x3b",    0, { } },
	/* 0x3c */ { "db 0x3c",    0, { } },
	/* 0x3d */ { "db 0x3d",    0, { } },
	/* 0x3e */ { "db 0x3e",    0, { } },
	/* 0x3f */ { "db 0x3f",    0, { } },
	/* 0x40 */ { "eq",         0, { } },
	/* 0x41 */ { "ne",         0, { } },
	/* 0x42 */ { "lt",         0, { } },
	/* 0x43 */ { "le",         0, { } },
	/* 0x44 */ { "gt",         0, { } },
	/* 0x45 */ { "ge",         0, { } },
	/* 0x46 */ { "db 0x46",    0, { } },
	/* 0x47 */ { "db 0x47",    0, { } },
	/* 0x48 */ { "db 0x48",    0, { } },
	/* 0x49 */ { "db 0x49",    0, { } },
	/* 0x4a */ { "db 0x4a",    0, { } },
	/* 0x4b */ { "db 0x4b",    0, { } },
	/* 0x4c */ { "db 0x4c",    0, { } },
	/* 0x4d */ { "db 0x4d",    0, { } },
	/* 0x4e */ { "db 0x4e",    0, { } },
	/* 0x4f */ { "db 0x4f",    0, { } },
	/* 0x50 */ { "retval",     0, { } },
	/* 0x51 */ { "retnil",     0, { } },
	/* 0x52 */ { "rettrue",    0, { } },
	/* 0x53 */ { "db 0x53",    0, { } },
	/* 0x54 */ { "ret",        0, { } },
	/* 0x55 */ { "db 0x55",    0, { } },
    /* 0x56 */ { "namedargptr", 2, { T3OP_TYPE_8U, T3OP_TYPE_16U }},
	/* 0x57 */ { "namedargtab", 0, { } },             /* varying-length operands */
    /* 0x58 */ { "call", 2, { T3OP_TYPE_8U, T3OP_TYPE_CODE_ABS }},
    /* 0x59 */ { "ptrcall", 1, { T3OP_TYPE_8U }},
	/* 0x5a */ { "db 0x5a",    0, { } },
	/* 0x5b */ { "db 0x5b",    0, { } },
	/* 0x5c */ { "db 0x5c",    0, { } },
	/* 0x5d */ { "db 0x5d",    0, { } },
	/* 0x5e */ { "db 0x5e",    0, { } },
	/* 0x5f */ { "db 0x5f",    0, { } },
    /* 0x60 */ { "getprop", 1, { T3OP_TYPE_PROP }},
    /* 0x61 */ { "callprop", 2, { T3OP_TYPE_8U, T3OP_TYPE_PROP }},
    /* 0x62 */ { "ptrcallprop", 1, { T3OP_TYPE_8U }},
    /* 0x63 */ { "getpropself", 1, { T3OP_TYPE_PROP }},
    /* 0x64 */ { "callpropself", 2, { T3OP_TYPE_8U, T3OP_TYPE_PROP }},
    /* 0x65 */ { "ptrcallpropself", 1, { T3OP_TYPE_8U }},
    /* 0x66 */ { "objgetprop", 2, { T3OP_TYPE_OBJ, T3OP_TYPE_PROP }},
    /* 0x67 */ { "objcallprop", 3,
                   { T3OP_TYPE_8U, T3OP_TYPE_OBJ, T3OP_TYPE_PROP }},
    /* 0x68 */ { "getpropdata", 1, { T3OP_TYPE_PROP }},
	/* 0x69 */ { "ptrgetpropdata",    0, { } },
    /* 0x6a */ { "getproplcl1", 2, { T3OP_TYPE_8U, T3OP_TYPE_PROP }},
    /* 0x6b */ { "callproplcl1", 3,
                   { T3OP_TYPE_8U, T3OP_TYPE_8U, T3OP_TYPE_PROP }},
    /* 0x6c */ { "getpropr0", 1, { T3OP_TYPE_PROP }},
    /* 0x6d */ { "callpropr0", 2, { T3OP_TYPE_8U, T3OP_TYPE_PROP }},
	/* 0x6e */ { "db 0x6e",    0, { } },
	/* 0x6f */ { "db 0x6f",    0, { } },
	/* 0x70 */ { "db 0x70",    0, { } },
	/* 0x71 */ { "db 0x71",    0, { } },
    /* 0x72 */ { "inherit",    2, { T3OP_TYPE_8U, T3OP_TYPE_PROP }},
    /* 0x73 */ { "ptrinherit", 1, { T3OP_TYPE_8U }},
    /* 0x74 */ { "expinherit", 3,
                   { T3OP_TYPE_8U, T3OP_TYPE_PROP, T3OP_TYPE_OBJ }},
    /* 0x75 */ { "ptrexpinherit", 2, { T3OP_TYPE_8U, T3OP_TYPE_OBJ }},
	/* 0x76 */ { "varargc",    0, { } },
    /* 0x77 */ { "delegate",   2, { T3OP_TYPE_8U, T3OP_TYPE_PROP }},
    /* 0x78 */ { "ptrdelegate", 1, { T3OP_TYPE_PROP }},
	/* 0x79 */ { "db 0x79",    0, { } },
	/* 0x7a */ { "swap2",      0, { } },
    /* 0x7b */ { "swapn",      2, { T3OP_TYPE_8U, T3OP_TYPE_8U }},
	/* 0x7c */ { "getargn0",   0, { } },
	/* 0x7d */ { "argargn1",   0, { } },
	/* 0x7e */ { "getargn2",   0, { } },
	/* 0x7f */ { "getargn3",   0, { } },
    /* 0x80 */ { "getlcl1",    1, { T3OP_TYPE_8U }},
    /* 0x81 */ { "getlcl2",    1, { T3OP_TYPE_16U }},
    /* 0x82 */ { "getarg1",    1, { T3OP_TYPE_8U }},
    /* 0x83 */ { "getarg2",    1, { T3OP_TYPE_16U }},
	/* 0x84 */ { "pushself",   0, { } },
    /* 0x85 */ { "getdblcl",   2, { T3OP_TYPE_16U, T3OP_TYPE_16U }},
    /* 0x86 */ { "getdbarg",   2, { T3OP_TYPE_16U, T3OP_TYPE_16U }},
	/* 0x87 */ { "getargc",    0, { } },
	/* 0x88 */ { "dup",        0, { } },
	/* 0x89 */ { "disc",       0, { } },
    /* 0x8a */ { "disc1",      1, { T3OP_TYPE_8U }},
	/* 0x8b */ { "getr0",      0, { } },
    /* 0x8c */ { "getdbargc",  1, { T3OP_TYPE_16U }},
	/* 0x8d */ { "swap",       0, { } },
    /* 0x8e */ { "pushctxele", 1, { T3OP_TYPE_CTX_ELE }},
	/* 0x8f */ { "dup2",       0, { } },
	/* 0x90 */ { "switch",     0, { } },                  /* varying-length operands */
    /* 0x91 */ { "jmp",        1, { T3OP_TYPE_CODE_REL }},
    /* 0x92 */ { "jt",         1, { T3OP_TYPE_CODE_REL }},
    /* 0x93 */ { "jf",         1, { T3OP_TYPE_CODE_REL }},
    /* 0x94 */ { "je",         1, { T3OP_TYPE_CODE_REL }},
    /* 0x95 */ { "jne",        1, { T3OP_TYPE_CODE_REL }},
    /* 0x96 */ { "jgt",        1, { T3OP_TYPE_CODE_REL }},
    /* 0x97 */ { "jge",        1, { T3OP_TYPE_CODE_REL }},
    /* 0x98 */ { "jlt",        1, { T3OP_TYPE_CODE_REL }},
    /* 0x99 */ { "jle",        1, { T3OP_TYPE_CODE_REL }},
    /* 0x9a */ { "jst",        1, { T3OP_TYPE_CODE_REL }},
    /* 0x9b */ { "jsf",        1, { T3OP_TYPE_CODE_REL }},
    /* 0x9c */ { "ljsr",       1, { T3OP_TYPE_CODE_REL }},
    /* 0x9d */ { "lret",       1, { T3OP_TYPE_16U }},
    /* 0x9e */ { "jnil",       1, { T3OP_TYPE_CODE_REL }},
    /* 0x9f */ { "jnotnil",    1, { T3OP_TYPE_CODE_REL }},
    /* 0xa0 */ { "jr0t",       1, { T3OP_TYPE_CODE_REL }},
    /* 0xa1 */ { "jr0f",       1, { T3OP_TYPE_CODE_REL }},
    /* 0xa2 */ { "iternext",   2, { T3OP_TYPE_16U, T3OP_TYPE_CODE_REL }},
	/* 0xa3 */ { "db 0xa3",    0, { } },
	/* 0xa4 */ { "db 0xa4",    0, { } },
	/* 0xa5 */ { "db 0xa5",    0, { } },
    /* 0xa6 */ { "getspn",     1, { T3OP_TYPE_8U }},
	/* 0xa7 */ { "db 0xa7",    0, { } },
	/* 0xa8 */ { "db 0xa8",    0, { } },
	/* 0xa9 */ { "db 0xa9",    0, { } },
	/* 0xaa */ { "getlcln1",   0, { } },
	/* 0xab */ { "getlcln1",   0, { } },
	/* 0xac */ { "getlcln2",   0, { } },
	/* 0xad */ { "getlcln3",   0, { } },
	/* 0xae */ { "getlcln4",   0, { } },
	/* 0xaf */ { "getlcln5",   0, { } },
    /* 0xb0 */ { "say",        1, { T3OP_TYPE_STR }},
    /* 0xb1 */ { "builtin_a",  2, { T3OP_TYPE_8U, T3OP_TYPE_8U }},
    /* 0xb2 */ { "builtin_b",  2, { T3OP_TYPE_8U, T3OP_TYPE_8U }},
    /* 0xb3 */ { "builtin_c",  2, { T3OP_TYPE_8U, T3OP_TYPE_8U }},
    /* 0xb4 */ { "builtin_d",  2, { T3OP_TYPE_8U, T3OP_TYPE_8U }},
    /* 0xb5 */ { "builtin1",   3, { T3OP_TYPE_8U, T3OP_TYPE_8U, T3OP_TYPE_8U }},
    /* 0xb6 */ { "builtin2",   0, { T3OP_TYPE_16U, T3OP_TYPE_8U, T3OP_TYPE_8U }},
	/* 0xb7 */ { "callext",    0, { } },
	/* 0xb8 */ { "throw",      0, { } },
	/* 0xb9 */ { "sayval",     0, { } },
	/* 0xba */ { "index",      0, { } },
    /* 0xbb */ { "idxlcl1int8", 2, { T3OP_TYPE_8U, T3OP_TYPE_8U }},
    /* 0xbc */ { "idxint8",    1, { T3OP_TYPE_8U }},
	/* 0xbd */ { "db 0xbd",    0, { } },
	/* 0xbe */ { "db 0xbe",    0, { } },
	/* 0xbf */ { "db 0xbf",    0, { } },
    /* 0xc0 */ { "new1",       2, { T3OP_TYPE_8U, T3OP_TYPE_8U }},
    /* 0xc1 */ { "new2",       2, { T3OP_TYPE_16U, T3OP_TYPE_8U }},
    /* 0xc2 */ { "trnew1",     2, { T3OP_TYPE_8U, T3OP_TYPE_8U }},
    /* 0xc3 */ { "trnew2",     2, { T3OP_TYPE_16U, T3OP_TYPE_8U }},
	/* 0xc4 */ { "db 0xc4",    0, { } },
	/* 0xc5 */ { "db 0xc5",    0, { } },
	/* 0xc6 */ { "db 0xc6",    0, { } },
	/* 0xc7 */ { "db 0xc7",    0, { } },
	/* 0xc8 */ { "db 0xc8",    0, { } },
	/* 0xc9 */ { "db 0xc9",    0, { } },
	/* 0xca */ { "db 0xca",    0, { } },
	/* 0xcb */ { "db 0xcb",    0, { } },
	/* 0xcc */ { "db 0xcc",    0, { } },
	/* 0xcd */ { "db 0xcd",    0, { } },
	/* 0xce */ { "db 0xce",    0, { } },
	/* 0xcf */ { "db 0xcf",    0, { } },
    /* 0xd0 */ { "inclcl",     1, { T3OP_TYPE_16U }},
    /* 0xd1 */ { "declcl",     1, { T3OP_TYPE_16U }},
    /* 0xd2 */ { "addilcl1",   2, { T3OP_TYPE_8U, T3OP_TYPE_8S }},
    /* 0xd3 */ { "addilcl4",   2, { T3OP_TYPE_16U, T3OP_TYPE_32S }},
    /* 0xd4 */ { "addtolcl",   1, { T3OP_TYPE_16U }},
    /* 0xd5 */ { "subfromlcl", 1, { T3OP_TYPE_16U }},
    /* 0xd6 */ { "zerolcl1",   1, { T3OP_TYPE_8U }},
    /* 0xd7 */ { "zerolcl2",   1, { T3OP_TYPE_16U }},
    /* 0xd8 */ { "nillcl1",    1, { T3OP_TYPE_8U }},
    /* 0xd9 */ { "nillcl2",    1, { T3OP_TYPE_16U }},
    /* 0xda */ { "onelcl1",    1, { T3OP_TYPE_8U }},
    /* 0xdb */ { "onelcl2",    1, { T3OP_TYPE_16U }},
	/* 0xdc */ { "db 0xdc",    0, { } },
	/* 0xdd */ { "db 0xdd",    0, { } },
	/* 0xde */ { "db 0xde",    0, { } },
	/* 0xdf */ { "db 0xdf",    0, { } },
    /* 0xe0 */ { "setlcl1",    1, { T3OP_TYPE_8U }},
    /* 0xe1 */ { "setlcl2",    1, { T3OP_TYPE_16U }},
    /* 0xe2 */ { "setarg1",    1, { T3OP_TYPE_8U }},
    /* 0xe3 */ { "setarg2",    1, { T3OP_TYPE_16U }},
	/* 0xe4 */ { "setind",     0, { } },
    /* 0xe5 */ { "setprop",    1, { T3OP_TYPE_PROP }},
	/* 0xe6 */ { "ptrsetprop", 0, { } },
    /* 0xe7 */ { "setpropself", 1, { T3OP_TYPE_PROP }},
    /* 0xe8 */ { "objsetprop", 2, { T3OP_TYPE_OBJ, T3OP_TYPE_PROP }},
    /* 0xe9 */ { "setdblcl",   2, { T3OP_TYPE_16U, T3OP_TYPE_16U }},
    /* 0xea */ { "setdbarg",   2, { T3OP_TYPE_16U, T3OP_TYPE_16U }},
	/* 0xeb */ { "setself",    0, { } },
	/* 0xec */ { "loadctx",    0, { } },
	/* 0xed */ { "storectx",   0, { } },
    /* 0xee */ { "setlcl1r0",  1, { T3OP_TYPE_8U }},
    /* 0xef */ { "setindlcl1i8", 2, { T3OP_TYPE_8U, T3OP_TYPE_8U }},
	/* 0xf0 */ { "db 0xf0",    0, { } },
	/* 0xf1 */ { "bp",         0, { } },
	/* 0xf2 */ { "nop",        0, { } },
	/* 0xf3 */ { "db 0xf3",    0, { } },
	/* 0xf4 */ { "db 0xf4",    0, { } },
	/* 0xf5 */ { "db 0xf5",    0, { } },
	/* 0xf6 */ { "db 0xf6",    0, { } },
	/* 0xf7 */ { "db 0xf7",    0, { } },
	/* 0xf8 */ { "db 0xf8",    0, { } },
	/* 0xf9 */ { "db 0xf9",    0, { } },
	/* 0xfa */ { "db 0xfa",    0, { } },
	/* 0xfb */ { "db 0xfb",    0, { } },
	/* 0xfc */ { "db 0xfc",    0, { } },
	/* 0xfd */ { "db 0xfd",    0, { } },
	/* 0xfe */ { "db 0xfe",    0, { } },
	/* 0xff */ { "db 0xff",    0, { } }
};

/* ------------------------------------------------------------------------ */
/*
 *   disassemble an instruction
 */
void CTcT3Unasm::disasm_instr(CTcUnasSrc *src, CTcUnasOut *out, char ch_op)
{
    t3_instr_info_t *info;
    int i;
    ulong acc;
    char ch[10];
    ulong prv_ofs = src->get_ofs();
    
    /* get the information on this instruction */
    info = &instr_info[(int)(uchar)ch_op];
    out->print("%8lx  %-14.14s ", src->get_ofs() - 1, info->nm);

    /* check the instruction type */
    switch((uchar)ch_op)
    {
    case OPC_SWITCH:
        /* 
         *   It's a switch instruction - special handling is required,
         *   since this instruction doesn't fit any of the normal
         *   patterns.  First, get the number of elements in the case
         *   table - this is a UINT2 value at the start of the table.  
         */
        src->next_byte(ch);
        src->next_byte(ch+1);
        acc = osrp2(ch);

        /* display the count */
        out->print("0x%x\n", (uint)acc);

        /* display the table */
        for (i = 0 ; i < (int)acc ; ++i)
        {
            const char *dt;
            char valbuf[128];
            const char *val = valbuf;

            /* note the current offset */
            prv_ofs = src->get_ofs();
            
            /* read the DATAHOLDER value */
            src->next_byte(ch);
            src->next_byte(ch+1);
            src->next_byte(ch+2);
            src->next_byte(ch+3);
            src->next_byte(ch+4);

            /* read the jump offset */
            src->next_byte(ch+5);
            src->next_byte(ch+6);

            /* 
             *   stop looping if the offset hasn't changed - this probably
             *   means we're stuck trying to interpret as a "switch" some
             *   data at the end of the stream that happens to look like a
             *   switch but really isn't (such as an exception table, or
             *   debug records) 
             */
            if (src->get_ofs() == prv_ofs)
                break;

            /* show the value */
            switch(ch[0])
            {
            case VM_NIL:
                dt = "nil";
                val = "";
                break;
                
            case VM_TRUE:
                dt = "true";
                val = "";
                break;
                
            case VM_OBJ:
                dt = "object";
                sprintf(valbuf, "0x%08lx", t3rp4u(ch+1));
                break;
                
            case VM_PROP:
                dt = "prop";
                sprintf(valbuf, "0x%04x", osrp2(ch+1));
                break;
                
            case VM_INT:
                dt = "int";
                sprintf(valbuf, "0x%08lx", t3rp4u(ch+1));
                break;

            case VM_ENUM:
                dt = "enum";
                sprintf(valbuf, "0x%08lx", t3rp4u(ch+1));
                break;
                
            case VM_SSTRING:
                dt = "sstring";
                sprintf(valbuf, "0x%08lx", t3rp4u(ch+1));
                break;
                
            case VM_LIST:
                dt = "list";
                sprintf(valbuf, "0x%08lx", t3rp4u(ch+1));
                break;
                
            case VM_FUNCPTR:
                dt = "funcptr";
                sprintf(valbuf, "0x%08lx", t3rp4u(ch+1));
                break;

            default:
                dt = "???";
                val = "???";
                break;
            }

            /* show the slot data */
            out->print("          0x%08lx      %-8.8s(%-10.10s) "
                       "-> +0x%04lx (0x%08lx)\n",
                       src->get_ofs() - 7, dt, val, osrp2(ch+5),
                       src->get_ofs() - 2 + osrp2s(ch+5));
        }

        /* read and show the 'default' jump offset */
        src->next_byte(ch);
        src->next_byte(ch+1);
        out->print("          0x%08lx      default              "
                   "-> +0x%04lx (0x%08lx)\n",
                   src->get_ofs() - 2, osrp2(ch),
                   src->get_ofs() - 2 + osrp2s(ch));

        /* done */
        break;

    case OPC_NAMEDARGTAB:
        /* named argument table */
        src->next_byte(ch);
        src->next_byte(ch+1);
        src->next_byte(ch+2);
        acc = osrp2(ch);
        out->print("len=0x%x, cnt=0x%x [", (uint)acc, (uint)(uchar)*ch);
        acc = (uchar)*ch;

        /* show the names */
        for (i = 0 ; i < (int)acc ; ++i)
        {
            /* get the length */
            src->next_byte(ch);
            src->next_byte(ch);
            uint len = osrp2(ch);

            /* get the name */
            char name[128];
            uint j;
            for (j = 0 ; j < len && j < sizeof(name) ; ++j)
                src->next_byte(name + j);

            /* show the name */
            out->print("%s%.*s", i > 0 ? ", " : ":", (int)j, name);

            /* skip any excess portion of the name */
            for ( ; j < len ; ++j)
                src->next_byte(ch);
        }

        /* end the list, and we're done */
        out->print("]");
        break;

    default:
        /* show all parameters */
        for (i = 0 ; i < info->op_cnt ; ++i)
        {
            /* add a separator if this isn't the first one */
            if (i != 0)
                out->print(", ");
            
            /* display the operand */
            switch(info->op_type[i])
            {
            case T3OP_TYPE_8S:
                /* 8-bit signed integer */
                src->next_byte(ch);
                out->print("0x%x", (int)ch[0]);
                break;

            case T3OP_TYPE_8U:
                /* 8-bit unsigned integer */
                src->next_byte(ch);
                out->print("0x%x", (uint)(uchar)ch[0]);
                break;

            case T3OP_TYPE_16S:
                /* 16-bit signed integer */
                src->next_byte(ch);
                src->next_byte(ch+1);
                acc = osrp2s(ch);
                out->print("0x%x", (int)acc);
                break;

            case T3OP_TYPE_16U:
                /* 16-bit unsigned integer */
                src->next_byte(ch);
                src->next_byte(ch+1);
                acc = osrp2(ch);
                out->print("0x%x", (uint)acc);
                break;

            case T3OP_TYPE_32S:
                /* 32-bit signed integer */
                src->next_byte(ch);
                src->next_byte(ch+1);
                src->next_byte(ch+2);
                src->next_byte(ch+3);
                acc = t3rp4u(ch);
                out->print("0x%lx", acc);
                break;

            case T3OP_TYPE_32U:
                /* 32-bit unsigned integer */
                src->next_byte(ch);
                src->next_byte(ch+1);
                src->next_byte(ch+2);
                src->next_byte(ch+3);
                acc = t3rp4u(ch);
                out->print("0x%lx", acc);
                break;

            case T3OP_TYPE_STR:
                /* string offset */
                src->next_byte(ch);
                src->next_byte(ch+1);
                src->next_byte(ch+2);
                src->next_byte(ch+3);
                acc = t3rp4u(ch);
                out->print("string(0x%lx)", acc);
                break;

            case T3OP_TYPE_LIST:
                /* list offset */
                src->next_byte(ch);
                src->next_byte(ch+1);
                src->next_byte(ch+2);
                src->next_byte(ch+3);
                acc = t3rp4u(ch);
                out->print("list(0x%lx)", acc);
                break;

            case T3OP_TYPE_CODE_ABS:
                /* 32-bit absolute code address */
                src->next_byte(ch);
                src->next_byte(ch+1);
                src->next_byte(ch+2);
                src->next_byte(ch+3);
                acc = t3rp4u(ch);
                out->print("code(0x%08lx)", acc);
                break;

            case T3OP_TYPE_CODE_REL:
                /* 16-bit relative code address */
                src->next_byte(ch);
                src->next_byte(ch+1);
                acc = osrp2s(ch);
                if ((long)acc < 0)
                    out->print("-0x%04x (0x%08lx)",
                               -(int)acc, src->get_ofs() - 2 + acc);
                else
                    out->print("+0x%04x (0x%08lx)",
                               (int)acc, src->get_ofs() - 2 + acc);
                break;

            case T3OP_TYPE_OBJ:
                /* object ID */
                src->next_byte(ch);
                src->next_byte(ch+1);
                src->next_byte(ch+2);
                src->next_byte(ch+3);
                acc = t3rp4u(ch);
                out->print("object(0x%lx)", acc);
                break;

            case T3OP_TYPE_PROP:
                /* property ID */
                src->next_byte(ch);
                src->next_byte(ch+1);
                acc = osrp2(ch);
                out->print("property(0x%x)", (uint)acc);
                break;

            case T3OP_TYPE_ENUM:
                /* enum */
                src->next_byte(ch);
                src->next_byte(ch+1);
                src->next_byte(ch+2);
                src->next_byte(ch+3);
                acc = t3rp4u(ch);
                out->print("enum(0x%lx)", acc);
                break;

            case T3OP_TYPE_CTX_ELE:
                /* context element identifier */
                src->next_byte(ch);
                switch(ch[0])
                {
                case PUSHCTXELE_TARGPROP:
                    out->print("targetprop");
                    break;

                case PUSHCTXELE_TARGOBJ:
                    out->print("targetobj");
                    break;

                case PUSHCTXELE_DEFOBJ:
                    out->print("definingobj");
                    break;

                default:
                    out->print("0x%x", (int)ch[0]);
                    break;
                }
                break;

            case T3OP_TYPE_INLINE_STR:
                /* get the string length */
                src->next_byte(ch);
                src->next_byte(ch+1);

                /* show it */
                out->print("string(inline)");

                /* skip the string */
                for (acc = osrp2(ch) ; acc != 0 ; --acc)
                    src->next_byte(ch);

                /* done */
                break;

            default:
                out->print("...unknown type...");
                break;
            }
        }

        /* end the line */
        out->print("\n");
    }
}

/* ------------------------------------------------------------------------ */
/*
 *   Show an exception table 
 */
void CTcT3Unasm::show_exc_table(class CTcUnasSrc *src, class CTcUnasOut *out,
                                unsigned long base_ofs)
{
    unsigned entries;
    char ch[10];
    
    /* read the number of entries */
    src->next_byte(ch);
    src->next_byte(ch+1);

    /* show the entries */
    for (entries = osrp2(ch) ; entries != 0 ; --entries)
    {
        unsigned long start_ofs;
        unsigned long end_ofs;
        unsigned exc_obj_id;
        unsigned long catch_ofs;
        
        /* read the code start offset */
        src->next_byte(ch);
        src->next_byte(ch+1);
        start_ofs = base_ofs + osrp2(ch);

        /* read the code end offset */
        src->next_byte(ch);
        src->next_byte(ch+1);
        end_ofs = base_ofs + osrp2(ch);

        /* read the object ID */
        src->next_byte(ch);
        src->next_byte(ch+1);
        src->next_byte(ch+2);
        src->next_byte(ch+3);
        exc_obj_id = base_ofs + t3rp4u(ch);

        /* read the catch offset */
        src->next_byte(ch);
        src->next_byte(ch+1);
        catch_ofs = base_ofs + osrp2(ch);

        /* show it */
        out->print("    from %lx to %lx object %x catch %lx\n",
                   start_ofs, end_ofs, exc_obj_id, catch_ofs);
    }
}

