home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / IRIT / IRITS.ZIP / INPTEVAL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-05  |  57.0 KB  |  1,920 lines

  1. /*****************************************************************************
  2. *   "Irit" - the 3d polygonal solid modeller.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Mar. 1990   *
  5. ******************************************************************************
  6. *   Module to evaluate the binary tree generated by the InptPrsr module.     *
  7. *   All the objects are handled the same but the numerical one, which is     *
  8. * moved as a RealType and not as an object (only internally within this         *
  9. * module) as it is frequently used and consumes much less memory this way.   *
  10. *   Note this module is par of InptPrsr module and was splited only because  *
  11. * of text file sizes problems...                         *
  12. *****************************************************************************/
  13.  
  14. #ifdef __MSDOS__
  15. #include <alloc.h>
  16. #include <graphics.h>
  17. #include <dir.h>
  18. #endif /* __MSDOS__ */
  19.  
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <math.h>
  23. #include <string.h>
  24. #include "program.h"
  25. #include "allocatg.h"
  26. #include "viewobjg.h"
  27. #include "convexg.h"
  28. #include "primitvg.h"
  29. #include "geomat3d.h"
  30. #include "windowsg.h"
  31. #include "dataprsg.h"
  32. #include "objects.h"
  33. #include "geomvalg.h"
  34. #include "dosintrg.h"
  35. #include "inptprsg.h"
  36. #include "inptprsl.h"
  37. #include "overload.h"
  38. #include "matherr.h"
  39. #include "ctrl-brk.h"
  40.  
  41. #ifndef __MSDOS__
  42. #include "xgraphic.h"
  43. #endif /* __MSDOS__ */
  44.  
  45. #include "graphgng.h"
  46.  
  47.  
  48. int IPGlblEvalError;                 /* Global used by EvalTree. */
  49. extern char IPGlblCharData[LINE_LEN_LONG];    /* Used for both parse & eval. */
  50.  
  51. /*   I prefer to put the declarations of static functions just before the    */
  52. /* function themselves, but the tables below needs them so...             */
  53. static void PrintHelp(char *HelpHeader);
  54. static void IfCondition(RealType *Left, char *Cond, RealType *Right,
  55.                             ParseTree *PBody);
  56. static void ForLoop(ParseTree *PLeft, ParseTree *PCond,
  57.                    ParseTree *PRight, ParseTree *PBody);
  58. static struct ObjectStruct *GenObjectList(ParseTree *PObjParams);
  59. static int CountNumExpressions(ParseTree *Root);
  60. static ParseTree *FetchExpression(ParseTree *Root, int i, int n);
  61. static int RetrieveMathError(void);
  62. static int CountNumParameters(ParseTree *Root);
  63. static ParseTree *FetchParameter(ParseTree *Root, int i, int n);
  64. static int FuncParamMismatch(ParseTree *Root);
  65. static void LocalPrintTree(ParseTree *Root, int Level, char *Str);
  66. static void RebindVariable(ParseTree *Root, ObjectStruct *PObj);
  67. static int RetrieveMathError(void);
  68.  
  69. NumFuncTableType NumFuncTable[] = {
  70.     { "ACOS",    ARCCOS,    acos,    1,    { NUMERIC_OBJ }    },
  71.     { "ASIN",    ARCSIN,    asin,    1,    { NUMERIC_OBJ }    },
  72.     { "ATAN2",    ARCTAN2, atan2,    2,    { NUMERIC_OBJ, NUMERIC_OBJ }  },
  73.     { "ATAN",    ARCTAN,    atan,    1,    { NUMERIC_OBJ }    },
  74.     { "COS",    COS,    cos,    1,    { NUMERIC_OBJ }    },
  75.     { "EXP",    EXP,    exp,    1,    { NUMERIC_OBJ }    },
  76.     { "ABS",    FABS,    fabs,    1,    { NUMERIC_OBJ }    },
  77.     { "LN",    LN,    log,    1,    { NUMERIC_OBJ }    },
  78.     { "LOG",    LOG,    log10,    1,    { NUMERIC_OBJ }    },
  79.     { "SIN",    SIN,    sin,    1,    { NUMERIC_OBJ }    },
  80.     { "SQRT",    SQRT,    sqrt,    1,    { NUMERIC_OBJ }    },
  81.     { "TAN",    TAN,    tan,    1,    { NUMERIC_OBJ }    },
  82.     { "CPOLY",    CPOLY,    GeomCountPolys,    1,    { GEOMETRIC_OBJ } },
  83.     { "AREA",    AREA,    GeomObjectArea,    1,    { GEOMETRIC_OBJ } },
  84.     { "VOLUME",    VOLUME,    GeomObjectVolume, 1,    { GEOMETRIC_OBJ } },
  85.     { "TIME",    TIME,    DosGetTime,    1,    { NUMERIC_OBJ } },
  86. };
  87. int NumFuncTableSize = sizeof(NumFuncTable) / sizeof(NumFuncTableType);
  88.  
  89. /* Although the type of parameters is specified (for InptPrsrTypeCheck rtn)  */
  90. /* All the parameters to the following dispatched functions are passed by    */
  91. /* address. There is a problem in TurboC (ANSI C?) that all the real types   */
  92. /* are passed as double, even if the are float. As RealType may be float,    */
  93. /* the problems is hidden by passing parameters by address...             */
  94. ObjFuncTableType ObjFuncTable[] = {
  95.     { "VECTOR",    VECTOR,    GenVecObject,    3,
  96.             { NUMERIC_OBJ,   NUMERIC_OBJ,   NUMERIC_OBJ  } },
  97.     { "ROTX",    ROTX,    GenMatObjectRotX,    1,    { NUMERIC_OBJ } },
  98.     { "ROTY",    ROTY,    GenMatObjectRotY,    1,      { NUMERIC_OBJ } },
  99.     { "ROTZ",    ROTZ,    GenMatObjectRotZ,    1,    { NUMERIC_OBJ } },
  100.     { "TRANS",    TRANS,    GenMatObjectTrans,    1,    { VECTOR_OBJ } },
  101.     { "SCALE",    SCALE,    GenMatObjectScale,    1,    { VECTOR_OBJ } },
  102.     { "BOX",    BOX,    GenBOXObject,        4,
  103.             { VECTOR_OBJ,  NUMERIC_OBJ,  NUMERIC_OBJ,  NUMERIC_OBJ  } },
  104.     { "GBOX",    GBOX,    GenGBOXObject,        4,
  105.             { VECTOR_OBJ,  VECTOR_OBJ,   VECTOR_OBJ,   VECTOR_OBJ  } },
  106.     { "CONE",    CONE,    GenCONEObject,        3,
  107.             { VECTOR_OBJ,  VECTOR_OBJ,   NUMERIC_OBJ  } },
  108.     { "CYLIN",    CYLIN,    GenCYLINObject,        3,
  109.             { VECTOR_OBJ,  VECTOR_OBJ,   NUMERIC_OBJ  } },
  110.     { "SPHERE",    SPHERE,    GenSPHEREObject,    2,
  111.             { VECTOR_OBJ,  NUMERIC_OBJ  } },
  112.     { "TORUS",    TORUS,    GenTORUSObject,        4,
  113.             { VECTOR_OBJ,  VECTOR_OBJ,   NUMERIC_OBJ,  NUMERIC_OBJ  } },
  114.     { "PLANE",    PLANE,    GenPLANEObject,        3,
  115.             { VECTOR_OBJ,  VECTOR_OBJ,   NUMERIC_OBJ  } },
  116.     { "POLY",    POLY,    GenPOLYObject,        1, { OBJ_LIST_OBJ } },
  117.     { "CROSSEC", CROSSEC, GenCROSSECObject,    1, { ANY_OBJ } },
  118.     { "SURFREV", SURFREV, GenSURFREVObject,    1, { GEOMETRIC_OBJ } },
  119.     { "EXTRUDE", EXTRUDE, GenEXTRUDEObject,    2,
  120.             { GEOMETRIC_OBJ, VECTOR_OBJ } },
  121.     { "LIST",    LIST,    GenObjectList,        ANY_PARAM_NUM },
  122.     { "LOAD",   LOAD,   DataPrsrGetObject,    1, { STRING_OBJ } },
  123.     { "CONVEX",    CONVEX, ConvexPolyObjectN,    1, { GEOMETRIC_OBJ } },
  124. };
  125. int ObjFuncTableSize = sizeof(ObjFuncTable) / sizeof(ObjFuncTableType);
  126.  
  127. /* Although the type of parameters is specified (for InptPrsrTypeCheck rtn). */
  128. GenFuncTableType GenFuncTable[] = {
  129.     { "EXIT",    EXIT,    MyExit,        0, },
  130.     { "VIEW",    VIEW,    WndwViewGeomObject, 2,    { OBJ_LIST_OBJ,    NUMERIC_OBJ } },
  131.     { "DIR",    DIR,    DosPrintDir,    1,    { STRING_OBJ } },
  132.     { "CHDIR",    CHDIR,    DosChangeDir,    1,    { STRING_OBJ } },
  133.     { "NORMAL",    NORMAL,    ViewSetNormals,    3,
  134.                 { NUMERIC_OBJ,    NUMERIC_OBJ, NUMERIC_OBJ } },
  135.     { "INCLUDE", INCLUDE, FileInclude,    1,    { STRING_OBJ } },
  136.     { "GDUMP",    GDUMP,    DataPrsrPutObject,  2,    { STRING_OBJ, GEOMETRIC_OBJ } },
  137.     { "MDUMP",    MDUMP,    DataPrsrPutObject,  2,    { STRING_OBJ, MATRIX_OBJ } },
  138.     { "FREE",    FREEOBJ, FreeObject,    1,    { ANY_OBJ } },
  139.     { "INTERACT", INTERACT, InteractGeomObject, 2,    { OBJ_LIST_OBJ, NUMERIC_OBJ } },
  140.     { "PAUSE",    PAUSE,    WndwPause,    1,    { NUMERIC_OBJ } },
  141.     { "IF",    IFCOND, IfCondition,    4,
  142.         { NUMERIC_OBJ,    STRING_OBJ,    NUMERIC_OBJ, ANY_OBJ } },
  143.     { "FOR",    FORLOOP, ForLoop,    4,
  144.         { NUMERIC_OBJ,    NUMERIC_OBJ,    NUMERIC_OBJ, ANY_OBJ } },
  145.     { "HELP",    PRHELP,    PrintHelp,    1,    { STRING_OBJ } },
  146.     { "VARLIST", VARLIST, PrintObjectList,    0, },
  147.     { "ALIAS",    ALIAS,    AliasEdit,    2,    { STRING_OBJ, STRING_OBJ } },
  148.     { "BEEP",    BEEP,   GGTone,        2,    { NUMERIC_OBJ, NUMERIC_OBJ } },
  149.     { "EDIT",    EDIT,    DosEditFile,    1,    { STRING_OBJ } },
  150.     { "SYSTEM",    SYSTEM,    DosSystem,    0, },
  151.     { "LOGFILE", LOGFILE, WndwLogPrint,    1,    { NUMERIC_OBJ } },
  152.     { "COLOR",    COLOR,    SetGeomObjectColor, 2,    { GEOMETRIC_OBJ, NUMERIC_OBJ } },
  153. };
  154. int GenFuncTableSize = sizeof(GenFuncTable) / sizeof(GenFuncTableType);
  155.  
  156. ConstantTableType ConstantTable[] = {
  157.     { "PI",    M_PI },
  158.  
  159.     { "ON",    1.0 },
  160.     { "TRUE",    1.0 },
  161.     { "OFF",    0.0 },
  162.     { "FALSE",    0.0 },
  163.  
  164.     { "BLACK",  (double) BLACK },
  165.     { "BLUE",    (double) BLUE },
  166.     { "GREEN",    (double) GREEN },
  167.     { "CYAN",    (double) CYAN },
  168.     { "RED",    (double) RED },
  169.     { "MAGENTA", (double) MAGENTA },
  170.     { "YELLOW", (double) YELLOW },
  171.     { "WHITE",  (double) WHITE },
  172. };
  173. int ConstantTableSize = sizeof(ConstantTable) / sizeof(ConstantTableType);
  174.  
  175. /*****************************************************************************
  176. *   Routine to do type checking to the given tree - return type if found one *
  177. * or returns ERROR_EXPR if error in types was detected.                 *
  178. *****************************************************************************/
  179. int InptPrsrTypeCheck(ParseTree *Root, int Level)
  180. {
  181.     int Right, Left, Result;
  182.  
  183.     if (Level == 0 &&
  184.     Root->NodeKind != PARAMETER &&        /* What is allowed on top level. */
  185.     Root->NodeKind != EQUAL &&
  186.     !IS_GEN_PROCEDURE(Root->NodeKind)) {
  187.     IPGlblEvalError = IE_ERR_NoAssignment;
  188.     strcpy(IPGlblCharData, "");
  189.     return ERROR_EXPR;
  190.     }
  191.  
  192.     switch(Root->NodeKind) {
  193.     case ARCSIN:               /* Functions which returns Real Type: */
  194.     case ARCCOS:
  195.     case ARCTAN:
  196.     case ARCTAN2:
  197.     case COS:
  198.     case EXP:
  199.     case FABS:
  200.     case LN:
  201.     case LOG:
  202.     case SIN:
  203.     case SQRT:
  204.     case TAN:
  205.     case CPOLY:
  206.     case AREA:
  207.     case VOLUME:
  208.     case TIME:
  209.         if (FuncParamMismatch(Root)) return ERROR_EXPR;
  210.         return NUMERIC_EXPR;
  211.     case VECTOR:          /* Object functions which returns Vector Type: */
  212.         if (FuncParamMismatch(Root)) return ERROR_EXPR;
  213.         return VECTOR_EXPR;
  214.     case ROTX:
  215.     case ROTY:
  216.     case ROTZ:
  217.     case TRANS:
  218.     case SCALE:
  219.         if (FuncParamMismatch(Root)) return ERROR_EXPR;
  220.         return MATRIX_EXPR;
  221.     case BOX:
  222.     case GBOX:
  223.     case CONE:
  224.     case CYLIN:
  225.     case SPHERE:
  226.     case TORUS:
  227.     case PLANE:
  228.     case POLY:
  229.     case CROSSEC:
  230.     case SURFREV:
  231.     case EXTRUDE:
  232.     case LOAD:
  233.     case CONVEX:
  234.         if (FuncParamMismatch(Root)) return ERROR_EXPR;
  235.         return GEOMETRIC_EXPR;
  236.     case LIST:
  237.         if (FuncParamMismatch(Root)) return ERROR_EXPR;
  238.         return OBJ_LIST_EXPR;
  239.     case EXIT:
  240.     case SYSTEM:
  241.     case VARLIST:
  242.         if (Level == 0) return NON_EXPR;
  243.         else {
  244.         IPGlblEvalError = IE_ERR_TypeMismatch;
  245.                 UpdateCharError("Procedure ", Root->NodeKind);
  246.         return ERROR_EXPR;
  247.         }
  248.     case VIEW:
  249.         case DIR:
  250.     case CHDIR:
  251.     case NORMAL:
  252.     case INCLUDE:
  253.     case GDUMP:
  254.     case MDUMP:
  255.     case FREEOBJ:
  256.     case INTERACT:
  257.     case IFCOND:
  258.     case FORLOOP:
  259.     case PRHELP:
  260.     case PAUSE:
  261.     case ALIAS:
  262.     case BEEP:
  263.     case EDIT:
  264.     case LOGFILE:
  265.     case COLOR:
  266.         if (Level == 0) {
  267.         if (FuncParamMismatch(Root)) return ERROR_EXPR;
  268.         return NON_EXPR;
  269.         }
  270.         else {
  271.         IPGlblEvalError = IE_ERR_TypeMismatch;
  272.                 UpdateCharError("Procedure ", Root->NodeKind);
  273.         return ERROR_EXPR;
  274.         }
  275.     case PLUS:
  276.     case MINUS:
  277.     case MULT:
  278.     case DIV:
  279.     case POWER:
  280.         Right = InptPrsrTypeCheck(Root->Right, Level+1);
  281.         Left  = InptPrsrTypeCheck(Root->Left,  Level+1);
  282.         if (Right == ERROR_EXPR || Left == ERROR_EXPR) return ERROR_EXPR;
  283.         if (!OverLoadTypeCheck(Root->NodeKind, Right, Left, &Result)) {
  284.         IPGlblEvalError = IE_ERR_TypeMismatch;
  285.                 UpdateCharError("Operator ", Root->NodeKind);
  286.         return ERROR_EXPR;
  287.         }
  288.         else return Result;
  289.     case UNARMINUS:
  290.         if ((Right = InptPrsrTypeCheck(Root->Right, Level+1)) == ERROR_EXPR)
  291.         return ERROR_EXPR;
  292.         else if (!OverLoadTypeCheck(Root->NodeKind, Right, 0, &Result)) {
  293.         IPGlblEvalError = IE_ERR_TypeMismatch;
  294.                 UpdateCharError("Operator ", Root->NodeKind);
  295.         return ERROR_EXPR;
  296.         }
  297.         else return Result;
  298.     case EQUAL:
  299.         if ((Right = InptPrsrTypeCheck(Root->Right, Level+1)) == ERROR_EXPR)
  300.         return ERROR_EXPR;
  301.         if (Root->Left->NodeKind != PARAMETER) {
  302.         IPGlblEvalError = IE_ERR_AssignLeftOp;
  303.         InptPrsrPrintTree(Root->Left, IPGlblCharData);
  304.         return ERROR_EXPR;
  305.         }
  306.         return Right;
  307.     case NUMBER:
  308.         return NUMERIC_EXPR;
  309.     case PARAMETER:
  310.         if (IS_GEOM_OBJ(Root->U.PObj)) return GEOMETRIC_EXPR;
  311.         else
  312.         if (IS_NUM_OBJ(Root->U.PObj)) return NUMERIC_EXPR;
  313.         else
  314.         if (IS_VEC_OBJ(Root->U.PObj)) return VECTOR_EXPR;
  315.         else
  316.         if (IS_MAT_OBJ(Root->U.PObj)) return MATRIX_EXPR;
  317.         else
  318.         if (IS_STR_OBJ(Root->U.PObj)) return STRING_EXPR;
  319.         else
  320.         if (IS_OLST_OBJ(Root->U.PObj)) return OBJ_LIST_EXPR;
  321.         else
  322.         if (IS_UNDEF_OBJ(Root->U.PObj)) {
  323.         IPGlblEvalError = IE_ERR_UndefObject;
  324.         strcpy(IPGlblCharData, Root->U.PObj->Name);
  325.         return ERROR_EXPR;
  326.         }
  327.         IPGlblEvalError = IE_ERR_FatalError;
  328.         sprintf(IPGlblCharData, "Object = %s, Type %d",
  329.                 Root->U.PObj->Name, Root->U.PObj->ObjType);
  330.         return ERROR_EXPR;
  331.     case STRING:
  332.         return STRING_EXPR;
  333.     default:                     /* Should never happen. */
  334.         IPGlblEvalError = IE_ERR_FatalError;
  335.             UpdateCharError("Token ", Root->NodeKind);
  336.         return ERROR_EXPR;
  337.     }
  338. }
  339.  
  340. /*****************************************************************************
  341. *   Routine to evaluate    a value    of a given tree    root and parameter.         *
  342. * Note we change the tree itself during the evaluation process.             *
  343. * Also note we assume the tree is type checked (via InptPrsrTypeCheck rtn).  *
  344. *****************************************************************************/
  345. struct ParseTree *InptPrsrEvalTree(ParseTree *Root, int Level)
  346. {
  347.     char *ErrorMsg;
  348.     struct ParseTree *TempL, *TempR, *Temp1, *Temp2, *Temp3, *Temp4;
  349.     struct PolygonStruct *PPoly;
  350.  
  351.     switch(Root->NodeKind) {
  352.     case ARCSIN:       /* Real return functions with one real parameter. */
  353.     case ARCCOS:
  354.     case ARCTAN:
  355.     case COS:
  356.     case EXP:
  357.     case FABS:
  358.     case LN:
  359.     case LOG:
  360.     case SIN:
  361.     case SQRT:
  362.     case TAN:
  363.     case TIME:
  364.         if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
  365.         return NULL;
  366.         Root->ObjType = NUMERIC_OBJ;
  367.         /* Use table entries to call the function directly. */
  368.         Root->U.R = (NumFuncTable[Root->NodeKind-NUM_FUNC_OFFSET].Func)
  369.                                 (TempR->U.R);
  370.         if (RetrieveMathError()) return NULL;
  371.         return Root;
  372.  
  373.     case CPOLY:
  374.     case AREA:
  375.     case VOLUME:
  376.         if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
  377.         return NULL;
  378.         Root->ObjType = NUMERIC_OBJ;
  379.         /* Use table entries to call the function directly. */
  380.         Root->U.R = (NumFuncTable[Root->NodeKind-NUM_FUNC_OFFSET].Func)
  381.                             (TempR->U.PObj);
  382.         if (RetrieveMathError()) return NULL;
  383.         return Root;
  384.  
  385.     case ARCTAN2:      /* Real return functions with two real parameters. */
  386.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 2),
  387.                             Level+1)) == NULL ||
  388.             (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 2),
  389.                             Level+1)) == NULL)
  390.         return NULL;
  391.         Root->ObjType = NUMERIC_OBJ;
  392.         /* Use table entries to call the function directly. */
  393.         Root->U.R = (NumFuncTable[Root->NodeKind-NUM_FUNC_OFFSET].Func)
  394.                               (Temp1->U.R, Temp2->U.R);
  395.         if (RetrieveMathError()) return NULL;
  396.         return Root;
  397.  
  398.     case VECTOR:  /* Object return functions with three real parameters. */
  399.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 3),
  400.                             Level+1)) == NULL ||
  401.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 3),
  402.                             Level+1)) == NULL ||
  403.         (Temp3 = InptPrsrEvalTree(FetchParameter(Root->Right, 2, 3),
  404.                             Level+1)) == NULL)
  405.         return NULL;
  406.         Root->ObjType = VECTOR_OBJ;
  407.         /* Use table entries to call the function directly. */
  408.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  409.         ("", &Temp1->U.R, &Temp2->U.R, &Temp3->U.R,
  410.                             (ObjectStruct *) NULL);
  411.         return Root;
  412.  
  413.     case ROTX:
  414.     case ROTY:
  415.     case ROTZ:
  416.         if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
  417.         return NULL;
  418.         Root->ObjType = MATRIX_OBJ;
  419.         /* Use table entries to call the function directly. */
  420.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  421.                                 (&TempR->U.R);
  422.         if (RetrieveMathError()) return NULL;
  423.         return Root;
  424.  
  425.     case TRANS:
  426.     case SCALE:
  427.         if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
  428.         return NULL;
  429.         Root->ObjType = MATRIX_OBJ;
  430.         /* Use table entries to call the function directly. */
  431.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  432.                             (TempR->U.PObj->U.Vec);
  433.         if (RetrieveMathError()) return NULL;
  434.         return Root;
  435.  
  436.     case BOX:
  437.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 4),
  438.                             Level+1)) == NULL ||
  439.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 4),
  440.                             Level+1)) == NULL ||
  441.         (Temp3 = InptPrsrEvalTree(FetchParameter(Root->Right, 2, 4),
  442.                             Level+1)) == NULL ||
  443.         (Temp4 = InptPrsrEvalTree(FetchParameter(Root->Right, 3, 4),
  444.                             Level+1)) == NULL)
  445.         return NULL;
  446.         Root->ObjType = GEOMETRIC_OBJ;
  447.  
  448.         /* Use table entries to call the function directly. */
  449.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  450.         (Temp1->U.PObj->U.Vec, &Temp2->U.R, &Temp3->U.R, &Temp4->U.R);
  451.         return Root;
  452.  
  453.     case GBOX:
  454.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 4),
  455.                             Level+1)) == NULL ||
  456.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 4),
  457.                             Level+1)) == NULL ||
  458.         (Temp3 = InptPrsrEvalTree(FetchParameter(Root->Right, 2, 4),
  459.                             Level+1)) == NULL ||
  460.         (Temp4 = InptPrsrEvalTree(FetchParameter(Root->Right, 3, 4),
  461.                             Level+1)) == NULL)
  462.         return NULL;
  463.         Root->ObjType = GEOMETRIC_OBJ;
  464.         /* Use table entries to call the function directly. */
  465.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  466.         (Temp1->U.PObj->U.Vec, Temp2->U.PObj ->U.Vec,
  467.          Temp3->U.PObj->U.Vec, Temp4->U.PObj ->U.Vec);
  468.         return Root;
  469.  
  470.     case CONE:
  471.     case CYLIN:
  472.     case PLANE:
  473.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 3),
  474.                             Level+1)) == NULL ||
  475.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 3),
  476.                             Level+1)) == NULL ||
  477.         (Temp3 = InptPrsrEvalTree(FetchParameter(Root->Right, 2, 3),
  478.                             Level+1)) == NULL)
  479.         return NULL;
  480.         Root->ObjType = GEOMETRIC_OBJ;
  481.         /* Use table entries to call the function directly. */
  482.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  483.         (Temp1->U.PObj->U.Vec, Temp2->U.PObj->U.Vec, &Temp3->U.R);
  484.         return Root;
  485.  
  486.     case SPHERE:
  487.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 2),
  488.                             Level+1)) == NULL ||
  489.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 2),
  490.                             Level+1)) == NULL)
  491.         return NULL;
  492.         Root->ObjType = GEOMETRIC_OBJ;
  493.         /* Use table entries to call the function directly. */
  494.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  495.         (Temp1->U.PObj->U.Vec, &Temp2->U.R);
  496.         return Root;
  497.  
  498.     case TORUS:
  499.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 4),
  500.                             Level+1)) == NULL ||
  501.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 4),
  502.                             Level+1)) == NULL ||
  503.         (Temp3 = InptPrsrEvalTree(FetchParameter(Root->Right, 2, 4),
  504.                             Level+1)) == NULL ||
  505.         (Temp4 = InptPrsrEvalTree(FetchParameter(Root->Right, 3, 4),
  506.                             Level+1)) == NULL)
  507.         return NULL;
  508.         Root->ObjType = GEOMETRIC_OBJ;
  509.         /* Use table entries to call the function directly. */
  510.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  511.         (Temp1->U.PObj->U.Vec, Temp2->U.PObj->U.Vec,
  512.          &Temp3->U.R, &Temp4->U.R);
  513.         return Root;
  514.  
  515.     case POLY:
  516.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 1),
  517.                             Level+1)) == NULL)
  518.         return NULL;
  519.         Root->ObjType = GEOMETRIC_OBJ;
  520.         /* Use table entries to call the function directly. */
  521.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  522.         (Temp1->U.PObj);
  523.         if (Root->U.PObj == NULL) return NULL;
  524.         return Root;
  525.  
  526.     case CROSSEC:
  527.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 1),
  528.                             Level+1)) == NULL)
  529.         return NULL;
  530.         Root->ObjType = GEOMETRIC_OBJ;
  531.         /* Use table entries to call the function directly. */
  532.         if (IS_GEOM_OBJ(Temp1 -> U.PObj))
  533.         Root->U.PObj =
  534.             (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  535.             (Temp1->U.PObj);
  536.         else
  537.         Root->U.PObj =
  538.             (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  539.             ((ObjectStruct *) NULL);
  540.         if (Root->U.PObj == NULL) return NULL;
  541.         return Root;
  542.  
  543.     case EXTRUDE:
  544.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 2),
  545.                             Level+1)) == NULL ||
  546.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 2),
  547.                             Level+1)) == NULL)
  548.         return NULL;
  549.         Root->ObjType = GEOMETRIC_OBJ;
  550.         /* Use table entries to call the function directly. */
  551.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  552.         (Temp1->U.PObj, Temp2->U.PObj->U.Vec);
  553.         if (Root->U.PObj == NULL) return NULL;
  554.         return Root;
  555.  
  556.     case SURFREV:
  557.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 1),
  558.                             Level+1)) == NULL)
  559.         return NULL;
  560.         Root->ObjType = GEOMETRIC_OBJ;
  561.         /* Use table entries to call the function directly. */
  562.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  563.         (Temp1->U.PObj);
  564.         if (Root->U.PObj == NULL) return NULL;
  565.         return Root;
  566.  
  567.     case LOAD:
  568.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 1),
  569.                             Level+1)) == NULL)
  570.         return NULL;
  571.         /* Use table entries to call the function directly. */
  572.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  573.         (Temp1->U.PObj->U.Str, "");
  574.         if (Root->U.PObj == NULL) {
  575.             DataPrsrParseError(&ErrorMsg);
  576.         IPGlblEvalError = IE_ERR_DataPrsrError;
  577.         strcpy(IPGlblCharData, ErrorMsg);
  578.         return NULL;
  579.         }
  580.         Root->ObjType = Root -> U.PObj -> ObjType;
  581.         return Root;
  582.  
  583.     case CONVEX:
  584.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 1),
  585.                             Level+1)) == NULL)
  586.         return NULL;
  587.         /* Use table entries to call the function directly. */
  588.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  589.         (Temp1->U.PObj);
  590.         Root->ObjType = Temp1 -> U.PObj -> ObjType;
  591.         return Root;
  592.  
  593.     case LIST:
  594.         Root->ObjType = OBJ_LIST_OBJ;
  595.         /* Use table entries to call the function directly. */
  596.         Root->U.PObj = (ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].Func)
  597.         (Root -> Right);
  598.         if (Root->U.PObj == NULL) return NULL;
  599.         return Root;
  600.  
  601.     case VIEW:
  602.     case INTERACT:
  603.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 2),
  604.                             Level+1)) == NULL ||
  605.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 2),
  606.                             Level+1)) == NULL)
  607.         return NULL;
  608.         Root->ObjType = UNDEF_OBJ;
  609.         /* Use table entries to call the function directly. */
  610.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
  611.                         (Temp1->U.PObj, &Temp2->U.R);
  612.         return Root;
  613.  
  614.     case EXIT:
  615.         /* Yes - we finished for today... */
  616.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)(0);
  617.  
  618.     case PAUSE:
  619.     case LOGFILE:
  620.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 1),
  621.                             Level+1)) == NULL)
  622.         return NULL;
  623.         /* Use table entries to call the function directly. */
  624.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)(&Temp1 -> U.R);
  625.         Root->ObjType = UNDEF_OBJ;
  626.         return Root;
  627.  
  628.     case VARLIST:
  629.     case SYSTEM:
  630.         /* Use table entries to call the function directly. */
  631.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)(GlblObjList);
  632.         Root->ObjType = UNDEF_OBJ;
  633.         return Root;
  634.  
  635.     case DIR:
  636.     case CHDIR:
  637.     case INCLUDE:
  638.     case PRHELP:
  639.     case EDIT:
  640.         if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
  641.         return NULL;
  642.         /* Use table entries to call the function directly. */
  643.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
  644.              (TempR->U.PObj->U.Str);
  645.         Root->ObjType = UNDEF_OBJ;
  646.         return Root;
  647.  
  648.     case GDUMP:
  649.     case MDUMP:
  650.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 2),
  651.                             Level+1)) == NULL ||
  652.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 2),
  653.                             Level+1)) == NULL)
  654.         return NULL;
  655.         Root->ObjType = UNDEF_OBJ;
  656.         /* Use table entries to call the function directly. */
  657.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
  658.                     (Temp1->U.PObj->U.Str, Temp2->U.PObj);
  659.         if (DataPrsrParseError(&ErrorMsg) != 0) {
  660.         IPGlblEvalError = IE_ERR_DataPrsrError;
  661.         strcpy(IPGlblCharData, ErrorMsg);
  662.         return NULL;
  663.         }
  664.         return Root;
  665.  
  666.     case BEEP:
  667.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 2),
  668.                             Level+1)) == NULL ||
  669.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 2),
  670.                             Level+1)) == NULL)
  671.         return NULL;
  672.         Root->ObjType = UNDEF_OBJ;
  673.         /* Use table entries to call the function directly. */
  674.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
  675.                     ((int) Temp1->U.R, (int) Temp2->U.R);
  676.         return Root;
  677.  
  678.     case COLOR:
  679.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 2),
  680.                             Level+1)) == NULL ||
  681.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 2),
  682.                             Level+1)) == NULL)
  683.         return NULL;
  684.         Root->ObjType = UNDEF_OBJ;
  685.         /* Use table entries to call the function directly. */
  686.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
  687.                         (Temp1->U.PObj, &Temp2->U.R);
  688.         return Root;
  689.  
  690.     case ALIAS:
  691.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 2),
  692.                             Level+1)) == NULL ||
  693.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 2),
  694.                             Level+1)) == NULL)
  695.         return NULL;
  696.         Root->ObjType = UNDEF_OBJ;
  697.         /* Use table entries to call the function directly. */
  698.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
  699.                 (Temp1->U.PObj->U.Str, Temp2->U.PObj->U.Str);
  700.         return Root;
  701.  
  702.     case FREEOBJ:
  703.         if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
  704.         return NULL;
  705.         if (TempR->ObjType == NUMERIC_OBJ) {
  706.         IPGlblEvalError = IE_ERR_TypeMismatch;
  707.         strcpy(IPGlblCharData, "Func FREE, parameter 1");
  708.         return Root;
  709.         }
  710.         if (strlen(TempR->U.PObj->Name) == 0) {
  711.         IPGlblEvalError = IE_ERR_FreeSimple;
  712.                 UpdateCharError("Procedure ", FREEOBJ);
  713.         return Root;
  714.         }
  715.         if (TempR->U.PObj->Count > 0) {
  716.         IPGlblEvalError = IE_ERR_FreeNoRefObj;
  717.         strcpy(IPGlblCharData, TempR->U.PObj->Name);
  718.         return Root;
  719.         }
  720.         /* Use table entries to call the function directly. */
  721.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
  722.              (TempR->U.PObj);
  723.         Root->ObjType = UNDEF_OBJ;
  724.         TempR->U.PObj = NULL;        /* Make sure its disconnected... */
  725.         return Root;
  726.  
  727.     case NORMAL:
  728.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 3),
  729.                             Level+1)) == NULL ||
  730.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 3),
  731.                             Level+1)) == NULL ||
  732.         (Temp3 = InptPrsrEvalTree(FetchParameter(Root->Right, 2, 3),
  733.                             Level+1)) == NULL)
  734.         return NULL;
  735.         /* Use table entries to call the function directly. */
  736.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
  737.                 (&Temp1->U.R, &Temp2->U.R, &Temp3->U.R);
  738.         Root->ObjType = UNDEF_OBJ;
  739.         return Root;
  740.  
  741.     case IFCOND:
  742.         if ((Temp1 = InptPrsrEvalTree(FetchParameter(Root->Right, 0, 4),
  743.                             Level+1)) == NULL ||
  744.         (Temp2 = InptPrsrEvalTree(FetchParameter(Root->Right, 1, 4),
  745.                             Level+1)) == NULL ||
  746.         (Temp3 = InptPrsrEvalTree(FetchParameter(Root->Right, 2, 4),
  747.                             Level+1)) == NULL)
  748.         return NULL;
  749.         /* Use table entries to call the function directly. */
  750.         (GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].Func)
  751.             (&Temp1->U.R, Temp2->U.PObj->U.Str, &Temp3->U.R,
  752.                     FetchParameter(Root->Right, 3, 4));
  753.         Root->ObjType = UNDEF_OBJ;
  754.         return Root;
  755.  
  756.     case FORLOOP:
  757.         /* Note we cannt use dispatching in the loop mechanism as we */
  758.         /* transfer the procedure ParseTree structures...         */
  759.         ForLoop(FetchParameter(Root->Right, 0, 4),
  760.             FetchParameter(Root->Right, 1, 4),
  761.             FetchParameter(Root->Right, 2, 4),
  762.             FetchParameter(Root->Right, 3, 4));
  763.  
  764.         Root->ObjType = UNDEF_OBJ;
  765.         return Root;
  766.  
  767.     case PLUS:
  768.     case MINUS:
  769.     case MULT:
  770.     case DIV:
  771.     case POWER:
  772.         Root->ObjType = NUMERIC_OBJ;
  773.         if (((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
  774.          || ((TempL = InptPrsrEvalTree(Root->Left,  Level+1)) == NULL))
  775.         return NULL;
  776.         Temp1 = OverLoadEvalOper(Root, TempR, TempL,
  777.                     &IPGlblEvalError, IPGlblCharData);
  778.         if (RetrieveMathError()) return NULL;
  779.         else return Temp1;
  780.  
  781.     case UNARMINUS:
  782.         Root->ObjType = NUMERIC_OBJ;
  783.         if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
  784.         return NULL;
  785.         Temp1 = OverLoadEvalOper(Root, TempR, NULL,
  786.                     &IPGlblEvalError, IPGlblCharData);
  787.         if (RetrieveMathError()) return NULL;
  788.         else return Temp1;
  789.  
  790.     case NUMBER:
  791.         Root->ObjType = NUMERIC_OBJ;
  792.             return Root;
  793.  
  794.     case PARAMETER:
  795.         if (Level == 0) {          /* If only object - print its content. */
  796.         PrintObject(Root->U.PObj);
  797.         Root->ObjType = Root->U.PObj->ObjType;
  798.         return Root;
  799.         }
  800.         switch(Root->U.PObj->ObjType) {
  801.         case NUMERIC_OBJ:   /* In numeric var case - simply copy it. */
  802.             Root->ObjType = NUMERIC_OBJ;
  803.             Root->U.R = Root->U.PObj->U.R;
  804.             Root->NodeKind = NUMBER; /* Disconnect the var. binding. */
  805.             return Root;
  806.                 case GEOMETRIC_OBJ:
  807.                 case VECTOR_OBJ:
  808.                 case MATRIX_OBJ:
  809.                 case STRING_OBJ:
  810.         case OBJ_LIST_OBJ:
  811.             Root->ObjType = Root->U.PObj->ObjType;
  812.             return Root;
  813.         }
  814.  
  815.     case STRING:
  816.         Root->ObjType = STRING_OBJ;
  817.             return Root;
  818.  
  819.     case EQUAL:
  820.         if ((TempR = InptPrsrEvalTree(Root->Right, Level+1)) == NULL)
  821.         return NULL;
  822.         TempL = Root->Left;
  823.         PPoly = NULL;
  824.         if (IS_UNDEF_OBJ(TempL->U.PObj))          /* Its new object. */
  825.         InsertObject(TempL->U.PObj);       /* Insert to global vars. */
  826.         else
  827.         if (IS_GEOM_OBJ(TempL->U.PObj))    /* If old var. was geometric. */
  828.         PPoly = TempL->U.PObj->U.Pl;
  829.  
  830.         if (IS_GEOM_NODE(TempR) ||
  831.         IS_VEC_NODE(TempR) ||
  832.         IS_MAT_NODE(TempR) ||
  833.         IS_STR_NODE(TempR) ||
  834.         IS_OLST_NODE(TempR)) {
  835.         if (TempL -> U.PObj == TempR -> U.PObj) return TempR;/* A=A. */
  836.         TempL->ObjType = TempR->ObjType;
  837.         CopyObject(TempL->U.PObj, TempR->U.PObj, FALSE);
  838.         }
  839.         else if (IS_NUM_NODE(TempR)) {
  840.         TempL->ObjType = TempL->U.PObj->ObjType = NUMERIC_OBJ;
  841.         TempL->U.PObj->U.R = TempR->U.R;
  842.         }
  843.         if (PPoly != NULL) MyFree((char *) (PPoly), POLYGON_TYPE);
  844.  
  845.         Root->ObjType = UNDEF_OBJ;
  846.         return TempR;
  847.     }
  848.     return NULL;                    /* Makes warning silent. */
  849. }
  850.  
  851. /*****************************************************************************
  852. *   Routine to print help on the given subject HelpHeader.             *
  853. * Note a match is if the HelpHeader in prefix of help file line.         *
  854. *****************************************************************************/
  855. static void PrintHelp(char *HelpHeader)
  856. {
  857.     int    i, Reset = TRUE;
  858.     char *Path, s[LINE_LEN];
  859.     FILE *f;
  860.  
  861.     Path = searchpath(HelpFileName);
  862.  
  863.     if ((f = fopen(Path, "r")) == NULL) {
  864.     sprintf(s, "Cann't open help file %s\n", HelpFileName);
  865.     WndwInputWindowPutStr(s, RED);
  866.     return;
  867.     }
  868.  
  869.     for (i=0; i<strlen(HelpHeader); i++)
  870.     if (islower(HelpHeader[i])) HelpHeader[i] = toupper(HelpHeader[i]);
  871.  
  872.     while (fgets(s, LINE_LEN-1, f) != NULL) {
  873.     for (i=0; i<strlen(HelpHeader); i++)
  874.         if (HelpHeader[i] != s[i]) break;
  875.     if (i >= strlen(HelpHeader)) {          /* Found match - print it. */
  876.         while (fgets(s, LINE_LEN-1, f) != NULL && s[0] != '$') {
  877.         WndwInputWindowPutStrFS(&s[1], GREEN, Reset);/* Skip char 1. */
  878.         Reset = FALSE;
  879.         }
  880.         return;
  881.     }
  882.     }
  883.  
  884.     sprintf(s, "No help on %s\n", HelpHeader);
  885.     WndwInputWindowPutStr(s, RED);
  886. }
  887.  
  888. /*****************************************************************************
  889. *   Routine to execute the IF structure.                     *
  890. *****************************************************************************/
  891. static void IfCondition(RealType *Left, char *Cond, RealType *Right,
  892.                             ParseTree *PBody)
  893. {
  894.     int i, NumOfExpr;
  895.  
  896.     if (strcmp(Cond, "=")  == 0 && (*Left) != (*Right)) return;
  897.     if (strcmp(Cond, "<>") == 0 && (*Left) == (*Right)) return;
  898.     if (strcmp(Cond, "<=") == 0 && (*Left) >  (*Right)) return;
  899.     if (strcmp(Cond, ">=") == 0 && (*Left) <  (*Right)) return;
  900.     if (strcmp(Cond, ">")  == 0 && (*Left) <= (*Right)) return;
  901.     if (strcmp(Cond, "<")  == 0 && (*Left) >= (*Right)) return;
  902.  
  903.     /* If we are here, then the condition holds: */
  904.     for(i=0; i<(NumOfExpr = CountNumExpressions(PBody)); i++) {
  905.     InptPrsrEvalTree(FetchExpression(PBody, i, NumOfExpr), 0);
  906.     if (WasCtrlBrk ||         /* async. break send from the user. */
  907.         IPGlblEvalError) break;
  908.     }
  909. }
  910.  
  911. /*****************************************************************************
  912. *   Routine to execute the FOR structure loop.                     *
  913. *   Note that as InptPrsrEvalTree routine is destructive on its input tree,  *
  914. * we must make a copy of the body before executing it!                 *
  915. *   We wish we could access the loop variable directly, but the user might   *
  916. * be stupid and free it in the loop - so me must access it by name.         *
  917. *****************************************************************************/
  918. static void ForLoop(ParseTree *PStart, ParseTree *PInc,
  919.                    ParseTree *PEnd, ParseTree *PBody)
  920. {
  921.     int i, NumOfExpr, LoopCount;
  922.     char *LoopVarName = NULL;
  923.     RealType LoopVar, StartVal, Increment, EndVal;
  924.     ParseTree *PTemp;
  925.     ObjectStruct *PLoopVar;
  926.  
  927.     /* Find the only two cases where loop variable is allowed - when then */
  928.     /* given starting value is a parameter, or assignment to parameter... */
  929.     if (PStart -> NodeKind == PARAMETER) LoopVarName = PStart -> U.PObj -> Name;
  930.     else
  931.     if (PStart -> NodeKind == EQUAL && PStart -> Left -> NodeKind == PARAMETER)
  932.     LoopVarName = PStart -> Left -> U.PObj -> Name;
  933.     /* Rebind the iteration variable to body - it might be new: */
  934.     RebindVariable(PBody, PStart -> Left -> U.PObj);
  935.  
  936.     PStart = InptPrsrEvalTree(PStart, 1);     /* Evaluate starting value. */
  937.     PInc   = InptPrsrEvalTree(PInc, 1);        /* Evaluate increment value. */
  938.     PEnd   = InptPrsrEvalTree(PEnd, 1);              /* Evaluate end value. */
  939.     if (IPGlblEvalError ||
  940.     PStart == NULL || PInc == NULL || PEnd == NULL) return;
  941.     StartVal = PStart -> U.R;
  942.     Increment = PInc -> U.R;
  943.     EndVal = PEnd -> U.R;
  944.  
  945.     NumOfExpr = CountNumExpressions(PBody);    /* Num. of expr. in the body. */
  946.     for (LoopVar = StartVal, LoopCount = 0;
  947.     (Increment > 0 ? LoopVar <= EndVal : LoopVar >= EndVal);
  948.     LoopVar += Increment, LoopCount++) {
  949.     if (WasCtrlBrk ||         /* Async. break send from the user. */
  950.         IPGlblEvalError || GlblFatalError) return;
  951.     if (LoopVarName != NULL) {
  952.         if ((PLoopVar = GetObject(LoopVarName)) != NULL &&
  953.          IS_NUM_OBJ(PLoopVar))
  954.         PLoopVar -> U.R = LoopVar; /* Update loop var. */
  955.         else {
  956.         IPGlblEvalError = IE_ERR_ModifIterVar;
  957.         strcpy(IPGlblCharData, LoopVarName);
  958.         }
  959.     }
  960.  
  961.     for(i=0; i<NumOfExpr; i++) {
  962.         PTemp = FetchExpression(PBody, i, NumOfExpr);
  963.         if (LoopCount == 0 && InptPrsrTypeCheck(PTemp, 0) == ERROR_EXPR)
  964.         return;
  965.         else {
  966.         if (LoopVar == EndVal) {
  967.             /* Use the original tree. Note we must evaluate the      */
  968.             /* original tree at list once as ObjType's are updated.  */
  969.             InptPrsrEvalTree(PTemp, 0);     /* Eval as its top level... */
  970.         }
  971.         else {
  972.             PTemp = InptPrsrCopyTree(PTemp);
  973.             InptPrsrEvalTree(PTemp, 0);     /* Eval as its top level... */
  974.             InptPrsrFreeTree(PTemp);         /* Not needed any more. */
  975.         }
  976.         }
  977.     }
  978.     }
  979. }
  980.  
  981. /*****************************************************************************
  982. *   Routine to create an OBJECT LIST object out of all parameters.         *
  983. *****************************************************************************/
  984. static struct ObjectStruct *GenObjectList(ParseTree *PObjParams)
  985. {
  986.     int i, NumOfParams;
  987.     struct ParseTree *Param;
  988.     struct ObjectStruct *PObj;
  989.  
  990.     NumOfParams = CountNumParameters(PObjParams);
  991.     if (NumOfParams > MAX_OBJ_LIST) {
  992.     IPGlblEvalError = IE_ERR_ListTooLong;
  993.     return NULL;
  994.     }
  995.  
  996.     PObj = AllocObject("", OBJ_LIST_OBJ, NULL);
  997.  
  998.     for(i=0; i<NumOfParams; i++) {
  999.     Param = FetchParameter(PObjParams, i, NumOfParams);
  1000.     if (Param -> NodeKind != PARAMETER) {
  1001.         IPGlblEvalError = IE_ERR_NonParamInList;
  1002.         MyFree((char *) PObj, OBJECT_TYPE);
  1003.         return NULL;
  1004.     }
  1005.     if (Param -> U.PObj -> ObjType == UNDEF_OBJ) {
  1006.         IPGlblEvalError = IE_ERR_UndefObject;
  1007.         strcpy(IPGlblCharData, Param -> U.PObj -> Name);
  1008.         MyFree((char *) PObj, OBJECT_TYPE);
  1009.         return NULL;
  1010.     }
  1011.     PObj -> U.PObjList[i] = Param -> U.PObj;
  1012.     Param -> U.PObj -> Count++;        /* Increase number of references. */
  1013.     }
  1014.  
  1015.     if (NumOfParams < MAX_OBJ_LIST) PObj -> U.PObjList[NumOfParams] = NULL;
  1016.     return PObj;
  1017. }
  1018.  
  1019. /*****************************************************************************
  1020. *   Routine to count number of expressions seperated by a COLON are given    *
  1021. * in the tree ROOT. This routine is similar to CountNumParameters below.     *
  1022. *****************************************************************************/
  1023. static int CountNumExpressions(ParseTree *Root)
  1024. {
  1025.     int i=1;
  1026.  
  1027.     while (Root->NodeKind == COLON) {
  1028.     i++;
  1029.     Root = Root->Right;
  1030.     }
  1031.     return i;
  1032. }
  1033.  
  1034. /*****************************************************************************
  1035. *   Routine to fetch the i expression out of a tree represent n expressions  *
  1036. * (0 <= i < n) seperated by colonc. Similar to FetchParameter routine below. *
  1037. *****************************************************************************/
  1038. static ParseTree *FetchExpression(ParseTree *Root, int i, int n)
  1039. {
  1040.     int j;
  1041.  
  1042.     for (j=0; j<i; j++) Root = Root->Right;
  1043.  
  1044.     if (i == n-1) return Root;
  1045.     else return Root->Left;
  1046. }
  1047.  
  1048. /*****************************************************************************
  1049. *   Routine to retrieve math error if was one. return TRUE if was error.     *
  1050. *****************************************************************************/
  1051. static int RetrieveMathError(void)
  1052. {
  1053.     int Error;
  1054.     char *FuncName;
  1055.  
  1056. #ifdef __MSDOS__
  1057.     if ((Error = MathError(&FuncName)) != 0) {
  1058.     switch (Error) {
  1059.         case DOMAIN:
  1060.         strcpy(IPGlblCharData, "DOMAIN ");
  1061.         break;
  1062.         case SING:
  1063.         strcpy(IPGlblCharData, "SING ");
  1064.         break;
  1065.         case OVERFLOW:
  1066.         strcpy(IPGlblCharData, "O.F. ");
  1067.         break;
  1068.         case UNDERFLOW:
  1069.         strcpy(IPGlblCharData, "U.F. ");
  1070.         break;
  1071.         case TLOSS:
  1072.         strcpy(IPGlblCharData, "TLOSS ");
  1073.         break;
  1074.         default:
  1075.         strcpy(IPGlblCharData, "Undef. ");
  1076.         break;
  1077.     }
  1078.     strcat(IPGlblCharData, "error - func. ");
  1079.     strcat(IPGlblCharData, FuncName);
  1080.     IPGlblEvalError = IE_ERR_FPError;
  1081.     return TRUE;
  1082.     }
  1083. #endif /* __MSDOS__ */
  1084.  
  1085.     return FALSE;
  1086. }
  1087.  
  1088. /*****************************************************************************
  1089. *   Routine to count number of paramters where given: parameters are defined *
  1090. * as subtrees seperated by commas, i.e.: the infix form 1, 2, 3, 4 is          *
  1091. * represented as [1, [2, [3, 4]]] in the tree supplied to this function and  *
  1092. * 4 (number of parameters) is returned.                         *
  1093. *****************************************************************************/
  1094. static int CountNumParameters(ParseTree *Root)
  1095. {
  1096.     int i=1;
  1097.  
  1098.     while (Root->NodeKind == COMMA) {
  1099.     i++;
  1100.     Root = Root->Right;
  1101.     }
  1102.     return i;
  1103. }
  1104.  
  1105. /*****************************************************************************
  1106. *   Routine to fetch the i paramter out of a tree represent n parameters     *
  1107. * (0 <= i < n). See CountNumParameters for more description of structure.    *
  1108. * Note it is assumed the tree HAS n parameters and 0<=i<n (No input error).  *
  1109. *****************************************************************************/
  1110. static ParseTree *FetchParameter(ParseTree *Root, int i, int n)
  1111. {
  1112.     int j;
  1113.  
  1114.     for (j=0; j<i; j++) Root = Root->Right;
  1115.  
  1116.     if (i == n-1) return Root;
  1117.     else return Root->Left;
  1118. }
  1119.  
  1120. /*****************************************************************************
  1121. *   Routine to test number of parameters and type of them against was is     *
  1122. * defined in its global tables Num/Obj/GenFuncTable. return TRUE if mismatch *
  1123. * was detected:                                     *
  1124. *****************************************************************************/
  1125. static int FuncParamMismatch(ParseTree *Root)
  1126. {
  1127.     int FuncOffset, Count, i;
  1128.  
  1129.     switch(Root->NodeKind) {
  1130.     case ARCSIN:               /* Numeric (real returned) functions. */
  1131.     case ARCCOS:
  1132.     case ARCTAN:
  1133.     case ARCTAN2:
  1134.     case COS:
  1135.     case EXP:
  1136.     case FABS:
  1137.     case LN:
  1138.     case LOG:
  1139.     case SIN:
  1140.     case SQRT:
  1141.     case TAN:
  1142.  
  1143.     case CPOLY:
  1144.     case AREA:
  1145.     case VOLUME:
  1146.     case TIME:
  1147.         FuncOffset = Root->NodeKind-NUM_FUNC_OFFSET;
  1148.         if (NumFuncTable[FuncOffset].NumOfParam == ANY_PARAM_NUM)
  1149.         return FALSE;
  1150.         /* See if number of parameters is ok: */
  1151.         if ((Count = CountNumParameters(Root->Right)) !=
  1152.         NumFuncTable[FuncOffset].NumOfParam) {
  1153.         IPGlblEvalError = IE_ERR_NumPrmMismatch;
  1154.         sprintf(IPGlblCharData, "Func %s - %d expected, %d found",
  1155.             NumFuncTable[FuncOffset].FuncName,
  1156.             NumFuncTable[FuncOffset].NumOfParam,
  1157.             Count);
  1158.         return TRUE;
  1159.         }
  1160.         /* See if type of parameters is consistent: */
  1161.         for (i=0; i<Count; i++) {
  1162.         if (NumFuncTable[FuncOffset].ParamObjType[i] == ANY_OBJ)
  1163.             continue;
  1164.         if (NumFuncTable[FuncOffset].ParamObjType[i] !=
  1165.             InptPrsrTypeCheck(FetchParameter(Root->Right, i, Count),
  1166.                                     1)) {
  1167.             IPGlblEvalError = IE_ERR_TypeMismatch;
  1168.             sprintf(IPGlblCharData, "Func %s, parameter %d",
  1169.             NumFuncTable[FuncOffset].FuncName, i+1);
  1170.             return TRUE;
  1171.         }
  1172.         }
  1173.         return FALSE;
  1174.  
  1175.     case VECTOR:                 /* Object (returned) functions. */
  1176.  
  1177.     case ROTX:
  1178.     case ROTY:
  1179.     case ROTZ:
  1180.  
  1181.     case TRANS:
  1182.     case SCALE:
  1183.  
  1184.     case BOX:
  1185.     case GBOX:
  1186.     case CONE:
  1187.     case CYLIN:
  1188.     case SPHERE:
  1189.     case TORUS:
  1190.     case PLANE:
  1191.     case POLY:
  1192.     case CROSSEC:
  1193.     case SURFREV:
  1194.     case EXTRUDE:
  1195.     case LIST:
  1196.     case LOAD:
  1197.     case CONVEX:
  1198.         FuncOffset = Root->NodeKind-OBJ_FUNC_OFFSET;
  1199.         if (ObjFuncTable[FuncOffset].NumOfParam == ANY_PARAM_NUM)
  1200.         return FALSE;
  1201.         /* See if number of parameters is ok: */
  1202.         if ((Count = CountNumParameters(Root->Right)) !=
  1203.         ObjFuncTable[FuncOffset].NumOfParam) {
  1204.         IPGlblEvalError = IE_ERR_NumPrmMismatch;
  1205.         sprintf(IPGlblCharData, "Func %s - %d expected, %d found",
  1206.             ObjFuncTable[FuncOffset].FuncName,
  1207.             ObjFuncTable[FuncOffset].NumOfParam,
  1208.             Count);
  1209.         return TRUE;
  1210.         }
  1211.         /* See if type of parameters is consistent: */
  1212.         for (i=0; i<Count; i++) {
  1213.         if (ObjFuncTable[FuncOffset].ParamObjType[i] == ANY_OBJ)
  1214.             continue;
  1215.         if (ObjFuncTable[FuncOffset].ParamObjType[i] !=
  1216.             InptPrsrTypeCheck(FetchParameter(Root->Right, i, Count),
  1217.                                     1)) {
  1218.             IPGlblEvalError = IE_ERR_TypeMismatch;
  1219.             sprintf(IPGlblCharData, "Func %s, parameter %d",
  1220.             ObjFuncTable[FuncOffset].FuncName, i+1);
  1221.             return TRUE;
  1222.         }
  1223.         }
  1224.         return FALSE;
  1225.  
  1226.     case EXIT:
  1227.     case VIEW:
  1228.     case DIR:
  1229.     case CHDIR:
  1230.     case NORMAL:
  1231.     case INCLUDE:
  1232.     case GDUMP:
  1233.     case MDUMP:
  1234.     case FREEOBJ:
  1235.     case INTERACT:
  1236.     case PAUSE:
  1237.     case IFCOND:
  1238.     case FORLOOP:
  1239.     case PRHELP:
  1240.     case VARLIST:
  1241.     case ALIAS:
  1242.     case BEEP:
  1243.     case EDIT:
  1244.     case LOGFILE:
  1245.     case COLOR:
  1246.         FuncOffset = Root->NodeKind-GEN_FUNC_OFFSET;
  1247.         if (GenFuncTable[FuncOffset].NumOfParam == ANY_PARAM_NUM)
  1248.         return FALSE;
  1249.         /* See if number of parameters is ok: */
  1250.         if ((Count = CountNumParameters(Root->Right)) !=
  1251.         GenFuncTable[FuncOffset].NumOfParam) {
  1252.         IPGlblEvalError = IE_ERR_NumPrmMismatch;
  1253.         sprintf(IPGlblCharData, "Func %s - %d expected, %d found",
  1254.             GenFuncTable[FuncOffset].FuncName,
  1255.             GenFuncTable[FuncOffset].NumOfParam,
  1256.             Count);
  1257.         return TRUE;
  1258.         }
  1259.         /* See if type of parameters is consistent: */
  1260.         for (i=0; i<Count; i++) {
  1261.         if (GenFuncTable[FuncOffset].ParamObjType[i] == ANY_OBJ) continue;
  1262.         if (GenFuncTable[FuncOffset].ParamObjType[i] !=
  1263.             InptPrsrTypeCheck(FetchParameter(Root->Right, i, Count),
  1264.                                     1)) {
  1265.             IPGlblEvalError = IE_ERR_TypeMismatch;
  1266.             sprintf(IPGlblCharData, "Func %s, parameter %d",
  1267.             GenFuncTable[FuncOffset].FuncName, i+1);
  1268.             return TRUE;
  1269.         }
  1270.         }
  1271.         return FALSE;
  1272.     default:
  1273.         IPGlblEvalError = IE_ERR_FatalError;
  1274.         UpdateCharError("Undefined function - ", Root->NodeKind);
  1275.         return TRUE;
  1276.     }
  1277. }
  1278.  
  1279. /*****************************************************************************
  1280. *   Routine to free a tree - release all memory    allocated by it.         *
  1281. *****************************************************************************/
  1282. void InptPrsrFreeTree(ParseTree *Root)
  1283. {
  1284.     char s[LINE_LEN];
  1285.  
  1286.     if (!Root) return;
  1287.  
  1288.     switch (Root -> NodeKind) {
  1289.     case ARCSIN:
  1290.     case ARCCOS:
  1291.     case ARCTAN:
  1292.     case ARCTAN2:
  1293.     case COS:
  1294.     case EXP:
  1295.     case FABS:
  1296.     case LN:
  1297.     case LOG:
  1298.     case SIN:
  1299.     case SQRT:
  1300.     case TAN:
  1301.  
  1302.     case CPOLY:
  1303.     case AREA:
  1304.     case VOLUME:
  1305.     case TIME:
  1306.  
  1307.     case VECTOR:
  1308.  
  1309.     case ROTX:
  1310.     case ROTY:
  1311.     case ROTZ:
  1312.     case TRANS:
  1313.     case SCALE:
  1314.  
  1315.     case BOX:
  1316.     case GBOX:
  1317.     case CONE:
  1318.     case CYLIN:
  1319.     case SPHERE:
  1320.     case TORUS:
  1321.     case PLANE:
  1322.     case POLY:
  1323.     case CROSSEC:
  1324.     case SURFREV:
  1325.     case EXTRUDE:
  1326.     case LIST:
  1327.     case LOAD:
  1328.     case CONVEX:
  1329.  
  1330.     case DIR:
  1331.     case CHDIR:
  1332.     case NORMAL:
  1333.     case INCLUDE:
  1334.     case GDUMP:
  1335.     case MDUMP:
  1336.     case FREEOBJ:
  1337.     case VIEW:
  1338.     case INTERACT:
  1339.     case IFCOND:
  1340.     case FORLOOP:
  1341.     case PRHELP:
  1342.     case PAUSE:
  1343.     case ALIAS:
  1344.     case BEEP:
  1345.     case EDIT:
  1346.     case LOGFILE:
  1347.     case COLOR:
  1348.         InptPrsrFreeTree(Root->Right);
  1349.         if ((Root->ObjType == VECTOR_OBJ ||
  1350.          Root->ObjType == MATRIX_OBJ ||
  1351.          Root->ObjType == GEOMETRIC_OBJ ||
  1352.          Root->ObjType == OBJ_LIST_OBJ) &&
  1353.         strlen(Root->U.PObj->Name) == 0)
  1354.         MyFree((char *) Root->U.PObj, OBJECT_TYPE);/* Its temporary. */
  1355.         MyExprFree(Root);
  1356.         break;
  1357.  
  1358.     case EXIT:
  1359.     case SYSTEM:
  1360.     case VARLIST:
  1361.         MyExprFree(Root);
  1362.         break;
  1363.  
  1364.     case DIV:
  1365.     case MINUS:
  1366.     case MULT:
  1367.     case PLUS:
  1368.     case POWER:
  1369.         InptPrsrFreeTree(Root->Right);
  1370.         InptPrsrFreeTree(Root->Left);
  1371.         if ((Root->ObjType == VECTOR_OBJ ||
  1372.          Root->ObjType == MATRIX_OBJ ||
  1373.          Root->ObjType == GEOMETRIC_OBJ ||
  1374.          Root->ObjType == OBJ_LIST_OBJ) &&
  1375.         strlen(Root->U.PObj->Name) == 0)
  1376.         MyFree((char *) Root->U.PObj, OBJECT_TYPE);/* Its temporary. */
  1377.         MyExprFree(Root);
  1378.         break;
  1379.  
  1380.     case UNARMINUS:
  1381.         InptPrsrFreeTree(Root->Right);
  1382.         if ((Root->ObjType == VECTOR_OBJ ||
  1383.          Root->ObjType == MATRIX_OBJ ||
  1384.          Root->ObjType == GEOMETRIC_OBJ ||
  1385.          Root->ObjType == OBJ_LIST_OBJ) &&
  1386.         strlen(Root->U.PObj->Name) == 0)
  1387.         MyFree((char *) Root->U.PObj, OBJECT_TYPE);/* Its temporary. */
  1388.         MyExprFree(Root);
  1389.         break;
  1390.  
  1391.     case COMMA:
  1392.     case COLON:
  1393.     case EQUAL:
  1394.         InptPrsrFreeTree(Root->Right);
  1395.         InptPrsrFreeTree(Root->Left);
  1396.         MyExprFree(Root);
  1397.         break;
  1398.  
  1399.     case NUMBER:
  1400.         MyExprFree(Root);
  1401.         break;
  1402.  
  1403.     case PARAMETER:
  1404.         if (Root->U.PObj &&
  1405.         (Root->U.PObj->ObjType == UNDEF_OBJ ||/*No assign took place.*/
  1406.          strlen(Root->U.PObj->Name) == 0))       /* Its temporary. */
  1407.         MyFree((char *) Root->U.PObj, OBJECT_TYPE);
  1408.         MyExprFree(Root);
  1409.         break;
  1410.  
  1411.     case STRING:
  1412.         MyFree((char *) Root->U.PObj, OBJECT_TYPE);/* The string object. */
  1413.         MyExprFree(Root);
  1414.         break;
  1415.  
  1416.     case TOKENSTART:
  1417.         MyExprFree(Root);
  1418.         break;
  1419.  
  1420.     case OPENPARA:
  1421.     case CLOSPARA:
  1422.         MyExprFree(Root);
  1423.         break;
  1424.  
  1425.     default:
  1426.         /*   We might free partially build (by InptPrsr) tree when error */
  1427.         /* is detected, and such tree may have nodes with NodeKind>=1000.*/
  1428.         if (Root->NodeKind >= 1000) {
  1429.         MyExprFree(Root);
  1430.         }
  1431.         else {
  1432.         sprintf(s, "%s (%d).\n",
  1433.             "InptPrsrFreeTree: Undefined ParseTree type to free",
  1434.             Root -> NodeKind);
  1435.         FatalError(s);
  1436.         }
  1437.         break;
  1438.     }
  1439. }
  1440.  
  1441. /*****************************************************************************
  1442. *   Routine to print a content of ROOT (using inorder traversal):         *
  1443. * level    holds: 0 for lowest level +/-, 1 for *, /, 2 for ^ operations.         *
  1444. * If *str = NULL print on stderr, else on given    string Str.             *
  1445. *****************************************************************************/
  1446. void InptPrsrPrintTree(ParseTree *Root, char *Str)
  1447. {
  1448.     strcpy(IPGlblCharData, "");               /* Make the string empty. */
  1449.  
  1450.     if (Str == NULL) {
  1451.     strcpy(IPGlblCharData, "");           /* Make the string empty. */
  1452.     LocalPrintTree(Root, 0, IPGlblCharData);       /* Copy to local str. */
  1453.     fprintf(stderr, IPGlblCharData);             /* and print... */
  1454.     }
  1455.     else {
  1456.     strcpy(Str, "");               /* Make the string empty. */
  1457.     LocalPrintTree(Root, 0, Str); /* Dont print to stderr - copy to str. */
  1458.     }
  1459. }
  1460.  
  1461. /*****************************************************************************
  1462. *   Routine to print a content of ROOT (using inorder traversal):         *
  1463. * level    holds: 0 for lowest level +/-, 1 for *, /, 2 for ^ operations.         *
  1464. * It is assumed Str has at list LINE_LEN_LONG places to write the expression.*
  1465. *****************************************************************************/
  1466. static void LocalPrintTree(ParseTree *Root, int Level, char *Str)
  1467. {
  1468.     int    CloseFlag = FALSE, Len;
  1469.  
  1470.     if (!Root) return;
  1471.     if ((Len = strlen(Str)) > LINE_LEN_LONG * 2 / 3)/* Prevent from overflow.*/
  1472.     if (Str[Len-1] == '.') return;   /* "..." was allready concatenated. */
  1473.     else {
  1474.         strcat(Str, "...");
  1475.         return;
  1476.     }
  1477.  
  1478. #   ifdef DEBUG
  1479.     strcat(Str, "[");   /* Usefull to see ALL nestings - no preceedings. */
  1480. #   endif /* DEBUG */
  1481.  
  1482.     switch(Root->NodeKind) {
  1483.     case ARCCOS:
  1484.     case ARCSIN:
  1485.     case ARCTAN:
  1486.     case ARCTAN2:
  1487.     case COS:
  1488.     case EXP:
  1489.     case FABS:
  1490.     case LN:
  1491.     case LOG:
  1492.     case SIN:
  1493.     case SQRT:
  1494.     case TAN:
  1495.  
  1496.     case CPOLY:
  1497.     case AREA:
  1498.     case VOLUME:
  1499.     case TIME:
  1500.         Level = 0;
  1501.         CloseFlag = TRUE;
  1502.             strcat(Str, NumFuncTable[Root->NodeKind-NUM_FUNC_OFFSET].FuncName);
  1503.         strcat(Str, "(");
  1504.         break;
  1505.  
  1506.     case VECTOR:
  1507.  
  1508.     case ROTX:
  1509.     case ROTY:
  1510.     case ROTZ:
  1511.     case TRANS:
  1512.     case SCALE:
  1513.  
  1514.     case BOX:
  1515.     case GBOX:
  1516.     case CONE:
  1517.     case CYLIN:
  1518.     case SPHERE:
  1519.     case TORUS:
  1520.     case PLANE:
  1521.     case POLY:
  1522.     case CROSSEC:
  1523.     case SURFREV:
  1524.     case EXTRUDE:
  1525.     case LIST:
  1526.     case LOAD:
  1527.     case CONVEX:
  1528.         Level = 0;
  1529.         CloseFlag = TRUE;
  1530.             strcat(Str, ObjFuncTable[Root->NodeKind-OBJ_FUNC_OFFSET].FuncName);
  1531.         strcat(Str, "(");
  1532.         break;
  1533.  
  1534.     case VIEW:
  1535.     case DIR:
  1536.     case CHDIR:
  1537.     case NORMAL:
  1538.     case INCLUDE:
  1539.     case GDUMP:
  1540.     case MDUMP:
  1541.     case FREEOBJ:
  1542.     case INTERACT:
  1543.     case IFCOND:
  1544.     case FORLOOP:
  1545.     case PRHELP:
  1546.     case PAUSE:
  1547.     case ALIAS:
  1548.     case BEEP:
  1549.     case EDIT:
  1550.     case LOGFILE:
  1551.     case COLOR:
  1552.         Level = 0;
  1553.         CloseFlag = TRUE;
  1554.             strcat(Str, GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].FuncName);
  1555.         strcat(Str, "(");
  1556.         break;
  1557.  
  1558.     case EXIT:
  1559.     case SYSTEM:
  1560.     case VARLIST:
  1561.             strcat(Str, GenFuncTable[Root->NodeKind-GEN_FUNC_OFFSET].FuncName);
  1562.         strcat(Str, "()");           /* procedures with no parameters. */
  1563.         return;
  1564.  
  1565.     case DIV:
  1566.         if (Level > 1) {
  1567.         strcat(Str, "(");
  1568.             CloseFlag = TRUE;
  1569.         }
  1570.         Level = 1;                           /* Div Level. */
  1571.         LocalPrintTree(Root->Left, Level, Str);
  1572.         strcat(Str, "/");
  1573.         break;
  1574.  
  1575.     case MINUS:
  1576.         if (Level > 0) {
  1577.         strcat(Str, "(");
  1578.             CloseFlag = TRUE;
  1579.         }
  1580.         Level = 0;                         /* Minus Level. */
  1581.         LocalPrintTree(Root->Left, Level, Str);
  1582.         strcat(Str, "-");
  1583.         break;
  1584.  
  1585.     case MULT:
  1586.         if (Level > 1) {
  1587.         strcat(Str, "(");
  1588.             CloseFlag = TRUE;
  1589.         }
  1590.         Level = 1;                           /* Mul Level. */
  1591.         LocalPrintTree(Root->Left, Level, Str);
  1592.         strcat(Str, "*");
  1593.         break;
  1594.  
  1595.     case PLUS:
  1596.         if (Level > 0) {
  1597.         strcat(Str, "(");
  1598.             CloseFlag = TRUE;
  1599.         }
  1600.         Level = 0;                          /* Plus Level. */
  1601.         LocalPrintTree(Root->Left, Level, Str);
  1602.         strcat(Str, "+");
  1603.         break;
  1604.  
  1605.     case POWER:
  1606.         Level = 2;                         /* Power Level. */
  1607.         LocalPrintTree(Root->Left, Level, Str);
  1608.         strcat(Str, "^");
  1609.         break;
  1610.  
  1611.     case UNARMINUS:
  1612.         strcat(Str, "(-");
  1613.         Level = 0;
  1614.         CloseFlag = TRUE;
  1615.         break;
  1616.  
  1617.     case COMMA:
  1618.         LocalPrintTree(Root->Left, Level, Str);
  1619.         strcat(Str, ",");
  1620.         break;
  1621.  
  1622.     case COLON:
  1623.         LocalPrintTree(Root->Left, Level, Str);
  1624.         strcat(Str, ":");
  1625.         break;
  1626.  
  1627.     case EQUAL:
  1628.         LocalPrintTree(Root->Left, Level, Str);
  1629.         strcat(Str, "=");
  1630.         break;
  1631.  
  1632.     case NUMBER:
  1633.         sprintf(&Str[strlen(Str)], "%lg", Root->U.R);
  1634.         break;
  1635.  
  1636.     case PARAMETER:
  1637.         sprintf(&Str[strlen(Str)], "%s", Root->U.PObj->Name);
  1638.         break;
  1639.  
  1640.     case STRING:
  1641.         sprintf(&Str[strlen(Str)], "\"%s\"", Root->U.PObj->U.Str);
  1642.         break;
  1643.  
  1644.     case OPENPARA:
  1645.         strcat(Str, "(");
  1646.         break;
  1647.  
  1648.     case CLOSPARA:
  1649.         strcat(Str, ")");
  1650.         break;
  1651.  
  1652.     case TOKENSTART:
  1653.         break;
  1654.  
  1655.     default:
  1656.         FatalError("LocalPrintTree: Undefined ParseTree type to print, exit");
  1657.     }
  1658.     LocalPrintTree(Root->Right, Level, Str);
  1659.     if (CloseFlag) strcat(Str, ")");
  1660.  
  1661. #   ifdef DEBUG
  1662.     strcat(Str, "]");   /* Usefull to see ALL nestings - no preceedings. */
  1663. #   endif /* DEBUG */
  1664. }
  1665.  
  1666. /*****************************************************************************
  1667. *   Routine to copy a parse tree - Generate brand new ParseTree structure    *
  1668. * but bind to non-temp variables if they are exists - their Name is not NULL *
  1669. *   This means that updating these objects in the copied tree, will affect   *
  1670. * these objects in the original tree.                         *
  1671. *****************************************************************************/
  1672. ParseTree *InptPrsrCopyTree(ParseTree *Root)
  1673. {
  1674.     struct ParseTree *NewRoot;
  1675.  
  1676.     if (Root == NULL) return NULL;
  1677.  
  1678.     NewRoot = MyExprMalloc();
  1679.  
  1680.     switch(Root->NodeKind) {
  1681.     case ARCSIN:
  1682.     case ARCCOS:
  1683.     case ARCTAN:
  1684.     case ARCTAN2:
  1685.     case COS:
  1686.     case EXP:
  1687.     case FABS:
  1688.     case LN:
  1689.     case LOG:
  1690.     case SIN:
  1691.     case SQRT:
  1692.     case TAN:
  1693.     case CPOLY:
  1694.     case AREA:
  1695.     case VOLUME:
  1696.     case TIME:
  1697.  
  1698.     case VECTOR:
  1699.  
  1700.     case ROTX:
  1701.     case ROTY:
  1702.     case ROTZ:
  1703.     case TRANS:
  1704.     case SCALE:
  1705.  
  1706.     case BOX:
  1707.     case GBOX:
  1708.     case CONE:
  1709.     case CYLIN:
  1710.     case SPHERE:
  1711.     case TORUS:
  1712.     case PLANE:
  1713.     case POLY:
  1714.     case CROSSEC:
  1715.     case SURFREV:
  1716.     case EXTRUDE:
  1717.     case LIST:
  1718.     case LOAD:
  1719.     case CONVEX:
  1720.  
  1721.     case VIEW:
  1722.     case DIR:
  1723.     case CHDIR:
  1724.     case NORMAL:
  1725.     case INCLUDE:
  1726.     case GDUMP:
  1727.     case MDUMP:
  1728.     case FREEOBJ:
  1729.     case INTERACT:
  1730.     case IFCOND:
  1731.     case FORLOOP:
  1732.     case PRHELP:
  1733.     case PAUSE:
  1734.     case ALIAS:
  1735.     case BEEP:
  1736.     case EDIT:
  1737.     case LOGFILE:
  1738.     case COLOR:
  1739.  
  1740.     case UNARMINUS:
  1741.         NewRoot -> NodeKind = Root -> NodeKind;
  1742.         NewRoot -> ObjType = Root -> ObjType;
  1743.         NewRoot -> Right = InptPrsrCopyTree(Root -> Right);
  1744.         return NewRoot;
  1745.  
  1746.     case EXIT:
  1747.     case SYSTEM:
  1748.     case VARLIST:
  1749.         NewRoot -> NodeKind = Root -> NodeKind;
  1750.         NewRoot -> ObjType = Root -> ObjType;
  1751.         return NewRoot;
  1752.  
  1753.     case DIV:
  1754.     case MINUS:
  1755.     case MULT:
  1756.     case PLUS:
  1757.     case POWER:
  1758.  
  1759.     case COMMA:
  1760.     case COLON:
  1761.     case EQUAL:
  1762.         NewRoot -> NodeKind = Root -> NodeKind;
  1763.         NewRoot -> ObjType = Root -> ObjType;
  1764.         NewRoot -> Right = InptPrsrCopyTree(Root -> Right);
  1765.         NewRoot -> Left  = InptPrsrCopyTree(Root -> Left);
  1766.         return NewRoot;
  1767.  
  1768.     case NUMBER:
  1769.         NewRoot -> NodeKind = Root -> NodeKind;
  1770.         NewRoot -> ObjType = Root -> ObjType;
  1771.         NewRoot -> U.R = Root -> U.R;
  1772.         return NewRoot;
  1773.  
  1774.     case PARAMETER:
  1775.     case STRING:
  1776.         NewRoot -> NodeKind = Root -> NodeKind;
  1777.         NewRoot -> ObjType = Root -> ObjType;
  1778.         NewRoot -> U.PObj = Root -> U.PObj;        /* Point on SAME object. */
  1779.         return NewRoot;
  1780.  
  1781.     case TOKENSTART:
  1782.         NewRoot -> NodeKind = Root -> NodeKind;
  1783.         NewRoot -> ObjType = Root -> ObjType;
  1784.         return NewRoot;
  1785.  
  1786.     default:
  1787.         FatalError("InptPrsrCopyTree: Undefined ParseTree type to copy, exit\n");
  1788.     }
  1789.     return NULL;                    /* Makes warning silent. */
  1790. }
  1791.  
  1792. /*****************************************************************************
  1793. *  Routine to rebind a variable - given a tree, scan it and update each      *
  1794. * occurance of that variable to point to PObj.                     *
  1795. *****************************************************************************/
  1796. static void RebindVariable(ParseTree *Root, ObjectStruct *PObj)
  1797. {
  1798.     if (Root == NULL) return;
  1799.  
  1800.     switch(Root->NodeKind) {
  1801.     case ARCSIN:
  1802.     case ARCCOS:
  1803.     case ARCTAN:
  1804.     case ARCTAN2:
  1805.     case COS:
  1806.     case EXP:
  1807.     case FABS:
  1808.     case LN:
  1809.     case LOG:
  1810.     case SIN:
  1811.     case SQRT:
  1812.     case TAN:
  1813.     case CPOLY:
  1814.     case AREA:
  1815.     case VOLUME:
  1816.     case TIME:
  1817.  
  1818.     case VECTOR:
  1819.  
  1820.     case ROTX:
  1821.     case ROTY:
  1822.     case ROTZ:
  1823.     case TRANS:
  1824.     case SCALE:
  1825.  
  1826.     case BOX:
  1827.     case GBOX:
  1828.     case CONE:
  1829.     case CYLIN:
  1830.     case SPHERE:
  1831.     case TORUS:
  1832.     case PLANE:
  1833.     case POLY:
  1834.     case CROSSEC:
  1835.     case SURFREV:
  1836.     case EXTRUDE:
  1837.     case LIST:
  1838.     case LOAD:
  1839.     case CONVEX:
  1840.  
  1841.     case VIEW:
  1842.     case DIR:
  1843.     case CHDIR:
  1844.     case NORMAL:
  1845.     case INCLUDE:
  1846.     case GDUMP:
  1847.     case MDUMP:
  1848.     case FREEOBJ:
  1849.     case INTERACT:
  1850.     case IFCOND:
  1851.     case FORLOOP:
  1852.     case PRHELP:
  1853.     case PAUSE:
  1854.     case ALIAS:
  1855.     case BEEP:
  1856.     case EDIT:
  1857.     case LOGFILE:
  1858.     case COLOR:
  1859.  
  1860.     case UNARMINUS:
  1861.         RebindVariable(Root -> Right, PObj);
  1862.         return;
  1863.  
  1864.     case EXIT:
  1865.     case SYSTEM:
  1866.     case VARLIST:
  1867.         return;
  1868.  
  1869.     case DIV:
  1870.     case MINUS:
  1871.     case MULT:
  1872.     case PLUS:
  1873.     case POWER:
  1874.  
  1875.     case COMMA:
  1876.     case COLON:
  1877.     case EQUAL:
  1878.         RebindVariable(Root -> Right, PObj);
  1879.         RebindVariable(Root -> Left, PObj);
  1880.         return;
  1881.  
  1882.     case NUMBER:
  1883.         return;
  1884.  
  1885.     case PARAMETER:
  1886.     case STRING:
  1887.         if (strcmp(Root -> U.PObj -> Name, PObj -> Name) == 0) {
  1888.         /* I wish I cound free that, but nesting loops might try */
  1889.         /* to free the same place n times... We will loose this  */
  1890.         /* variable place if it defined for the first time. Fix  */
  1891.         /* it if you really care...                 */
  1892.         /*
  1893.         if (IS_UNDEF_OBJ(Root -> U.PObj))
  1894.             MyFree((char *) Root->U.PObj, OBJECT_TYPE);
  1895.         */
  1896.         Root -> U.PObj = PObj;
  1897.         }
  1898.             return;
  1899.  
  1900.     case TOKENSTART:
  1901.         return;
  1902.  
  1903.     default:
  1904.         FatalError("RebindVariable: Undefined ParseTree type, exit\n");
  1905.     }
  1906. }
  1907.  
  1908. /*****************************************************************************
  1909. *   Routine to return evaluation error if happen one, zero elsewhere         *
  1910. *****************************************************************************/
  1911. int InptPrsrEvalError(char **Message)
  1912. {
  1913.     int    Temp;
  1914.  
  1915.     *Message = IPGlblCharData;
  1916.     Temp = IPGlblEvalError;
  1917.     IPGlblEvalError = 0;
  1918.     return Temp;
  1919. }
  1920.