Metropoli BBS
VIEWER: inpteval.c MODE: TEXT (ASCII)
/*****************************************************************************
*   "Irit" - the 3d 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...					     *
*****************************************************************************/

#ifdef __MSDOS__
#include <alloc.h>
#include <dir.h>
#endif /* __MSDOS__ */

#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 "dataprsr.h"
#include "dosintr.h"
#include "freeform.h"
#include "geomat3d.h"
#include "geomvals.h"
#include "graphgen.h"
#include "inptprsg.h"
#include "inptprsl.h"
#include "matherr.h"
#include "objects.h"
#include "overload.h"
#include "primitiv.h"
#include "viewobj.h"
#include "windows.h"

InptPrsrEvalErrType IPGlblEvalError = IPE_NO_ERR;/* Global used by EvalTree. */
extern char IPGlblCharData[LINE_LEN_LONG];    /* Used for both parse & eval. */

/*   I prefer to put the declarations of static functions just before the    */
/* function themselves, but the tables below needs them so...		     */
static int FetchParameters(ParseTree *Root, int NumParams, int Level,
							 ParseTree *Params[]);
static void PrintHelp(char *HelpHeader);
static void IfCondition(ParseTree *Left, ParseTree *Cond, ParseTree *Right,
							  ParseTree *PBody);
static void ForLoop(ParseTree *PStart, ParseTree *PInc, ParseTree *PEnd,
							ParseTree *PBody);
static ObjectStruct *GenObjectList(ParseTree *PObjParams);
static ObjectStruct *CtlPtFromParams(ParseTree *PObjParams);
static int CountNumExpressions(ParseTree *Root);
static ParseTree *FetchExpression(ParseTree *Root, int i, int n);
static int RetrieveMathError(void);
static int CountNumParameters(ParseTree *Root);
static ParseTree *FetchParameter(ParseTree *Root, int i, int n);
static int FuncParamMismatch(ParseTree *Root);
static void LocalPrintTree(ParseTree *Root, int Level, char *Str);
static void RebindVariable(ParseTree *Root, ObjectStruct *PObj);
static int RetrieveMathError(void);

/* 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 } },
};
int NumFuncTableSize = sizeof(NumFuncTable) / sizeof(NumFuncTableType);

ObjFuncTableType ObjFuncTable[] = {
    { "VECTOR",	  VECTOR,	GenVecObject,		3,	{ NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "CTLPT",	  CTLPT,	CtlPtFromParams,	ANY_PARAM_NUM, { 0 } },
    { "ROTX",	  ROTX,		GenMatObjectRotX,	1,	{ NUMERIC_EXPR } },
    { "ROTY",	  ROTY,		GenMatObjectRotY,	1,	{ NUMERIC_EXPR } },
    { "ROTZ",	  ROTZ,		GenMatObjectRotZ,	1,	{ NUMERIC_EXPR } },
    { "TRANS",	  TRANS,	GenMatObjectTrans,	1,	{ VECTOR_EXPR } },
    { "SCALE",	  SCALE,	GenMatObjectScale,	1,	{ VECTOR_EXPR } },
    { "BOX",	  BOX,		GenBOXObject,		4,	{ VECTOR_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "GBOX",	  GBOX,		GenGBOXObject,		4,	{ VECTOR_EXPR, VECTOR_EXPR, VECTOR_EXPR, VECTOR_EXPR } },
    { "CONE",	  CONE,		GenCONEObject,		3,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR } },
    { "CON2",	  CONE2,	GenCONE2Object,		4,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "CYLIN",	  CYLIN,	GenCYLINObject,		3,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR } },
    { "SPHERE",	  SPHERE,	GenSPHEREObject,	2,	{ VECTOR_EXPR, NUMERIC_EXPR } },
    { "TORUS",	  TORUS,	GenTORUSObject,		4,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "CIRCPOLY", CIRCPOLY,	GenPLANEObject,		3,	{ VECTOR_EXPR, VECTOR_EXPR, NUMERIC_EXPR } },
    { "POLY",	  POLY,		GenPOLYGONObject,	1,	{ OLST_EXPR } },
    { "CROSSEC",  CROSSEC,	GenCROSSECObject,	1,	{ POLY_CURVE_EXPR } },
    { "SURFREV",  SURFREV,	GenSURFREVObject,	1,	{ POLY_CURVE_EXPR } },
    { "EXTRUDE",  EXTRUDE,	GenEXTRUDEObject,	2,	{ POLY_CURVE_EXPR, VECTOR_EXPR } },
    { "LIST",	  LIST,		GenObjectList,		ANY_PARAM_NUM, { 0 } },
    { "LOAD",     LOAD,		DataPrsrGetObjects,	1,	{ STRING_EXPR } },
    { "CONVEX",	  CONVEX,	ConvexPolyObjectN,	1,	{ POLY_EXPR } },
    { "SBEZIER",  SBEZIER,	GenBezierSurfaceObject, 1,	{ OLST_EXPR } },
    { "CBEZIER",  CBEZIER,	GenBezierCurveObject,	1,	{ OLST_EXPR } },
    { "SBSPLINE", SBSPLINE,	GenBsplineSurfaceObject, 4,	{ NUMERIC_EXPR, NUMERIC_EXPR, OLST_EXPR, OLST_EXPR } },
    { "CBSPLINE", CBSPLINE,	GenBsplineCurveObject,	3,	{ NUMERIC_EXPR, OLST_EXPR, OLST_EXPR } },
    { "SEVAL",    SEVAL,	EvalSurfaceObject,	3,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "CEVAL",    CEVAL,	EvalCurveObject,	2,	{ CURVE_EXPR, NUMERIC_EXPR } },
    { "STANGENT", STANGENT,	TangentSurfaceObject,	4,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "CTANGENT", CTANGENT,	TangentCurveObject,	2,	{ CURVE_EXPR, NUMERIC_EXPR } },
    { "SNORMAL",  SNORMAL,	NormalSurfaceObject,	3,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "SDIVIDE",  SDIVIDE,	DivideSurfaceObject,	3,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "CDIVIDE",  CDIVIDE,	DivideCurveObject,	2,	{ CURVE_EXPR, NUMERIC_EXPR } },
    { "SREGION",  SREGION,	RegionFromSurfaceObject, 4,	{ SURFACE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "CREGION",  CREGION,	RegionFromCurveObject,	3,	{ CURVE_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "SREFINE",  SREFINE,	RefineSurfaceObject,	4,	{ SURFACE_EXPR, NUMERIC_OBJ, NUMERIC_OBJ, OLST_EXPR } },
    { "CREFINE",  CREFINE,	RefineCurveObject,	3,	{ CURVE_EXPR, NUMERIC_OBJ, OLST_EXPR } },
    { "SRAISE",   SRAISE,	RaiseSurfaceObject,	3,	{ SURFACE_EXPR, NUMERIC_OBJ, NUMERIC_OBJ } },
    { "CRAISE",   CRAISE,	RaiseCurveObject,	2,	{ CURVE_EXPR, NUMERIC_OBJ } },
    { "CSURFACE", CSURFACE,	CurveFromSurface,	3,	{ SURFACE_EXPR, NUMERIC_OBJ, NUMERIC_OBJ } },
    { "CMESH",    CMESH,	CurveFromSrfMesh,	3,	{ SURFACE_EXPR, NUMERIC_OBJ, NUMERIC_OBJ } },
    { "NTH",	  NTH,		GetNthList,		2,	{ OLST_EXPR, NUMERIC_EXPR } },
    { "GPOLYGON", GPOLYGON,	Geometry2Polygons,	1,	{ OLST_GEOM_EXPR } },
    { "GPOLYLINE", GPOLYLINE,	Geometry2Polylines,	1,	{ OLST_GEOM_EXPR } },
    { "CIRCLE",   CIRCLE,	GenCircleCurveObject,	2,	{ VECTOR_EXPR, NUMERIC_EXPR } },
    { "ARC",	  ARC,		GenArcCurveObject,	3,	{ VECTOR_EXPR, VECTOR_EXPR, VECTOR_EXPR } },
    { "RULEDSRF", RULEDSRF,	GenRuledSrfObject,	2,	{ CURVE_EXPR, CURVE_EXPR } },
    { "BOOLSUM",  BOOLSUM,	GenBoolSumSrfObject,	4,	{ CURVE_EXPR, CURVE_EXPR, CURVE_EXPR, CURVE_EXPR } },
    { "SFROMCRVS", SFROMCRVS,	GenSrfFromCrvsObject,	1,	{ OLST_EXPR } },
    { "SWEEPSRF", SWEEPSRF,	GenSweepSrfObject,	3,	{ CURVE_EXPR, CURVE_EXPR, CURVE_EXPR | NUMERIC_EXPR } },
    { "OFFSET",	  OFFSET,	GenOffsetObject,	2,	{ CURVE_EXPR | SURFACE_EXPR, NUMERIC_EXPR } },
    { "CEDITPT",  CEDITPT,	EditCrvControlPoint,	3,	{ CURVE_EXPR, CTLPT_EXPR, NUMERIC_EXPR } },
    { "SEDITPT",  SEDITPT,	EditSrfControlPoint,	4,	{ SURFACE_EXPR, CTLPT_EXPR, NUMERIC_EXPR, NUMERIC_EXPR } },
    { "MERGEPOLY",MERGEPOLY,	GenObjectFromPolyList,	1,	{ 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...				     */
typedef void (*VoidFuncIntPtr)(int);
GenFuncTableType GenFuncTable[] = {
    { "EXIT",	EXIT,		MyExit,			0,	{ 0 } },
    { "VIEW",	VIEW,		WndwViewGeomObject,	2,	{ OLST_GEOM_EXPR, NUMERIC_EXPR } },
    { "DIR",	DIR,		DosPrintDir,		1,	{ STRING_EXPR } },
    { "CHDIR",	CHDIR,		DosChangeDir,		1,	{ STRING_EXPR } },
    { "NORMAL",	NORMAL,		ViewSetNormals,		3,	{ NUMERIC_EXPR,	NUMERIC_EXPR, NUMERIC_EXPR } },
    { "INCLUDE", INCLUDE,	FileInclude,		1,	{ STRING_EXPR } },
    { "SAVE",	SAVE,		DataPrsrPutObject,	2,	{ STRING_EXPR, ANY_EXPR } },
    { "FREE",	FREEOBJ,	FreeObject,		1,	{ ANY_EXPR } },
    { "INTERACT", INTERACT, 	InteractPolyObject,	2,	{ OLST_GEOM_EXPR, NUMERIC_EXPR } },
    { "PAUSE",	PAUSE,		WndwPause,		1,	{ NUMERIC_EXPR } },
    { "IF",	IFCOND, 	IfCondition,		4,	{ NUMERIC_EXPR,	STRING_EXPR, NUMERIC_EXPR, ANY_EXPR } },
    { "FOR",	FORLOOP, 	ForLoop,		4,	{ NUMERIC_EXPR,	NUMERIC_EXPR, NUMERIC_EXPR, ANY_EXPR } },
    { "HELP",	PRHELP,		PrintHelp,		1,	{ STRING_EXPR } },
    { "VARLIST", VARLIST, 	PrintObjectList,	0,	{ 0 } },
    { "ALIAS",	ALIAS,		AliasEdit,		2,	{ STRING_EXPR, STRING_EXPR } },
    { "BEEP",	BEEP,   	GGTone,			2,	{ NUMERIC_EXPR, NUMERIC_EXPR } },
    { "EDIT",	EDIT,		DosEditFile,		1,	{ STRING_EXPR } },
    { "SYSTEM",	SYSTEM,		(VoidFuncIntPtr) DosSystem, 0,   { 0 } },
    { "LOGFILE", LOGFILE, 	WndwLogPrint,		1,	{ NUMERIC_EXPR } },
    { "COLOR",	COLOR,		SetObjectColor, 	2,	{ GEOM_EXPR, NUMERIC_EXPR } },
    { "SNOC",	SNOC,		SnocList,		2,	{ ANY_EXPR, OLST_EXPR } },
    { "ATTRIB",	ATTRIB,		SetObjectStrAttrib,	3,	{ GEOM_EXPR, STRING_EXPR, STRING_EXPR } },
    { "CLOSED", CLOSED,		ViewSetClosed,		1,	{ NUMERIC_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 },

    { "E2",     (double) CAGD_PT_E2_TYPE },
    { "E3",     (double) CAGD_PT_E3_TYPE },
    { "P2",     (double) CAGD_PT_P2_TYPE },
    { "P3",     (double) CAGD_PT_P3_TYPE },

    { "BLACK",  (double) BLACK },
    { "BLUE",	(double) BLUE },
    { "GREEN",	(double) GREEN },
    { "CYAN",	(double) CYAN },
    { "RED",	(double) RED },
    { "MAGENTA", (double) MAGENTA },
    { "YELLOW", (double) YELLOW },
    { "WHITE",  (double) 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 },
};
int ConstantTableSize = sizeof(ConstantTable) / sizeof(ConstantTableType);

/*****************************************************************************
*   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 (Level == 0 &&
	Root->NodeKind != PARAMETER &&	    /* What is allowed on top level. */
	Root->NodeKind != EQUAL &&
	!IS_GEN_FUNCTION(Root->NodeKind)) {
	IPGlblEvalError = IE_ERR_NO_ASSIGNMENT;
	strcpy(IPGlblCharData, "");
	return ERROR_EXPR;
    }

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

    if (IS_GEN_FUNCTION(Root->NodeKind)) {   /* Funcs which returns 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;
	}
    }

    switch (Root->NodeKind) {
	case VECTOR:	      /* Object functions which returns Vector Type: */
	case STANGENT:
	case CTANGENT:
	case SNORMAL:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return VECTOR_EXPR;
	case CTLPT:	      /* Object functions which returns Ctl Pt Type: */
	case CEVAL:
	case SEVAL:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return CTLPT_EXPR;
	case ROTX:
	case ROTY:
	case ROTZ:
	case TRANS:
	case SCALE:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return MATRIX_EXPR;
	case BOX:
	case GBOX:
	case CONE:
	case CONE2:
	case CYLIN:
	case SPHERE:
	case TORUS:
	case CIRCPOLY:
	case POLY:
	case CROSSEC:
	case CONVEX:
	case GPOLYGON:
	case GPOLYLINE:
	case MERGEPOLY:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return POLY_EXPR;
	case CBEZIER:
	case CBSPLINE:
	case CREFINE:
	case CRAISE:
	case CSURFACE:
	case CMESH:
	case CIRCLE:
	case ARC:
	case CREGION:
	case CEDITPT:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return CURVE_EXPR;
	case SBEZIER:
	case SBSPLINE:
	case SREFINE:
	case SRAISE:
	case RULEDSRF:
	case BOOLSUM:
	case SWEEPSRF:
	case SREGION:
	case SFROMCRVS:
	case SEDITPT:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return SURFACE_EXPR;
	case LOAD:
	case NTH:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return ANY_EXPR;
	case OFFSET:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return SURFACE_EXPR | CURVE_EXPR;
	case SURFREV:
	case EXTRUDE:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return SURFACE_EXPR | POLY_EXPR;
	case LIST:
	case SDIVIDE:
	case CDIVIDE:
	    if (FuncParamMismatch(Root)) return ERROR_EXPR;
	    return OLST_EXPR;
	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 NUMBER:
	    return NUMERIC_EXPR;
	case PARAMETER:
	    switch (Root->U.PObj->ObjType) {
                case POLY_OBJ:
                    return POLY_EXPR;
		case NUMERIC_OBJ:
		    return NUMERIC_EXPR;
		case VECTOR_OBJ:
		    return VECTOR_EXPR;
		case CTLPT_OBJ:
		    return CTLPT_EXPR;
		case MATRIX_OBJ:
		    return MATRIX_EXPR;
		case STRING_OBJ:
		    return STRING_EXPR;
		case OBJ_LIST_OBJ:
		    return OLST_EXPR;
		case CURVE_OBJ:
		    return CURVE_EXPR;
		case SURFACE_OBJ:
		    return SURFACE_EXPR;
		case UNDEF_OBJ:
		    IPGlblEvalError = IE_ERR_UNDEF_OBJECT;
		    strcpy(IPGlblCharData, Root->U.PObj->Name);
		    return ERROR_EXPR;
	    }
	    IPGlblEvalError = IE_ERR_FATAL_ERROR;
	    sprintf(IPGlblCharData, "Object = %s, Type %d",
				Root->U.PObj->Name, Root->U.PObj->ObjType);
	    return ERROR_EXPR;
	case STRING:
	    return STRING_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)
{
    char *ErrorMsg;
    RealType R;
    ParseTree *TempL, *TempR, *Params[5];
    PolygonStruct *PPoly;
    ObjectStruct *PObj;

    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 (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.R = (NumFuncTable[Root->NodeKind-NUM_FUNC_OFFSET].Func)
							     (Params[0]->U.R);
	    Root->ObjType = NUMERIC_OBJ;
	    if (RetrieveMathError()) return NULL;
	    return Root;

	case CPOLY:
	case AREA:
	case VOLUME:
	    if (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.R = (NumFuncTable[Root->NodeKind-NUM_FUNC_OFFSET].Func)
					       		  (Params[0]->U.PObj);
	    Root->ObjType = NUMERIC_OBJ;
	    if (RetrieveMathError()) return NULL;
	    return Root;

	case ARCTAN2:	  /* Real return functions with two real parameters. */
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.R = (NumFuncTable[Root->NodeKind-NUM_FUNC_OFFSET].Func)
					     (Params[0]->U.R, Params[1]->U.R);
	    Root->ObjType = NUMERIC_OBJ;
	    if (RetrieveMathError()) return NULL;
	    return Root;

	case VECTOR:  /* Object return functions with three real parameters. */
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		("", &Params[0]->U.R, &Params[1]->U.R, &Params[2]->U.R, NULL);
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case CTLPT:
	case LIST:
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
							       (Root -> Right);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case ROTX:
	case ROTY:
	case ROTZ:
	    if (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
							     (&Params[0]->U.R);
	    if (RetrieveMathError()) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case TRANS:
	case SCALE:
	    if (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
						    (Params[0]->U.PObj->U.Vec);
	    if (RetrieveMathError()) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case BOX:
	    if (!FetchParameters(Root, 4, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		(Params[0]->U.PObj->U.Vec, &Params[1]->U.R, &Params[2]->U.R,
                					    &Params[3]->U.R);
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case GBOX:
	    if (!FetchParameters(Root, 4, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		(Params[0]->U.PObj->U.Vec, Params[1]->U.PObj ->U.Vec,
		 Params[2]->U.PObj->U.Vec, Params[3]->U.PObj ->U.Vec);
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case CONE:
	case CYLIN:
	case CIRCPOLY:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		(Params[0]->U.PObj->U.Vec, Params[1]->U.PObj->U.Vec,
                					&Params[2]->U.R);
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case SPHERE:
	case CIRCLE:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
			           (Params[0]->U.PObj->U.Vec, &Params[1]->U.R);
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case TORUS:
	case CONE2:
	    if (!FetchParameters(Root, 4, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		(Params[0]->U.PObj->U.Vec, Params[1]->U.PObj->U.Vec,
		 &Params[2]->U.R, &Params[3]->U.R);
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case SEVAL:
	case SNORMAL:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
			  (Params[0]->U.PObj, &Params[1]->U.R, &Params[2]->U.R);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case STANGENT:
	case SREGION:
	    if (!FetchParameters(Root, 4, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
			  (Params[0]->U.PObj, &Params[1]->U.R,
			   &Params[2]->U.R, &Params[3]->U.R);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case CDIVIDE:
	case CEVAL:
	case CTANGENT:
	case CRAISE:
	case OFFSET:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
			  (Params[0]->U.PObj, &Params[1]->U.R);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case SREFINE:
	    if (!FetchParameters(Root, 4, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		       (Params[0]->U.PObj, &Params[1]->U.R,
                       		     &Params[2]->U.R, Params[3]->U.PObj);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case CREFINE:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
	         (Params[0]->U.PObj, &Params[1]->U.R, Params[2]->U.PObj);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case SDIVIDE:
	case SRAISE:
	case CSURFACE:
	case CREGION:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		   (Params[0]->U.PObj, &Params[1]->U.R, &Params[2]->U.R);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case CMESH:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		   (Params[0]->U.PObj,
		    &Params[1]->U.R, &Params[2]->U.R);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

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

	    if (IS_NUM_OBJ(Root->U.PObj)) {
		Root->ObjType = NUMERIC_OBJ;
		MyFree((char *) Root->U.PObj, ALLOC_OBJECT);
		Root->U.R = Root->U.PObj->U.R;
		Root->NodeKind = NUMBER;     /* Disconnect the var. binding. */
		return Root;
            }
            else {
		Root->ObjType = Root->U.PObj->ObjType;
		/* Since at this point, no one is pointing on it: */
		Root->U.PObj->Count = 0;
		return Root;
	    }

	case POLY:
	case SBEZIER:
	case CBEZIER:
	case SURFREV:
	case CONVEX:
	case GPOLYGON:
	case GPOLYLINE:
	case SFROMCRVS:
	case MERGEPOLY:
	    if (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
							   (Params[0]->U.PObj);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case CBSPLINE:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
			(&Params[0]->U.R, Params[1]->U.PObj, Params[2]->U.PObj);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case SBSPLINE:
	    if (!FetchParameters(Root, 4, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
			(&Params[0]->U.R, &Params[1]->U.R,
			 Params[2]->U.PObj, Params[3]->U.PObj);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case CROSSEC:
	    if (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    Root->ObjType = POLY_OBJ;
	    /* Use table entries to call the function directly. */
	    if (IS_POLY_OBJ(Params[0] -> U.PObj))
		Root->U.PObj =
		    (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
			(Params[0]->U.PObj);
	    else
		Root->U.PObj =
		    (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)(NULL);
	    if (Root->U.PObj == NULL) return NULL;
	    return Root;

	case EXTRUDE:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
				 (Params[0]->U.PObj, Params[1]->U.PObj->U.Vec);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case RULEDSRF:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
				 (Params[0]->U.PObj, Params[1]->U.PObj);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case BOOLSUM:
	    if (!FetchParameters(Root, 4, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
				 (Params[0]->U.PObj, Params[1]->U.PObj,
				  Params[2]->U.PObj, Params[3]->U.PObj);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case CEDITPT:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
				 (Params[0]->U.PObj, Params[1]->U.PObj,
				  &Params[2]->U.R);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case SEDITPT:
	    if (!FetchParameters(Root, 4, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
				 (Params[0]->U.PObj, Params[1]->U.PObj,
				  &Params[2]->U.R, &Params[3]->U.R);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case ARC:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		          (Params[0]->U.PObj->U.Vec, Params[1]->U.PObj->U.Vec,
						     Params[2]->U.PObj->U.Vec);
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case SWEEPSRF:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    if (IS_NUM_NODE(Params[2])) {
	    	Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		     (Params[0]->U.PObj, Params[1]->U.PObj, NULL,
							       &Params[2]->U.R);
	    }
	    else {
		R = 1.0;
	    	Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
		     (Params[0]->U.PObj, Params[1]->U.PObj, Params[2]->U.PObj,
									    &R);
	    }
	    if (Root->U.PObj == NULL) return NULL;
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case LOAD:
	    if (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
						(Params[0]->U.PObj->U.Str, "");
	    if (Root->U.PObj == NULL) {
	        DataPrsrParseError(&ErrorMsg);
		IPGlblEvalError = IE_ERR_DATA_PRSR_ERROR;
		strcpy(IPGlblCharData, ErrorMsg);
		return NULL;
	    }
	    Root->ObjType = Root -> U.PObj -> ObjType;
	    return Root;

	case SNOC:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;

	    if (Params[0]->ObjType == NUMERIC_OBJ) {
		PObj = GenNumObject("", &Params[0]->U.R, NULL);
		/* Use table entries to call the function directly. */
		(GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
						    (PObj, Params[1]->U.PObj);
		MyFree((char *) PObj, ALLOC_OBJECT);
	    }
	    else {
		/* Use table entries to call the function directly. */
		(GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
					(Params[0]->U.PObj, Params[1]->U.PObj);
	    }
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case VIEW:
	case INTERACT:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    Root->ObjType = UNDEF_OBJ;
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
					  (Params[0]->U.PObj, &Params[1]->U.R);
	    return Root;

	case COLOR:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    Root->ObjType = UNDEF_OBJ;
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
			    (Params[0]->U.PObj, REAL_TO_INT(Params[1]->U.R));
	    return Root;

	case EXIT:
	    /* Yes - we finished for today... */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)(0);

	case PAUSE:
	case LOGFILE:
	case CLOSED:
	    if (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
	            					  (&Params[0] -> U.R);
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case VARLIST:
	case SYSTEM:
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)(GlblObjList);
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case DIR:
	case CHDIR:
	case INCLUDE:
	case PRHELP:
	case EDIT:
	    if (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
			 (Params[0]->U.PObj->U.Str);
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case SAVE:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    if (Params[1]->ObjType == NUMERIC_OBJ) {
		PObj = GenNumObject("", &Params[1]->U.R, NULL);
	    	/* Use table entries to call the function directly. */
	        (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
					(Params[0]->U.PObj->U.Str, PObj);
		MyFree((char *) PObj, ALLOC_OBJECT);
	    }
	    else {
		/* Use table entries to call the function directly. */
		(GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
				(Params[0]->U.PObj->U.Str, Params[1]->U.PObj);
	    }

	    if (DataPrsrParseError(&ErrorMsg) != 0) {
		IPGlblEvalError = IE_ERR_DATA_PRSR_ERROR;
		strcpy(IPGlblCharData, ErrorMsg);
		return NULL;
	    }
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case BEEP:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
		 (REAL_TO_INT(Params[0]->U.R), REAL_TO_INT(Params[1]->U.R));
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case ALIAS:
	    if (!FetchParameters(Root, 2, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
			 (Params[0]->U.PObj->U.Str, Params[1]->U.PObj->U.Str);
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case ATTRIB:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
			(Params[0]->U.PObj,
			 Params[1]->U.PObj->U.Str, Params[2]->U.PObj->U.Str);
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case FREEOBJ:
	    if (!FetchParameters(Root, 1, Level, Params)) return NULL;
	    if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
		return NULL;
	    if (TempR->ObjType == NUMERIC_OBJ) {
		IPGlblEvalError = IE_ERR_TYPE_MISMATCH;
		strcpy(IPGlblCharData, "Func FREE, parameter 1");
		return Root;
	    }
	    if (strlen(TempR->U.PObj->Name) == 0) {
		IPGlblEvalError = IE_ERR_FREE_SIMPLE;
                UpdateCharError("Procedure ", FREEOBJ);
		return Root;
	    }
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
							      (TempR->U.PObj);
	    Root->ObjType = UNDEF_OBJ;
	    TempR->U.PObj = NULL;	    /* Make sure its disconnected... */
	    return Root;

	case NORMAL:
	    if (!FetchParameters(Root, 3, Level, Params)) return NULL;
	    /* Use table entries to call the function directly. */
	    (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
		          (&Params[0]->U.R, &Params[1]->U.R, &Params[2]->U.R);
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case IFCOND:
	    IfCondition(FetchParameter(Root->Right, 0, 4),
			FetchParameter(Root->Right, 1, 4),
			FetchParameter(Root->Right, 2, 4),
			FetchParameter(Root->Right, 3, 4));
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	case FORLOOP:
	    ForLoop(FetchParameter(Root->Right, 0, 4),
		    FetchParameter(Root->Right, 1, 4),
		    FetchParameter(Root->Right, 2, 4),
		    FetchParameter(Root->Right, 3, 4));
	    Root->ObjType = UNDEF_OBJ;
	    return Root;

	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))
		return NULL;
	    TempR = OverLoadEvalOper(Root, TempR, TempL,
					&IPGlblEvalError, IPGlblCharData);
	    if (RetrieveMathError())
		return NULL;
	    else
		return TempR;

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

	case NUMBER:
	    Root->ObjType = NUMERIC_OBJ;
            return Root;

	case PARAMETER:
	    if (Level == 0) {	      /* If only object - print its content. */
		Root->U.PObj->Count--;   /* Remove reference from this tree. */
		PrintObject(Root->U.PObj);
		Root->U.PObj->Count++;		      /* Add reference back. */
		Root->ObjType = Root->U.PObj->ObjType;
		return Root;
	    }
	    if (IS_NUM_OBJ(Root->U.PObj)) {
		Root->ObjType = NUMERIC_OBJ;
		Root->U.PObj->Count--;
		Root->U.R = Root->U.PObj->U.R;
		Root->NodeKind = NUMBER;     /* Disconnect the var. binding. */
		return Root;
            }
	    else {
		Root->ObjType = Root->U.PObj->ObjType;
		return Root;
	    }

	case STRING:
	    Root->ObjType = STRING_OBJ;
            return Root;

	case EQUAL:
	    if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
		return NULL;
	    TempL = Root->Left;
	    PPoly = NULL;
	    if (IS_UNDEF_OBJ(TempL->U.PObj))		  /* Its new object. */
		InsertObject(TempL->U.PObj);	   /* Insert to global vars. */
	    else if (IS_POLY_OBJ(TempL->U.PObj))    /* If old var. was poly. */
		PPoly = TempL->U.PObj->U.Pl.P;

            if (IS_NUM_NODE(TempR)) {
		TempL->ObjType = TempL->U.PObj->ObjType = NUMERIC_OBJ;
		TempL->U.PObj->U.R = TempR->U.R;
	    }
            else {
		if (TempL -> U.PObj == TempR -> U.PObj) return TempR;/* A=A. */
		TempL->ObjType = TempR->ObjType;
		CopyObject(TempL->U.PObj, TempR->U.PObj, FALSE);
	    }
	    if (PPoly != NULL) MyFree((char *) (PPoly), ALLOC_POLYGON);

	    Root->ObjType = UNDEF_OBJ;
	    return TempR;
    }
    return NULL;				    /* Makes warning silent. */
}

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

/*****************************************************************************
*   Routine to print help on the given subject HelpHeader.		     *
* Note a match is if the HelpHeader in prefix of help file line.	     *
*****************************************************************************/
static void PrintHelp(char *HelpHeader)
{
    int	i;
    char *Path, s[LINE_LEN];
    FILE *f;

    Path = searchpath(GlblHelpFileName);

    if (strlen(HelpHeader) == 0)
	HelpHeader = "Commands";	    /* Print a list of all commands. */

    if ((f = fopen(Path, "r")) == NULL) {
	sprintf(s, "Cannot open help file \"%s\".\n", GlblHelpFileName);
	WndwInputWindowPutStr(s);
	return;
    }

    for (i = 0; i < (int) strlen(HelpHeader); i++)
	if (islower(HelpHeader[i])) HelpHeader[i] = toupper(HelpHeader[i]);

    while (fgets(s, LINE_LEN-1, f) != NULL) {
	if (strncmp(HelpHeader, s, strlen(HelpHeader)) == 0) {
	    /* Found match - print it. */
	    while (fgets(s, LINE_LEN-1, f) != NULL && s[0] != '$') {
		WndwInputWindowPutStr(&s[1]);		     /* Skip char 1. */
	    }
	    fclose(f);
	    return;
	}
    }

    fclose(f);

    sprintf(s, "No help on %s\n", HelpHeader);
    WndwInputWindowPutStr(s);
}

/*****************************************************************************
*   Routine to execute the IF structure.				     *
*****************************************************************************/
static void IfCondition(ParseTree *Left, ParseTree *Cond, ParseTree *Right,
							  ParseTree *PBody)
{
    int i, NumOfExpr;
    RealType L, R;
    char *Str;

    Left = InptPrsrEvalTree(Left, 1);
    Cond = InptPrsrEvalTree(Cond, 1);
    Right = InptPrsrEvalTree(Right, 1);

    L = Left->U.R;
    Str = Cond->U.PObj->U.Str;
    R = Right->U.R;

    if ((strcmp(Str, "=")  == 0 && L == R) ||
	(strcmp(Str, "<>") == 0 && L != R) ||
	(strcmp(Str, "<=") == 0 && L <= R) ||
	(strcmp(Str, ">=") == 0 && L >= R) ||
	(strcmp(Str, ">")  == 0 && L > R) ||
	(strcmp(Str, "<")  == 0 && L < R)) {
	/* If we are here, then the condition holds: */
	for (i = 0; i < (NumOfExpr = CountNumExpressions(PBody)); i++) {
	    InptPrsrEvalTree(FetchExpression(PBody, i, NumOfExpr), 0);
	    if (GlblWasCtrlBrk ||	 /* async. break send from the user. */
		IPGlblEvalError) break;
	}
    }
}

/*****************************************************************************
*   Routine to execute the FOR structure loop.				     *
*   Note that as InptPrsrEvalTree routine is destructive on its input tree,  *
* we must make a copy of the body before executing it!			     *
*   We wish we could access the loop variable directly, but the user might   *
* be stupid and free it in the loop - so me must access it by name.	     *
*****************************************************************************/
static void ForLoop(ParseTree *PStart, ParseTree *PInc, ParseTree *PEnd,
							ParseTree *PBody)
{
    int i, NumOfExpr, LoopCount;
    char *LoopVarName = NULL;
    RealType LoopVar, StartVal, Increment, EndVal;
    ParseTree *PTemp;
    ObjectStruct *PLoopVar;

    /* Find the only two cases where loop variable is allowed - when then */
    /* given starting value is a parameter, or assignment to parameter... */
    if (PStart -> NodeKind == PARAMETER)
	LoopVarName = PStart -> U.PObj -> Name;
    else if (PStart -> NodeKind == EQUAL &&
	     PStart -> Left -> NodeKind == PARAMETER) {
	LoopVarName = PStart -> Left -> U.PObj -> Name;
	/* Rebind the iteration variable to body - it might be new: */
	RebindVariable(PBody, PStart -> Left -> U.PObj);
	if (GetObject(LoopVarName) == NULL)		/* It is really new. */
	    PStart -> Left -> U.PObj -> Count++;
    }

    PStart = InptPrsrEvalTree(PStart, 1);	 /* Evaluate starting value. */
    PInc   = InptPrsrEvalTree(PInc, 1);		/* Evaluate increment value. */
    PEnd   = InptPrsrEvalTree(PEnd, 1);		      /* Evaluate end value. */
    if (IPGlblEvalError ||
	PStart == NULL || PInc == NULL || PEnd == NULL) return;
    StartVal = PStart -> U.R;
    Increment = PInc -> U.R;
    EndVal = PEnd -> U.R;

    NumOfExpr = CountNumExpressions(PBody);    /* Num. of expr. in the body. */
    for (LoopVar = StartVal, LoopCount = 0;
	APX_EQ(LoopVar, EndVal) ||
	(Increment > 0 ? LoopVar <= EndVal : LoopVar >= EndVal);
	LoopVar += Increment, LoopCount++) {
	if (GlblWasCtrlBrk ||		 /* Async. break send from the user. */
	    IPGlblEvalError || GlblFatalError) return;
	if (LoopVarName != NULL) {
	    if ((PLoopVar = GetObject(LoopVarName)) != NULL &&
		 IS_NUM_OBJ(PLoopVar))
		PLoopVar -> U.R = LoopVar; /* Update loop var. */
	    else {
		IPGlblEvalError = IE_ERR_MODIF_ITER_VAR;
		strcpy(IPGlblCharData, LoopVarName);
	    }
	}

	for (i = 0; i < NumOfExpr; i++) {
	    PTemp = FetchExpression(PBody, i, NumOfExpr);
	    if (LoopCount == 0 && InptPrsrTypeCheck(PTemp, 0) == ERROR_EXPR)
		return;
	    else {
		if (LoopVar == EndVal) {
		    /* Use the original tree. Note we must evaluate the      */
		    /* original tree at least once as ObjType's are updated. */
		    InptPrsrEvalTree(PTemp, 0);	 /* Eval as its top level... */
		}
		else {
		    PTemp = InptPrsrCopyTree(PTemp);
		    InptPrsrEvalTree(PTemp, 0);	 /* Eval as its top level... */
		    InptPrsrFreeTree(PTemp);	     /* Not needed any more. */
		}
	    }
	}
    }
}

/*****************************************************************************
*   Routine to create an OBJECT LIST object out of all parameters.	     *
*****************************************************************************/
static ObjectStruct *GenObjectList(ParseTree *PObjParams)
{
    int i, NumOfParams;
    ParseTree *Param;
    ObjectStruct *PObj;

    NumOfParams = CountNumParameters(PObjParams);
    if (NumOfParams > MAX_OBJ_LIST) {
	IPGlblEvalError = IE_ERR_LIST_TOO_LONG;
	return NULL;
    }

    PObj = AllocObject("", OBJ_LIST_OBJ, NULL);

    for (i = 0; i < NumOfParams; i++) {
	if ((Param = InptPrsrEvalTree(FetchParameter(PObjParams, i,
						     NumOfParams),
				      1)) == NULL) {
	    MyFree((char *) PObj, ALLOC_OBJECT);
	    return NULL;
        }
	if (Param -> NodeKind == NUMBER ||
	    (Param -> NodeKind == UNARMINUS &&
	     Param -> ObjType == NUMERIC_OBJ)) {
	    /* This is a special case in which the data is saved in parse    */
            /* tree instead of as an underneath object - make an object!     */
	    PObj -> U.PObjList[i] = AllocObject("", NUMERIC_OBJ, NULL);
	    PObj -> U.PObjList[i] -> U.R = Param -> U.R;
	}
        else {
	    if (Param -> U.PObj -> ObjType == UNDEF_OBJ) {
		IPGlblEvalError = IE_ERR_UNDEF_OBJECT;
		strcpy(IPGlblCharData, Param -> U.PObj -> Name);
		PObj -> U.PObjList[i] = NULL;
		MyFree((char *) PObj, ALLOC_OBJECT);
		return NULL;
	    }

	    PObj -> U.PObjList[i] = Param -> U.PObj;
	    Param -> U.PObj -> Count++;    /* Increase number of references. */
        }
    }

    if (NumOfParams < MAX_OBJ_LIST) PObj -> U.PObjList[NumOfParams] = NULL;
    return PObj;
}

/*****************************************************************************
*   Routine to create an Control Point Object out of all parameters.	     *
*****************************************************************************/
static ObjectStruct *CtlPtFromParams(ParseTree *PObjParams)
{
    int i, NumPts, NumOfParams, PtType,
	CoordCount = 0;
    ParseTree *Param;
    ObjectStruct *PObj;

    NumOfParams = CountNumParameters(PObjParams);

    PObj = AllocObject("", CTLPT_OBJ, NULL);

    for (i = 0; i < NumOfParams; i++) {
	if ((Param = InptPrsrEvalTree(FetchParameter(PObjParams, i,
						     NumOfParams),
				      1)) == NULL) {
	    MyFree((char *) PObj, ALLOC_OBJECT);
	    return NULL;
        }
        if (Param -> ObjType != NUMERIC_OBJ) {
	    IPGlblEvalError = IE_ERR_TYPE_MISMATCH;
	    strcpy(IPGlblCharData, "Numeric data expected");
	    MyFree((char *) PObj, ALLOC_OBJECT);
	    return NULL;
        }

	if (i == 0) {
	    PtType = PObj -> U.CtlPt.PtType = (CagdPointType) Param -> U.R;
	    switch (PtType) {
		case CAGD_PT_E2_TYPE:
		    NumPts = 2;
		    CoordCount = 1;
		    break;
		case CAGD_PT_E3_TYPE:
		    NumPts = 3;
		    CoordCount = 1;
		    break;
		case CAGD_PT_P2_TYPE:
		    NumPts = 3;
		    break;
		case CAGD_PT_P3_TYPE:
		    NumPts = 4;
		    break;
		default:
		    IPGlblEvalError = IE_ERR_TYPE_MISMATCH;
		    strcpy(IPGlblCharData, "E2, E3, P2, P3 expected");
		    MyFree((char *) PObj, ALLOC_OBJECT);
		    return NULL;
	    }
	    if (NumOfParams - 1 != NumPts) {
		IPGlblEvalError = IE_ERR_NUM_PRM_MISMATCH;
		sprintf(IPGlblCharData, "%d expected", NumPts);
		MyFree((char *) PObj, ALLOC_OBJECT);
		return NULL;
	    }
	}
        else
	    PObj -> U.CtlPt.Coords[CoordCount++] = Param -> U.R;
    }

    return PObj;
}

/*****************************************************************************
*   Routine to count number of expressions seperated by a COLON are given    *
* in the tree ROOT. This routine is similar to CountNumParameters below.     *
*****************************************************************************/
static int CountNumExpressions(ParseTree *Root)
{
    int i=1;

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

/*****************************************************************************
*   Routine to fetch the i expression out of a tree represent n expressions  *
* (0 <= i < n) seperated by colonc. Similar to FetchParameter routine below. *
*****************************************************************************/
static ParseTree *FetchExpression(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 retrieve math error if was one. return TRUE if was error.     *
*****************************************************************************/
static int RetrieveMathError(void)
{
    int Error;
    char *FuncName, *p;

#ifdef __MSDOS__
    if ((Error = MathError(&FuncName)) != 0) {
	switch (Error) {
	    case DOMAIN:
		p = "DOMAIN";
		break;
	    case SING:
		p = "SING";
		break;
	    case OVERFLOW:
		p = "O.F.";
		break;
	    case UNDERFLOW:
		p = "U.F.";
		break;
	    case TLOSS:
		p = "TLOSS";
		break;
	    default:
		p = "Undef.";
		break;
	}
        strcpy(IPGlblCharData, p);
	strcat(IPGlblCharData, " error - func. ");
	strcat(IPGlblCharData, FuncName);
	IPGlblEvalError = IE_ERR_FP_ERROR;
	return TRUE;
    }
#endif /* __MSDOS__ */

    return FALSE;
}

/*****************************************************************************
*  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.					     *
*****************************************************************************/
static int CountNumParameters(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 CountNumParameters for more description of structure.    *
* Note it is assumed the tree HAS n parameters and 0<=i<n (No input error).  *
*****************************************************************************/
static ParseTree *FetchParameter(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 FetchParameters(ParseTree *Root, int NumParams, int Level,
							 ParseTree *Params[])
{
    int i;

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

    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 = CountNumParameters(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(FetchParameter(Root->Right, i, Count), 1))) {
	    sprintf(IPGlblCharData, "Func %s,%sparameter %d",
		    FuncTable[FuncOffset].FuncName,
		    IPGlblEvalError == IE_ERR_UNDEF_OBJECT ? " 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];
    int ValidObject;

    if (!Root) return;

    ValidObject = Root->ObjType != NUMERIC_OBJ && Root->ObjType != UNDEF_OBJ;

    if (IS_FUNCTION(Root -> NodeKind)) {
	if (IS_NO_PARAM_FUNC(Root -> NodeKind))
	    MyExprFree(Root);
	else {
	    InptPrsrFreeTree(Root->Right);
	    if (ValidObject && strlen(Root->U.PObj->Name) == 0)
		MyFree((char *) Root->U.PObj, ALLOC_OBJECT);     /* Its temp.*/
	    MyExprFree(Root);
        }
	return;
    }

    switch (Root -> NodeKind) {
	case DIV:
	case MINUS:
	case MULT:
	case PLUS:
	case POWER:
	    InptPrsrFreeTree(Root->Right);
	    InptPrsrFreeTree(Root->Left);
	    if (ValidObject && strlen(Root->U.PObj->Name) == 0)
		MyFree((char *) Root->U.PObj, ALLOC_OBJECT);/* Its temporary.*/
	    MyExprFree(Root);
	    break;

	case UNARMINUS:
	    InptPrsrFreeTree(Root->Right);
	    if (ValidObject && strlen(Root->U.PObj->Name) == 0)
		MyFree((char *) Root->U.PObj, ALLOC_OBJECT);/* Its temporary.*/
	    MyExprFree(Root);
	    break;

	case COMMA:
	case COLON:
	case EQUAL:
  	    InptPrsrFreeTree(Root->Right);
	    InptPrsrFreeTree(Root->Left);
	    MyExprFree(Root);
	    break;

	case NUMBER:
	    MyExprFree(Root);
	    break;

	case PARAMETER:
	    if (Root->U.PObj) {
		/* No assign took place -  Its temporary. */
		if ((Root->U.PObj->ObjType == UNDEF_OBJ ||
		     strlen(Root->U.PObj->Name) == 0))
		    MyFree((char *) Root->U.PObj, ALLOC_OBJECT);
		else
		    Root->U.PObj->Count--;
	    }
	    MyExprFree(Root);
	    break;

	case STRING:
	    MyFree((char *) Root->U.PObj, ALLOC_OBJECT);/* The string object.*/
	    MyExprFree(Root);
	    break;

	case TOKENSTART:
	    MyExprFree(Root);
	    break;

	case OPENPARA:
	case CLOSPARA:
	    MyExprFree(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) {
		MyExprFree(Root);
	    }
	    else {
		sprintf(s, "%s (%d).\n",
		    "InptPrsrFreeTree: Undefined ParseTree type to free",
		    Root -> NodeKind);
		FatalError(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 at list LINE_LEN_LONG places to write the expression.*
*****************************************************************************/
static void LocalPrintTree(ParseTree *Root, int Level, char *Str)
{
    int	CloseFlag = FALSE, Len, i;

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

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

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

    switch (i * 100) {
	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 NUMBER:
		    sprintf(&Str[strlen(Str)], "%lg", Root->U.R);
		    break;

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

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

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

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

		case TOKENSTART:
		    break;

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

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

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

/*****************************************************************************
*   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 = MyExprMalloc();

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

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

	case COMMA:
	case COLON:
	case EQUAL:
	    NewRoot -> NodeKind = Root -> NodeKind;
	    NewRoot -> ObjType = Root -> ObjType;
	    NewRoot -> Right = InptPrsrCopyTree(Root -> Right);
	    NewRoot -> Left  = InptPrsrCopyTree(Root -> Left);
	    return NewRoot;

	case NUMBER:
	    NewRoot -> NodeKind = Root -> NodeKind;
	    NewRoot -> ObjType = Root -> ObjType;
	    NewRoot -> U.R = Root -> U.R;
	    return NewRoot;

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

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

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

/*****************************************************************************
*  Routine to rebind a variable - given a tree, scan it and update each      *
* occurance of that variable to point to PObj.				     *
*****************************************************************************/
static void RebindVariable(ParseTree *Root, ObjectStruct *PObj)
{
    if (Root == NULL) return;

    if (IS_FUNCTION(Root->NodeKind)) {		       /* All the functions. */
	RebindVariable(Root -> Right, PObj);
	return;
    }

    switch (Root->NodeKind) {
	case UNARMINUS:
	    RebindVariable(Root -> Right, PObj);
	    return;

	case DIV:
	case MINUS:
	case MULT:
	case PLUS:
	case POWER:

	case COMMA:
	case COLON:
	case EQUAL:
	    RebindVariable(Root -> Right, PObj);
	    RebindVariable(Root -> Left, PObj);
	    return;

	case NUMBER:
	    return;

	case PARAMETER:
	case STRING:
	    if (strcmp(Root -> U.PObj -> Name, PObj -> Name) == 0) {
		/* I wish I could free that, but nesting loops might try */
		/* to free the same place n times... We will loose this  */
		/* variable place if it defined for the first time. Fix  */
		/* it if you really care...				 */
		/*
		if (IS_UNDEF_OBJ(Root -> U.PObj))
		    MyFree((char *) Root->U.PObj, ALLOC_OBJECT);
		*/
		Root -> U.PObj = PObj;
	    }
            return;

	case TOKENSTART:
	    return;

	default:
	    FatalError("RebindVariable: Undefined ParseTree type, exit\n");
    }
}

/*****************************************************************************
*   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;
}
[ RETURN TO DIRECTORY ]