# include	<ingres.h>
# include	<aux.h>
# include	<symbol.h>
# include	<tree.h>
# include	<access.h>
# include	"../decomp/globs.h"
# include	<sccs.h>
# include	<errors.h>

SCCSID(@(#)interp.c	8.6	5/30/88)



/*
**
** INTERPRET
**
**	 Processes the retrieved tuple from the De.ov_source relation
**	 according to the symbols in the list.  Recognition
**	 of characteristic delimiters and separators initiates
**	 action appropriate to a target list or qualification list
**	 as the case may be.
**	
**	 Between delimiters, the symbol list is expected to be in
**	 Polish postfix form.  A qualification list is further
**	 expected to be in conjunctive normal form, with Boolean
**	 operators infixed.
**
*/


double	pow();
double	sqrt();
double	log();
double	exp();
double	sin();
double	cos();
double	atan();

# define SPUSH(v)	(++((struct stacksym *) v))
# define SPOP(v)	(((struct stacksym *) v)--)

SYMBOL *
interpret(istlist,list)
int     istlist; /* signals a target list: used for string substitution */
SYMBOL	**list;	/* ptr to list of sym pointers */
{
	register SYMBOL		*tos;
	SYMBOL			*op1,*op2;	/*operands popped off stack*/
	register ANYTYPE	*val1,*val2;	/*ptrs to values of operands*/
	int			opval, optype, l1;
	char			*s1;
	int			byflag;
	long			hitid;
	extern char		*Usercode;
	extern			ov_err();
	int			cb_mark;
	extern char		*ov_ovqpbuf;
	extern char		*locv();
	int			i;

#	ifdef xOTR1
	if (tTf(72, 0))
	{
		printf("INTERP:  list=%x\n",list);
		printf("         istlist = %d\n", istlist);
	}
#	endif


	byflag = (list == De.ov_bylist);	/* set byflag if aggregate function */
	tos = (SYMBOL *)(De.ov_stack-1);
	/* reset the concat and ascii operator buffer */
	seterr(De.ov_ovqpbuf, CBUFULL, ov_err);
	cb_mark = markbuf(De.ov_ovqpbuf);

loop:
#	ifdef xOTR1
	if (tTf(72, 1) && tos >= (SYMBOL *) De.ov_stack)
	{
		printf("\ttops of stack=");
		prstack(tos);	/* print top of stack element */
	}
#	endif
	/* check for stack overflow */
	l1 = getsymbol(SPUSH(tos), &list); 	/* getsymbol changes the value of list */

	if (l1)
	{

		freebuf(De.ov_ovqpbuf, cb_mark);
		return (tos);
	}
	optype = tos->type;
	opval = tos->value.sym_data.i2type;
	op1 = tos;
	SPOP(tos);		/* assume that stack will be popped */

	switch(optype)
	{
	  case CHAR:
					/* do any chars have to be inserted? */
		if (istlist && (Patnum || Globnum))
		{
		    insert_chars(op1);
		}
	  case INT:
	  case FLOAT:
		SPUSH(tos);		/* just leave symbol on stack */
		goto loop;

	  case COP:
		SPUSH(tos);		/* new symbol goes on stack */
		tos->type = CHAR;
		switch (opval)
		{

		  case opDBA:
			tos->value.sym_data.cptype = Admin.adhdr.adowner;
			tos->len = 2;
			goto loop;

		  case opUSERCODE:
			tos->value.sym_data.cptype = Usercode;
			tos->len = 2;
			goto loop;
		}

	  case AND:		/* if top value false return immediately */
		if (!tos->value.sym_data.i2type)
		{
			freebuf(De.ov_ovqpbuf, cb_mark);
			return(tos);
		}
		else
			SPOP(tos);
		freebuf(De.ov_ovqpbuf, cb_mark);
		goto loop;

	  case OR:		/* if top value is true then skip to
				** end of disjunction. */
		if (tos->value.sym_data.i2type)
		{
			SPUSH(tos);
			do
			{
				getsymbol(tos, &list); 	/* getsymbol changes the value of list */
			} while (tos->type != AND);
			optype = AND;
			SPOP(tos);
		}
		SPOP(tos);
		goto loop;

	  case RESDOM:
		freebuf(De.ov_ovqpbuf, cb_mark); /* init the concat and ascii buffer */
		if (De.ov_result)
		{
			if (opval)	/* if gt zero then opval represents a real domain */
			{
				if (byflag)
					opval++;	/* skip over count field for ag functs */
				rcvt(tos, De.ov_result->relfrmt[opval], De.ov_result->relfrml[opval]);
				tout(tos, De.ov_outtup+De.ov_result->reloff[opval], De.ov_result->relfrml[opval]);
			}
			else	/* opval refers to the tid and this is an update */
			{
				De.ov_uptid = tos->value.sym_data.i4type;	/* copy tid */
				if (De.de_qmode == mdREPL || (De.ov_diffrel && De.de_qmode == mdDEL && De.ov_result->reldum.relindxd > 0 ))
				{
					/* De.ov_origtup must be left with the orig
					** unaltered tuple, and De.ov_outtup must
					** be initialized with the orig tuple.
					**
					** De.ov_outtup only matters with REPL.
					** Scan() sets up De.ov_origtup so when
					** De.ov_source == De.ov_result, origtup is already
					** correct.
					*/

					if (De.ov_diffrel)
					{
						if (l1 = get(De.ov_result, &De.ov_uptid, &hitid, De.ov_origtup, CURTUP))
							syserr("interp:get on resdom %s, %d", locv(De.ov_uptid), l1);
						bmove(De.ov_origtup, De.ov_outtup, De.ov_result->reldum.relwid);
					}
					else
					{
						bmove(De.ov_intup, De.ov_outtup, De.ov_result->reldum.relwid);
					}
				}
			}
		}
		else
		{
			/*
			** This is really here for the 68k machines,
			** this works on the VAX, but nowhere else...
 			if ( tos->type == INT && tos->len == 1)
 				tos->value.sym_data.i1type = tos->value.sym_data.i2type;
			*/
			if (Equel)
				equelatt(tos);	/* send attribute to equel */
			else
			{
				if (tos->type == CHAR)
					s1 = tos->value.sym_data.cptype;
				else
					s1 = tos->value.sym_data.c0type;
				printatt(tos->type, tos->len & I1MASK, s1);	/* print attribute */
			}
		}
		SPOP(tos);
		goto loop;


	  case BOP:
		op2 = (SYMBOL *)SPOP(tos);
		op1 = (SYMBOL *)tos;
		typecheck(op1, op2, opval);
		val1 = &op1->value.sym_data;
		val2 = &op2->value.sym_data;

		switch (tos->type)
		{
		  case INT:
			switch (tos->len)
			{
			  case 1:
				switch (opval)
				{
				  case opADD:
					val1->i1type += val2->i1type;
					goto loop;

				  case opSUB:
					val1->i1type -= val2->i1type;
					goto loop;

				  case opMUL:
					val1->i1type *= val2->i1type;
					goto loop;

				  case opDIV:
					val1->i1type /= val2->i1type;
					goto loop;

				  case opMOD:
					val1->i1type %= val2->i1type;
					goto loop;

				  case opPOW:
					itof(op1);
					itof(op2);
					val1->f8type = pow(val1->f8type, val2->f8type);
					goto loop;

				  /* relational operator */
				  default:
					tos->len = 2;
					if (val1->i1type > val2->i1type)
						l1 = 1;
					else
						if (val1->i1type == val2->i1type)
							l1 = 0;
						else
							l1 = -1;
					val1->i2type = relop_interp(opval, l1);
					goto loop;
				}
			  case 2:
				switch (opval)
				{
				  case opADD:
					val1->i2type += val2->i2type;
					goto loop;

				  case opSUB:
					val1->i2type -= val2->i2type;
					goto loop;

				  case opMUL:
					val1->i2type *= val2->i2type;
					goto loop;

				  case opDIV:
					val1->i2type /= val2->i2type;
					goto loop;

				  case opMOD:
					val1->i2type %= val2->i2type;
					goto loop;

				  case opPOW:
					itof(op1);
					itof(op2);
					val1->f8type = pow(val1->f8type, val2->f8type);
					goto loop;

				  /* relational operator */
				  default:
					l1 = val1->i2type - val2->i2type;
					val1->i2type = relop_interp(opval, l1);
					goto loop;
				}

			  case 4:
				switch(opval)
				{
				  case opADD:
					val1->i4type += val2->i4type;
					goto loop;

				  case opSUB:
					val1->i4type -= val2->i4type;
					goto loop;

				  case opMUL:
					val1->i4type *= val2->i4type;
					goto loop;

				  case opDIV:
					val1->i4type /= val2->i4type;
					goto loop;

				  case opMOD:
					val1->i4type %= val2->i4type;
					goto loop;

				  case opPOW:
					itof(op1);
					itof(op2);
					val1->f8type = pow(val1->f8type, val2->f8type);
					goto loop;

				  /* relational operator */
				  default: 
					tos->len = 2;
					if (val1->i4type > val2->i4type)
						l1 = 1;
					else
						if (val1->i4type == val2->i4type)
							l1 = 0;
						else
							l1 = -1;

					val1->i2type = relop_interp(opval, l1);
					goto loop;

				}
			}

		  case FLOAT:
			switch (tos->len)
			{
			  case 4:
				switch (opval)
				{
				  case opADD:
					val1->f4type += val2->f4type;
					goto loop;

				  case opSUB:
					val1->f4type -= val2->f4type;
					goto loop;

				  case opMUL:
					val1->f4type *= val2->f4type;
					goto loop;

				  case opDIV:
					val1->f4type /= val2->f4type;
					goto loop;

				  case opPOW:
					val1->f4type = pow(val1->f4type, val2->f4type);
					goto loop;

				  default:
					tos->type = INT;
					tos->len = 2;
					if (val1->f4type > val2->f4type)
						l1 = 1;
					else
						if (val1->f4type == val2->f4type)
							l1 = 0;
						else
							l1 = -1;
					val1->i2type = relop_interp(opval, l1);
					goto loop;
				}
			  case 8:
				switch (opval)
				{
				  case opADD:
					val1->f8type += val2->f8type;
					goto loop;

				  case opSUB:
					val1->f8type -= val2->f8type;
					goto loop;

				  case opMUL:
					val1->f8type *= val2->f8type;
					goto loop;

				  case opDIV:
					val1->f8type /= val2->f8type;
					goto loop;

				  case opPOW:
					val1->f8type = pow(val1->f8type, val2->f8type);
					goto loop;

				  default:
					tos->type = INT;
					tos->len = 2;
					if (val1->f8type > val2->f8type)
						l1 = 1;
					else
						if (val1->f8type == val2->f8type)
							l1 = 0;
						else
							l1 = -1;
					val1->i2type = relop_interp(opval, l1);
					goto loop;
				}
			}

		case CHAR:
			switch (opval) 
			{
				case opSUB:
				    newstring(op1, op2);
				    goto loop;
				case opADD:
				case opCONCAT:
				    concatsym(op1, op2);	/* concatenate the two symbols */
				    goto loop;
				default:
				    l1 = lexcomp(val1->cptype, size(op1), val2->cptype, op2->len & I1MASK,0);
				    tos->type = INT;
				    tos->len = 2;
				    val1->i2type = relop_interp(opval, l1);
				    goto loop;
			}
		}	/* end of BOP */
 
	   case UOP:
		val1 = &tos->value.sym_data;
		switch (opval)
		{
		   case opMINUS:
		   case opABS:
			if (tos->type == CHAR)
				ov_err(BADUOPC);
			l1 = opval == opMINUS;
			switch (tos->type)
			{
			   case INT:
				switch (tos->len)
				{
				  case 1:
					if (l1 || val1->i1type < 0)
						val1->i1type = -val1->i1type;
			   		goto loop;
				  case 2:
					if (l1 || val1->i2type < 0)
						val1->i2type = -val1->i2type;
			   		goto loop;

				  case 4:
					if (l1 || val1->i4type < 0)
						val1->i4type = -val1->i4type;
					goto loop;
				}

			  case FLOAT:
				switch (tos->len)
				{
				  case 4:
					if (l1 || val1->f4type < 0.0)
						val1->f4type = -val1->f4type;
					goto loop;
				  case 8:
					if (l1 || val1->f8type < 0.0)
						val1->f8type = -val1->f8type;
					goto loop;
				}
			}

		  case opNOT:
			val1->i2type = !val1->i2type;
		  case opPLUS:
			if (tos->type == CHAR)
				ov_err(BADUOPC);
			goto loop;

		  case opASCII:
			ascii(tos);
			goto loop;

		  case opINT1:
			typecoerce(tos, INT, 1);
			goto loop;

		  case opINT2:
			typecoerce(tos, INT, 2);
			goto loop;

		  case opINT4:
			typecoerce(tos, INT, 4);
			goto loop;

		  case opFLOAT4:
			typecoerce(tos, FLOAT, 4);
			goto loop;

		  case opFLOAT8:
			typecoerce(tos, FLOAT, 8);
			goto loop;

		  default:
			if (tos->type == CHAR)
				ov_err(BADUOPC);
			if (tos->type == INT)
				itof(tos);
			if (tos->len == 4)
			{
				val1->f8type = val1->f4type;
				tos->len = 8;
			}
			switch (opval)
			{
			  case opATAN:
				val1->f8type = atan(val1->f8type);
				goto loop;
	
			  case opLOG:
				val1->f8type = log(val1->f8type);
				goto loop;
	
			  case opSIN:
				val1->f8type = sin(val1->f8type);
				goto loop;

			  case opCOS:
				val1->f8type = cos(val1->f8type);
				goto loop;

			  case opSQRT:
				val1->f8type = sqrt(val1->f8type);
				goto loop;

			  case opEXP:
				val1->f8type = exp(val1->f8type);
				goto loop;

			  default:
				syserr("interp:bad uop %d",opval);
			}
		}


	   case AOP:
		aop_interp(opval, tos);
		SPOP(tos);		/* pop this symbol */
		goto loop;

	}
	syserr("interp: fell out");
	/*NOTREACHED*/
}
/*
**	relop_interp interprets the relational operators
**	(ie. EQ, NE etc.) and returns true or false
**	by evaluating l1.
**
**	l1 should be greater than, equal or less than zero.
*/

relop_interp(opval, l1)
int	opval;
int	l1;
{
	register int	i;

	i = l1;

	switch (opval)
	{

	  case opEQ:
		return (i == 0);

	  case opNE:
		return (i != 0);

	  case opLT:
		return (i < 0);

	  case opLE:
		return (i <= 0);

	  case opGT:
		return (i > 0);

	  case opGE:
		return (i >= 0);

	  default:
		syserr("relop:bad relop or bop %d", opval);
	}
	/*NOTREACHED*/
}
/*
**	Aggregate values are stored in De.ov_outtup. De.ov_tend points
**	to the spot for the next aggregate. Aop_interp()
**	computes the value for the aggregate and leaves
**	the result in the position pointed to by De.ov_tend.
*/

aop_interp(opval, tos)
int		opval;
register SYMBOL	*tos;
{
	register int	i;
	int		l1;
	ANYTYPE		numb;	/* used for type conversion */

#ifndef	VAX
	l1 = (tos->type != CHAR);
	switch (opval) {
	case opCOUNT:
	case opCOUNTU:
	  i = 4;
	  l1 = 1;
	  break;
	case opANY:
	  i = 2;
	  l1 = 1;
	  break;
	case opAVG:
	case opAVGU:
	  i = 8;
	  break;
	default:
	  i = tos->len;
	}
	if (l1)
	{
		l1 = De.ov_tend - De.ov_outtup;
		De.ov_tend = De.ov_outtup + ((l1 - 1)|(i-1))+1;
	}
#endif
	bmove(De.ov_tend, (char *) &numb, 8);	/* note: this assumes that
				there are always 8 bytes which can be moved.
				** if it moves beyond De.ov_tend, it's ok */
	switch (opval)
	{

	  case opSUMU:
	  case opSUM:
		if (*De.ov_counter <= 1)
			goto puta;
		switch (tos->type)
		{
		  case INT:
			switch(tos->len)
			{
			  case 1:
				tos->value.sym_data.i1type += numb.i1type;
				goto puta;

			  case 2:
				tos->value.sym_data.i2type += numb.i2type;
				goto puta;

			  case 4:
				tos->value.sym_data.i4type += numb.i4type;
				goto puta;
			}

		  case FLOAT:
			if (tos->len == 4)
				tos->value.sym_data.f4type += numb.f4type;
			else
				tos->value.sym_data.f8type += numb.f8type;
			goto puta;

		  default:
			ov_err(BADSUMC);	/* cant sum char fields */
		}

	  case opCOUNTU:
	  case opCOUNT:
		tos->type = CNTTYPE;
		tos->len = CNTLEN;
		tos->value.sym_data.i4type = *De.ov_counter;
		goto puta;

	  case opANY:
		tos->type = OANYTYPE;
		tos->len = OANYLEN;
		if (*De.ov_counter)
		{
			tos->value.sym_data.i2type = 1;
			if (!De.ov_bylist && (De.ov_agcount == 1))
				De.ov_targvc = 0;	/* if simple agg. stop scan */
		}
		else
			tos->value.sym_data.i2type = 0;
		goto puta;

	  case opMIN:
	  case opMAX:
		if (*De.ov_counter<=1)
			goto puta;
		switch (tos->type)
		{
		  case INT:
			switch (tos->len)
			{
			  case 1:
				i = (tos->value.sym_data.i1type < numb.i1type);
				break;

			  case 2:
				i = (tos->value.sym_data.i2type < numb.i2type);
				break;

			  case 4:
				i = (tos->value.sym_data.i4type < numb.i4type);
				break;
			}
			break;

		  case FLOAT:
			if (tos->len == 4)
				i = (tos->value.sym_data.f4type < numb.f4type);
			else
				i = (tos->value.sym_data.f8type < numb.f8type);
			break;

		  case CHAR:
			l1 = size(tos);
			i = (lexcomp(tos->value.sym_data.cptype, l1, De.ov_tend, l1,0) < 0);
			break;

		  default:	
			syserr("interp:bad op type for opMIN/MAX %d", tos->type);
		}

		/* check result of comparison */
		if (opval == opMAX)
			i = !i;	/* complement test for opMAX */
		if (i)
			goto puta;	/* condition true. new value */

		/* condition false. Keep old value */
		goto done;


	  case opAVGU:
	  case opAVG:
		if (tos->type == INT)
			itof(tos);
		else
			if (tos->type == CHAR)
				ov_err(BADAVG);
		if (tos->len == 4)
		{
			tos->value.sym_data.f8type = tos->value.sym_data.f4type;
		/*	tos->len = 8; */
		}
		if (*De.ov_counter > 1)
		{
			tos->value.sym_data.f8type = numb.f8type + (tos->value.sym_data.f8type - numb.f8type) / *De.ov_counter;
		}
		tos->len = 8;
		goto puta;

	  default:
		syserr("interp:bad agg op %d", tos->type);
	}

puta:
	tout(tos, De.ov_tend, tos->len);
done:
	De.ov_tend += tos->len & I1MASK;
}
