/*#define DEBUG*/
/*
	Copyright 1982
	Alcyon Corporation
	8716 Production Ave.
	San Diego, Ca.  92121
*/

#include "parser.h"
int opdontop;
int strassign;

/*
 * expr - expression evaluator
 *		This handles all the expression syntax in C.  This is a straight-
 *		forward operator-stack/oppri scheme for translating infix into
 *		a binary expression tree.
 */
char *expr()						/* returns 0 or ptr to node*/
{
	register char *p;
	register char *opdsave, *oprsave;
	register int token, op, oppri, i, opdotsave;
	int type, sc;
	long size;

	opdsave = opdp;
	strassign = 0;
	oprsave = opp;
	opdotsave = opdontop;
	if( !opp || !opdp ) {
		opp = opstack;
		opdp = opdstack;
	}
	else
		opp++;
	opp->o_op = STACKEND;
	opp->o_pri = STKPRI;
	opap = exprp;
	opdontop = 0;

	while( (token=gettok()) != EOF ) {
		switch( token ) {
	/*
	 * the following are the terminal nodes of the expresion tree,
	 * note that when we see a terminal node, we push it and then go
	 * and get the next token.  When we see an operator, we need to
	 * check the operator stack to see if we can do a reduction.
	 */
		case CINT:
			if( doopd(cnalloc(INT,cvalue)) ) {
exprerr:
				if( token == SEMI || token == RCURBR )
					pbtok(token);
				error("invalid expression");
				opdp = opdsave;
				opp = oprsave;
				opdontop = opdotsave;
				return(0);
			}
			continue;
	
		case CFLOAT:	/*[vlh] 3.4*/
			if( doopd(fpcnalloc(FLOAT,clvalue)) )
				goto exprerr;
			continue;
	
		case CLONG:
			if( doopd(lcnalloc(LONG,clvalue)) )
				goto exprerr;
			continue;
	
		case SYMBOL:
			if( !((p=csp)->s_attrib&SDEFINED) ) {
				if( peek(LPAREN) ) {	/*assume function call*/
					p->s_sc = EXTERNAL;
					p->s_type = FUNCTION|INT;
				}
				else if( commastop )	/*in initialization?*/
					p->s_sc = EXTERNAL;
				else
					error("undefined symbol: %.8s",p->s_symbol);
				p->s_attrib =| SDEFINED;
			}
			if (p->s_sc==EXTERNAL || function(p->t_type)) {
				if (!reducep || p->s_sc==EXTERNAL || peek(LPAREN)) {
					p = enalloc(p);
					p->t_sc = EXTERNAL;
				}
				else {	/* [vlh] 3.4 if (main).... */
					p = cnalloc(CINT,1);	/* eval function name */
				}
			}
			else
				p=snalloc(p->s_type,p->s_sc,p->s_offset,p->s_dp,p->s_ssp);
			if( doopd(p) )
				goto exprerr;
			continue;
	
		case STRING:
			outtstr(cvalue);
			if( doopd(snalloc(ARRAY|CHAR,STATIC,cvalue,0,0)) )
				goto exprerr;
			continue;
	/*
	 * do special checking for unary ops and operators that can be
	 * either unary or binary operators, such as -, &, *, etc.
	 */
		case RESWORD:
			if( cvalue != R_SIZEOF ) {
				goto exprerr;
			}
			token = SIZEOF;
		case COMPL:
		case NOT:
			if( opdontop )			/*can't have: operand unary-op*/
				goto exprerr;
			break;

		case LBRACK:
			opdontop = 0;
			break;
	
		case RBRACK:
		case RPAREN:
			if( !opdontop )		/*can't be: operator )*/
				goto exprerr;
			break;
	
		case PREINC:
			if( opdontop )			/*assume its lvalue++*/
				token = POSTINC;
			break;

		case PREDEC:
			if( opdontop )			/*assume its lvalue--*/
				token = POSTDEC;
			break;
	
		case SUB:
			if(!opdontop) {	/*if no operand, assume unary*/
				if( peek(CINT) ) {
					cvalue = -cvalue;
					continue;
				}
				if( peek(CLONG) ) {
					clvalue = -clvalue;
					continue;
				}
				if( peek(CFLOAT) ) {	/*[vlh] 3.4*/
					if (!fflag) {		/* IEEE format */
						if (clvalue & 0x80000000)
							clvalue =& 0x7fffffff;
						else
							clvalue =| 0x80000000;
					}
					else			/* FFP format */
						if (clvalue & 0x80)
							clvalue =& 0xffffff7f;
						else
							clvalue =| 0x80;
					continue;
				}
				token = UMINUS;
			}
			break;
	
		case AND:
			if(!opdontop)
				token = ADDR;
			break;

		case MULT:
			if( !opdontop )
				token = INDR;
			break;
	/*
	 * for left parenthesis, we need to see if this is a casting operator.
	 */

		case LPAREN:
			if( !opdontop ) {	/*see if casting or abstract declarator*/
				sc = type = 0;
				if( gettype(&sc,&type,&size) ) {
					sc = (type == STRUCT) ? dalloc(size) : cdp;
					p = snalloc(type,STATIC,0,sc,sc);
					p->t_type =| declarator(1);
					if( !next(RPAREN) )
						goto exprerr;
					if( tdp )
						p->t_type=addtdtype(tdp,p->t_type,p->t_dp,
							&(p->t_ssp));
					pushopd(p);
					token = CAST;
					if( opp->o_op == SIZEOF ) {
						opdontop++;
						continue;
					}
				}
			}
			else  /*we've seen (), look for NACALL*/
				token = (next(RPAREN)) ? MPARENS : CALL;
			break;
	
		case PERIOD:
		case APTR:
			smember++;			/*next token needs to be struct membr*/
			strucptr[smember+instruct] = csp->s_struc;
			break;
	
		}
	/*
	 * we have seen an operator, get its info and then check the operator
	 * stack.
	 */
		if( binop(token) ) {
	/*
	 * handle special binary operators, such as CAST and post-inc and
	 * post-dec.
	 */
			if(!opdontop) {
				if( token != PREDEC && token != PREINC && token != CAST )
					goto exprerr;
			}
			if( token != POSTDEC && token != POSTINC && token != MPARENS )
				opdontop = 0;				/*this fixes x++ op problem.*/
		}
		oppri = oppriority(token);
		if( commastop && token == COMMA )	/*need to stop at comma(init)*/
			oppri = COLPRI;
		if( colonstop && token == COLON )	/*need to stop at colon(case)*/
			oppri = COLPRI;
		while( 1 ) {
			if( oppri > opp->o_pri ||
					(oppri == opp->o_pri && rasop(token)) ) {
	/*
	 * we have encountered a higher priority (or right-associative)
	 * operator, hence we need to stack it.
	 */
				if( ++opp >= &opstack[OPSSIZE] )
					ferror("expression too complex");
				if( token == POSTINC || token == POSTDEC )
					oppri = PSTPRI;
				else if( token == LPAREN || token == LBRACK ||
						token == CALL )
					oppri = CALPRI;
				opp->o_op = token;
				opp->o_pri = oppri;
				break;
			}
	/*
	 * we have encountered a lower priority operator, hence we need to
	 * do a reduction.
	 */
			op = opp->o_op;
			opp--;
			type = CINT;
			switch( op ) {
		
			case STACKEND:			/*we accept the expression...*/
				pbtok(token);
				if (!strassign) {
					if (!maketree(0))
						goto exprerr;
				}
				if (!(p=popopd()))
					goto exprerr;
				opdp = opdsave;
				opp = oprsave;
				opdontop = opdotsave;
				return(p);
		
			case LPAREN:			/*assure these have matching )*/
			case CALL:
				if( token != RPAREN )
					goto exprerr;
				break;

			case MPARENS:
				if( !maketree(NACALL) )
					goto exprerr;
				continue;
		
			case LBRACK:
				if( token != RBRACK )
					goto exprerr;
				if(!maketree(ADD))	/*array[index]->*(array+index)*/
					goto exprerr;
				op = INDR;
				break;
		
			case PREINC:			/*turn these into binary operators*/
			case POSTINC:			/*which in reality they are...*/
			case PREDEC:
			case POSTDEC:
				pushopd(cnalloc(INT,1));
			default:
				if(!maketree(op))
					goto exprerr;
				continue;			/*see if we can reduce some more...*/
			}
			if( op != LPAREN && !maketree(op) )
				goto exprerr;
			break;
		}
	}
	error("unexpected EOF");
	return(0);
}

/* talloc - expression area tree node allocation
 *		Allocates area and checks for overflow.*/
char *talloc(size)					/* returns pointer to node*/
int size;							/* size of node to alloc*/
{
	register char *p;

	p = opap;
	if( p + size >= &exprarea[EXPSIZE] )
		ferror("expression too complex");
	opap = p + size;
	return(p);
}

/*
 * enalloc - external name alloc
 *		Allocates an expression tree node for an external name and
 *		copies symbol table info and symbol into tree node.
 */
char *enalloc(sp)					/* returns - none*/
struct symbol *sp;					/* pointer to symbol table entry*/
{
	register struct extnode *ep;

	ep = talloc(sizeof(*ep));
	ep->t_op = SYMBOL;
	ep->t_sc = sp->s_sc;
	ep->t_type = sp->s_type;
	ep->t_dp = sp->s_dp;
	ep->t_ssp = sp->s_ssp;
	ep->t_offset = sp->s_offset;
	symcopy(sp->s_symbol,ep->t_symbol);
	return(ep);
}

/* cnalloc - constant node allocation
 *		Allocates a constant tree node and fills the info fields.*/
char *cnalloc(type,value)		/* returns pointer to node*/
int type;							/* data type*/
int value;							/* constant value*/
{
	register struct conode *cp;

	cp = talloc(sizeof(*cp));
	cp->t_op = CINT;
	cp->t_type = type;
	cp->t_dp = 0;
	cp->t_ssp = 0;
	cp->t_value = value;
	return(cp);
}

/* lcnalloc - long constant node allocation*/
/*		Allocates a constant tree node and fills the info fields.*/
char *lcnalloc(type,value)		/* returns pointer to node*/
int type;						/* data type*/
long value;						/* constant value*/
{
	register struct lconode *cp;

	cp = talloc(sizeof(*cp));
	cp->t_op = CLONG;
	cp->t_type = type;
	cp->t_dp = 0;
	cp->t_ssp = 0;
	cp->t_lvalue = value;
	return(cp);
}

/* fpcnalloc - floating point constant node allocation*/
/*		Allocates a constant tree node and fills the info fields.*/
char *fpcnalloc(type,value)		/*[vlh] 3.4 returns pointer to node*/
int type;						/* data type*/
long value;						/* constant value*/
{
	register struct lconode *cp;

	cp = talloc(sizeof(*cp));
	cp->t_op = CFLOAT;
	cp->t_type = type;
	cp->t_dp = 0;
	cp->t_ssp = 0;
	cp->t_lvalue = value;
	return(cp);
}

/* tnalloc - tree node allocation*/
/*		Allocates an operator tree node and fills the info fields*/
char *tnalloc(op,type,dp,ssp,left,right)	/* returns pointer to node*/
int op;								/* operator*/
int type;							/* operator type*/
int dp;								/* dimension pointer or other info*/
int ssp;							/* structure length pointer*/
char *left;							/* left subtree*/
char *right;						/* right subtree*/
{
	register struct tnode *tp;

	tp = talloc(sizeof(*tp));
	tp->t_op = op;
	tp->t_type = type;
	tp->t_dp = dp;
	tp->t_ssp = ssp;
	tp->t_left = left;
	tp->t_right = right;
	return(tp);
}

/* pushopd - put operand node onto operand stack*/
/*		Checks for operand stack overflow.*/
pushopd(tp)							/* returns - none*/
struct tnode *tp;					/* pointer to tree node to push*/
{
#ifdef DEBUG
	error("pushopd %d",tp->t_op);
#endif
	if( opdp >= &opdstack[OPDSIZE] )
		ferror("expression too complex");
	*opdp++ = tp;
}

/* popopd - pop operand stack*/
/*		Checks for stack underflow*/
char *popopd()						/* returns ptr to top operand*/
{
	register struct tnode *tp;

	if( opdp <= &opdstack[0] )
		return(0);
	tp = *--opdp;
#ifdef DEBUG
	error("popopd: %d",tp->t_op);
#endif
	return(tp);
}

/* doopd - handle constant or symbol node operand*/
/*		Pushes node onto operand stack and handles opdontop flag.*/
doopd(tp)						/* returns 1 if syntax error, 0 for ok*/
struct tnode *tp;				/* pointer to tree node*/
{
	pushopd(tp);
	if( opdontop )
		return(1);
	opdontop++;
	return(0);
}

	/*
	 * This indicates if a conversion operator is needed given the types
	 * of the two operands.  The upper diagonal is applied ONLY if this
	 * is an assignment operator and the indexes are swapped so the lower
	 * diagonal is used otherwise.
	 * INT		UNSN		LONG		DOUB		PTR
	 */
char cvmap[5][5] {
	0,			UNSN_INT,	LONG_INT,	DOUB_INT,	PTR_INT,	/*INT*/
	INT_UNSN,	0,			LONG_UNSN,	DOUB_UNSN,	PTR_UNSN,	/*UNSN*/
	INT_LONG,	UNSN_LONG,	0,			DOUB_LONG,	PTR_LONG,	/*LONG*/
	INT_DOUB,	UNSN_DOUB,	LONG_DOUB,	0,			BADCONV,	/*DOUB*/
	INT_PTR,	UNSN_PTR,	LONG_PTR,	BADCONV,	PTR_PTR,	/*PTR*/
};

/*
 * maketree - given operator, takes operands and builds up tree
 *		This takes the given operator, allocates a node for it
 *		and links up the subtrees on the operand stack.  A lot of
 *		work is in inserting the proper conversions.
 */
maketree(op)						/* returns success or failure */
int op;								/* new root operator*/
{
	register struct tnode *ltp, *rtp, *p;
	register int type, ltype, rtype, lconv, conv, pconv, ilen;

#ifdef DEBUG
	error("maketree: op = %d",op);
#endif
	if( binop(op) ) {
		if(!(rtp=popopd()))
			return(0);
		rtype = (rtp=funcref(arrayref(rtp)))->t_type;
	}
	if(!(ltp=popopd()))
		return(0);
	if( op == SIZEOF ) {	/* [vlh] 3.4 ilen */
		ilen = dsize(ltp->t_type,ltp->t_dp,ltp->t_ssp);
		pushopd(cnalloc(INT,ilen));
		return(1);
	}
	if( op != ADDR ) {
		ltp = arrayref(ltp);
		if( op != CALL && op != NACALL )
			ltp = funcref(ltp);
	}
	if( specops(op,ltp,rtp) )
		return( 1 );
	ltype = ltp->t_type;
	if( lintegral(op) )
		integral(ltp,LONG);
	if( rintegral(op) )
		integral(rtp,LONG);
	if( lvalop(op) && ltp->t_op != SYMBOL && ltp->t_op != INDR &&
			ltp->t_op != BFIELD )
		error("assignable operand required");
	if( unaryop(op) ) {
		if(!unopeval(op,ltp))
			pushopd(tnalloc(op,ltype,ltp->t_dp,ltp->t_ssp,ltp));
		return;
	}
	if( ltype == STRUCT || rtype == STRUCT ) {
		if (ltype==STRUCT && rtype==STRUCT && op==ASSIGN) { /*[vlh]*/
			pushopd(ltp);
			maketree(ADDR);
			pushopd(rtp);
			maketree(ADDR);
			maketree(STASSIGN);
			strassign = 1;
			return(1);
		}
		ltype = rtype = INT;
		error("illegal structure operation");
	}
	type = ltype;
	if( rtype == TYPELESS ) {
		rtp->t_type = rtype = INT;
		lconv = conv = 0;
	}
	else {
		lconv = ttoconv(ltype);
		conv = ttoconv(rtype);
		if (!asgop(op) && conv > lconv) {
			conv = cvmap[conv][lconv];
			lconv = 1;
			type = rtype;
		}
		else {
			conv = cvmap[lconv][conv];
			lconv = 0;
		}
	}
	if( asgop(op) ) {
		if( (op == ASSIGN || op == FRETURN) && (conv == INT_PTR ||
				conv == UNSN_PTR) && rtp->t_op != CINT )
			error("short assigned to pointer");
		if( op == ASSIGN || op == CAST ) {
			switch( conv ) {

			case INT_PTR:
			case UNSN_PTR:
			case PTR_PTR:
			case PTR_LONG:
			case LONG_PTR:
				conv = 0;
				break;
			}
		}
	}
	else if( op == COLON && suptype(ltype) != 0 && ltype == rtype )
		conv = 0;
	else if( relop(op) && conv == PTR_PTR )
		conv = 0;
	pconv = 0;
	if ((relop(op) || op==FRETURN) && alltype(ltype) == (STRUCT | POINTER)
				&& (conv == INT_PTR || conv == LONG_PTR))	/* [vlh] 3.4 */
		conv = 0;	/* int compare to struct pointer, no conversion */
	if( conv == PTR_PTR ) {
		conv = 0;
		if( op == SUB ) {
			type = LONG;
			pconv++;
		}
		else if(op != FRETURN && ( (alltype(ltype) != alltype(rtype) ||
					alltype(ltype) != (POINTER|CHAR)) ) )
			conv = BADCONV;
	}
	if( conv ) {
		if( conv == BADCONV )
			error("illegal type conversion");
		else if( lconv ) {
			ltp = cvopgen(ltp,type,conv,psize(rtp),op);
		}
		else {
			rtp = cvopgen(rtp,type,conv,psize(ltp),op);
		}
	}
	else if( op == CAST && rtp->t_type != CHAR ) {
		rtp->t_type = ltp->t_type;
		rtp->t_ssp = ltp->t_ssp;		/* [vlh] 3.4 */
		rtp->t_dp = ltp->t_dp;			/* [vlh] 3.4 */
	}
	if( relop(op) )
		type = INT;
	if( op == CAST )
		pushopd(rtp);
	else if(!binopeval(op,ltp,rtp)) {
		if( btype(ltype) == STRUCT || btype(rtype) != STRUCT )
			p = ltp;
		else
			p = rtp;
		pushopd(tnalloc(op,type,p->t_dp,p->t_ssp,ltp,rtp));
	}
	if( pconv && ltype != (POINTER|CHAR) ) {
		if(!(ltp=popopd()))
			return(0);
		pushopd(cvopgen(ltp,LONG,PTR_LONG,psize(ltp->t_left),op));
	}
	return(1);
}

/* specops - handle special operators in building tree*/
specops(op,ltp,rtp)				/* returns 1 if op special, 0 otherwise*/
int op;							/* operator*/
struct tnode *ltp;				/* left subtree pointer*/
struct tnode *rtp;				/* right subtree pointer*/
{
	register int type, sr_size, sl_size;

	type = ltp->t_type;
	switch (op) {

	case 0:
		break;

	default:
		return(0);

	case APTR:							/*expr -> name*/
		integral(ltp,LONG);				/*we need to turn expr into a*/
		ltp->t_type = POINTER|STRUCT;	/*pointer to a struct, then use*/
		pushopd(ltp);					/*expr . name stuff*/
		maketree(INDR);
		ltp = popopd();					/*ltp cannot be 0*/
	case PERIOD:						/*expr . name*/
		if( !(isstel(rtp)) )
			error("invalid structure member name");
		type = rtp->t_type;
		if( array(type) ) {
			type = delspchk(type);
			rtp->t_dp++;
		}
		tadjust(ltp,type,rtp->t_dp,rtp->t_ssp);
		pushopd(ltp);
		maketree(ADDR);
		pushopd(cnalloc(TYPELESS,rtp->t_offset));
		maketree(ADD);
		if( notarray(rtp->t_type) )
			maketree(INDR);
		ltp = popopd();
		if( rtp->t_sc == BFIELDCL )		/*ltp cannot be 0*/
			ltp = tnalloc(BFIELD,type,rtp->t_dp,rtp->t_ssp,ltp);
		break;

	case QMARK:
		if( rtp->t_op != COLON )
			error("invalid ?: operator syntax");
		if( ltp->t_op == CINT && rtp->t_left->t_op == CINT &&
				rtp->t_right->t_op == CINT )
			ltp->t_value = (ltp->t_value ? rtp->t_left->t_value :
					rtp->t_right->t_value);
		else
			ltp = tnalloc(op,rtp->t_type,0,0,ltp,rtp);
		break;

	case LAND:
	case LOR:
	case COMMA:							/*don't need conversions here*/
		ltp = tnalloc(op,INT,0,0,ltp,rtp);
		break;

	case INDR:
		if( ltp->t_op == ADDR  )		/**& is null op*/
			ltp = ltp->t_left;
		else {
			if( function(type) )
				error("indirection on function invalid");
			ltp = tnalloc(INDR,delspchk(type),ltp->t_dp,ltp->t_ssp,ltp);
		}
		break;

	case STASSIGN:	/*[vlh]*/
		sr_size = psize(rtp);
		sl_size = psize(ltp);
		if( sl_size >= sr_size )
			ltp = tnalloc(STASSIGN,sr_size,0,0,ltp,rtp);
		else
			error("invalid structure assignment");
		break;

	case NACALL:
	case CALL:
		if( notfunction(type) )
			error("illegal call");
		ltp = tnalloc(op,delspchk(type),ltp->t_dp,ltp->t_ssp,ltp,rtp);
		break;

	case ADDR:
		if( ltp->t_op == INDR ) {		/*&* is null op*/
/*			ltp->t_left->t_type = addsp(type,POINTER);*/
/*			ltp->t_left->t_dp = ltp->t_dp;*/
/*			ltp->t_left->t_ssp = ltp->t_ssp;*/
			ltp = ltp->t_left;
		}
		else {
			if( ltp->t_op != SYMBOL )
				error("& operand illegal");
			else if( ltp->t_sc == REGISTER )
				error("address of register");
			ltp = tnalloc(ADDR,addsp(type,POINTER),ltp->t_dp,ltp->t_ssp,
					ltp);
		}
		break;
	}
	pushopd(ltp);
	return(1);
}

/* cvopgen - generate a conversion operator*/
/*		Generates conversions necessary for integers, pointers and longs.*/
char *cvopgen(tp,type,conv,len,op)	/* returns pointer to conv node*/
struct tnode *tp;					/* pointer to node to do conversion*/
int type;							/* type to convert to*/
int conv;							/* specified conversion*/
long len;							/* object length [vlh] 3.4 i=>l */
int op;								/* for cast operator*/
{
	register struct tnode *rtp;
	register int cop, ilen;

	switch(conv) {

	case INT_PTR:
	case UNSN_PTR:
		if( op == CAST || op == FRETURN ) {
			cop = INT2L;			/*of the ptd to objects length plus*/
			if( len != 1L ) {		/*an integer to long covnversion*/
				ilen = len;
				rtp = cnalloc(INT,ilen);
				tp = tnalloc(MULT,type,0,0,tp,rtp);
			}
			break;
		}
	case PTR_LONG:						/*need to generate mult or div*/
	case LONG_PTR:						/*of the ptd to objects length*/
		if( len == 1 )
			return(tp);
		ilen = len;
		cop = (conv == PTR_LONG ? DIV : MULT);
		rtp = cnalloc(INT,ilen);
		break;

	case INT_LONG:
	case UNSN_LONG:
		cop = INT2L;
		break;

	case INT_DOUB:	/*[vlh] 3.4*/
	case UNSN_DOUB:
		cop = INT2F;
		break;

	case LONG_DOUB:	/*[vlh] 3.4*/
		cop = LONG2F;
		break;

	case DOUB_LONG:	/*[vlh] 3.4*/
		cop = FLOAT2L;
		break;

	case DOUB_INT:	/*[vlh] 3.4*/
	case DOUB_UNSN:
		cop = FLOAT2I;
		break;

	case LONG_INT:
	case LONG_UNSN:
		cop = LONG2I;
		break;

	default:
		error("invalid conversion");
		return(tp);
	}
	return( tnalloc(cop,type,0,0,tp,rtp) );
}

/* tadjust - expression tree type adjustment*/
/*		Adjusts the types of subtrees to agree with the top of the tree.*/
tadjust(tp,type,dp,ssp)				/* returns - none*/
struct tnode *tp;					/* pointer to tree*/
int type;							/* type to adjust to*/
int dp;								/* dimension pointer or info*/
int ssp;							/* structure pointer*/
{
	register int op;

	tp->t_type = type;
	if( dp >= 0 ) {
		tp->t_dp = dp;
		tp->t_ssp = ssp;
	}
	if( (op=tp->t_op) == ADDR )
		type = delspchk(type);
	else if( op == INDR )
		type = addsp(type,POINTER);
	else if( op != ADD && op != SUB )
		return;
	tadjust(tp->t_left,type,dp,ssp);
}

/* funcref - handle tree function reference*/
/*		Turns a reference to a function into the address of the function.*/
char *funcref(tp)					/* returns pointer to node*/
struct tnode *tp;					/* pointer to old node*/
{
	if( function(tp->t_type) )
		tp = tnalloc(ADDR,addsp(tp->t_type,POINTER),tp->t_dp,tp->t_ssp,tp);
	return(tp);
}

/* arrayref - handle tree array reference*/
/*		Turns a reference to an array into the address of the array.*/
char *arrayref(tp)					/* returns pointer to tree node*/
struct tnode *tp;					/* tree node pointer*/
{
	if( array(tp->t_type) && !(isstel(tp)) ) {
		tp->t_dp++;
		pushopd(tp);
		tadjust(tp,delspchk(tp->t_type),-1,0);
		maketree(ADDR);
		tp = popopd();				/*tp cannot be 0*/
	}
	return(tp);
}

/* integral - checks operand for integral type*/
/*		This checks for needing an integral operand.*/
integral(tp,atype)					/* returns - none*/
struct tnode *tp;					/* pointer to tree node*/
int atype;							/* alternate type allowable*/
{
	register int type;

	if( (type=tp->t_type) != INT && type != UNSIGNED && type != CHAR &&
			!suptype(type) && type != atype )
		error("invalid operand type");
}

/* ttoconv - maps normal type into conversion table type*/
ttoconv(type)						/* returns conversion type*/
int type;							/* type to convert*/
{
	switch(type) {

	case CHAR:
	case INT:
		return(0);

	case UNSIGNED:
		return(1);

	case LONG:
		return(2);

	case FLOAT:
	case DOUBLE:
		return(3);

	default:
		return(4);
	}
}

/* binopeval - does binary operator constant expression evaluation*/
/*		Does the constant expression evaluation for binary operators.*/
binopeval(op,ltp,rtp)				/* returns 1 if done, 0 if not*/
int op;								/* operator to evaluate*/
struct tnode *ltp;					/* pointer to left subtree*/
struct tnode *rtp;					/* pointer to right subtree*/
{
	register int lvalue, rvalue;

	if( ltp->t_op != CINT )
		return(0);
	lvalue = ltp->t_value;
	if( rtp->t_op != CINT )
		return(0);
	rvalue = rtp->t_value;
	switch (op) {

	case ADD:
		lvalue =+ rvalue;
		break;

	case SUB:
		lvalue =- rvalue;
		break;

	case MULT:
		lvalue =* rvalue;
		break;

	case DIV:
		lvalue =/ rvalue;
		break;

	case MOD:
		lvalue =% rvalue;
		break;

	case AND:
		lvalue =& rvalue;
		break;

	case OR:
		lvalue =| rvalue;
		break;

	case XOR:
		lvalue =^ rvalue;
		break;

	case LSH:
		lvalue =<< rvalue;
		break;

	case RSH:
		lvalue =>> rvalue;
		break;

	case EQUALS:
		lvalue = (lvalue == rvalue);
		break;

	case NEQUALS:
		lvalue = (lvalue != rvalue);
		break;

	case GREAT:
		lvalue = (lvalue > rvalue);
		break;

	case LESS:
		lvalue = (lvalue < rvalue);
		break;

	case GREATEQ:
		lvalue = (lvalue >= rvalue);
		break;

	case LESSEQ:
		lvalue = (lvalue <= rvalue);
		break;

	default:
		return(0);
	}
	ltp->t_value = lvalue;
	pushopd(ltp);
	return(1);
}

/* unopeval - unary operator constant expression evaluation*/
/*		Does constant expression evaluation for unary operators.*/
unopeval(op,tp)						/* returns 1 if done, 0 otherwise*/
int op;								/* operator to evaluate*/
struct tnode *tp;					/* pointer to subexpression*/
{
	register int value;

	if( tp->t_op != CINT )
		return(0);
	value = tp->t_value;
	switch( op ) {

	case COMPL:
		value = ~ value;
		break;

	case UMINUS:
		value = - value;
		break;

	case NOT:
		value = ! value;
		break;

	default:
		return(0);
	}
	tp->t_value = value;
	pushopd(tp);
	return(1);
}

/* cexpr - evaluate a constant integer expression*/
/*		Used in evaluating array bounds, bit field numbers, etc.*/
cexpr()
{
	register struct tnode *tp;
	register char *savep;

	savep = exprp;
	exprp = opap;
	commastop++;
	if( (tp=expr()) && tp->t_op != CINT )
		error("constant required");
	commastop--;
	exprp = savep;
	return( tp->t_value );
}

/* delspchk - delete one special reference and check if non-zero*/
delspchk(type)						/*returns new special type*/
int type;							/* type to modify*/
{
	if(!(suptype(type)))
		error("bad indirection");
	return( delsp(type) );
}

/* psize - return size of object ptd at by pointer*/
long								/* [vlh] 3.4 int => long */
psize(tp)							/* returns size of object in bytes*/
struct tnode *tp;					/* pointer to tree node*/
{
	if ( !(suptype(tp->t_type)) )	/* what case ??? */
		return(1);
	return( dsize(delsp(tp->t_type),tp->t_dp,tp->t_ssp) );
}
