/*****************************************************************************

	Reduce()

	This function attempts to reduce the expression stack.  It is called
by PushEx when the stack has two or more values on it and therefore might be
reduceable.

*****************************************************************************/

#include "ZPort.h"		/* define portability identifiers */
#include "DefTeco.h"		/* define general identifiers */
#include "DefError.h"		/* define identifiers for error messages */
#include "DefChars.h"		/* define identifiers for characters */

extern	char	ZChrIt();	/* type conversion: LONG to char */
extern	VOID	ErrMsg();	/* display an error message */

EXTERN	struct	EStck EStack[]; /* expression stack */
EXTERN	WORD	EStBot;		/* expression stack bottom */
EXTERN	WORD	EStTop;		/* expression stack top */


DEFAULT Reduce()		/* reduce the expression stack */

{
	LOCAL BOOLEAN	Reducd;

Reducd = YES;
do {

/*****************************************************************************
	if it's x+y, x-y, x*y, x/y, x&y or x#y,  reduce it
*****************************************************************************/
	if ((EStTop >= (EStBot + 3)) &&
	    (EStack[EStTop].ElType == OPERAND) &&
	    (EStack[EStTop-1].ElType == OPERATOR) &&
	    (EStack[EStTop-2].ElType == OPERAND) &&
	    (EStack[EStTop-1].Elemnt != ')') &&
	    (EStack[EStTop-1].Elemnt != '('))
		{
		switch (ZChrIt(EStack[EStTop-1].Elemnt)) {
			case '+':	EStack[EStTop-2].Elemnt +=
					EStack[EStTop].Elemnt;
					break;
			case '-':	EStack[EStTop-2].Elemnt -=
					EStack[EStTop].Elemnt;
					break;
			case '*':	EStack[EStTop-2].Elemnt *=
					EStack[EStTop].Elemnt;
					break;
			case '/':	EStack[EStTop-2].Elemnt /=
					EStack[EStTop].Elemnt;
					break;
			case '&':	EStack[EStTop-2].Elemnt &=
					EStack[EStTop].Elemnt;
					break;
			case '#':	EStack[EStTop-2].Elemnt |=
					EStack[EStTop].Elemnt;
					break;
			}
		EStTop -= 2;
		EStack[EStTop].ElType = OPERAND;
		}

/*****************************************************************************
	check for unary plus or minus
*****************************************************************************/

	else if ((EStTop >= (EStBot + 2)) &&
		 (EStack[EStTop].ElType == OPERAND) &&
		 (EStack[EStTop-1].ElType == OPERATOR))
		switch (ZChrIt(EStack[EStTop-1].Elemnt)) {
			case '+':	EStack[EStTop-1].Elemnt =
					EStack[EStTop].Elemnt;
					--EStTop;
					EStack[EStTop].ElType = OPERAND;
					break;
			case '-':	EStack[EStTop-1].Elemnt =
					- EStack[EStTop].Elemnt;
					--EStTop;
					EStack[EStTop].ElType = OPERAND;
					break;
			default :	Reducd = NO;
			}

/*****************************************************************************
	if it's (x),  reduce it to x
*****************************************************************************/

	else if ((EStTop >= (EStBot + 3)) &&
		 (EStack[EStTop].ElType == OPERATOR) &&
		 (EStack[EStTop-1].ElType == OPERAND) &&
		 (EStack[EStTop-2].ElType == OPERATOR) &&
		 (EStack[EStTop].Elemnt == ')') &&
		 (EStack[EStTop-2].Elemnt == '('))
		{
		EStTop -= 2;
		EStack[EStTop].Elemnt = EStack[EStTop+1].Elemnt;
		EStack[EStTop].ElType = OPERAND;
		}

/*****************************************************************************
	check for one's complement operator ^_.  This operator complements
the PRECEEDING argument.
*****************************************************************************/

	else if ((EStTop > EStBot) &&
		 (EStack[EStTop].ElType == OPERATOR) &&
		 (EStack[EStTop].Elemnt == USCHAR))
		{
		if ((EStTop == (EStBot + 1)) ||
		    (EStack[EStTop-1].ElType != OPERAND))
			{
			ErrMsg(ERR_NAB);	/* no arg before ^_ */
			return(FAILURE);
			}
		--EStTop;
		EStack[EStTop].Elemnt = ~EStack[EStTop].Elemnt;
		}
	else
		Reducd = NO;
	}
while (Reducd);
return(SUCCESS);
}
