/*****************************************************************************
*   "Irit" - the 3d (not only polygonal) solid modeller.		     *
*									     *
* Written by:  Gershon Elber				Ver 0.2, Mar. 1990   *
******************************************************************************
*   Module to evaluate the binary tree generated by the InptPrsr module.     *
*   All the objects are handled the same but the numerical one, which is     *
* moved as a RealType and not as an object (only internally within this	     *
* module) as it is frequently used and consumes much less memory this way.   *
*   Note this module is par of InptPrsr module and was splited only because  *
* of text file sizes problems...					     *
*****************************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include "program.h"
#include "allocate.h"
#include "attribut.h"
#include "convex.h"
#include "ctrl-brk.h"
#include "dosintr.h"
#include "freeform.h"
#include "geomat3d.h"
#include "geomvals.h"
#include "inptprsg.h"
#include "inptprsl.h"
#include "objects.h"
#include "overload.h"
#include "primitiv.h"
#include "windows.h"
#include "iritgrap.h"

InptPrsrEvalErrType
    IPGlblEvalError = IPE_NO_ERR;		 /* Global used by EvalTree. */

/*   I prefer to put the declarations of static functions just before the    */
/* function themselves, but the tables below needs them so...		     */
static int InptEvalFetchParameters(ParseTree *Root, FuncTableType *FuncTable,
	   int NumParams, int Level, ParseTree *Params[], VoidPtr ParamPtrs[]);
static int FuncParamMismatch(ParseTree *Root);
static void LocalPrintTree(ParseTree *Root, int Level, char *Str);

/* Although the type of parameters is specified (for InptPrsrTypeCheck rtn)  */
/* All the parameters to the following dispatched functions are passed by    */
/* address. There is a problem in TurboC (ANSI C?) that all the real types   */
/* are passed as double, even if the are float. As RealType may be float,    */
/* the problems is hidden by passing parameters by address...		     */

NumFuncTableType NumFuncTable[] = {
    { "ACOS",	 ARCCOS,acos,		1,	{ NUMERIC_EXPR } },
    { "ASIN",	 ARCSIN,asin,		1,	{ NUMERIC_EXPR } },
    { "ATAN2",	 ARCTAN2,atan2,		2,	{ NUMERIC_EXPR, NUMERIC_EXPR } },
    { "ATAN",	 ARCTAN,atan,		1,	{ NUMERIC_EXPR } },
    { "COS",	 COS,	cos,		1,	{ NUMERIC_EXPR } },
    { "EXP",	 EXP,	exp,		1,	{ NUMERIC_EXPR } },
    { "ABS",	 FABS,	fabs,		1,	{ NUMERIC_EXPR } },
    { "LN",	 LN,	log,		1,	{ NUMERIC_EXPR } },
    { "LOG",	 LOG,	log10,		1,	{ NUMERIC_EXPR } },
    { "SIN",	 SIN,	sin,		1,	{ NUMERIC_EXPR } },
    { "SQRT",	 SQRT,	sqrt,		1,	{ NUMERIC_EXPR } },
    { "TAN",	 TAN,	tan,		1,	{ NUMERIC_EXPR } },
    { "CPOLY",	 CPOLY,	PolyCountPolys,	1,	{ POLY_EXPR } },
    { "AREA",	 AREA,	PolyObjectArea,	1,	{ POLY_EXPR } },
    { "VOLUME",  VOLUME,PolyObjectVolume,1, 	{ POLY_EXPR } },
    { "TIME",	 TIME,	DosGetTime,	1,	{ NUMERIC_EXPR } },
    { "LISTSIZE",LISTSIZE,GetListSize,	1,	{ OLST_EXPR | POLY_EXPR } },
    { "THISOBJ", THISOBJ,ThisObjectIs,	1,	{ ANY_EXPR } }
};
int NumFuncTableSize = sizeof(NumFuncTable) / sizeof(NumFuncTableType);

ObjFuncTableType ObjFuncTable[] = {
    { "POINT",	  POINT,	GenPTObject,		3,	{ NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		POINT_EXPR },
    { "VECTOR",	  VECTOR,	GenVECObject,		3,	{ NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		VECTOR_EXPR },
    { "PLANE",	  PLANE,	GenPLANEObject,		4,	{ NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, PLANE_EXPR },
    { "CTLPT",	  CTLPT,	InptEvalCtlPtFromParams, ANY_PARAM_NUM, { 0 },						CTLPT_EXPR },
    { "ROTX",	  ROTX,		GMGenMatObjectRotX,	1,	{ NUMERIC_EXPR },					MATRIX_EXPR },
    { "ROTY",	  ROTY,		GMGenMatObjectRotY,	1,	{ NUMERIC_EXPR },					MATRIX_EXPR },
    { "ROTZ",	  ROTZ,		GMGenMatObjectRotZ,	1,	{ NUMERIC_EXPR },					MATRIX_EXPR },
    { "TRANS",	  TRANS,	GMGenMatObjectTrans,	1,	{ VECTOR_EXPR },					MATRIX_EXPR },
    { "SCALE",	  SCALE,	GMGenMatObjectScale,	1,	{ VECTOR_EXPR },					MATRIX_EXPR },
    { "BOX",	  BOX,		GenBOXObject,		4,	{ VECTOR_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, POLY_EXPR },
    { "GBOX",	  GBOX,		GenGBOXObject,		4,	{ VECTOR_EXPR, VECTOR_EXPR, VECTOR_EXPR, VECTOR_EXPR }, POLY_EXPR },
    { "CONE",	  CONE,		GenCONEObject,		3,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR },		POLY_EXPR },
    { "CON2",	  CONE2,	GenCONE2Object,		4,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, POLY_EXPR },
    { "CYLIN",	  CYLIN,	GenCYLINObject,		3,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR },		POLY_EXPR },
    { "SPHERE",	  SPHERE,	GenSPHEREObject,	2,	{ VECTOR_EXPR, NUMERIC_EXPR },				POLY_EXPR },
    { "TORUS",	  TORUS,	GenTORUSObject,		4,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, POLY_EXPR },
    { "CIRCPOLY", CIRCPOLY,	GenPOLYDISKObject,	3,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR },		POLY_EXPR },
    { "POLY",     POLY,		GenPOLYGONObject,	2,	{ OLST_EXPR, NUMERIC_EXPR },				POLY_EXPR },
    { "CROSSEC",  CROSSEC,	GenCROSSECObject,	1,	{ POLY_CURVE_EXPR },					POLY_EXPR },
    { "SURFREV",  SURFREV,	GenSURFREVObject,	1,	{ POLY_CURVE_EXPR },					POLY_EXPR | SURFACE_EXPR },
    { "EXTRUDE",  EXTRUDE,	GenEXTRUDEObject,	2,	{ POLY_CURVE_EXPR, VECTOR_EXPR },			POLY_EXPR | SURFACE_EXPR },
    { "LIST",	  LIST,		InptEvalGenObjectList,	ANY_PARAM_NUM, { 0 },						OLST_EXPR },
    { "LOAD",     LOAD,		LoadObjectFromFile,	1,	{ STRING_EXPR },					ANY_EXPR },
    { "CONVEX",	  CONVEX,	ConvexPolyObjectN,	1,	{ POLY_EXPR },						POLY_EXPR },
    { "SBEZIER",  SBEZIER,	GenBezierSurfaceObject, 1,	{ OLST_EXPR },						SURFACE_EXPR },
    { "CBEZIER",  CBEZIER,	GenBezierCurveObject,	1,	{ OLST_EXPR },						CURVE_EXPR },
    { "SBSPLINE", SBSPLINE,	GenBsplineSurfaceObject,4,	{ NUMERIC_EXPR, NUMERIC_EXPR, OLST_EXPR, OLST_EXPR },	SURFACE_EXPR },
    { "CBSPLINE", CBSPLINE,	GenBsplineCurveObject,	3,	{ NUMERIC_EXPR, OLST_EXPR, OLST_EXPR },			CURVE_EXPR },
    { "SEVAL",    SEVAL,	EvalSurfaceObject,	3,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		CTLPT_EXPR },
    { "CEVAL",    CEVAL,	EvalCurveObject,	2,	{ CURVE_EXPR, NUMERIC_EXPR },				CTLPT_EXPR },
    { "STANGENT", STANGENT,	TangentSurfaceObject,	4,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, VECTOR_EXPR },
    { "CTANGENT", CTANGENT,	TangentCurveObject,	2,	{ CURVE_EXPR, NUMERIC_EXPR },				VECTOR_EXPR },
    { "SNORMAL",  SNORMAL,	NormalSurfaceObject,	3,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		VECTOR_EXPR },
    { "SDIVIDE",  SDIVIDE,	DivideSurfaceObject,	3,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		OLST_EXPR },
    { "CDIVIDE",  CDIVIDE,	DivideCurveObject,	2,	{ CURVE_EXPR, NUMERIC_EXPR },				OLST_EXPR },
    { "SREGION",  SREGION,	RegionFromSurfaceObject,4,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, SURFACE_EXPR },
    { "CREGION",  CREGION,	RegionFromCurveObject,	3,	{ CURVE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		CURVE_EXPR },
    { "SREFINE",  SREFINE,	RefineSurfaceObject,	4,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, OLST_EXPR }, SURFACE_EXPR },
    { "CREFINE",  CREFINE,	RefineCurveObject,	3,	{ CURVE_EXPR, NUMERIC_EXPR, OLST_EXPR },		CURVE_EXPR },
    { "SRAISE",   SRAISE,	RaiseSurfaceObject,	3,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		SURFACE_EXPR },
    { "CRAISE",   CRAISE,	RaiseCurveObject,	2,	{ CURVE_EXPR, NUMERIC_EXPR },				CURVE_EXPR },
    { "CSURFACE", CSURFACE,	CurveFromSurface,	3,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		CURVE_EXPR },
    { "CMESH",    CMESH,	CurveFromSrfMesh,	3,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		CURVE_EXPR },
    { "NTH",	  NTH,		GetNthList,		2,	{ OLST_EXPR, NUMERIC_EXPR },				ANY_EXPR },
    { "GPOLYGON", GPOLYGON,	Geometry2Polygons,	1,	{ OLST_GEOM_EXPR },					POLY_EXPR },
    { "GPOLYLINE",GPOLYLINE,	Geometry2Polylines,	1,	{ OLST_GEOM_EXPR },					POLY_EXPR },
    { "CIRCLE",   CIRCLE,	GenCircleCurveObject,	2,	{ VECTOR_EXPR, NUMERIC_EXPR },				CURVE_EXPR },
    { "ARC",	  ARC,		GenArcCurveObject,	3,	{ VECTOR_EXPR, VECTOR_EXPR, VECTOR_EXPR },		CURVE_EXPR },
    { "RULEDSRF", RULEDSRF,	GenRuledSrfObject,	2,	{ CURVE_EXPR, CURVE_EXPR },				SURFACE_EXPR },
    { "BOOLSUM",  BOOLSUM,	GenBoolSumSrfObject,	4,	{ CURVE_EXPR, CURVE_EXPR, CURVE_EXPR, CURVE_EXPR },	SURFACE_EXPR },
    { "BOOLONE",  BOOLONE,	GenBoolOneSrfObject,	1,	{ CURVE_EXPR },						SURFACE_EXPR },
    { "SFROMCRVS", SFROMCRVS,	GenSrfFromCrvsObject,	2,	{ OLST_EXPR, NUMERIC_EXPR },				SURFACE_EXPR },
    { "SWEEPSRF", SWEEPSRF,	GenSweepSrfObject,	4,	{ CURVE_EXPR, CURVE_EXPR, CURVE_EXPR | NUMERIC_EXPR, CURVE_EXPR | VECTOR_EXPR | NUMERIC_EXPR},	SURFACE_EXPR },
    { "OFFSET",	  OFFSET,	GenOffsetObject,	2,	{ CURVE_EXPR | SURFACE_EXPR, NUMERIC_EXPR },		CURVE_EXPR | SURFACE_EXPR },
    { "AOFFSET",  AOFFSET,	GenAOffsetObject,	4,	{ CURVE_EXPR | SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, CURVE_EXPR | SURFACE_EXPR | OLST_EXPR },
    { "COERCE",   COERCE,	CoerceObjectTo,		2,	{ ANY_EXPR, NUMERIC_EXPR },				ANY_EXPR },
    { "CEDITPT",  CEDITPT,	EditCrvControlPoint,	3,	{ CURVE_EXPR, CTLPT_EXPR, NUMERIC_EXPR },		CURVE_EXPR },
    { "SEDITPT",  SEDITPT,	EditSrfControlPoint,	4,	{ SURFACE_EXPR, CTLPT_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, SURFACE_EXPR },
    { "MERGEPOLY",MERGEPOLY,	GenObjectFromPolyList,	1,	{ OLST_EXPR },						POLY_EXPR },
    { "SMORPH",   SMORPH,	TwoSrfsMorphing,	3,	{ SURFACE_EXPR, SURFACE_EXPR, NUMERIC_EXPR },		SURFACE_EXPR },
    { "BZR2BSP",  BZR2BSP,	CnvrtBezierToBspline,	1,	{ SURFACE_EXPR | CURVE_EXPR },				CURVE_EXPR | SURFACE_EXPR },
    { "BSP2BZR",  BSP2BZR,	CnvrtBsplineToBezier,	1,	{ SURFACE_EXPR | CURVE_EXPR },				CURVE_EXPR | SURFACE_EXPR },
    { "SMERGE",   SMERGE,	MergeSrfSrf,		4,	{ SURFACE_EXPR, SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, SURFACE_EXPR },
    { "CDERIVE",  CDERIVE,	DeriveCurveObject,	1,	{ CURVE_EXPR },						CURVE_EXPR },
    { "SDERIVE",  SDERIVE,	DeriveSurfaceObject,	2,	{ SURFACE_EXPR, NUMERIC_EXPR },				SURFACE_EXPR },
    { "SNRMLSRF", SNRMLSRF,	SurfaceNormalObject,	1,	{ SURFACE_EXPR },					SURFACE_EXPR },
    { "SYMBPROD", SYMBPROD,	TwoCrvsSrfsProduct,	2,	{ CURVE_EXPR | SURFACE_EXPR, CURVE_EXPR | SURFACE_EXPR }, CURVE_EXPR | SURFACE_EXPR },
    { "SYMBDPROD",SYMBDPROD,	TwoCrvsSrfsDotProduct,	2,	{ CURVE_EXPR | SURFACE_EXPR, CURVE_EXPR | SURFACE_EXPR }, CURVE_EXPR | SURFACE_EXPR },
    { "SYMBCPROD",SYMBCPROD,	TwoCrvsSrfsCrossProduct,2,	{ CURVE_EXPR | SURFACE_EXPR, CURVE_EXPR | SURFACE_EXPR }, CURVE_EXPR | SURFACE_EXPR },
    { "SYMBSUM",  SYMBSUM,	TwoCrvsSrfsSum,		2,	{ CURVE_EXPR | SURFACE_EXPR, CURVE_EXPR | SURFACE_EXPR }, CURVE_EXPR | SURFACE_EXPR },
    { "SYMBDIFF", SYMBDIFF,	TwoCrvsSrfsDiff,	2,	{ CURVE_EXPR | SURFACE_EXPR, CURVE_EXPR | SURFACE_EXPR }, CURVE_EXPR | SURFACE_EXPR },
    { "HOMOMAT",  HOMOMAT,	GenMatObjectGeneric,	1,	{ OLST_EXPR },						MATRIX_EXPR },
    { "CINFLECT", CINFLECT,	CrvInflectionPts,	2,	{ CURVE_EXPR, NUMERIC_EXPR },				CURVE_EXPR | OLST_EXPR },
    { "CCRVTR",   CCRVTR,	CrvCurvaturePts,	2,	{ CURVE_EXPR, NUMERIC_EXPR },				CURVE_EXPR | OLST_EXPR },
    { "CZEROS",   CZEROS,	CrvZeros,		3,	{ CURVE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		OLST_EXPR },
    { "CEXTREMES",CEXTREMES,	CrvExtremes,		3,	{ CURVE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },		OLST_EXPR },
    { "CCINTER",  CCINTER,	CrvCrvInter,		4,	{ CURVE_EXPR, CURVE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },	SURFACE_EXPR | OLST_EXPR },
    { "NIL",      NIL,	        GetNilList,		0, 	{ 0 },							OLST_EXPR },
    { "COORD",    COORD,        GetObjectCoord,		2, 	{ ANY_EXPR, NUMERIC_EXPR },				NUMERIC_EXPR | CTLPT_EXPR | POINT_EXPR },
    { "COMPOSE",  COMPOSE,      CrvComposition,		2, 	{ CURVE_EXPR | SURFACE_EXPR, CURVE_EXPR },		CURVE_EXPR },
    { "PRISA",    PRISA,        SrfsPrisa,		5, 	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, VECTOR_EXPR }, OLST_EXPR },
    { "CRVPTDST", CRVPTDIST,    CrvPointDist,		4, 	{ CURVE_EXPR, POINT_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },	NUMERIC_EXPR | OLST_EXPR },
    { "CRVLNDST", CRVLNDIST,    CrvLineDist,		5, 	{ CURVE_EXPR, POINT_EXPR, VECTOR_EXPR, NUMERIC_EXPR, NUMERIC_EXPR },	  NUMERIC_EXPR | OLST_EXPR },
    { "ADAPISO",  ADAPISO,      SrfAdapIsoCurves,	5, 	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR }, OLST_EXPR | CURVE_EXPR },
    { "PDOMAIN",  PDOMAIN,	GetCrvSrfPDomain,	1,	{ SURFACE_EXPR | CURVE_EXPR }, OLST_EXPR }
};
int ObjFuncTableSize = sizeof(ObjFuncTable) / sizeof(ObjFuncTableType);

/* The cast for DosSystem below is because of the xlc compiler for the R6000 */
/* aix system complains on DosSystem as function with no arguments, so we    */
/* make it think it has one integer argument...				     */
GenFuncTableType GenFuncTable[] = {
    { "EXIT",	EXIT,		IritExit0,		0,	{ 0 } },
    { "VIEWOBJ",VIEWOBJ,	WndwViewObject,		1,	{ ANY_EXPR } },
    { "CHDIR",	CHDIR,		DosChangeDir,		1,	{ STRING_EXPR } },
    { "INCLUDE",INCLUDE,	FileInclude,		1,	{ STRING_EXPR } },
    { "SAVE",	SAVE,		SaveObjectInFile,	2,	{ STRING_EXPR, ANY_EXPR } },
    { "FREE",	FREEOBJ,	FreeObject,		1,	{ ANY_EXPR } },
    { "PAUSE",	PAUSE,		WndwPause,		1,	{ NUMERIC_EXPR } },
    { "IF",	IFCOND, 	InptEvalIfCondition,	ANY_PARAM_NUM, { 0 } },
    { "FOR",	FORLOOP, 	InptEvalForLoop,	4,	{ NUMERIC_EXPR,	NUMERIC_EXPR, NUMERIC_EXPR, ANY_EXPR } },
    { "HELP",	PRHELP,		InptEvalPrintHelp,	1,	{ STRING_EXPR } },
    { "VARLIST", VARLIST, 	PrintObjectList,	0,	{ 0 } },
    { "SYSTEM",	SYSTEM,		DosSystem,		1,	{ STRING_EXPR } },
    { "LOGFILE",LOGFILE, 	WndwLogPrint,		1,	{ NUMERIC_EXPR } },
    { "COLOR",	COLOR,		AttrSetObjectColor, 	2,	{ OLST_GEOM_EXPR, NUMERIC_EXPR } },
    { "SNOC",	SNOC,		SnocList,		2,	{ ANY_EXPR, OLST_EXPR } },
    { "ATTRIB",	ATTRIB,		SetObjectAttrib,	3,	{ ANY_EXPR, STRING_EXPR, STRING_EXPR | NUMERIC_EXPR } },
    { "FFCOMPAT",FFCOMPAT,	MakeFreeFormCompatible,	2,	{ CURVE_EXPR | SURFACE_EXPR, CURVE_EXPR | SURFACE_EXPR } },
    { "PRINTF", IRITPRINT,	IritObjectPrintfStdout,	2,	{ STRING_EXPR, OLST_EXPR } }
};
int GenFuncTableSize = sizeof(GenFuncTable) / sizeof(GenFuncTableType);

ConstantTableType ConstantTable[] = {
    { "PI",	M_PI },

    { "ON",	1.0 },
    { "TRUE",	1.0 },
    { "OFF",	0.0 },
    { "FALSE",	0.0 },

    { "COL",    (double) CAGD_CONST_U_DIR },
    { "ROW",    (double) CAGD_CONST_V_DIR },

    { "KV_OPEN", (double) KV_UNIFORM_OPEN },
    { "KV_FLOAT", (double) KV_UNIFORM_FLOAT },

    { "E1", (double) CAGD_PT_E1_TYPE },
    { "E2", (double) CAGD_PT_E2_TYPE },
    { "E3", (double) CAGD_PT_E3_TYPE },
    { "E4", (double) CAGD_PT_E4_TYPE },
    { "E5", (double) CAGD_PT_E5_TYPE },

    { "P1", (double) CAGD_PT_P1_TYPE },
    { "P2", (double) CAGD_PT_P2_TYPE },
    { "P3", (double) CAGD_PT_P3_TYPE },
    { "P4", (double) CAGD_PT_P4_TYPE },
    { "P5", (double) CAGD_PT_P5_TYPE },

    { "POLY_TYPE",    (double) IP_OBJ_POLY },
    { "NUMERIC_TYPE", (double) IP_OBJ_NUMERIC },
    { "POINT_TYPE",   (double) IP_OBJ_POINT },
    { "VECTOR_TYPE",  (double) IP_OBJ_VECTOR },
    { "PLANE_TYPE",   (double) IP_OBJ_PLANE },
    { "MATRIX_TYPE",  (double) IP_OBJ_MATRIX },
    { "CURVE_TYPE",   (double) IP_OBJ_CURVE },
    { "SURFACE_TYPE", (double) IP_OBJ_SURFACE },
    { "STRING_TYPE",  (double) IP_OBJ_STRING },
    { "CTLPT_TYPE",   (double) IP_OBJ_CTLPT },

    { "BLACK",  (double) IG_IRIT_BLACK },
    { "BLUE",	(double) IG_IRIT_BLUE },
    { "GREEN",	(double) IG_IRIT_GREEN },
    { "CYAN",	(double) IG_IRIT_CYAN },
    { "RED",	(double) IG_IRIT_RED },
    { "MAGENTA",(double) IG_IRIT_MAGENTA },
    { "YELLOW", (double) IG_IRIT_YELLOW },
    { "WHITE",  (double) IG_IRIT_WHITE },

    { "MSDOS",  (double) MACHINE_MSDOS },
    { "SGI",    (double) MACHINE_SGI },
    { "HP",     (double) MACHINE_HP },
    { "SUN",    (double) MACHINE_SUN },
    { "APOLLO", (double) MACHINE_APOLLO },
    { "UNIX",   (double) MACHINE_UNIX },
    { "IBMOS2", (double) MACHINE_IBMOS2 },
    { "IBMNT",  (double) MACHINE_IBMNT },
    { "AMIGA",  (double) MACHINE_AMIGA },
};
int ConstantTableSize = sizeof(ConstantTable) / sizeof(ConstantTableType);

UserDefinedFuncDefType
    *UserDefinedFuncList = NULL;

/*****************************************************************************
*   Routine to do type checking to the given tree - return type if found one *
* or returns ERROR_EXPR if error in types was detected.			     *
*****************************************************************************/
IritExprType InptPrsrTypeCheck(ParseTree *Root, int Level)
{
    IritExprType Right, Left, Result;

    if (IS_NUM_FUNCTION(Root -> NodeKind)) {   /* Funcs returning Real Type: */
	if (FuncParamMismatch(Root))
	    return ERROR_EXPR;
	return NUMERIC_EXPR;
    }

    if (IS_GEN_FUNCTION(Root -> NodeKind)) {     /* Funcs returning nothing: */
	if (Level == 0) {
	    if (FuncParamMismatch(Root))
		return ERROR_EXPR;
	    return NO_EXPR;
	}
	else {
	    IPGlblEvalError = IE_ERR_TYPE_MISMATCH;
	    UpdateCharError("Procedure ", Root -> NodeKind);
	    return ERROR_EXPR;
	}
    }

    if (IS_OBJ_FUNCTION(Root -> NodeKind)) {     /* Funcs returning objects: */
	if (FuncParamMismatch(Root))
	    return ERROR_EXPR;
	return ObjFuncTable[Root -> NodeKind - OBJ_FUNC_OFFSET].RetType;
    }

    switch (Root -> NodeKind) {
	case PLUS:
	case MINUS:
	case MULT:
	case DIV:
	case POWER:
	    Right = InptPrsrTypeCheck(Root -> Right, Level + 1);
	    Left  = InptPrsrTypeCheck(Root -> Left,  Level + 1);
	    if (Right == ERROR_EXPR || Left == ERROR_EXPR)
		return ERROR_EXPR;
	    if (!OverLoadTypeCheck(Root -> NodeKind, Right, Left, &Result)) {
		IPGlblEvalError = IE_ERR_TYPE_MISMATCH;
                UpdateCharError("Operator ", Root -> NodeKind);
		return ERROR_EXPR;
	    }
	    else
		return Result;
	case UNARMINUS:
	    if ((Right = InptPrsrTypeCheck(Root -> Right, Level + 1))
							== ERROR_EXPR)
		return ERROR_EXPR;
	    else if (!OverLoadTypeCheck(Root -> NodeKind, Right, NO_EXPR,
								&Result)) {
		IPGlblEvalError = IE_ERR_TYPE_MISMATCH;
                UpdateCharError("Operator ", Root -> NodeKind);
		return ERROR_EXPR;
	    }
	    else
		return Result;
	case EQUAL:
	    if ((Right = InptPrsrTypeCheck(Root -> Right, Level + 1))
							== ERROR_EXPR)
		return ERROR_EXPR;
	    if (Root -> Left -> NodeKind != PARAMETER) {
		IPGlblEvalError = IE_ERR_ASSIGN_LEFT_OP;
		InptPrsrPrintTree(Root -> Left, IPGlblCharData);
		return ERROR_EXPR;
	    }
	    return Right;
	case BOOL_AND:
	case BOOL_OR:
	    if (InptPrsrTypeCheck(Root -> Right, Level + 1) != NUMERIC_EXPR ||
		InptPrsrTypeCheck(Root -> Left,  Level + 1) != NUMERIC_EXPR)
		return ERROR_EXPR;
	    return NUMERIC_EXPR;
	case BOOL_NOT:
	    if (InptPrsrTypeCheck(Root -> Right, Level + 1) != NUMERIC_EXPR)
		return ERROR_EXPR;
	    return NUMERIC_EXPR;
	case CMP_EQUAL:
	case CMP_NOTEQUAL:
	case CMP_LSEQUAL:
	case CMP_GTEQUAL:
	case CMP_LESS:
	case CMP_GREAT:
	    Right = InptPrsrTypeCheck(Root -> Right, Level + 1);
	    Left  = InptPrsrTypeCheck(Root -> Left,  Level + 1);
	    if (Right == ERROR_EXPR || Left == ERROR_EXPR)
		return ERROR_EXPR;
	    return NUMERIC_EXPR;
	case NUMBER:
	    return NUMERIC_EXPR;
	case PARAMETER:
	    switch (Root -> PObj -> ObjType) {
                case IP_OBJ_POLY:
                    return POLY_EXPR;
		case IP_OBJ_NUMERIC:
		    return NUMERIC_EXPR;
		case IP_OBJ_POINT:
		    return POINT_EXPR;
		case IP_OBJ_VECTOR:
		    return VECTOR_EXPR;
		case IP_OBJ_PLANE:
		    return PLANE_EXPR;
		case IP_OBJ_CTLPT:
		    return CTLPT_EXPR;
		case IP_OBJ_MATRIX:
		    return MATRIX_EXPR;
		case IP_OBJ_STRING:
		    return STRING_EXPR;
		case IP_OBJ_LIST_OBJ:
		    return OLST_EXPR;
		case IP_OBJ_CURVE:
		    return CURVE_EXPR;
		case IP_OBJ_SURFACE:
		    return SURFACE_EXPR;
		default:
		    IPGlblEvalError = IE_ERR_IP_OBJ_UNDEFINED;
		    sprintf(IPGlblCharData, "Object = %s, Type %d",
			    Root -> PObj -> Name, Root -> PObj -> ObjType);
		    return ERROR_EXPR;
	    }
	case STRING:
	    return STRING_EXPR;
	case USERFUNCDEF:
	    return ANY_EXPR;
	case USERPROCDEF:
	    return NO_EXPR;
	case USERINSTDEF:
	    return ANY_EXPR;
	case COLON:
	    if (Root -> Left &&
		Root -> Left -> NodeKind == EQUAL &&
		Root -> Left -> Right &&
		(Root -> Left-> Right -> NodeKind == USERPROCDEF ||
		 Root -> Left-> Right -> NodeKind == USERFUNCDEF)) {
		ParseTree *Body;

		/* A special form of function/procedure definition. */
		for (Body = Root;
		     Body -> NodeKind == COLON;
		     Body = Body -> Right);
		if (Root -> Left -> Left -> NodeKind != PARAMETER ||
		    Body == NULL ||
		    Body == Root)
		    return ERROR_EXPR;		    
	    }
	    else {
		Right = InptPrsrTypeCheck(Root -> Right, 0);
		Left  = InptPrsrTypeCheck(Root -> Left,  0);
		if (Right == ERROR_EXPR || Left == ERROR_EXPR)
		    return ERROR_EXPR;
	    }
	    return NO_EXPR;
	default:				     /* Should never happen. */
	    IPGlblEvalError = IE_ERR_FATAL_ERROR;
            UpdateCharError("Token ", Root -> NodeKind);
	    return ERROR_EXPR;
    }
}

/* Disable the function with no prototype warning on Borland's compilers. */
#ifdef __BORLANDC__
#pragma warn -pro
#endif /* __BORLANDC__ */

/*****************************************************************************
*   Routine to evaluate	a value	of a given tree	root and parameter.	     *
* Note we change the tree itself during the evaluation process.		     *
* Also note we assume the tree is type checked (via InptPrsrTypeCheck rtn).  *
*****************************************************************************/
ParseTree *InptPrsrEvalTree(ParseTree *Root, int Level)
{
    int Index, NumOfParam,
	PrintIt = (Level == 0 && Root -> NodeKind != EQUAL);
    char *ErrorMsg, *p, Name[LINE_LEN];
    ParseTree *TempL, *TempR, *Params[5],
	*RetVal = NULL;
    VoidPtr ParamPtrs[5];

    if (IS_NUM_FUNCTION(Root -> NodeKind)) {/* Funcs which return Real Type: */
	Index = Root -> NodeKind - NUM_FUNC_OFFSET;
	NumOfParam = NumFuncTable[Index].NumOfParam;

	switch(Root -> NodeKind) {
	    case ARCSIN:   /* Real return functions with one real parameter. */
	    case ARCCOS:
	    case ARCTAN:
	    case COS:
	    case EXP:
	    case FABS:
	    case LN:
	    case LOG:
	    case SIN:
	    case SQRT:
	    case TAN:
	    case TIME:
		if (!InptEvalFetchParameters(Root, NULL, 1, Level,
					     Params, ParamPtrs))
		    break;
		/* Use table entries to call the function directly. */
		Root -> PObj =
		    GenNUMValObject((NumFuncTable[Index].Func)
				        (Params[0] -> PObj -> U.R));
		RetVal = Root;
		break;

	    case ARCTAN2:
		if (!InptEvalFetchParameters(Root, NULL, 2, Level,
					     Params, ParamPtrs))
		    break;
		/* Use table entries to call the function directly. */
		Root -> PObj =
		    GenNUMValObject((NumFuncTable[Index].Func)
				        (Params[0] -> PObj -> U.R,
					 Params[1] -> PObj -> U.R));
		RetVal = Root;
		break;

	    default:
		if (!InptEvalFetchParameters(Root,
				     (FuncTableType *) &NumFuncTable[Index],
				     NumOfParam, Level, Params, ParamPtrs))
		    break;

		/* Use table entries to call the function directly. */
		switch (NumFuncTable[Index].NumOfParam) {
		    case 0:
		        Root -> PObj =
			    GenNUMValObject((NumFuncTable[Index].Func)());
			break;
		    case 1:
		        Root -> PObj =
			    GenNUMValObject((NumFuncTable[Index].Func)
					        (ParamPtrs[0]));
			break;
		    case 2:
			Root -> PObj =
			    GenNUMValObject((NumFuncTable[Index].Func)
					        (ParamPtrs[0], ParamPtrs[1]));
			break;
		    case 3:
			Root -> PObj =
			    GenNUMValObject((NumFuncTable[Index].Func)
					        (ParamPtrs[0], ParamPtrs[1],
						 ParamPtrs[2]));
			break;
		    case 4:
			Root -> PObj =
			    GenNUMValObject((NumFuncTable[Index].Func)
					        (ParamPtrs[0], ParamPtrs[1],
						 ParamPtrs[2], ParamPtrs[3]));
		        break;
		    case 5:
		        Root -> PObj =
			    GenNUMValObject((NumFuncTable[Index].Func)
					        (ParamPtrs[0], ParamPtrs[1],
						 ParamPtrs[2], ParamPtrs[3],
						 ParamPtrs[4]));
		        break;
		}

		RetVal = Root;
		break;
	}
    }
    else if (IS_OBJ_FUNCTION(Root -> NodeKind)) {/* Funcs returning objects: */
	Index = Root -> NodeKind - OBJ_FUNC_OFFSET;
	NumOfParam = ObjFuncTable[Index].NumOfParam;

	switch (Root -> NodeKind) {
	    case COORD:
	        if (!InptEvalFetchParameters(Root, NULL, 2, Level,
					     Params, ParamPtrs))
		    break;
	        /* Use table entries to call the function directly. */
		Root -> PObj =
		    (ObjFuncTable[Index].Func)
		        (Params[0] -> PObj, &Params[1] -> PObj -> U.R);
		if (Root -> PObj == NULL)
		    break;

		RetVal = Root;
		break;

	    case NTH:
		if (!InptEvalFetchParameters(Root, NULL, 2,
					     Level, Params, ParamPtrs))
		    break;
		/* Use table entries to call the function directly. */
		Root -> PObj =
		    (ObjFuncTable[Index].Func)
		        (Params[0] -> PObj, &Params[1] -> PObj -> U.R);
		if (Root -> PObj == NULL)
		    break;

		RetVal = Root;
		break;

	    case LOAD:
		if (!InptEvalFetchParameters(Root, NULL, 1,
					     Level, Params, ParamPtrs))
		    break;
		/* Use table entries to call the function directly. */
		Root -> PObj =
		    (ObjFuncTable[Index].Func)(Params[0] -> PObj -> U.Str, "");
		if (Root -> PObj == NULL) {
	            LoadSaveObjectParseError(&ErrorMsg);
		    IPGlblEvalError = IE_ERR_DATA_PRSR_ERROR;
		    strcpy(IPGlblCharData, ErrorMsg);
		    break;
		}
		RetVal = Root;
		break;

	    case CTLPT:
	    case LIST:
		/* Use table entries to call the function directly. */
		Root -> PObj = (ObjFuncTable[Index].Func)(Root -> Right);
		if (Root -> PObj == NULL)
		    break;
		RetVal = Root;
		break;

	    default:
		if (!InptEvalFetchParameters(Root,
				     (FuncTableType *) &ObjFuncTable[Index],
				     NumOfParam, Level, Params, ParamPtrs))
		    break;

		/* Use table entries to call the function directly. */
		switch (ObjFuncTable[Index].NumOfParam) {
		    case 0:
			Root -> PObj = (ObjFuncTable[Index].Func)();
			break;
		    case 1:
			Root -> PObj = (ObjFuncTable[Index].Func)
				(ParamPtrs[0]);
			break;
		    case 2:
			Root -> PObj = (ObjFuncTable[Index].Func)
				(ParamPtrs[0], ParamPtrs[1]);
			break;
		    case 3:
			Root -> PObj = (ObjFuncTable[Index].Func)
				(ParamPtrs[0], ParamPtrs[1], ParamPtrs[2]);
			break;
		    case 4:
			Root -> PObj = (ObjFuncTable[Index].Func)
				(ParamPtrs[0], ParamPtrs[1], ParamPtrs[2],
				 ParamPtrs[3]);
			break;
		    case 5:
			Root -> PObj = (ObjFuncTable[Index].Func)
				(ParamPtrs[0], ParamPtrs[1], ParamPtrs[2],
				 ParamPtrs[3], ParamPtrs[4]);
			break;
		}
		if (Root -> PObj == NULL)
		    break;
		RetVal = Root;
		break;
	}
    }
    else if (IS_GEN_FUNCTION(Root -> NodeKind)) {/* Funcs returning nothing: */
	Index = Root -> NodeKind - GEN_FUNC_OFFSET;
	NumOfParam = GenFuncTable[Index].NumOfParam;

	switch (Root -> NodeKind) {
	    case COLOR:
		if (!InptEvalFetchParameters(Root, NULL, 2, Level,
					     Params, ParamPtrs))
		    break;

		(GenFuncTable[Index].Func)
			 (Params[0] -> PObj,
			  REAL_TO_INT(Params[1] -> PObj -> U.R));
		break;
	
	    case VARLIST:
	        (GenFuncTable[Index].Func)(GlblObjList);
		break;

	    case SAVE:
	        if (!InptEvalFetchParameters(Root, NULL, 2, Level,
					     Params, ParamPtrs))
		    break;

		/* Use table entries to call the function directly. */
		(GenFuncTable[Index].Func)(Params[0] -> PObj -> U.Str,
					   Params[1] -> PObj);

		/* Save the matrix. */
		strncpy(Name, Params[0] -> PObj -> U.Str, LINE_LEN - 5);
		if ((p = strstr(Name, ".dat")) != NULL ||
		    (p = strstr(Name, ".DAT")) != NULL)
		    *p = 0;
		strcat(Name, ".mat");
		WndwViewSaveMatrix(Name);

	        if (LoadSaveObjectParseError(&ErrorMsg) != 0) {
		    IPGlblEvalError = IE_ERR_DATA_PRSR_ERROR;
		    strcpy(IPGlblCharData, ErrorMsg);
		    break;
	        }
		break;

	    case FREEOBJ:
	        if (!InptEvalFetchParameters(Root, NULL, 1, Level, Params,
					     ParamPtrs) ||
	            (TempR = InptPrsrEvalTree(Root -> Right, Level + 1))
								   == NULL)
		    break;

	        if (strlen(TempR -> PObj -> Name) == 0) {
		    IPGlblEvalError = IE_ERR_FREE_SIMPLE;
                    UpdateCharError("Procedure ", FREEOBJ);
		    RetVal = Root;
		    break;
	        }
	        /* Use table entries to call the function directly. */
	        (GenFuncTable[Index].Func)(TempR -> PObj);
	        TempR -> PObj = NULL;	    /* Make sure its disconnected... */
		break;

	    case IFCOND:
		switch (NumOfParam =
			          InptEvalCountNumParameters(Root -> Right)) {
		    case 2:
			InptEvalIfCondition(
			    InptEvalFetchParameter(Root -> Right, 0, 2),
			    InptEvalFetchParameter(Root -> Right, 1, 2),
			    NULL);
			break;
		    case 3:
			InptEvalIfCondition(
			    InptEvalFetchParameter(Root -> Right, 0, 3),
			    InptEvalFetchParameter(Root -> Right, 1, 3),
			    InptEvalFetchParameter(Root -> Right, 2, 3));
			break;
		    default:
			IPGlblEvalError = IE_ERR_NUM_PRM_MISMATCH;
			sprintf(IPGlblCharData,
				"IF clause (2 or 3 expected, found %d)",
				NumOfParam);
			break;
		}
		break;

	    case FORLOOP:
		InptEvalForLoop(InptEvalFetchParameter(Root -> Right, 0, 4),
				InptEvalFetchParameter(Root -> Right, 1, 4),
				InptEvalFetchParameter(Root -> Right, 2, 4),
				InptEvalFetchParameter(Root -> Right, 3, 4));
		break;

	    default:
		if (!InptEvalFetchParameters(Root,
				     (FuncTableType *) &GenFuncTable[Index],
				     NumOfParam, Level, Params, ParamPtrs))
		    break;

		/* Use table entries to call the function directly. */
		switch (GenFuncTable[Index].NumOfParam) {
		    case 0:
			(GenFuncTable[Index].Func)();
			break;
		    case 1:
			(GenFuncTable[Index].Func)
				(ParamPtrs[0]);
			break;
		    case 2:
			(GenFuncTable[Index].Func)
				(ParamPtrs[0], ParamPtrs[1]);
			break;
		    case 3:
			(GenFuncTable[Index].Func)
				(ParamPtrs[0], ParamPtrs[1], ParamPtrs[2]);
			break;
		    case 4:
			(GenFuncTable[Index].Func)
				(ParamPtrs[0], ParamPtrs[1], ParamPtrs[2],
				 ParamPtrs[3]);
			break;
		    case 5:
			(GenFuncTable[Index].Func)
				(ParamPtrs[0], ParamPtrs[1], ParamPtrs[2],
				 ParamPtrs[3], ParamPtrs[4]);
			break;
		}
		break;
	}
	RetVal = Root;
	if (Root -> PObj)
	    Root -> PObj -> ObjType = IP_OBJ_UNDEF;
	else
	    Root -> PObj = IPAllocObject("", IP_OBJ_UNDEF, NULL);
    }
    else {
        switch (Root -> NodeKind) {		  /* The rest of the world. */
	    case PLUS:
	    case MINUS:
	    case MULT:
	    case DIV:
	    case POWER:
	        if (((TempR = InptPrsrEvalTree(Root -> Right, Level + 1))
								== NULL) ||
		    ((TempL = InptPrsrEvalTree(Root -> Left,  Level + 1))
								== NULL))
		    break;
		TempR = OverLoadEvalOper(Root, TempR, TempL,
					 &IPGlblEvalError, IPGlblCharData);
		RetVal = TempR;
		break;

	    case UNARMINUS:
		if ((TempR = InptPrsrEvalTree(Root -> Right, Level + 1))
								      == NULL)
		    break;
		TempR = OverLoadEvalOper(Root, TempR, NULL,
					 &IPGlblEvalError, IPGlblCharData);
		RetVal = TempR;
		break;

	    case COLON:
		if (Root -> Left &&
		    Root -> Left -> NodeKind == EQUAL &&
		    Root -> Left -> Right &&
		    (Root -> Left-> Right -> NodeKind == USERPROCDEF ||
		     Root -> Left-> Right -> NodeKind == USERFUNCDEF)) {
		    /* A special form of function/procedure definition. */
		    InptEvalDefineFunc(Root);
		}
		else {
		    InptPrsrEvalTree(Root -> Left, 0);
		    InptPrsrEvalTree(Root -> Right, 0);
		}
		break;

	    case NUMBER:
		RetVal = Root;
		break;

	    case PARAMETER:
		RetVal = Root;
		break;

	    case STRING:
		RetVal = Root;
		break;

	    case EQUAL:
		if ((TempR = InptPrsrEvalTree(Root -> Right, Level + 1))
								== NULL)
		    break;
		TempL = Root -> Left;

		if (TempL -> PObj == TempR -> PObj) {
		    RetVal = TempR; /* A = A. */
		    break;
		}
		if (TempL -> PObj == NULL)
		    TempL -> PObj = IPAllocObject("", IP_OBJ_UNDEF, NULL);
		CopyObject(TempL -> PObj, TempR -> PObj, FALSE);

		RetVal = TempR;
		break;

	    case BOOL_AND:
	        if (((TempR = InptPrsrEvalTree(Root -> Right, Level + 1))
								== NULL) ||
		    ((TempL = InptPrsrEvalTree(Root -> Left,  Level + 1))
								== NULL))
		    break;
		if (Root -> PObj)
		    Root -> PObj -> ObjType = IP_OBJ_NUMERIC;
		else
		    Root -> PObj = IPAllocObject("", IP_OBJ_NUMERIC, NULL);
		Root -> PObj -> ObjType = IP_OBJ_NUMERIC;
		Root -> PObj -> U.R = (!APX_EQ(TempR -> PObj -> U.R, 0.0) &&
				       !APX_EQ(TempL -> PObj -> U.R, 0.0));
		RetVal = Root;
		break;

	    case BOOL_OR:
	        if (((TempR = InptPrsrEvalTree(Root -> Right, Level + 1))
								== NULL) ||
		    ((TempL = InptPrsrEvalTree(Root -> Left,  Level + 1))
								== NULL))
		    break;
		if (Root -> PObj)
		    Root -> PObj -> ObjType = IP_OBJ_NUMERIC;
		else
		    Root -> PObj = IPAllocObject("", IP_OBJ_NUMERIC, NULL);
		Root -> PObj -> U.R = (!APX_EQ(TempR -> PObj -> U.R, 0.0) ||
				       !APX_EQ(TempL -> PObj -> U.R, 0.0));
		RetVal = Root;
		break;

	    case BOOL_NOT:
		if ((TempR = InptPrsrEvalTree(Root -> Right, Level + 1))
								      == NULL)
		    break;
		if (Root -> PObj)
		    Root -> PObj -> ObjType = IP_OBJ_NUMERIC;
		else
		    Root -> PObj = IPAllocObject("", IP_OBJ_NUMERIC, NULL);
		Root -> PObj -> U.R = APX_EQ(TempR -> PObj -> U.R, 0.0);
		RetVal = Root;
		break;

	    case CMP_EQUAL:
	    case CMP_NOTEQUAL:
	    case CMP_LSEQUAL:
	    case CMP_GTEQUAL:
	    case CMP_LESS:
	    case CMP_GREAT:
	        if (((TempR = InptPrsrEvalTree(Root -> Right, Level + 1))
								== NULL) ||
		    ((TempL = InptPrsrEvalTree(Root -> Left,  Level + 1))
								== NULL))
		    break;
		RetVal = InptEvalCompareObject(Root, TempL, TempR,
					   &IPGlblEvalError, IPGlblCharData);
		break;

	    case USERINSTDEF:
		if (InptEvalCountNumParameters(Root -> Right) !=
		    Root -> UserFunc -> NumParams) {
		    IPGlblEvalError = IE_ERR_NUM_PRM_MISMATCH;
		    strcpy(IPGlblCharData, Root -> UserFunc -> FuncName);
		    break;
		}
		if (!InptEvalFetchParameters(Root, NULL,
					     Root -> UserFunc -> NumParams,
					     Level, Params, ParamPtrs))
		    break;

		RetVal = InptEvalUserFunc(Root, Params);
		break;
	}
    }

    if (PrintIt &&
	RetVal &&
	RetVal -> PObj &&
	RetVal -> PObj -> ObjType != IP_OBJ_UNDEF) {
	RetVal -> PObj -> Count--;	       /* Remove ref from this tree. */
	PrintObject(RetVal -> PObj);
	RetVal -> PObj -> Count++;		      /* Add reference back. */
    }

    return RetVal;
}

/* Restore the function with no prototype warning on Borland's compilers. */
#ifdef __BORLANDC__
#pragma warn .pro
#endif /* __BORLANDC__ */

/*****************************************************************************
*  Routine to count number of parameters where given: parameters are defined *
* as subtrees seperated by commas, i.e.: the infix form 1, 2, 3, 4 is 	     *
* represented as [1, [2, [3, 4]]] in the tree supplied to this function and  *
* 4 (number of parameters) is returned.					     *
*****************************************************************************/
int InptEvalCountNumParameters(ParseTree *Root)
{
    int i = 1;

    if (Root == NULL)
	return 0;

    while (Root -> NodeKind == COMMA) {
	i++;
	Root = Root -> Right;
    }
    return i;
}

/*****************************************************************************
*   Routine to fetch the i paramter out of a tree represent n parameters     *
* (0 <= i < n). See InptEvalCountNumParameters for more description of	     *
* structure.								     *
* Note it is assumed the tree HAS n parameters and 0<=i<n (No input error).  *
*****************************************************************************/
ParseTree *InptEvalFetchParameter(ParseTree *Root, int i, int n)
{
    int j;

    for (j = 0; j < i; j++)
	Root = Root -> Right;

    if (i == n - 1)
	return Root;
    else
	return Root -> Left;
}

/*****************************************************************************
*   Routine to fetch the parameters from the parsed tree.		     *
* Returns TRUE iff fetching was succesfull.				     *
*****************************************************************************/
static int InptEvalFetchParameters(ParseTree *Root, FuncTableType *FuncTable,
	   int NumParams, int Level, ParseTree *Params[], VoidPtr ParamPtrs[])
{
    int i;

    Level++;
    for (i = 0; i < NumParams; i++) {
	if ((Params[i] = InptPrsrEvalTree(InptEvalFetchParameter(Root -> Right,
								 i, NumParams),
					  Level)) == NULL)
	    return FALSE;

	if (FuncTable != NULL) {
	    if (FuncTable -> ParamObjType[i] == NUMERIC_EXPR)
		ParamPtrs[i] = &Params[i] -> PObj -> U.R;
	    else if (FuncTable -> ParamObjType[i] == POINT_EXPR)
		ParamPtrs[i] = Params[i] -> PObj -> U.Pt;
	    else if (FuncTable -> ParamObjType[i] == VECTOR_EXPR)
		ParamPtrs[i] = Params[i] -> PObj -> U.Vec;
	    else if (FuncTable -> ParamObjType[i] == CTLPT_EXPR)
		ParamPtrs[i] = &Params[i] -> PObj -> U.CtlPt;
	    else if (FuncTable -> ParamObjType[i] == PLANE_EXPR)
		ParamPtrs[i] = Params[i] -> PObj -> U.Plane;
	    else if (FuncTable -> ParamObjType[i] == STRING_EXPR)
		ParamPtrs[i] = Params[i] -> PObj -> U.Str;
	    else
		ParamPtrs[i] = Params[i] -> PObj;
	}
    }

    return TRUE;
}

/*****************************************************************************
*   Routine to test number of parameters and type of them against what is    *
* defined in its global tables Num/Obj/GenFuncTable. return TRUE if mismatch *
* was detected:								     *
*****************************************************************************/
static int FuncParamMismatch(ParseTree *Root)
{
    int FuncOffset, Count,
	i = Root -> NodeKind / 100;
    FuncTableType *FuncTable;

    switch (i * 100) {
	case NUM_FUNC:		       /* Numeric (real returned) functions. */
	    FuncOffset = Root -> NodeKind - NUM_FUNC_OFFSET;
	    FuncTable = (FuncTableType *) NumFuncTable;
	    break;
	case OBJ_FUNC:			     /* Object (returned) functions. */
	    FuncOffset = Root -> NodeKind - OBJ_FUNC_OFFSET;
	    FuncTable = (FuncTableType *) ObjFuncTable;
	    break;
	case GEN_FUNC:
	    FuncOffset = Root -> NodeKind - GEN_FUNC_OFFSET;
	    FuncTable = (FuncTableType *) GenFuncTable;
	    break;
	default:
	    IPGlblEvalError = IE_ERR_FATAL_ERROR;
	    UpdateCharError("Undefined function - ", Root -> NodeKind);
	    return TRUE;
    }

    if (FuncTable[FuncOffset].NumOfParam == ANY_PARAM_NUM)
	return FALSE;

    /* See if number of parameters is ok: */
    if ((Count = InptEvalCountNumParameters(Root -> Right)) !=
	FuncTable[FuncOffset].NumOfParam) {
	IPGlblEvalError = IE_ERR_NUM_PRM_MISMATCH;
	sprintf(IPGlblCharData, "Func %s - %d expected, %d found",
		FuncTable[FuncOffset].FuncName,
		FuncTable[FuncOffset].NumOfParam,
		Count);
	return TRUE;
    }

    /* See if type of parameters is consistent: */
    for (i = 0; i < Count; i++) {
	if (FuncTable[FuncOffset].ParamObjType[i] != ANY_EXPR &&
	    !(FuncTable[FuncOffset].ParamObjType[i] &
	      InptPrsrTypeCheck(InptEvalFetchParameter(Root -> Right,
						       i, Count), 1))) {
	    sprintf(IPGlblCharData, "Func %s,%sparameter %d",
		    FuncTable[FuncOffset].FuncName,
		    IPGlblEvalError == IE_ERR_IP_OBJ_UNDEFINED ? " undefined "
							       : " ",
		    i + 1);
	    IPGlblEvalError = IE_ERR_TYPE_MISMATCH;
	    return TRUE;
	}
    }
    return FALSE;
}

/*****************************************************************************
*   Routine to free a tree - release all memory	allocated by it.	     *
*****************************************************************************/
void InptPrsrFreeTree(ParseTree *Root)
{
    char s[LINE_LEN];

    if (!Root)
	return;

    if (IS_FUNCTION(Root -> NodeKind)) {
	if (IS_NO_PARAM_FUNC(Root -> NodeKind))
	    ExprFree(Root);
	else {
	    InptPrsrFreeTree(Root -> Right);
	    if (Root -> PObj != NULL && strlen(Root -> PObj -> Name) == 0)
		IPFreeObject(Root -> PObj);			 /* Its temp.*/
	    ExprFree(Root);
        }
	return;
    }

    switch (Root -> NodeKind) {
	case DIV:
	case MINUS:
	case MULT:
	case PLUS:
	case POWER:
	    InptPrsrFreeTree(Root -> Right);
	    InptPrsrFreeTree(Root -> Left);
	    if (Root -> PObj != NULL && strlen(Root -> PObj -> Name) == 0)
		IPFreeObject(Root -> PObj);			 /* Its tmp. */
	    ExprFree(Root);
	    break;

	case UNARMINUS:
	case BOOL_NOT:
	    InptPrsrFreeTree(Root -> Right);
	    if (Root -> PObj != NULL && strlen(Root -> PObj -> Name) == 0)
		IPFreeObject(Root -> PObj);			 /* Its tmp. */
	    ExprFree(Root);
	    break;

	case COMMA:
	case COLON:
	case EQUAL:
	case CMP_EQUAL:
	case CMP_NOTEQUAL:
	case CMP_LSEQUAL:
	case CMP_GTEQUAL:
	case CMP_LESS:
	case CMP_GREAT:
	case BOOL_OR:
	case BOOL_AND:
  	    InptPrsrFreeTree(Root -> Right);
	    InptPrsrFreeTree(Root -> Left);
	    ExprFree(Root);
	    break;

	case PARAMETER:
	    if (Root -> PObj) {
		/* If object is not part of global variable list - remove it.*/
		if (strlen(Root -> PObj -> Name) == 0)
		    IPFreeObject(Root -> PObj);
		else
		    Root -> PObj -> Count--;
	    }
	    ExprFree(Root);
	    break;

	case NUMBER:
	case STRING:
	    if (Root -> PObj)
		IPFreeObject(Root -> PObj);
	    ExprFree(Root);
	    break;

	case TOKENSTART:
	    ExprFree(Root);
	    break;

	case OPENPARA:
	case CLOSPARA:
	    ExprFree(Root);
	    break;

	default:
	    /*   We might free partially build (by InptPrsr) tree when error */
	    /* is detected, and such tree may have nodes with NodeKind>=1000.*/
	    if (Root -> NodeKind >= 1000) {
		ExprFree(Root);
	    }
	    else {
		sprintf(s, "%s (%d).\n",
		    "InptPrsrFreeTree: Undefined ParseTree type to free",
		    Root -> NodeKind);
		IritFatalError(s);
	    }
	    break;
    }
}

/*****************************************************************************
*   Routine to print a content of ROOT (using inorder traversal):	     *
* level	holds: 0 for lowest level +/-, 1 for *, /, 2 for ^ operations.	     *
* If *str = NULL print on stderr, else on given	string Str.		     *
*****************************************************************************/
void InptPrsrPrintTree(ParseTree *Root, char *Str)
{
    strcpy(IPGlblCharData, "");			   /* Make the string empty. */

    if (Str == NULL) {
	strcpy(IPGlblCharData, "");		   /* Make the string empty. */
	LocalPrintTree(Root, 0, IPGlblCharData);       /* Copy to local str. */
	fprintf(stderr, IPGlblCharData);		     /* and print... */
    }
    else {
	strcpy(Str, "");			   /* Make the string empty. */
	LocalPrintTree(Root, 0, Str); /* Dont print to stderr - copy to str. */
    }
}

/*****************************************************************************
*   Routine to print a content of ROOT (using inorder traversal):	     *
* level	holds: 0 for lowest level +/-, 1 for *, /, 2 for ^ operations.	     *
* It is assumed Str has atlist INPUT_LINE_LEN places to write the expression.*
*****************************************************************************/
static void LocalPrintTree(ParseTree *Root, int Level, char *Str)
{
    int Len, i,
	CloseFlag = FALSE;

    if (!Root)
	return;
    i = Root -> NodeKind / 100;

    if ((Len = strlen(Str)) > INPUT_LINE_LEN + 100)     /* Prevent overflow. */
	if (Str[Len - 1] == '.')
	    return;			 /* "..." was allready concatenated. */
	else {
	    strcat(Str, "...");
	    return;
	}

#   ifdef DEBUG1
	strcat(Str, "[");   /* Usefull to see ALL nestings - no preceedings. */
#   endif /* DEBUG1 */

    switch (i * 100) {
	case USER_FUNC:
	    switch (Root -> NodeKind) {
		case USERFUNCDEF:
		    Level = 0;
		    CloseFlag = TRUE;
		    strcat(Str, "function(");
		    break;
		case USERPROCDEF:
		    Level = 0;
		    CloseFlag = TRUE;
		    strcat(Str, "procedure(");
		    break;
		case USERINSTDEF:
		    Level = 0;
		    CloseFlag = TRUE;
		    strcat(Str, Root -> UserFunc -> FuncName);
		    strcat(Str, "(");
		    break;
	    }
	    break;

	case NUM_FUNC:
	    Level = 0;
	    CloseFlag = TRUE;
            strcat(Str,
		   NumFuncTable[Root -> NodeKind - NUM_FUNC_OFFSET].FuncName);
	    strcat(Str, "(");
	    break;

	case OBJ_FUNC:
	    Level = 0;
	    CloseFlag = TRUE;
            strcat(Str,
		   ObjFuncTable[Root -> NodeKind - OBJ_FUNC_OFFSET].FuncName);
	    strcat(Str, "(");
	    break;

	case GEN_FUNC:
	    Level = 0;
	    CloseFlag = TRUE;
            strcat(Str,
		   GenFuncTable[Root -> NodeKind - GEN_FUNC_OFFSET].FuncName);
	    strcat(Str, "(");
	    break;

	case OPERATORS:
	    switch (Root -> NodeKind) {
		case DIV:
		    if (Level > 1) {
			strcat(Str, "(");
		        CloseFlag = TRUE;
		    }
		    Level = 1;				       /* Div Level. */
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "/");
		    break;

		case MINUS:
		    if (Level > 0) {
			strcat(Str, "(");
	        	CloseFlag = TRUE;
		    }
		    Level = 0;				     /* Minus Level. */
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "-");
		    break;

		case MULT:
		    if (Level > 1) {
			strcat(Str, "(");
		        CloseFlag = TRUE;
		    }
		    Level = 1;				       /* Mul Level. */
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "*");
		    break;

		case PLUS:
		    if (Level > 0) {
			strcat(Str, "(");
	        	CloseFlag = TRUE;
		    }
		    Level = 0;				      /* Plus Level. */
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "+");
		    break;

		case POWER:
		    Level = 2;				     /* Power Level. */
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "^");
		    break;

		case UNARMINUS:
		    strcat(Str, "(-");
		    Level = 0;
		    CloseFlag = TRUE;
		    break;

		case COMMA:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, ",");
		    break;

		case COLON:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, ":");
		    break;

		case EQUAL:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "=");
		    break;

		case CMP_EQUAL:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "==");
		    break;

		case CMP_NOTEQUAL:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "!=");
		    break;

		case CMP_LSEQUAL:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "<=");
		    break;

		case CMP_GTEQUAL:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, ">=");
		    break;

		case CMP_LESS:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "<");
		    break;

		case CMP_GREAT:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, ">");
		    break;

		case BOOL_OR:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "||");
		    break;

		case BOOL_AND:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "&&");
		    break;

		case BOOL_NOT:
		    LocalPrintTree(Root -> Left, Level, Str);
		    strcat(Str, "!");
		    break;

		case NUMBER:
		    sprintf(&Str[strlen(Str)], "%lg", Root -> PObj -> U.R);
		    break;

		case PARAMETER:
		    sprintf(&Str[strlen(Str)], "%s", Root -> PObj -> Name);
		    break;

		case STRING:
		    sprintf(&Str[strlen(Str)], "\"%s\"",
			    Root -> PObj -> U.Str);
		    break;

		case OPENPARA:
		    strcat(Str, "(");
		    break;

		case CLOSPARA:
		    strcat(Str, ")");
		    break;

		case TOKENSTART:
		    break;

		default:
		    IritFatalError("LocalPrintTree: Undefined ParseTree type to print, exit");
            }
            break;

	default:
	    IritFatalError("LocalPrintTree: Undefined ParseTree type to print, exit");
    }
    LocalPrintTree(Root -> Right, Level, Str);
    if (CloseFlag)
	strcat(Str, ")");

#   ifdef DEBUG1
	strcat(Str, "]");   /* Usefull to see ALL nestings - no preceedings. */
#   endif /* DEBUG1 */
}

/*****************************************************************************
*   Routine to copy a parse tree - Generate brand new ParseTree structure    *
* but bind to non-temp variables if they are exists - their Name is not NULL *
*   This means that updating these objects in the copied tree, will affect   *
* these objects in the original tree.					     *
*****************************************************************************/
ParseTree *InptPrsrCopyTree(ParseTree *Root)
{
    ParseTree *NewRoot;

    if (Root == NULL)
	return NULL;

    NewRoot = ExprMalloc();

    if (IS_FUNCTION(Root -> NodeKind)) {	       /* All the functions. */
	NewRoot -> NodeKind = Root -> NodeKind;
	NewRoot -> Right = InptPrsrCopyTree(Root -> Right);
	if (IS_USER_FUNCTION(Root -> NodeKind))
	    NewRoot -> UserFunc = Root -> UserFunc;
	return NewRoot;
    }

    switch (Root -> NodeKind) {
	case DIV:
	case MINUS:
	case MULT:
	case PLUS:
	case POWER:

	case COMMA:
	case COLON:
	case EQUAL:
	case CMP_EQUAL:
	case CMP_NOTEQUAL:
	case CMP_LSEQUAL:
	case CMP_GTEQUAL:
	case CMP_LESS:
	case CMP_GREAT:
        case BOOL_OR:
        case BOOL_AND:
	    NewRoot -> NodeKind = Root -> NodeKind;
	    NewRoot -> Right = InptPrsrCopyTree(Root -> Right);
	    NewRoot -> Left  = InptPrsrCopyTree(Root -> Left);
	    return NewRoot;

	case UNARMINUS:
        case BOOL_NOT:
	    NewRoot -> NodeKind = Root -> NodeKind;
	    NewRoot -> Right = InptPrsrCopyTree(Root -> Right);
	    NewRoot -> Left  = NULL;
	    return NewRoot;

	case NUMBER:
	case PARAMETER:
	case STRING:
	    NewRoot -> NodeKind = Root -> NodeKind;
	    NewRoot -> PObj = Root -> PObj;	    /* Point on SAME object. */
	    NewRoot -> PObj -> Count++;      /* But increase its ref. count. */
	    return NewRoot;

	case TOKENSTART:
	    NewRoot -> NodeKind = Root -> NodeKind;
	    return NewRoot;

	default:
	    IritFatalError("InptPrsrCopyTree: Undefined ParseTree type to copy, exit");
    }
    return NULL;				    /* Makes warning silent. */
}

/*****************************************************************************
*   Routine to return evaluation error if happen one, zero elsewhere	     *
*****************************************************************************/
InptPrsrEvalErrType InptPrsrEvalError(char **Message)
{
    InptPrsrEvalErrType Temp;

    *Message = IPGlblCharData;
    Temp = IPGlblEvalError;
    IPGlblEvalError = IPE_NO_ERR;

    return Temp;
}
