/*	@(#)common 1.1 86/02/03 SMI	*/

#ifdef FORT
#undef BUFSTDERR
#endif
#ifndef ONEPASS
#undef BUFSTDERR
#endif
# ifndef EXIT
# define EXIT exit
# endif

int nerrors = 0;  /* number of errors */
int errline = -1; /* where last error took place */

extern unsigned int offsz;

unsigned caloff(){
	register i;
	unsigned int temp;
	unsigned int off;
	temp = 1;
	i = 0;
	do {
		temp <<= 1;
		++i;
		} while( temp > 0 );
	off = 1 << (i-1);
	return (off);
	}

	/* 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 */

	fflush( stdout );
	++nerrors;
	errline = lineno;
	where('u');
	fprintf( stderr, s, a );
	fprintf( stderr, "\n" );
#ifdef BUFSTDERR
	fflush(stderr);
#endif
	if( nerrors > 30 ) fatal( "too many errors");
	}

	/* VARARGS1 */
cerror( s, a, b, c ) char *s; { /* compiler error: die */
	fflush( stdout );
	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" );
		}
#ifdef BUFSTDERR
	fflush(stderr);
#endif
	EXIT(1);
	}

fatal( s, a, b, c ) char *s; { /* non-compiler but fatal error: die */
	fflush( stdout );
	where('f');
	fprintf( stderr, "fatal error: " );
	fprintf( stderr, s, a, b, c );
	fprintf( stderr, "\n" );
#ifdef BUFSTDERR
	fflush(stderr);
#endif
	EXIT(1);
	}
int Wflag = 0; /* Non-zero means do not print warnings */

	/* VARARGS1 */
werror( s, a, b ) char *s; {  /* warning */
	if(Wflag) return;
	fflush( stdout );
	where('w');
	fprintf( stderr, "warning: " );
	fprintf( stderr, s, a, b );
	fprintf( stderr, "\n" );
#ifdef BUFSTDERR
	fflush(stderr);
#endif
	}

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#ifdef	TESTALLOC
/*
 * this enables us to test 
 * tree allocation without having
 * to construct bizarre test programs
 */
#undef	TREESZ
#define TREESZ	16
#endif	TESTALLOC

#define	MAXTSEG	64				/* max # of tree segments */
static	NODE	treespace[TREESZ];		/* initial tree space */
static	NODE	*treeseg[MAXTSEG] = {treespace};/* table of seg pointers */
static	NODE	**activeseg = &treeseg[0];	/* ptr to active seg slot */
static	NODE	*node = treespace;		/* ptr to active segment */
static	NODE	*nextfree = treespace;		/* ptr to next free node */
static	int	nsegs = 1;			/* # of allocated segments */
static	int	recycling = 0;			/* =1 if using old nodes */

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

static NODE *
tsegalloc()
{
	NODE *newseg;
	if ( activeseg == &treeseg[nsegs-1] ) {
		/*
		 * no unused segments; allocate a new one
		 */
		if (nsegs == MAXTSEG) {
			cerror("out of tree space; try simplifying");
			/*NOTREACHED*/
		}
		newseg = (NODE *)malloc(TREESZ*sizeof(NODE));
		*++activeseg = newseg;
		nsegs++;
	} else {
		/*
		 * segment already allocated; use it
		 */
		newseg = *++activeseg;
		if (newseg == NIL) {
			cerror("tree space allocation");
			/*NOTREACHED*/
		}
	}
	return newseg;
}

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

tinit()
{
	/* initialize tree space allocation */
	activeseg = &treeseg[0];	/* ptr to active seg slot */
	node = *activeseg;		/* ptr to active segment */
	nextfree = node;		/* ptr to next free node */
	recycling = 0;
}

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

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

NODE *
talloc()
{
	register NODE *p, *q;
	static NODE *lastfrag;

	if ( nextfree < &node[TREESZ] )
		return nextfree++;
	if ( !recycling ) {
		recycling = 1;
		lastfrag = node;
	}
	q = lastfrag;
	for( p = TNEXT(q); p != q; p = TNEXT(p) ) {
		if (p->tn.op == FREE) {
			return lastfrag = p;
		}
	}
	/*
	 * current tree space segment is full;
	 * get a new one.
	 */
	nextfree = node = tsegalloc();
	recycling = 0;
	return nextfree++;
}

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

tcheck()
{
	/*
	 * ensure that all nodes have been freed.  Note that in the
	 * C compiler, some nodes remain active until the end of the
	 * current function, so this should not be called until then.
	 * In the backend-only configuration (fort) this is called
	 * on a statement-by-statement basis.
	 */

	register NODE *p;
	register NODE *limit;
	NODE **seg;

	if( !nerrors ) {
		/*
		 * all segments below the top one must be scanned
		 * from beginning to end.  The top one need only
		 * be scanned up to the high-water mark (nextfree)
		 */
		for( seg = &treeseg[0]; seg < activeseg; seg++ ) {
			limit = *seg + TREESZ;
			for (p = *seg; p < limit; p++ ) {
				if( p->in.op != FREE ) {
					cerror( "wasted space: %#x", p );
				}
			}
		}	
		limit = nextfree;
		for( p=node; p < limit; ++p ) {
			if( p->in.op != FREE ) {
				cerror( "wasted space: %#x", p );
			}
		}
	}
	tinit();
#ifdef FLEXNAMES
	freetstr();
#endif
}

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

tfree(p)
	register NODE *p;
{
	if (p == NIL)
		return;
again:
	switch(optype(p->in.op)) {
	case UTYPE:
		tfree(p->in.left);
		/*fall through*/
	case LTYPE:
		p->in.op = FREE;
		return;
	case BITYPE:
		tfree(p->in.left);
		p->in.op = FREE;
		p = p->in.right;
		goto again;
	}
}

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

	int down1, down2;

	more:
	down1 = down2 = 0;

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

	switch( optype( t->in.op ) ){

	case BITYPE:
		fwalk( t->in.left, f, down1 );
		t = t->in.right;
		down = down2;
		goto more;

	case UTYPE:
		t = t->in.left;
		down = down1;
		goto more;

		}
	}

walkf( t, f )
	register NODE *t;
	int (*f)();
{
	switch(optype(t->in.op)) {
	case LTYPE:
		break;
	case UTYPE:
		walkf(t->in.left, f);
		break;
	default:
		walkf(t->in.left, f);
		walkf(t->in.right, f);
		break;
	}
	(*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,
	FCCODES, "FCCODES", 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,
#ifdef VAX
	ER, "^", BITYPE|COMMFLG|SIMPFLG,
	ASG ER, "^=", BITYPE|COMMFLG|SIMPFLG|ASGFLG|ASGOPFLG,
#else
	ER, "^", BITYPE|COMMFLG,
	ASG ER, "^=", BITYPE|COMMFLG|ASGFLG|ASGOPFLG,
#endif
	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,
	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,
	CHK,  "CHK",  BITYPE,
	FABS, "FABS", UTYPE|INTRFLG,
	FCOS, "FCOS", UTYPE|INTRFLG,
	FSIN, "FSIN", UTYPE|INTRFLG,
	FTAN, "FTAN", UTYPE|INTRFLG,
	FACOS, "FACOS", UTYPE|INTRFLG,
	FASIN, "FASIN", UTYPE|INTRFLG,
	FATAN, "FATAN", UTYPE|INTRFLG,
	FCOSH, "FCOSH", UTYPE|INTRFLG,
	FSINH, "FSINH", UTYPE|INTRFLG,
	FTANH, "FTANH", UTYPE|INTRFLG,
	FEXP, "FEXP", UTYPE|INTRFLG,
	F10TOX, "F10TOX", UTYPE|INTRFLG,
	F2TOX, "F2TOX", UTYPE|INTRFLG,
	FLOGN, "FLOGN", UTYPE|INTRFLG,
	FLOG10, "FLOG10", UTYPE|INTRFLG,
	FLOG2, "FLOG2", UTYPE|INTRFLG,
	FSQR, "FSQR", UTYPE|INTRFLG,
	FSQRT, "FSQRT", UTYPE|INTRFLG,
	FAINT, "FAINT", UTYPE|INTRFLG,
	FANINT, "FANINT", UTYPE|INTRFLG,
	FNINT, "FNINT", UTYPE,
	-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 BUG4
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

#ifdef FLEXNAMES
#define	NTSTRBUF	40
#define	TSTRSZ		2048
char	itstrbuf[TSTRSZ];
char	*tstrbuf[NTSTRBUF] = { itstrbuf };
char	**curtstr = tstrbuf;
int	tstrused;

char *
tstr(cp)
	register char *cp;
{
	register int i = strlen(cp);
	register char *dp;
	
	if (tstrused + i >= TSTRSZ) {
		if (++curtstr >= &tstrbuf[NTSTRBUF])
			cerror("out of temporary string space");
		tstrused = 0;
		if (*curtstr == 0) {
			dp = (char *)malloc(TSTRSZ);
			*curtstr = dp;
		}
	}
	strcpy(dp = *curtstr+tstrused, cp);
	tstrused += i + 1;
	return (dp);
}
#endif

#ifdef malloc
#undef malloc
#endif malloc

/*
 * NOTE: malloc is defined as malloc_with_care everywhere but here.
 */
char *
malloc_with_care(nbytes)
{
	char *p;

	p = (char*)malloc(nbytes);
	if (p == NULL) {
		fatal("memory allocation exceeded");
		exit(1);
	}
	return(p);
}
