/*****************************************************************************
*   "Irit" - the 3d (not only polygonal) solid modeller.		     *
*									     *
* Written by:  Gershon Elber				Ver 0.2, Mar. 1990   *
******************************************************************************
*   Module to handle overloaded operators for the input parser module.	     *
* Note this module should be accessed by Input Parser only (InptPrsr.c).     *
*****************************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <signal.h>
#include "program.h"
#include "allocate.h"
#include "attribut.h"
#include "bool_lib.h"
#include "freeform.h"
#include "geomat3d.h"
#include "inptprsg.h"
#include "inptprsl.h"
#include "objects.h"
#include "overload.h"

/* The following table help to decide if the operand are legal for the given */
/* operator. 5 entries for PLUS, MINUS, MULT, DIV, POWER. Each entry is a    */
/* square matrix of number of object types by number of object types:	     */

static IritExprType OverLoadDiadicTable[5][13][13] =
/*    POLY_EXPR	 NUMERIC_EXPR  POINT_EXPR   VECTOR_EXPR  PLANE_EXPR  MATRIX_EXPR  CURVE_EXPR  SURFACE_EXPR STRING_EXPR  OLST_EXPR    CTLPT_EXPR  TRIVAR_EXPR TRIMSRF_EXPR */
{ { /* PLUS */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     STRING_EXPR, NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      VECTOR_EXPR, VECTOR_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      VECTOR_EXPR, VECTOR_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    MATRIX_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,	  CURVE_EXPR, NO_EXPR,     NO_EXPR,     NO_EXPR,     CURVE_EXPR, NO_EXPR,    NO_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   STRING_EXPR,  NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     STRING_EXPR, NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     OLST_EXPR,   NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     CURVE_EXPR, NO_EXPR,     NO_EXPR,     NO_EXPR,     CURVE_EXPR, NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR } },

  { /* MINUS */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, NO_EXPR,     NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      VECTOR_EXPR, VECTOR_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      VECTOR_EXPR, VECTOR_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    MATRIX_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    NO_EXPR,	  NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR } },

  { /* MULT */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    POLY_EXPR,   NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, POINT_EXPR,  VECTOR_EXPR, NO_EXPR,    MATRIX_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 POINT_EXPR,   NUMERIC_EXPR,NUMERIC_EXPR,NO_EXPR,    POINT_EXPR,  NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 VECTOR_EXPR,  NUMERIC_EXPR,NUMERIC_EXPR,NO_EXPR,    VECTOR_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { POLY_EXPR, MATRIX_EXPR,  POINT_EXPR,  VECTOR_EXPR, NO_EXPR,    MATRIX_EXPR, CURVE_EXPR, SURFACE_EXPR,NO_EXPR,     OLST_EXPR,   CTLPT_EXPR, TRIVAR_EXPR,TRIMSRF_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    CURVE_EXPR,  NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    SURFACE_EXPR,NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    OLST_EXPR,   NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,	 NO_EXPR,    CTLPT_EXPR,  NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    TRIVAR_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    TRIMSRF_EXPR,NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR } },

  { /* DIV */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,	  NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR } },

  { /* POWER */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, NO_EXPR,	    NO_EXPR,	 NO_EXPR,    MATRIX_EXPR, NO_EXPR,    NO_EXPR,     STRING_EXPR, NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      VECTOR_EXPR, VECTOR_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      VECTOR_EXPR, VECTOR_EXPR, NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 MATRIX_EXPR,  NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,	  NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    POLY_EXPR,   NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   STRING_EXPR,  NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     STRING_EXPR, NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	    NO_EXPR,	 NO_EXPR,    NO_EXPR,     NO_EXPR,    NO_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR,    NO_EXPR,    NO_EXPR } },
};

/* The following table help to decide if the operand are legal for the given */
/* operator. 1 entry for UNARMINUS. Each entry is a linear vector of length  */
/* of number of object types:						     */

static IritExprType OverLoadMonadicTable[1][13] =
/*  POLY_EXPR  NUMERIC_EXPR  POINT_EXPR  VECTOR_EXPR  PLANE_EXPR  MATRIX_EXPR  CURVE_EXPR  SURFACE_EXPR  STRING_EXPR  OLST_EXPR  CTLPT_EXPR TRIVAR_EXPR TRIMSRF_EXPR */
{ /* UNARMINUS */
  { POLY_EXPR, NUMERIC_EXPR, POINT_EXPR, VECTOR_EXPR, PLANE_EXPR, MATRIX_EXPR, CURVE_EXPR, SURFACE_EXPR, NO_EXPR,     OLST_EXPR, NO_EXPR,   NO_EXPR,    NO_EXPR }
};

static int OverLoadTypeCheckAux(int Operator,
				IritExprType Right,
				IritExprType Left,
				IritExprType *Result);
static IPObjectStruct *ConvSrfToPolys(ParseTree *Srf);

/*****************************************************************************
* DESCRIPTION:                                                               M
* Performs type checking on the overloaded operators.			     M
*   Returns TRUE if legal, and sets Result to returned object type.	     M
*   Allows multiple types (I.e. VECTOR_EXPR | MATRIX_EXPR is legal input).   M
*   Note output Result may be multiple types as well is a such case.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   Operator:     To apply to left and right operands.                       M
*   Right, Left:  The two operands of the operations.                        M
*   Result:       Type of the resulting operation.                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:          TRUE if operation is defined and legal, FALSE otherwise.   M
*                                                                            *
* KEYWORDS:                                                                  M
*   OverLoadTypeCheck                                                        M
*****************************************************************************/
int OverLoadTypeCheck(int Operator,
		      IritExprType Right,
		      IritExprType Left,
		      IritExprType *Result)
{
    int i, j, NumRightTypes, NumLeftTypes;
    IritExprType TmpResult;

    /* Compute how many types are feasible here (input). */
    for (i = 1, NumRightTypes = 0; i < NO_EXPR; i <<= 1)
	NumRightTypes += (i & Right) != 0;
    for (i = 1, NumLeftTypes = 0; i < NO_EXPR; i <<= 1)
	NumLeftTypes += (i & Left) != 0;

    if (NumLeftTypes == 0) {
	if (Operator == UNARMINUS) {
	    *Result = 0;
	    for (i = 1; i < NO_EXPR; i <<= 1)
		if ((i & Right) != 0)
		    if (OverLoadTypeCheckAux(Operator, (IritExprType) i, Left,
					     &TmpResult))
			*Result |= TmpResult;
	    return *Result != 0;
	}
	else
	    return FALSE;
    }
    if (NumLeftTypes < 1 || NumRightTypes < 1)
	return FALSE;
    else if (NumLeftTypes == 1 && NumRightTypes == 1)
	return OverLoadTypeCheckAux(Operator, Right, Left, Result);
    else {
	/* More than one type in the input - compute union of the output     */
    	/* types and return the union.					     */
	*Result = 0;
    	for (i = 1; i < NO_EXPR; i <<= 1)
	    if ((i & Right) != 0)
		for (j = 1; j < NO_EXPR; j <<= 1)
		    if ((j & Left) != 0)
			if (OverLoadTypeCheckAux(Operator,
						 (IritExprType) i,
						 (IritExprType) j,
						 &TmpResult))
			    *Result |= TmpResult;

	return *Result != 0;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Auxiliary function of OverLoadTypeCheck.                                   *
*                                                                            *
* PARAMETERS:                                                                *
*   Operator:     To apply to left and right operands.                       *
*   Right, Left:  The two operands of the operations.                        *
*   Result:       Type of the resulting operation.                           *
*                                                                            *
* RETURN VALUE:                                                              *
*   int:          TRUE if operation is defined and legal, FALSE otherwise.   *
*****************************************************************************/
static int OverLoadTypeCheckAux(int Operator,
				IritExprType Right,
				IritExprType Left,
				IritExprType *Result)
{
    int i, IRight, ILeft;

    for (i = 1, IRight = 0; i < Right; i <<= 1, IRight++);
    for (i = 1, ILeft  = 0; i < Left;  i <<= 1, ILeft++);

    switch (Operator) {
	case PLUS:
	case MINUS:
	case MULT:
	case DIV:
	case POWER:
	    *Result = OverLoadDiadicTable[Operator - OPERATORS_OFFSET]
					 [IRight][ILeft];
	    return *Result != NO_EXPR;
	case UNARMINUS:
	    *Result = OverLoadMonadicTable[0][IRight];
	    return *Result != NO_EXPR;
	default:
	    IritFatalError("OverLoadTypeCheck: undefined operator");
    }
    return FALSE;				    /* Makes warning silent. */
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Evaluates a monadic or diadic expression.				     M
*   It is assumed the two operands are valid for the given expression - a    M
* test which can be made using OverLoadTypeCheck routine (see above).	     M
*   Returns a pointer to a node with the result, NULL in case of error	     M
* (should not happen actually due to verification).			     M
*                                                                            *
* PARAMETERS:                                                                M
*   Root:           The (overload) expression to evaluate.                   M
*   TempR, TempL:   Two operands of the expression.		             M
*   IError:         Error type if was one.                                   M
*   CError:         Description of error if was one.                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   ParseTree *:    Reslut of evaluated tree.                                M
*                                                                            *
* KEYWORDS:                                                                  M
*   OverLoadEvalOper                                                         M
*****************************************************************************/
ParseTree *OverLoadEvalOper(ParseTree *Root,
			    ParseTree *TempR,
			    ParseTree *TempL,
			    InptPrsrEvalErrType *IError,
			    char *CError)
{
    int i,
	OperReversed = FALSE;
    char *Str;
    RealType R, *RL, *RR;
    ParseTree *Temp,
	*RetVal = Root;
    IPObjectStruct *TempLObj, *TempRObj;

    switch (Root -> NodeKind) {		      /* Dies if undefined operator. */
	case PLUS:
	case MINUS:
	case MULT:
	case DIV:
	case POWER:
	    if (TempR == NULL ||
		TempL == NULL ||
		TempR -> PObj == NULL ||
		TempL -> PObj == NULL)
		return NULL;					   /* Error! */
	    break;

	case UNARMINUS:
	    if (TempR == NULL || TempR -> PObj == NULL)
		return NULL;					   /* Error! */
	    break;

	default:
	    IritFatalError("OverLoadEvalOper: Undefined operator");
    }

    /* Make TempL be bigger, so we need handle less cases. */
    if (Root -> NodeKind != UNARMINUS &&
	((int) TempR -> PObj -> ObjType) > ((int) TempL -> PObj -> ObjType)) {
	Temp = TempR;
	TempR = TempL;
	TempL = Temp;

	OperReversed = TRUE;
    }

    switch (Root -> NodeKind) {
	case PLUS:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {
		Root -> PObj = GenNUMValObject(TempL -> PObj -> U.R +
					       TempR -> PObj -> U.R);
	    }
	    else if (IS_NUM_NODE(TempR) && IS_STR_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_STRING, NULL);
		Str = Root -> PObj -> U.Str;
		if (OperReversed) {
		    sprintf(Str, "%d", (int) (TempR -> PObj -> U.R));
		    strncpy(&Str[strlen(Str)],
			    TempL -> PObj -> U.Str, LINE_LEN - 1);
		}
		else {
		    strncpy(Str, TempL -> PObj -> U.Str, LINE_LEN - 1);
		    sprintf(&Str[strlen(Str)], "%d",
			    (int) (TempR -> PObj -> U.R));
		}
	    }
	    else if (IS_PT_NODE(TempR) && IS_PT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		PT_ADD(Root -> PObj -> U.Vec,
			TempL -> PObj -> U.Pt, TempR -> PObj -> U.Pt);
	    }
	    else if (IS_PT_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		PT_ADD(Root -> PObj -> U.Vec,
			TempL -> PObj -> U.Vec, TempR -> PObj -> U.Pt);
	    }
	    else if (IS_VEC_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		PT_ADD(Root -> PObj -> U.Vec,
			TempL -> PObj -> U.Vec, TempR -> PObj -> U.Vec);
	    }
	    else if (IS_MAT_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_MATRIX, NULL);
                MatAddTwo4by4(*Root -> PObj -> U.Mat,
			      *TempL -> PObj -> U.Mat,
			      *TempR -> PObj -> U.Mat);
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);

		Root -> PObj = BooleanOR(TempLObj, TempRObj);
		signal(SIGFPE, DefaultFPEHandler);  /* Default FPE trapping. */

		if (Root -> PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", PLUS, Root);
		    RetVal = NULL;
		}
	    }
	    else if (IS_STR_NODE(TempR) && IS_STR_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_STRING, NULL);
		Str = Root -> PObj -> U.Str;
		sprintf(Str, "%s%s", TempL -> PObj -> U.Str,
				     TempR -> PObj -> U.Str);
	    }
	    else if (IS_OLST_NODE(TempR) && IS_OLST_NODE(TempL)) {
	    	Root -> PObj = AppendLists(TempL -> PObj, TempR -> PObj);
	    }
	    else if ((IS_CTLPT_NODE(TempR) || IS_CRV_NODE(TempR)) &&
		     (IS_CTLPT_NODE(TempL) || IS_CRV_NODE(TempL))) {
		if (OperReversed)
		    Root -> PObj = MergeCurvesAndCtlPoints(TempR -> PObj,
							   TempL -> PObj);
		else
		    Root -> PObj = MergeCurvesAndCtlPoints(TempL -> PObj,
							   TempR -> PObj);
	    }
	    else
		RetVal = NULL;
	    break;
	case MINUS:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {
		Root -> PObj = GenNUMValObject(TempL -> PObj -> U.R -
					       TempR -> PObj -> U.R);
	    }
	    else if (IS_PT_NODE(TempR) && IS_PT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		PT_SUB(Root -> PObj -> U.Vec,
		       TempL -> PObj -> U.Pt, TempR -> PObj -> U.Pt);
	    }
	    else if (IS_PT_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		RL = OperReversed ? TempR -> PObj -> U.Pt
				  : TempL -> PObj -> U.Vec;
		RR = OperReversed ? TempL -> PObj -> U.Pt
				  : TempR -> PObj -> U.Vec;
		PT_SUB(Root -> PObj -> U.Vec, RL, RR);
	    }
	    else if (IS_VEC_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		PT_SUB(Root -> PObj -> U.Vec,
		       TempL -> PObj -> U.Vec, TempR -> PObj -> U.Vec);
	    }
	    else if (IS_MAT_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_MATRIX, NULL);
                MatSubTwo4by4(*Root -> PObj -> U.Mat,
			      *TempL -> PObj -> U.Mat,
			      *TempR -> PObj -> U.Mat);
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);

		Root -> PObj = BooleanSUB(TempLObj, TempRObj);
		signal(SIGFPE, DefaultFPEHandler);  /* Default FPE trapping. */

		if (Root -> PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", MINUS, Root);
		    RetVal = NULL;
		}
	    }
	    else
		RetVal = NULL;
	    break;
	case MULT:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {
		Root -> PObj = GenNUMValObject(TempL -> PObj -> U.R *
					       TempR -> PObj -> U.R);
	    }
	    else if (IS_PT_NODE(TempR) && IS_PT_NODE(TempL)) {
		Root -> PObj =
		    GenNUMValObject(DOT_PROD(TempL -> PObj -> U.Pt,
					     TempR -> PObj -> U.Pt));
	    }
	    else if (IS_PT_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root -> PObj =
		    GenNUMValObject(DOT_PROD(TempL -> PObj -> U.Vec,
					     TempR -> PObj -> U.Pt));
	    }
	    else if (IS_VEC_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root -> PObj =
		    GenNUMValObject(DOT_PROD(TempL -> PObj -> U.Vec,
					     TempR -> PObj -> U.Vec));
	    }
	    else if (IS_MAT_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_MATRIX, NULL);
                MatMultTwo4by4(*Root -> PObj -> U.Mat,
			       *TempL -> PObj -> U.Mat,
			       *TempR -> PObj -> U.Mat);
	    }
	    else if (IS_NUM_NODE(TempR) && IS_PT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_POINT, NULL);
		PT_COPY(Root -> PObj -> U.Pt, TempL -> PObj -> U.Pt);
		PT_SCALE(Root -> PObj -> U.Pt, TempR -> PObj -> U.R);
	    }
	    else if (IS_NUM_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		PT_COPY(Root -> PObj -> U.Vec, TempL -> PObj -> U.Vec);
		PT_SCALE(Root -> PObj -> U.Vec, TempR -> PObj -> U.R);
	    }
	    else if (IS_NUM_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_MATRIX, NULL);
		MatScale4by4(*Root -> PObj -> U.Mat,
			     *TempL -> PObj -> U.Mat,
			     &TempR -> PObj -> U.R);
	    }
	    else if (IS_POLY_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root -> PObj = GMTransformObject(TempR -> PObj,
						 *TempL -> PObj -> U.Mat);
	    }
	    else if (IS_MAT_NODE(TempR) &&
		     (IS_CRV_NODE(TempL) ||
		      IS_SRF_NODE(TempL) ||
		      IS_CTLPT_NODE(TempL) ||
		      IS_OLST_NODE(TempL) ||
		      IS_TRIVAR_NODE(TempL) ||
		      IS_TRIMSRF_NODE(TempL))) {
		Root -> PObj = GMTransformObject(TempL -> PObj,
						 *TempR -> PObj -> U.Mat);
	    }
	    else if (IS_VEC_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		MatMultVecby4by4(Root -> PObj -> U.Vec,
				 TempR -> PObj -> U.Vec,
				 *TempL -> PObj -> U.Mat);
	    }
	    else if (IS_PT_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_POINT, NULL);
		MatMultVecby4by4(Root -> PObj -> U.Pt,
				 TempR -> PObj -> U.Pt,
				 *TempL -> PObj -> U.Mat);
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);

		Root -> PObj = BooleanAND(TempLObj, TempRObj);
		signal(SIGFPE, DefaultFPEHandler);  /* Default FPE trapping. */

		if (Root -> PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", MULT, Root);
		    RetVal = NULL;
		}
	    }
	    else
		RetVal = NULL;
	    break;
	case DIV:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {  /* Numeric div. */
		if (TempR -> PObj -> U.R != 0.0) {
		    Root -> PObj = GenNUMValObject(TempL -> PObj -> U.R /
						   TempR -> PObj -> U.R);
		}
		else {
		    *IError = IE_ERR_DIV_BY_ZERO;
		    strcpy(CError, "/");
		    RetVal = NULL;
		}
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);

		Root -> PObj = OperReversed ? BooleanCUT(TempRObj, TempLObj)
					    : BooleanCUT(TempLObj, TempRObj);
		signal(SIGFPE, DefaultFPEHandler);  /* Default FPE trapping. */

		if (Root -> PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", DIV, Root);
		    RetVal = NULL;
		}
	    }
	    else
		RetVal = NULL;
	    break;
	case POWER:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {/* Numeric power. */
		Root -> PObj = GenNUMValObject(pow(TempL -> PObj -> U.R,
						   TempR -> PObj -> U.R));
	    }
	    else if (IS_NUM_NODE(TempR) && IS_MAT_NODE(TempL)) {
		/* Power MUST be integer in this case. */
		i = (int) TempR -> PObj -> U.R;
		if (!APX_EQ(i, TempR -> PObj -> U.R) || i < -1) {
		    *IError = IE_ERR_MAT_POWER;
		    strcpy(CError, "^");
		    RetVal = NULL;
		}
		Root -> PObj = IPAllocObject("", IP_OBJ_MATRIX, NULL);
		if (i == -1) {		     /* Generate the inverse matrix: */
		    if (!MatInverseMatrix(*TempL -> PObj -> U.Mat,
					  *Root -> PObj -> U.Mat)) {
			*IError = IE_ERR_MAT_POWER;
			strcpy(CError, "^");
			RetVal = NULL;
		    }
		}
		else {			      /* I must be positive integer. */
		    MatGenUnitMat(*Root -> PObj -> U.Mat);
		    while (i--)
		        MatMultTwo4by4(*Root -> PObj -> U.Mat,
				       *Root -> PObj -> U.Mat,
				       *TempL -> PObj -> U.Mat);
		}
	    }
	    else if (IS_NUM_NODE(TempR) && IS_STR_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_STRING, NULL);
		Str = Root -> PObj -> U.Str;
		if (OperReversed) {
		    sprintf(Str, GlblFloatFormat, TempR -> PObj -> U.R);
		    strcpy(&Str[strlen(Str)], TempL -> PObj -> U.Str);
		}
		else {
		    strcpy(Str, TempL -> PObj -> U.Str);
		    sprintf(&Str[strlen(Str)], GlblFloatFormat,
			    TempR -> PObj -> U.R);
		}
	    }
	    else if (IS_PT_NODE(TempR) && IS_PT_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		GMVecCrossProd(Root -> PObj ->U.Vec,
			       TempR -> PObj -> U.Pt,
			       TempL -> PObj -> U.Pt);
	    }
	    else if (IS_PT_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		GMVecCrossProd(Root -> PObj ->U.Vec,
			       OperReversed ? TempL -> PObj -> U.Vec
					    : TempR -> PObj -> U.Pt,
			       OperReversed ? TempR -> PObj -> U.Pt
					    : TempL -> PObj -> U.Vec);
	    }
	    else if (IS_VEC_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		GMVecCrossProd(Root -> PObj ->U.Vec,
			       TempR -> PObj -> U.Vec,
			       TempL -> PObj -> U.Vec);
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);

		Root -> PObj = BooleanMERGE(TempLObj, TempRObj);
		signal(SIGFPE, DefaultFPEHandler);  /* Default FPE trapping. */

		if (Root -> PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", MINUS, Root);
		    RetVal = NULL;
		}
	    }
	    else if (IS_STR_NODE(TempR) && IS_STR_NODE(TempL)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_STRING, NULL);
		Str = Root -> PObj -> U.Str;
		sprintf(Str, "%s%s", TempL -> PObj -> U.Str,
				     TempR -> PObj -> U.Str);
	    }
	    else
		RetVal = NULL;
	    break;
	case UNARMINUS:
	    if (IS_NUM_NODE(TempR)) {
		Root -> PObj = GenNUMValObject(-TempR -> PObj -> U.R);
	    }
	    else if (IS_PT_NODE(TempR)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_POINT, NULL);
		PT_COPY(Root -> PObj -> U.Pt, TempR -> PObj -> U.Pt);
		PT_SCALE(Root -> PObj -> U.Pt, -1.0);
	    }
	    else if (IS_VEC_NODE(TempR)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_VECTOR, NULL);
		PT_COPY(Root -> PObj -> U.Vec, TempR -> PObj -> U.Vec);
		PT_SCALE(Root -> PObj -> U.Vec, -1.0);
	    }
	    else if (IS_PLANE_NODE(TempR)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_PLANE, NULL);
		PLANE_COPY(Root -> PObj -> U.Plane, TempR -> PObj -> U.Plane);
		for (i = 0; i < 4; i++)
		    Root -> PObj -> U.Plane[i] = -Root -> PObj -> U.Plane[i];
	    }
	    else if (IS_MAT_NODE(TempR)) {
		Root -> PObj = IPAllocObject("", IP_OBJ_MATRIX, NULL);
		R = -1.0;
		MatScale4by4(*Root -> PObj -> U.Mat,
			     *TempR -> PObj -> U.Mat,
			     &R);
	    }
	    else if (IS_POLY_NODE(TempR)) {
		Root -> PObj = BooleanNEG(TempR -> PObj);
		signal(SIGFPE, DefaultFPEHandler);  /* Default FPE trapping. */
	    }
	    else if (IS_CRV_NODE(TempR)) {
		Root -> PObj = CurveReverse(TempR -> PObj);
	    }
	    else if (IS_SRF_NODE(TempR)) {
		Root -> PObj = SurfaceReverse(TempR -> PObj);
	    }
	    else if (IS_OLST_NODE(TempR)) {
		Root -> PObj = ReverseListObj(TempR -> PObj);
	    }
	    else
		RetVal = NULL;
	    break;
    }
    if (RetVal == NULL && *IError == IPE_NO_ERR) { /* Put general error msg: */
	*IError = IE_ERR_TYPE_MISMATCH;
	switch (Root -> NodeKind) {
	    case PLUS:
		strcpy(CError, "Operator +");
		break;
	    case MINUS:
		strcpy(CError, "Operator -");
		break;
	    case MULT:
		strcpy(CError, "Operator *");
		break;
	    case DIV:
		strcpy(CError, "Operator /");
		break;
	    case POWER:
		strcpy(CError, "Operator ^");
		break;
	    case UNARMINUS:
		strcpy(CError, "Operator (unary) -");
		break;
	}
    }

    return RetVal;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* If given object is a surface, its polygonal representation object is       *
* returned instead. Otherwise the given pointer is returned as is.           *
*                                                                            *
* PARAMETERS:                                                                *
*   Srf:       To convert to polygons and return a polygonal approximation.  *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPObjectStruct *:  A polygona approximation of Srf, or original object   *
*                      if not a surface.                                     *
*****************************************************************************/
static IPObjectStruct *ConvSrfToPolys(ParseTree *Srf)
{
    IPObjectStruct *PObjPolys;
    if (!IS_SRF_NODE(Srf))
	return Srf -> PObj;

    if ((PObjPolys = AttrGetObjectObjAttrib(Srf -> PObj, "_polygons"))
								== NULL) {
    	ComputeSurfacePolygons(Srf -> PObj);
    	PObjPolys = AttrGetObjectObjAttrib(Srf -> PObj, "_polygons");
    }

    return PObjPolys;
}
