DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T f

⟦55c45acb8⟧ TextFile

    Length: 24082 (0x5e12)
    Types: TextFile
    Names: »format.c«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦3f75c1919⟧ »EurOpenD3/utils/decomp.tar.Z« 
        └─⟦510c4d5ee⟧ 
            └─⟦this⟧ »decomp/format.c« 

TextFile

/*
 * Module: format.c
 *
 * Author: J. Reuter
 *
 * This module takes the tree of C-specific control operators
 * and basic blocks produced by hll() and prints out almost-C
 * code.
 */

#include "defs.h"
#include "nodes.h"
#include "machine.h"
#include "objfile.h"
#include "vartab.h"

#define LABEL(v) (node_array[v]->reach)

static char bigstring[1000] = "string";

format()
{
    treeprint( 0, 1 );
}

static
treeprint( v, tab )
register int v;
register int tab;
{
    register struct node *n;

    if ( !DEFINED(v) ) {
	tabover( tab );
	printf( "; /* NONE */\n" );
	return;
    }

    n = node_array[v];

    if ( LABEL(v) ) {
	printf( "\n" );
	tabover( tab - 1 );
	printf( "G%04d:\n", v );
    }

    switch ( n->node_type ) {

    case N_GOTO:
	tabover( tab );
	printf( "goto G%04d;\n", n->arcs[0] );
	break;

    case N_BREAK:
	tabover( tab );
	printf( "break;\n" );
	break;

    case N_CONTINUE:
	tabover( tab );
	printf( "continue;\n" );
	break;

    case N_CASELAB:
	tabover( tab - 1 );
	printf( "case %d:\n", n->varpart[V_CASESLOT] );
	break;

    case N_FLOW:
    case N_END:
	machprint( n->start_address, n->end_address, n->node_type, 0, tab );
	break;

    case N_BRANCH:
	machprint( n->start_address, n->end_address, n->node_type,
		  n->varpart[V_NEGATE], tab );

	tabover( tab );
	printf( "if ( %s ) {\n", bigstring );
	treeprint( n->child[THEN_ARC], tab + 1 );

	if ( DEFINED( n->child[ELSE_ARC] ) ) {
	    tabover( tab );
	    printf( "} else {\n" );
	    treeprint( n->child[ELSE_ARC], tab + 1 );
	}

	tabover( tab );
	printf( "}\n\n" );
	break;

    case N_IF:
	machprint( n->start_address, n->end_address, n->node_type,
		  n->varpart[V_NEGATE], tab );

	tabover( tab );
	printf( "if ( %s ) {\n", bigstring );
	treeprint( n->child[THEN_ARC], tab + 1 );

	if ( DEFINED( n->child[ELSE_ARC] ) ) {
	    tabover( tab );
	    printf( "} else {\n" );
	    treeprint( n->child[ELSE_ARC], tab + 1 );
	}

	tabover( tab );
	printf( "}\n\n" );
	break;

    case N_ORIF:
	tabover( tab );
	printf( "if ( " );
	fmt_pred( n, NONE );
	printf( " ) {\n" );
	treeprint( n->child[THEN_ARC], tab + 1 );

	if ( DEFINED( n->child[ELSE_ARC] ) ) {
	    tabover( tab );
	    printf( "} else {\n" );
	    treeprint( n->child[ELSE_ARC], tab + 1 );
	}

	tabover( tab );
	printf( "}\n\n" );
	break;

    case N_SWITCH:
	machprint( n->start_address, n->end_address, n->node_type, 0, tab );
	tabover( tab );
	printf( "switch ( %s ) {\n", bigstring );
	treeprint( n->child[0], tab + 1 );
	tabover( tab );
	printf( "}\n\n" );
	break;

    case N_CASE:
	break;

    case N_ITER:
	treeprint( n->child[0], tab );
	break;

    case N_LOOP:
	tabover( tab );
	printf( "while (1) {\n" );
	treeprint( n->child[0], tab + 1 );
	tabover( tab );
	printf( "}\n\n" );
	break;

    case N_WHILE:
	tabover( tab );
	printf( "while ( " );
	fmt_pred( node_array[ n->varpart[V_LOOP_PRED] ], NONE );
	printf( " ) {\n" );
	treeprint( n->child[0], tab + 1 );
	tabover( tab );
	printf( "}\n" );
	break;

    case N_UNTIL:
	tabover( tab );
	printf( "do {\n" );
	treeprint( n->child[0], tab + 1 );
	tabover( tab );
	printf( "} while ( " );
	fmt_pred( node_array[ n->varpart[V_LOOP_PRED] ], NONE );
	printf( " );\n\n" );
	break;
    }

    v = n->right_sibling;
    if ( DEFINED(v) )
	treeprint( v, tab );
}

/*
 * negate() propogates negated if predicates to the subpredicates
 * using DeMorgan's rule.  That is, an N_ORIF node with a negated
 * predicate is converted to an ANDIF node and each of the two
 * subpredicates is inverted.  Note that ANDIF is indicated by
 * leaving V_NEGATE set.
 *
 * This function recursively walks down the predicate tree until
 * no more N_ORIF nodes are found.
 */
static
negate( n )
register struct node *n;
{
    register struct node *p1, *p2;

    if ( n->node_type != N_ORIF )
	return;

    p1 = node_array[ n->varpart[V_PRED1] ];
    p2 = node_array[ n->varpart[V_PRED2] ];

    if ( n->varpart[V_NEGATE] ) {
	p1->varpart[V_NEGATE] = !p1->varpart[V_NEGATE];
	p2->varpart[V_NEGATE] = !p2->varpart[V_NEGATE];
    }

    negate( p1 );
    negate( p2 );
}

/*
 * fmt_pred() prints a C formatted predicate for N_IF, N_ORIF, N_WHILE,
 * and N_UNTIL statements.
 */
static
fmt_pred( n, fath_neg )
register struct node *n;
register int fath_neg;
{
    negate( n );

    /* must use parens for precedence when mixing &&, || */
    if ( fath_neg != NONE && n->varpart[V_NEGATE] != fath_neg &&
	n->node_type == N_ORIF )

	printf( "( " );

    if ( n->node_type == N_ORIF ) {
	fmt_pred( node_array[ n->varpart[V_PRED1] ], n->varpart[V_NEGATE] );

	if ( n->varpart[V_NEGATE] )
	    printf( " && " );
	else
	    printf( " || " );

	fmt_pred( node_array[ n->varpart[V_PRED2] ], n->varpart[V_NEGATE] );

    } else {
	machprint( n->start_address, n->end_address, n->node_type,
		  n->varpart[V_NEGATE], 0 );
	printf( "%s", bigstring );
    }

    if ( fath_neg != NONE && n->varpart[V_NEGATE] != fath_neg &&
	n->node_type == N_ORIF )

	printf( " )" );
}

static char tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";

/* move over 'n' "tab stops" (one stop = 4 spaces, ASCII tab = 8 spaces) */
static
tabover( n )
register int n;
{
    register char *s;

    s = tabs + 15 - ( n / 2 );
    printf( "%s", s );

    if ( n & 1 )
	printf( "    " );
}

extern char *typesuf[];

static struct operand {
    int op_argval;
    int op_indexed;
    int op_index_rn;
    int op_index_type;
    char opstring[40];
} operand[6];

static
machprint( addr, end_addr, nodetype, negate, tab )
address addr, end_addr;
int nodetype;
int negate;
int tab;
{
    struct opcode *op;
    VaxOpcode ins;
    unsigned char mode;
    int argtype, amode, argno, argval;
    int rn, type;
    struct nlist *s;
    char *str;
    struct relocation_info *r;
    char tempstring1[100];
    char tempstring2[100];

    /* initialize pass */
    relo_first();
    r = relo_next();

    /* the main loop */
    while ( addr < end_addr ) {
	argval = 0;

	ins = get_byte( addr );
	addr += 1;
	op = &opcode[ins];

	for (argno = 0; argno < op->numargs; argno++)
	    operand[argno].op_indexed = FALSE;

	for (argno = 0; argno < op->numargs; argno++) {

	    str = operand[argno].opstring;

	    argtype = op->argtype[argno];
	    if (is_branch_disp(argtype)) {
		mode = 0xAF + ( (typelen(argtype) & ~T_UNSIGNED) << 4);
	    } else {
		mode = get_byte( addr );
		addr += 1;
	    }

	    while ( r != NULL && addr > r->r_address )
		r = relo_next();

	    rn = regnm( mode );
	    type = typelen( argtype );
	    amode = addrmode(mode);

	    if ( r != NULL && addr == r->r_address ) {

		if ( amode == LONGDISP || amode == LONGDISPDEF ) {

		    argval = getdisp(addr, 4, rn, amode);
		    addr += 4;

		} else if ( amode == AUTOINC ) {

		    if ( rn != PC ) {
			printf( "ERR: strange relo autoinc reg\n" );
		    } else {
			/* immediate values */
			switch ( type & ~T_UNSIGNED ) {
			case TYPL:
			    argval = getdisp(addr, 4, rn, amode);
			    addr += 4;
			    break;

			default:
			    printf( "ERR: strange relo autoinc %d\n", type );
			    break;
			}
		    }

		} else {
		    printf( "ERR: bad relo mode %d\n", amode );
		}

		if ( r->r_extern ) {

		    s = &symtab[r->r_symbolnum];

		    if ( s->n_type == (N_EXT+N_UNDF) ) {

			if ( amode == LONGDISP || amode == LONGDISPDEF ) {
			    char *def;

			    if ( amode == LONGDISPDEF ) {
				def = "*";
				type |= T_POINTER;
			    } else {
				def = "";
			    }

			    if ( rn == PC )
				sprintf( str, "%s%s", def,
					ext_sym( r->r_symbolnum, type, argval ) );
			    else
				sprintf( str, "%s%s(r%02d)", def,
					ext_sym( r->r_symbolnum, type, argval ),
					rn );

			} else if ( amode == AUTOINC ) {
			    sprintf( str, "%s", ext_sym( r->r_symbolnum, type,
							argval ) );
			} else {
			    printf( "ERR: ext relo mode %d\n", amode );
			}
		    } else {
			printf( "ERR: ext relo type %d\n", s->n_type );
		    }

		} else {		/* not r->r_extern */

		    if ( amode == LONGDISP || amode == LONGDISPDEF ) {
			char *def;

			if ( amode == LONGDISPDEF ) {
			    def = "*";
			    type |= T_POINTER;
			} else {
			    def = "";
			}

			if ( rn == PC ) {
			    switch ( r->r_symbolnum ) {
			    case 4:
				/* static function */
				sprintf( str, "%s%s", def,
					int_sym( argval, type, C_TEXT ) );
				break;
			    case 5:
				/* global function */
				sprintf( str, "%s%s", def,
					int_sym( argval, type, C_TEXT ) );
				break;
			    case 6:
				/* static data, const, string */
				sprintf( str, "%s%s", def,
					int_sym( argval, type, C_DATA ) );
				break;
			    case 7:
				/* global data, const, string */
				sprintf( str, "%s%s", def,
					int_sym( argval, type, C_DATA ) );
				break;
			    case 8:
				/* bss */
				sprintf( str, "%s%s", def,
					int_sym( argval, type, C_BSS ) );
				break;
			    default:
				printf( "ERR: bad relo symbolnum %d\n",
				       r->r_symbolnum );
				break;
			    }
			} else {
			    /* other registers? */
			    sprintf( str, "%s%d(r%02d)", def, argval, rn );
			    printf( "\targ %d int longdisp sym#%d pcrel %d len %d reg %d\n",
				   argno, r->r_symbolnum, r->r_pcrel, r->r_length, rn );
			}

		    } else if ( amode == AUTOINC ) {

			switch ( r->r_symbolnum ) {
			case 6:
			    /* static data */
			    sprintf( str, "%s", int_sym( argval, type, C_DATA ) );
			    break;
			case 8:
			    /* static bss */
			    sprintf( str, "%s", int_sym( argval, type, C_BSS ) );
			    break;
			default:
			    printf( "ERR: auto relo symnum %d\n", r->r_symbolnum );
			    break;
			}
		    } else {
			printf( "ERR: int relo mode %d\n", amode );
		    }
		}

	    } else {		/* no relo info */

		switch (amode) {
		case LITSHORT:
		case LITUPTO31:
		case LITUPTO47:
		case LITUPTO63:
		    if ( type == TYPF || type == TYPD )
			sprintf( str, "%s", fltimm[mode] );
		    else
			sprintf( str, "%d", mode );
		    argval = mode;
		    break;

		case INDEX:
		    operand[argno].op_indexed = TRUE;
		    operand[argno].op_index_rn = rn;
		    operand[argno].op_index_type = T_LONG;
		    argno--;
		    break;

		case REG:
		    sprintf( str, "%s", reg_sym( rn, type ) );
		    break;

		case REGDEF:
		    sprintf( str, "*%s", reg_sym( rn, type | T_POINTER ) );
		    break;

		case AUTODEC:
		    if ( rn == SP )
			sprintf( str, "@arg@" );
		    else
			sprintf( str, "*(--%s)",
				reg_sym( rn, type | T_POINTER ) );
		    break;

		case AUTOINC:
		    if ( rn != PC ) {
			sprintf( str, "*%s++",
				reg_sym( rn, type | T_POINTER ) );
		    } else {
			/* immediate values */
			switch ( type & ~T_UNSIGNED ) {
			case TYPB:
			    argval = getdisp(addr, 1, rn, amode);
			    addr += 1;
			    break;

			case TYPW:
			    argval = getdisp(addr, 2, rn, amode);
			    addr += 2;
			    break;

			case TYPL:
			    argval = getdisp(addr, 4, rn, amode);
			    addr += 4;
			    break;

			default:
			    printf( "ERR: strange-autoinc %d\n", type );
			    break;
			}
			sprintf( str, "%d", argval );
		    }
		    break;

		case AUTOINCDEF:
		    if ( rn == PC ) {
			/* immediate deferred */
			argval = getdisp(addr, 4, rn, amode);
			addr += 4;
			sprintf( str, "*%d", argval );
		    } else {
			sprintf( str, "**(%s++)",
				reg_sym( rn, type | T_POINTER ) );
		    }
		    break;

		case BYTEDISP:
		    argval = getdisp(addr, 1, rn, amode);
		    regdisp( rn, argval, type, FALSE, str );
		    addr += 1;
		    break;

		case BYTEDISPDEF:
		    ;
		    argval = getdisp(addr, 1, rn, amode);
		    regdisp( rn, argval, type, TRUE, str );
		    addr += 1;
		    break;

		case WORDDISP:
		    argval = getdisp(addr, 2, rn, amode);
		    regdisp( rn, argval, type, FALSE, str );
		    addr += 2;
		    break;

		case WORDDISPDEF:
		    ;
		    argval = getdisp(addr, 2, rn, amode);
		    regdisp( rn, argval, type, TRUE, str );
		    addr += 2;
		    break;

		case LONGDISP:
		    argval = getdisp(addr, 4, rn, amode);
		    regdisp( rn, argval, type, FALSE, str );
		    addr += 4;
		    break;

		case LONGDISPDEF:
		    ;
		    argval = getdisp(addr, 4, rn, amode);
		    regdisp( rn, argval, type, TRUE, str );
		    addr += 4;
		    break;
		}
	    }
	    operand[argno].op_argval = argval;
	}

	/* print the decompiled instruction */

#define doindex( i ) if ( operand[i].op_indexed ) printf( "[%s]", \
		reg_sym( operand[i].op_index_rn, operand[i].op_index_type ) )

	switch( op->coptype ) {

	case MACRO:
	    /* machine code during N_FLOW or N_END is an error */
	    if ( nodetype == N_FLOW || nodetype == N_END ) {

		tabover( tab );
		printf( "ERR! %s\t", op->cop1 );

		for ( argno = 0; argno < op->numargs; argno++ ) {
		    if ( argno != 0 )
			printf( "," );
		    printf( "%s", operand[argno].opstring );
		    doindex(argno);
		}
		printf( "\n" );

	    } else if ( nodetype == N_SWITCH ) {

		if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) {

		    /* skip case table */
		    for ( argno = 0; argno <= argval; argno++ )
			addr += 2;

		    sprintf( bigstring, "%s", operand[0].opstring );
		    if ( operand[0].op_indexed ) {
			sprintf( tempstring1, "[%s]",
				reg_sym( operand[0].op_index_rn,
					operand[0].op_index_type ) );
			strcat( bigstring, tempstring1 );
		    }
		}
	    }
	    break;

	case COMP:
	    if ( nodetype != N_IF )
		fprintf( stderr, "cmp instruction not in N_IF block\n" );

	    if ( ins == O_CMPZV ) {

		if ( operand[0].op_argval != 0 ) {
		    sprintf( bigstring, "( (%s", operand[2].opstring );
		    if ( operand[2].op_indexed ) {
			sprintf( tempstring1, "[%s]",
				reg_sym( operand[2].op_index_rn,
					operand[2].op_index_type ) );
			strcat( bigstring, tempstring1 );
		    }

		    sprintf( tempstring1, " >> %d)", operand[0].op_argval );
		    strcat( bigstring, tempstring1 );

		} else {
		    sprintf( bigstring, "( %s", operand[2].opstring );
		    if ( operand[2].op_indexed ) {
			sprintf( tempstring1, "[%s]",
				reg_sym( operand[2].op_index_rn,
					operand[2].op_index_type ) );
			strcat( bigstring, tempstring1 );
		    }
		}

		if ( operand[1].op_argval != 32 ) {
		    sprintf( tempstring1, " & 0x%x )",
			    0x7fffffff >> ( 31 - operand[1].op_argval ) );
		    strcat( bigstring, tempstring1 );
		} else
		    strcat( bigstring, " )" );

		sprintf( tempstring1, "%s", operand[3].opstring );
		if ( operand[3].op_indexed ) {
		    sprintf( tempstring2, "[%s]",
			    reg_sym( operand[3].op_index_rn,
				    operand[3].op_index_type ) );
		    strcat( tempstring1, tempstring2 );
		}

	    } else {
		sprintf( bigstring, "%s", operand[0].opstring );
		if ( operand[0].op_indexed ) {
		    sprintf( tempstring1, "[%s]",
			    reg_sym( operand[0].op_index_rn,
				    operand[0].op_index_type ) );
		    strcat( bigstring, tempstring1 );
		}

		sprintf( tempstring1, "%s", operand[1].opstring );
		if ( operand[1].op_indexed ) {
		    sprintf( tempstring2, "[%s]",
			    reg_sym( operand[1].op_index_rn,
				    operand[1].op_index_type ) );
		    strcat( tempstring1, tempstring2 );
		}
	    }
	    break;

	case TEST:
	    if ( nodetype != N_IF )
		fprintf( stderr, "tst instruction not in N_IF block\n" );

	    sprintf( bigstring, "%s", operand[0].opstring );
	    if ( operand[0].op_indexed ) {
		sprintf( tempstring1, "[%s]",
			reg_sym( operand[0].op_index_rn,
				operand[0].op_index_type ) );
		strcat( bigstring, tempstring1 );
	    }

	    sprintf( tempstring1, "0" );
	    break;

	case CBRANCH:
	    if ( nodetype == N_BRANCH ) {
		strcpy( bigstring, "@prev@" );
		strcpy( tempstring1, "0" );
	    }

	    if ( nodetype == N_IF || nodetype == N_BRANCH ) {
		if (ins == O_BNEQ && !negate || ins == O_BEQL && negate )
		    strcat( bigstring, " != " );
		else if (ins == O_BEQL && !negate || ins == O_BNEQ && negate)
		    strcat( bigstring, " == " );
		else if (ins == O_BGTR && !negate || ins == O_BLEQ && negate)
		    strcat( bigstring, " > " );
		else if (ins == O_BLEQ && !negate || ins == O_BGTR && negate)
		    strcat( bigstring, " <= " );
		else if (ins == O_BGEQ && !negate || ins == O_BLSS && negate)
		    strcat( bigstring, " >= " );
		else if (ins == O_BLSS && !negate || ins == O_BGEQ && negate)
		    strcat( bigstring, " < " );
		else if (ins == O_BGTRU && !negate || ins == O_BLEQU && negate)
		    strcat( bigstring, " >u " );
		else if (ins == O_BLEQU && !negate || ins == O_BGTRU && negate)
		    strcat( bigstring, " <=u " );

		strcat( bigstring, tempstring1 );

	    } else
		fprintf( stderr, "bcnd instruction not in N_IF or N_BRANCH\n");

	    break;

	case BBRANCH:
	    if ( nodetype != N_IF )
		fprintf( stderr, "bbit instruction not in N_IF\n");

	    if ( ins == O_BBCC || ins == O_BBSS || ins == O_BBCS ||
		ins == O_BBSC || ins == O_BBCCI || ins == O_BBSSI ) {

		    sprintf( bigstring, "%s ", negate ? "!" : "" );
		    strcat( bigstring, op->cop1 );

		    sprintf( tempstring1, " %s", operand[0].opstring );
		    strcat( bigstring, tempstring1 );
		    if ( operand[0].op_indexed ) {
			sprintf( tempstring1, "[%s]",
				reg_sym( operand[0].op_index_rn,
				    operand[0].op_index_type ) );
			strcat( bigstring, tempstring1 );
		    }

		    sprintf( tempstring1, ",%s", operand[1].opstring );
		    strcat( bigstring, tempstring1 );
		    if ( operand[1].op_indexed ) {
			sprintf( tempstring1, "[%s]",
				reg_sym( operand[1].op_index_rn,
				    operand[1].op_index_type ) );
			strcat( bigstring, tempstring1 );
		    }
	    } else if ( ins == O_SOBGEQ || ins == O_SOBGTR ) {
		sprintf( bigstring, "--%s", operand[0].opstring );
		if ( operand[0].op_indexed ) {
		    sprintf( tempstring1, "[%s]",
			    reg_sym( operand[0].op_index_rn,
				    operand[0].op_index_type ) );
		    strcat( bigstring, tempstring1 );
		}

		if ( ins == O_SOBGEQ && !negate )
		    strcat( bigstring, " >= 0" );
		else if ( ins == O_SOBGEQ && negate )
		    strcat( bigstring, " < 0" );
		else if ( ins == O_SOBGTR && !negate )
		    strcat( bigstring, " > 0" );
		else if ( ins == O_SOBGTR && negate )
		    strcat( bigstring, " <= 0" );

	    } else if ( ins == O_AOBLSS || ins == O_AOBLEQ ) {
		sprintf( bigstring, "++%s", operand[1].opstring );
		if ( operand[1].op_indexed ) {
		    sprintf( tempstring1, "[%s]",
			    reg_sym( operand[1].op_index_rn,
				    operand[1].op_index_type ) );
		    strcat( bigstring, tempstring1 );
		}

		if ( ins == O_AOBLSS && !negate )
		    strcat( bigstring, " < " );
		else if ( ins == O_AOBLSS && negate )
		    strcat( bigstring, " >= " );
		else if ( ins == O_AOBLEQ && !negate )
		    strcat( bigstring, " <= " );
		else if ( ins == O_AOBLEQ && negate )
		    strcat( bigstring, " > " );

		sprintf( tempstring1, "%s", operand[0].opstring );
		strcat( bigstring, tempstring1 );
		if ( operand[0].op_indexed ) {
		    sprintf( tempstring1, "[%s]",
			    reg_sym( operand[0].op_index_rn,
				    operand[0].op_index_type ) );
		    strcat( bigstring, tempstring1 );
		}
	    } else if ( ins == O_ACBL || ins == O_ACBW || ins == O_ACBB ||
		       ins == O_ACBF || ins == O_ACBD ) {

		sprintf( bigstring, "( %s", operand[2].opstring );
		if ( operand[2].op_indexed ) {
		    sprintf( tempstring1, "[%s]",
			    reg_sym( operand[2].op_index_rn,
				    operand[2].op_index_type ) );
		    strcat( bigstring, tempstring1 );
		}

		sprintf( tempstring1, " += %s", operand[1].opstring );
		if ( operand[1].op_indexed ) {
		    sprintf( tempstring2, "[%s]",
			    reg_sym( operand[1].op_index_rn,
				    operand[1].op_index_type ) );
		    strcat( tempstring1, tempstring2 );
		}

		if ( operand[2].op_argval >= 0 )
		    if ( !negate ) {
			strcat( tempstring1, " ) <= " );
		    } else {
			strcat( tempstring1, " ) > " );
		    }
		else
		    if ( !negate ) {
			strcat( tempstring1, " ) >= " );
		    } else {
			strcat( tempstring1, " ) < " );
		    }

		strcat( bigstring, tempstring1 );
			    
		sprintf( tempstring1, "%s", operand[0].opstring );
		if ( operand[0].op_indexed ) {
		    sprintf( tempstring2, "[%s]",
			    reg_sym( operand[0].op_index_rn,
				    operand[0].op_index_type ) );
		    strcat( tempstring1, tempstring2 );
		}

		strcat( bigstring, tempstring1 );

	    } else {

		if ( ins == O_BLBS || ins == O_BLBC ) {
		    sprintf( bigstring, "( %s", operand[0].opstring );
		    if ( operand[0].op_indexed ) {
			sprintf( tempstring1, "[%s]",
				reg_sym( operand[0].op_index_rn,
					operand[0].op_index_type ) );
			strcat( bigstring, tempstring1 );
		    }

		} else if ( ins == O_BBS || ins == O_BBC ) {
		    sprintf( bigstring, "( %s", operand[1].opstring );
		    if ( operand[1].op_indexed ) {
			sprintf( tempstring1, "[%s]",
				reg_sym( operand[1].op_index_rn,
					operand[1].op_index_type ) );
			strcat( bigstring, tempstring1 );
		    }
		}

		if ( ins == O_BLBS && !negate  ||  ins == O_BLBC && negate )
		    strcat( bigstring, " & 1 ) != 0" );
		else if ( ins == O_BLBC && !negate || ins == O_BLBS && negate )
		    strcat( bigstring, " & 1 ) == 0" );
		else if (ins == O_BBS && !negate  ||  ins == O_BBC && negate) {
		    sprintf( tempstring1, " & 0x%x ) != 0",
			    1 << operand[0].op_argval );
		    strcat( bigstring, tempstring1 );
		} else if (ins == O_BBC && !negate || ins == O_BBS && negate) {
		    sprintf( tempstring1, " & 0x%x ) != 0",
			    1 << operand[0].op_argval );
		    strcat( bigstring, tempstring1 );
		}
	    }
	    break;

	case A1OPA0:
	    tabover( tab );
	    printf( "%s", operand[1].opstring );
	    doindex(1);
	    printf( "%s", op->cop1 );
	    printf( "%s", operand[0].opstring );
	    doindex(0);
	    printf( ";\n" );
	    break;

	case A2EQ1OP0:
	    tabover( tab );
	    printf( "%s", operand[2].opstring );
	    doindex(2);
	    printf( " = %s", operand[1].opstring );
	    doindex(1);
	    printf( "%s", op->cop1 );
	    printf( "%s", operand[0].opstring );
	    doindex(0);
	    printf( ";\n" );
	    break;

	case A0OP:
	    tabover( tab );
	    printf( "%s", operand[0].opstring );
	    doindex(0);
	    printf( "%s;\n", op->cop1 );
	    break;

	case OPONLY:
	    tabover( tab );
	    printf( "%s;\n", op->cop1 );
	    break;

	case CALLS:
	    tabover( tab );
	    printf( "@val@ = %s", operand[1].opstring );
	    doindex(1);
	    printf( "( @%s args@ );\n", operand[0].opstring );
	    break;

	case PUSH:
	    tabover( tab );
	    printf( "@arg@ = %s", operand[0].opstring );
	    doindex(0);
	    printf( ";\n" );
	    break;

	case PUSHA:
	    tabover( tab );
	    printf( "@arg@ = &%s", operand[0].opstring );
	    doindex(0);
	    printf( ";\n" );
	    break;

	case EXTZV:
	    tabover( tab );
	    printf( "%s", operand[3].opstring );
	    doindex(3);
	    printf( " = " );
	    if ( operand[0].op_argval != 0 ) {
		printf( "( %s", operand[2].opstring );
		doindex(2);
		printf( " >> %d )", operand[0].op_argval );
	    } else {
		printf( "%s", operand[2].opstring );
		doindex(2);
	    }
	    if ( operand[1].op_argval != 32 )
		printf( " & 0x%x;\n",
		       0x7fffffff >> ( 31 - operand[1].op_argval ) );
	    else
		printf( ";\n" );
	    break;
	}
    }
}


/*
 * Print the displacement of an instruction that uses displacement
 * addressing.
 */
static int
getdisp(addr, nbytes, rn, mode)
address addr;
int nbytes;
int rn;
int mode;
{
    int argval;

    switch (nbytes) {
    case 1:
	argval = get_byte( addr );
	break;

    case 2:
	argval = get_word( addr );
	break;

    case 4:
	argval = get_long( addr );
	break;
    }
    if (rn == PC && mode >= BYTEDISP) {
	argval += addr + nbytes;
    }
    return argval;
}

static
regdisp( rn, offset, type, defr, str )
int rn, offset, type, defr;
char *str;
{
    char *ds;

    if ( defr )
	ds = "*";
    else
	ds = "";

    switch ( rn ) {

    /* arguments */
    case AP:
	if ( offset < 0 )
	    printf( "ERR: bad argument offset %d\n", offset );
	else
	    sprintf( str, "%s%s", ds, arg_sym( offset, type ) );
	break;

    /* locals */
    case FP:
	if ( offset > 0 )
	    printf( "ERR: bad local offset %d\n", offset );
	else
	    sprintf( str, "%s%s", ds, loc_sym( -offset, type ) );
	break;

    case PC:
	if ( defr )
	    printf( "ERR: PC deferred\n" );
	sprintf( str, "G%04d", offset );
	break;

    /* everything else */
    default:
	sprintf( str, "%s%s->O%03d%s", ds, reg_sym( rn, type | T_POINTER ),
		offset, typesuf[ type ] );
	break;
    }
}