# ifndef EXIT
# define EXIT exit
# endif

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

NODE *NIL;  /* pointer which always has 0 in it */

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

/*
 * user error - nonfatal error
 *
 * the routine where is different for pass 1 and pass 2;
 *  it tells where the error took place
 */
	/* VARARGS1 */
uerror(s, a)
char *s;
{
	++nerrors;
	where('u');
	fprintf( stderr, s, a );
	fprintf( stderr, "\n" );
	if( nerrors > 30 ) cerror( "too many errors");
}

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

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

/*
 * initialize expression tree search
 */
tinit()
{
	NODE *p;

	for( p=node; p<= &node[TREESZ-1]; ++p ) p->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->op ==FREE ) return(lastfree=p);

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

/*
 * ensure that all nodes have been freed
 */
tcheck()
{
	NODE *p;
	int	flag = 0;

	if( !nerrors )
		for( p=node; p<= &node[TREESZ-1]; ++p )
			if( p->op != FREE ) {
				werror( "wasted space: %o, op = %s", p, opst[p->op] );
				flag++;
			}
	if (flag > 1)	/* for now we allow one to slip by */
		cerror("too many lost tree nodes");
	tinit();
}

/*
 * free the tree p
 */
tfree(p)
NODE *p;
{
	extern tfree1();

	if (p->op != FREE)
		walkf(p, tfree1);
}

tfree1(p)
NODE *p;
{
	if (p == 0)
		cerror("freeing blank tree!");
	else
		p->op = FREE;
}

fwalk(t, f, down)
register NODE *t;
int (*f)();
{
	int down1, down2;

more:
	down1 = down2 = 0;

	(*f)( t, down, &down1, &down2 );

	switch(optype(t->op))
	{
		case BITYPE:
			fwalk( t->left, f, down1 );
			t = t->right;
			down = down2;
			goto more;
	
		case UTYPE:
			t = t->left;
			down = down1;
			goto more;
	
	}
}

walkf(t, f)
register NODE *t;
int (*f)();
{
	register opty;

	opty = optype(t->op);

	if (opty != LTYPE)
		walkf(t->left, f);
	if (opty == BITYPE)
		walkf(t->right, f);
	(*f)( t );
}


int dope[ DSIZE ];
char *opst[DSIZE];

struct dopest {
	int	dopeop;
	char	opst[8];
	int	dopeval;
} indope[] = {
	NAME, "NAME", LTYPE,
	STRING, "STRING", LTYPE,
	REG, "REG", LTYPE,
	OREG, "OREG", LTYPE,
	ICON, "ICON", LTYPE,
	FCON, "FCON", LTYPE,
	CCODES, "CCODES", LTYPE,
	UNARY MINUS, "U-", UTYPE,
	UNARY MUL, "U*", UTYPE,
	UNARY AND, "U&", UTYPE,
	UNARY CALL, "UCALL", UTYPE|CALLFLG,
	UNARY FORTCALL, "UFCALL", UTYPE|CALLFLG,
	NOT, "!", UTYPE|LOGFLG,
	COMPL, "~", UTYPE,
	FORCE, "FORCE", UTYPE,
	INIT, "INIT", UTYPE,
	SCONV, "SCONV", UTYPE,
	PCONV, "PCONV", 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,
	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,
	FLD, "FLD", UTYPE,
	PMCONV, "PMCONV", BITYPE,
	PVCONV, "PVCONV", BITYPE,
	PACONV,	"PACONV",	BITYPE,
	PSCONV,	"PSCONV",	BITYPE,
	RETURN, "RETURN", BITYPE|ASGFLG|ASGOPFLG,
	CAST, "CAST", BITYPE|ASGFLG|ASGOPFLG,
	GOTO, "GOTO", UTYPE,
	STASG, "STASG", BITYPE|ASGFLG,
	STARG, "STARG", UTYPE,
	STCALL, "STCALL", BITYPE|CALLFLG,
	UNARY STCALL, "USTCALL", UTYPE|CALLFLG,

-1,	0
};

mkdope()
{
	register struct dopest *q;

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

/*
 * output a nice description of the type of t
 */
tprint(t)
TWORD 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;
		}
	}
}
