# include	"../ingres.h"

/*
**  EXPR -- evaluate expression
**
**	This module evaluates an expression in somewhat standard
**	infix notation.  Several restrictions apply.  There are
**	no variables, since this can be simulated with the macro
**	processor.  No numeric overflow is checked.  There may be
**	no spaces, tabs, or newlines in the expression.
**
**	The text of the expression is read from 'macgetch', so
**	that must be initialized before calling this routine.
**
**	Operators accepted are + - * / < > >= <= = != % ( )
**	& |.
**	Operands may be signed integers.
**	Standard precedence applies.
**
**	An expression can be viewed as a sequence of operands,
**	and operators.  If the terminator is considered to be
**	an operator, then the sequence must be composed
** 	of n matched pairs of operators and operands.  NOT and
**	Negation are considered to be part of the operand and
**	are treated as such.  Thus to evaluate an expression,
**	n pairs are read until the terminator is found as the
**	last operator.
**
**	Parameters:
**		none
**
**	Returns:
**		value of the expression.  Undetermined value
**		on error.
**
**	Side Effects:
**		Macro processing can occur.
**
**	Defines:
**		expr -- the main entry point.
**		valof -- the guts of the expression processor.
**		exprfind -- finds and chews on operands.
**		opfind -- finds and chews on operations.
**		exp_op -- performs operations.
**		numberget -- converts numbers.
**		exprgch -- to get characters.
**		pushop, popop, pushnum, popnum -- stack operations.
**		ExprNstack, ExprNptr, ExprOstack, ExprOptr --
**			stacks + associated data.
**		ExprError -- an error flag.
**		ExprPrec -- the precedence tables.
**		ExprPeek -- the lookbehind character for exprgch.
**
**	Requires:
**		macgetch -- to get the next character.
**
**	Required By:
**		branch.c
**
**	Files:
**		none
**
**	Trace Flags:
**		none
**
**	History:
**		8/15/79 (eric) (6.2/7) -- changed STACKSIZE to
**			STACKSZ for v7 C compiler.
**		2/27/79 -- written by John Woodfill, with some
**			cleanup by Eric.
*/






# define 	STACKSZ		50
# define	RIGHTP		21
# define	END		22
# define	SEPERATOR	0
# define	OR		1
# define	AND		2
# define	EQUALS		3
# define	NEQ		4
# define	LESS		5
# define	LEQ		6
# define	GREATER		7
# define	GEQ		8
# define	ADD		9
# define 	SUBTRACT	10
# define	MULTIPLY	11
# define	DIVIDE		12
# define	MOD		13


int 	ExprPrec[] =			/* Precedence table */
{
	0,	/* filler */
	1,	/* 1 -- OR */
	2,	/* 2 -- AND */
	3,	/* 3 -- EQUALS */
	3,	/* 4 -- NEQ */
	4,	/* 5 -- LESS */
	4,	/* 6 -- LEQ */
	4,	/* 7 -- GREATER */
	4,	/* 8 -- GEQ */
	5,	/* 9 -- ADD */
	5,	/* 10 -- SUBTRACT */
	6,	/* 11 -- MULTIPLY */
	6,	/* 12 -- DIVIDE */
	6	/* 13 -- MOD */
};


int	ExprNstack[STACKSZ];
int	*ExprNptr;
int	ExprOstack[STACKSZ];
int	*ExprOptr;
int	ExprError;
char	ExprPeek;











expr()
{
	ExprNptr = ExprNstack;
	ExprOptr = ExprOstack;
	ExprError = FALSE;
	ExprPeek = -1;
	return(valof(END));
}
/*
**  VALOF -- compute value of expression
**
**	This is the real expression processor.  It handles sequencing
**	and precedence.
**
**	Parameters:
**		terminator -- the symbol which should terminate
**			the expression.
**
**	Returns:
**		The value of the expression.
**
**	Side Effects:
**		Gobbles input.
**
**	Requires:
**		exprfind -- to read operands.
**		opfind -- to read operators.
**		exp_op -- to perform operations.
**
**	Called By:
**		expr
**
**	Diagnostics:
**		Extra Parenthesis found: assumed typo
**			An unmatched right parenthesis was read.
**			It was thrown away.
**		Insufficient parenthesis found: assumed zero.
**			An unmatched left parenthesis was left
**			in the operator stack at the end of the
**			expression.  The value zero was taken
**			for the expression.
**
**	Syserrs:
**		none
*/

valof(terminator)
int	terminator;
{
	register int	number;
	register int	operator;

	pushop(SEPERATOR);		/* initialize the stack */

	for(;;)
	{
		number = exprfind();
		if (ExprError) 
			return(0);
		operator = opfind();
		if (ExprError)
			return(0);

		if (operator == RIGHTP || operator == END)
			break;

		/* Do all previous operations with a higher precedence */
		while (ExprPrec[operator] <= ExprPrec[ExprOptr[-1]])	
			number = exp_op(popop(), popnum(), number);
		pushop(operator);
		pushnum(number);
	}
	if (operator != terminator)		/* ExprError in operators */
		if (operator == RIGHTP)
			printf("Extra parenthesis found: assumed typo.\n");
		else
		{
			ExprError = TRUE;
			printf("Insufficient parenthesis found: Assumed zero.\n");
			return(0);
		}
	/* Empty stack for this call of valof */
	while ((operator = popop()) != SEPERATOR)
		number = exp_op(operator, popnum(), number);

	return(number);
}
/*
**  EXPRFIND -- find and chomp operand
**
**	This routine reads the next operand.  It generally just
**	reads numbers, except it also knows about unary operators
**	! and - (where it calls itself recursively), and paren-
**	theses (where it calls valof recursively).
**
**	Parameters:
**		none
**
**	Returns:
**		value of operand.
**
**	Side Effects:
**		Gobbles input.
**
**	Requires:
**		numberget -- to read numbers.
**		exprgch.
**
**	Called By:
**		valof
**		exprfind (recursively)
**
**	Trace Flags:
**		none
**
**	Diagnostics:
**		Expression expected: end of expression found.
**			Nothing was found.  Zero is returned.
**		Expression expected: %c found; assumed zero.
**			A syntax error -- nothing was found
**			which was acceptable.
*/



exprfind()
{
	register int	result;
	register int	c;

	c = exprgch();

	switch(c)
	{
 
	  case '0':
	  case '1':
	  case '2':
	  case '3':
	  case '4':
	  case '5':
	  case '6':
	  case '7':
	  case '8':
	  case '9':
		return(numberget(c));

	  case '!':
		result = exprfind();
		return(ExprError ? 0 : (result <= 0));

	  case '-':
		result = exprfind();
		return(ExprError ? 0 : -result);

	  case '(':
		return(valof(RIGHTP));

	  case ' ':
	  case '\n':
	  case '/t':
	  case '\0':
		printf("Expression expected: end of expression found.\n");
		ExprError = TRUE;
		return(0);

	  default:
		printf("Expression expected; '%c' found: Assumed zero.\n", c);
		ExprError = TRUE;
		return(0);
	}
}
/*
**  OPFIND -- find and translate operator
**
**	This reads the next operator from the input stream and
**	returns the internal code for it.
**
**	Parameters:
**		none
**
**	Returns:
**		The code for the next operator.
**		Zero on error.
**
**	Side Effects:
**		Gobbles input.
**
**	Requires:
**		exprgch.
**
**	Called By:
**		valof
**
**	Trace Flags:
**		none
**
**	Diagnostics:
**		Operator expected: '%c' found.
**			Gibberish in input.
*/

opfind()
{
	register int	c;

	c = exprgch();

	switch(c)
	{
	  
	  case '/':
		return(DIVIDE);

	  case '=':
		return(EQUALS);

	  case  '&':
		return(AND);

	  case '|':
		return(OR);

	  case '+':
		return(ADD);

	  case '-':
		return(SUBTRACT);

	  case '*':
		return(MULTIPLY);

	  case '<':
		c = exprgch();
		if (c == '=')
		{
			return(LEQ);
		}
		ExprPeek = c;
		return(LESS);

	  case '>':
		c = exprgch();
		if (c == '=')
		{
			return(GEQ);
		}
		ExprPeek = c;
		return(GREATER);

	  case '%':
		return(MOD);

	  case '!':
		c = exprgch();
		if (c == '=')
		{
			return(NEQ);
		}
		else
		{
			printf("Operator expected: '!%c' found.\n", c);
			ExprError = TRUE;
			return(0);
		}

	  case ')':
		return(RIGHTP);

	  case ' ':
  	  case '\t':
	  case '\n':
	  case '\0':
		return(END);

	  default:
		printf("Operator expected: '%c' found.\n", c);
		ExprError = TRUE;
		return(0);
		
	}
}
/*
**  EXP_OP -- perform operation
**
**	Performs an operation between two values.
**
**	Parameters:
**		op -- the operation to perform.
**		lv -- the left operand.
**		rv -- the right operand.
**
**	Returns:
**		The value of the operation.
**
**	Side Effects:
**		none
**
**	Requires:
**		none
**
**	Called By:
**		valof.
**
**	Trace Flags:
**		none
**
**	Diagnostics:
**		none
*/

exp_op(op, lv, rv)
int	op;
int	lv;
int	rv;
{
	switch(op)
	{

	  case OR:
		return((lv > 0) || (rv > 0));

	  case AND:
		return((lv > 0) && (rv > 0));

	  case EQUALS:
		return(lv == rv);

	  case NEQ:
		return(lv != rv);

	  case LESS:
		return(lv < rv);

	  case LEQ:
		return(lv <= rv);

	  case GREATER:
		return(lv > rv);

	  case GEQ:
		return(lv >= rv);

	  case ADD:
		return(lv + rv);

	  case SUBTRACT:
		return(lv - rv);

	  case MULTIPLY:
		return(lv * rv);

	  case DIVIDE:
		if (rv == 0) 
		{
			printf("Divide by zero: zero assumed.\n");
			return(0);
		}
		else
			return(lv / rv);

	  case MOD:
		return(lv % rv);

	  default:
		syserr("exp_op: bad op %d", op);

	}
}
/*
**  NUMBERGET -- read and convert a number
**
**	Reads and converts a signed integer.
**
**	Parameters:
**		none
**
**	Returns:
**		The next number in the input stream.
**
**	Side Effects:
**		Gobbles input.
**
**	Requires:
**		exprgch.
**
**	Called By:
**		exprfind.
*/

numberget(cx)
char	cx;
{
	register int	result;
	register int	c;

	c = cx;

	result = 0;
	do
	{
		result = result * 10 + c - '0';
		c = exprgch();
	} while (c >= '0' && c <= '9');
	ExprPeek = c;
	return(result);
}
/*
**  EXPRGCH -- expression character get
**
**	Gets the next character from the expression input.  Takes
**	a character out of ExprPeek first.  Also maps spaces, tabs,
**	and newlines into zero bytes.
**
**	Parameters:
**		none
**
**	Returns:
**		Next character.
**
**	Side Effects:
**		Gobbles input.
**		Clears ExprPeek if set.
**
**	Requires:
**		ExprPeek -- the peek character.
**		macgetch -- to get the next character if ExprPeek
**			is not set.
*/

exprgch()
{
	register int	c;

	c = ExprPeek;
	if (c < 0)
		c = macgetch();
	ExprPeek = -1;
	if (c == ' ' || c == '\n' || c == '\t')
		c = 0;
	return (c);
}
/*
**  Stack operations.
*/


/* Popop returns the top of the operator stack and decrements this stack. */
popop()
{
	if (ExprOptr <= ExprOstack)
		syserr("popop: underflow");
	return(*--ExprOptr);
}



/* Pushop increments the stack pointer and pushes op on the stack. */
pushop(op)
int	op;
{
	*ExprOptr++ = op;
}



/* Popnum returns the top of the number stack and decrements the stack pointer. */
popnum()
{
	if (ExprNptr <= ExprNstack)
		syserr("popnum: underflow");
	return(*--ExprNptr);
}




/* Pushnum increments the stack pointer and pushes num onto the stack */
pushnum(num)
int 	num;
{
	*ExprNptr++ = num;
}
