# ifndef EXIT
# define EXIT exit
# endif

int nerrors = 0;  /* number of errors */

NODE *lastfree;  /* pointer to last free node; (for allocator) */

# ifndef MYWHERE
where(c){ /* print location of error  */
	/* c is either 'u', 'c', or 'w' */
	fprintf( stderr, "%s, line %d: ", ftitle, lineno );
	}
# endif

	/* VARARGS1 */
uerror( s, a ) char *s; { /* nonfatal error message */
	/* the routine where is different for pass 1 and pass 2;
	/*  it tells where the error took place */

	++nerrors;
	where('u');
	fprintf( stderr, s, a );
	fprintf( stderr, "\n" );
	if( nerrors > 30 ) cerror( "too many errors");
	fflush(stderr);	/* rob */
	}

	/* VARARGS1 */
cerror( s, a, b, c ) char *s; { /* compiler error: die */
	where('c');
	if( nerrors && nerrors <= 30 ){
		/* give the compiler the benefit of the doubt */
		fprintf( stderr,
			"cannot recover from earlier errors: goodbye!\n" );
		}
	else {
		fprintf( stderr, "compiler error: " );
		fprintf( stderr, s, a, b, c );
		fprintf( stderr, "\n" );
		fflush( stdout );
		fprintf( stderr, "for diagnostic purposes, we dump core\n" );
		fflush( stderr );
		abort();
		}
	EXIT(1);
	}

	/* VARARGS1 */
werror( s, a, b ) char *s; {  /* warning */
	where('w');
	fprintf( stderr, "warning: " );
	fprintf( stderr, s, a, b );
	fprintf( stderr, "\n" );
	}

tinit(){ /* initialize expression tree search */

	NODE *p;

	for( p=node; p<= &node[TREESZ-1]; ++p ) p->in.op = FREE;
	lastfree = node;

	}

# define TNEXT(p) (p== &node[TREESZ-1]?node:p+1)

NODE *
talloc(){
	NODE *p, *q;

	q = lastfree;
	for( p = TNEXT(q); p!=q; p= TNEXT(p))
		if( p->in.op ==FREE ) return(lastfree=p);

	cerror( "out of tree space; simplify expression");
	/* NOTREACHED */
	}

tcheck(){ /* ensure that all nodes have been freed */

	NODE *p;

	if( !nerrors )
		for( p=node; p<= &node[TREESZ-1]; ++p ) {
			if( p->in.op != FREE ){
				cerror( "wasted space: %d", p-node );
				}
			}
	tinit();
	}

tfree(p)  NODE *p; {
	/* allow tree fragments to be freed, also */
	if( !p ) return;
	switch( optype( p->tn.op ) ){
	case BITYPE:
		tfree( p->in.right );
	case UTYPE:
		tfree( p->in.left );
		}
	p->in.op = FREE;
	}

int dope[ DSIZE ];
char *opst[DSIZE];
NODE node[TREESZ];

char	ftitle[100] = "";   	/* title of the file */
int	lineno;		/* line number of the input file */


struct dopest { int dopeop; char opst[8]; int dopeval; } indope[] = {

	NAME, "NAME", LTYPE,
	STRING, "STRING", LTYPE,
	REG, "REG", LTYPE,
	TEMP, "TEMP", LTYPE,
	VAUTO, "AUTO", LTYPE,
	VPARAM, "PARAM", LTYPE,
	ICON, "ICON", LTYPE,
	FCON, "FCON", LTYPE,
	CCODES, "CCODES", LTYPE,
	UNARY MINUS, "U-", UTYPE,
	UNARY MUL, "STAR", UTYPE,
	UNARY AND, "U&", UTYPE,
	UNARY CALL, "UCALL", UTYPE|CALLFLG,
	UNARY FORTCALL, "UFCALL", UTYPE|CALLFLG,
	NOT, "!", UTYPE|LOGFLG,
	COMPL, "~", UTYPE,
	INIT, "INIT", UTYPE,
	CONV, "CONV", UTYPE,
	PLUS, "+", BITYPE|FLOFLG|SIMPFLG|COMMFLG,
	ASG PLUS, "+=", BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG,
	MINUS, "-", BITYPE|FLOFLG|SIMPFLG,
	ASG MINUS, "-=", BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG,
	MUL, "*", BITYPE|FLOFLG|MULFLG,
	ASG MUL, "*=", BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG,
	AND, "&", BITYPE|SIMPFLG|COMMFLG,
	ASG AND, "&=", BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG,
	QUEST, "?", BITYPE,
	COLON, ":", BITYPE,
	ANDAND, "&&", BITYPE|LOGFLG,
	OROR, "||", BITYPE|LOGFLG,
	CM, ",", BITYPE,
	COMOP, ",OP", BITYPE,
	FREE, "FREE!?!", LTYPE,
	ASSIGN, "=", BITYPE|ASGFLG,
	DIV, "/", BITYPE|FLOFLG|MULFLG|DIVFLG,
	ASG DIV, "/=", BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG,
	MOD, "%", BITYPE|DIVFLG,
	ASG MOD, "%=", BITYPE|DIVFLG|ASGFLG|ASGOPFLG,
	LS, "<<", BITYPE|SHFFLG,
	ASG LS, "<<=", BITYPE|SHFFLG|ASGFLG|ASGOPFLG,
	RS, ">>", BITYPE|SHFFLG,
	ASG RS, ">>=", BITYPE|SHFFLG|ASGFLG|ASGOPFLG,
	OR, "|", BITYPE|COMMFLG|SIMPFLG,
	ASG OR, "|=", BITYPE|COMMFLG|SIMPFLG|ASGFLG|ASGOPFLG,
	ER, "^", BITYPE|COMMFLG|SIMPFLG,
	ASG ER, "^=", BITYPE|COMMFLG|SIMPFLG|ASGFLG|ASGOPFLG,
	INCR, "++", BITYPE|ASGFLG,
	DECR, "--", BITYPE|ASGFLG,
	STREF, "->", BITYPE,
	CALL, "CALL", BITYPE|CALLFLG,
	FORTCALL, "FCALL", BITYPE|CALLFLG,
	EQ, "==", BITYPE|LOGFLG,
	NE, "!=", BITYPE|LOGFLG,
	LE, "<=", BITYPE|LOGFLG,
	LT, "<", BITYPE|LOGFLG,
	GE, ">", BITYPE|LOGFLG,
	GT, ">", BITYPE|LOGFLG,
	UGT, "UGT", BITYPE|LOGFLG,
	UGE, "UGE", BITYPE|LOGFLG,
	ULT, "ULT", BITYPE|LOGFLG,
	ULE, "ULE", BITYPE|LOGFLG,
	ARS, "A>>", BITYPE,
	TYPE, "TYPE", LTYPE,
	LB, "[", BITYPE,
	CBRANCH, "CBRANCH", BITYPE,
	GENLAB, "GENLAB", UTYPE,
	GENUBR, "GENUBR", UTYPE,
	GENBR, "GENBR", UTYPE,
	CMP, "CMP", BITYPE,
	FLD, "FLD", UTYPE,
	PMUL, "P*", BITYPE,
	PDIV, "P/", BITYPE,
	RETURN, "RETURN", BITYPE|ASGFLG,
	CAST, "CAST", BITYPE|ASGFLG,
	GOTO, "GOTO", UTYPE,
	STASG, "STASG", BITYPE,
	STARG, "STARG", UTYPE,
	STCALL, "STCALL", BITYPE|CALLFLG,
	UNARY STCALL, "USTCALL", UTYPE|CALLFLG,
	RNODE, "RNODE", LTYPE,
	SNODE, "SNODE", LTYPE,
	QNODE, "QNODE", LTYPE,
	MANY, "MANY", BITYPE,
	FUNARG, "ARG", UTYPE,
	UOP0, "UOP0", UTYPE|SPFLG,
	UOP1, "UOP1", UTYPE|SPFLG,
	UOP2, "UOP2", UTYPE|SPFLG,
	UOP3, "UOP3", UTYPE|SPFLG,
	UOP4, "UOP4", UTYPE|SPFLG,
	UOP5, "UOP5", UTYPE|SPFLG,
	UOP6, "UOP6", UTYPE|SPFLG,
	UOP7, "UOP7", UTYPE|SPFLG,
	UOP8, "UOP8", UTYPE|SPFLG,
	UOP9, "UOP9", UTYPE|SPFLG,

-1,	0
};

mkdope(){
	register struct dopest *q;

	for( q = indope; q->dopeop >= 0; ++q ){
		dope[q->dopeop] = q->dopeval;
		opst[q->dopeop] = q->opst;
		}
	}

# ifndef NODBG
tprint( t )  TWORD t; { /* output a nice description of the type of t */

	static char * tnames[] = {
		"undef",
		"farg",
		"char",
		"short",
		"int",
		"long",
		"float",
		"double",
		"strty",
		"unionty",
		"enumty",
		"moety",
		"uchar",
		"ushort",
		"unsigned",
		"ulong",
		"?", "?"
		};

	for(;; t = DECREF(t) ){

		if( ISPTR(t) ) printf( "PTR " );
		else if( ISFTN(t) ) printf( "FTN " );
		else if( ISARY(t) ) printf( "ARY " );
		else {
			printf( "%s", tnames[t] );
			return;
			}
		}
	}
# endif

bigsize( t ) TWORD t; {
	/* return a type size for t */
	switch( t ) {

	case CHAR:
	case UCHAR:
		return( SZCHAR );

	case SHORT:
	case USHORT:
		return( SZSHORT );

	case VOID:
	case INT:
	case UNSIGNED:
		return( SZINT );

	case LONG:
	case ULONG:
		return( SZLONG );

	case FLOAT:
		return( SZLONG+1 );  /* must appear > long */
	case DOUBLE:
		return( SZLONG+2 );

		}

	if( ISPTR(t) || ISARY(t) ) return( SZPOINT );
	cerror( "bad bigsize" );
	}

cbigger( p ) NODE *p; {
	/* returns 1 if the conversion op p makes things bigger */
	TWORD tl, t;

	if( p->tn.op != CONV ) cerror( "cbigger" );
	return( bigsize( p->tn.type ) > bigsize( p->in.left->tn.type ) );
	}
