/***************************************************************************** * "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 #include #endif /* __MSDOS__ */ #include #include #include #include #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<=iRight; 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; }