home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 460.lha / 3DPlot_v2.0 / sources / funceval3.c < prev    next >
C/C++ Source or Header  |  1991-01-04  |  15KB  |  775 lines

  1. /**********************************************************
  2. *                              *
  3. *  Convert() converts a string containing a math          *
  4. *  function in two variables, X and Y, to a postfix      *
  5. *  notation string with the numeric constants and      *
  6. *  functions converted to one byte symbols.  If any      *
  7. *  syntax errors occur they will be posted in the global  *
  8. *  external variable SyntaxErr.  Definitions are in      *
  9. *  syntxerr.h.                          *
  10. *                              *
  11. *  Evaluate() will substitute the X and Y values passed   *
  12. *  to it and return the value of the function.          *
  13. *                              *
  14. *  This program may be freely used for non-profit      *
  15. *  purposes as long as the copyright notice remains      *
  16. *  in the code.                       *
  17. *                              *
  18. ***********************************************************
  19. *                              *
  20. *          Copyright 1987  Randy C. Finch          *
  21. *                              *
  22. **********************************************************/
  23.  
  24. /*--------------  INCLUDES  ----------------*/
  25.  
  26. #include "common.h"
  27.  
  28.  
  29. /*----------------  DEFINES  -----------------*/
  30.  
  31. #define NUMSYM 128     /* Number of constants allowed in function */
  32. #define SYMBASE 128    /* Base value for constants symbols */
  33. #define STACKSIZE 256  /* Stack size */
  34. #define SIN  1           /* Symbol for sine */
  35. #define COS  2           /* Symbol for cosine */
  36. #define TAN  3           /* Symbol for tangent */
  37. #define ASIN 4           /* Symbol for arcsine */
  38. #define ACOS 5           /* Symbol for arccosine */
  39. #define ATAN 6           /* Symbol for arctangent */
  40. #define SINH 7           /* Symbol for hyperbolic sine */
  41. #define COSH 8           /* Symbol for hyperbolic cosine */
  42. #define TANH 9           /* Symbol for hyperbolic tangent */
  43. #define EXP  10        /* Symbol for exponential */
  44. #define SQRT 11        /* Symbol for square root */
  45. #define LN   12        /* Symbol for natural logarithm */
  46. #define LOG  13        /* Symbol for logarithn base 10 */
  47. #define NULL 0           /* Symbol for null */
  48. #define TRUE 1           /* Symbol for true condition */
  49. #define FALSE 0        /* Symbol for false condition */
  50.  
  51.  
  52. /*------------    EXTERNAL GLOBALS  ------------*/
  53.  
  54. unsigned char SyntaxErr;
  55.  
  56.  
  57. /*----------------  GLOBALS  ----------------*/
  58.  
  59. struct CharStack {
  60.   unsigned char c[STACKSIZE];
  61.   long        top;
  62. };
  63.  
  64. struct NumStack {
  65.   double n[STACKSIZE];
  66.   long     top;
  67. };
  68.  
  69. static struct CharStack cstack;
  70.  
  71. static struct NumStack nstack;
  72.  
  73. static double Constants[NUMSYM];
  74.  
  75. static unsigned char CurConstant;
  76.  
  77. static unsigned char NewExpr[256];
  78.  
  79.  
  80. /*----------------  FUNCTIONS  ----------------*/
  81.  
  82. static char CharInStr(s,c)
  83.   unsigned char *s;
  84.   unsigned char c;
  85. {
  86.   while (*s != NULL) {
  87.      if (*s == c) return TRUE;
  88.      ++s;
  89.   }
  90.   return FALSE;
  91. } /* CharInStr */
  92.  
  93.  
  94. static void Deposit(num)
  95.   double num;
  96. {
  97.   Constants[CurConstant - SYMBASE] = num;
  98. } /* Deposit */
  99.  
  100.  
  101. static void Substitute(symb, ptr, len)
  102.   unsigned char symb;
  103.   unsigned char *ptr;
  104.   unsigned long len;
  105. {
  106.   *ptr = symb;
  107.  
  108.   if (len > 1) {
  109.      do {
  110.     ++ptr;
  111.     *ptr = *(ptr + len - 1);
  112.      } while (*ptr != NULL);
  113.   }
  114. } /* Substitute */
  115.  
  116.  
  117. static void RemoveSpaces(str)
  118.   unsigned char *str;
  119. {
  120.   unsigned char *ptr;
  121.  
  122.   while (*str != NULL) {
  123.      if (*str == ' ') {
  124.     ptr = str;
  125.     do {
  126.        *ptr = *(ptr + 1);
  127.        ++ptr;
  128.     } while ( *(ptr - 1) != NULL);
  129.  
  130.     --str;
  131.      }
  132.  
  133.      ++str;
  134.   }
  135. } /* RemoveSpaces */
  136.  
  137.  
  138. static void AddZero(ptr)
  139.   char *ptr;
  140. {
  141.   unsigned long len;
  142.   char *i;
  143.  
  144.   len = strlen(ptr);
  145.  
  146.   for (i=ptr+len+1; i>ptr; --i)
  147.      *i = *(i - 1);
  148.  
  149.   *ptr = '0';
  150. } /* AddZero */
  151.  
  152.  
  153. static unsigned char CPop()
  154. {
  155.   if (cstack.top == 0) return 0;
  156.   else {
  157.      --cstack.top;
  158.      return cstack.c[cstack.top + 1];
  159.   }
  160. } /* CPop */
  161.  
  162.  
  163. static char CPush(c)
  164.   unsigned char c;
  165. {
  166.   if (cstack.top == STACKSIZE) return FALSE;
  167.   else {
  168.      ++cstack.top;
  169.      cstack.c[cstack.top] = c;
  170.      return TRUE;
  171.   }
  172. } /* CPush */
  173.  
  174.  
  175. static unsigned char CTopOfStack()
  176. {
  177.   return cstack.c[cstack.top];
  178. } /* CTopOfStack */
  179.  
  180.  
  181. static double NPop()
  182. {
  183.   --nstack.top;
  184.   return nstack.n[nstack.top + 1];
  185. } /* NPop */
  186.  
  187.  
  188. static void NPush(n)
  189.   double n;
  190. {
  191.   ++nstack.top;
  192.   nstack.n[nstack.top] = n;
  193. } /* NPush */
  194.  
  195.  
  196. static char IsFunction(c)
  197.   unsigned char c;
  198. {
  199.   if ( (c >= SIN) && (c <= LOG) )
  200.      return TRUE;
  201.   else
  202.      return FALSE;
  203. } /* IsFunction */
  204.  
  205.  
  206. static char IsSymbol(c)
  207.   unsigned char c;
  208. {
  209.   if ((c >= SYMBASE) && (c < SYMBASE+NUMSYM))
  210.      return TRUE;
  211.   else
  212.      return FALSE;
  213. } /* IsSymbol */
  214.  
  215.  
  216. static char Precedence(c1,c2)
  217.   unsigned char c1,c2;
  218. {
  219.   if ( (CharInStr("+-*/",c1)) && (c2 == '^') )
  220.      return FALSE;
  221.  
  222.   else if ( (CharInStr("+-",c1)) && (CharInStr("*/",c2)) )
  223.      return FALSE;
  224.  
  225.   else if ( ((c1 == '(') && (c2 != ')')) || (c2 == '(') )
  226.      return FALSE;
  227.  
  228.   else if ( (CharInStr("+-*/^",c1)) && (IsFunction(c2)) )
  229.      return FALSE;
  230.  
  231.   else
  232.      return TRUE;
  233. } /* Precedence */
  234.  
  235.  
  236. static unsigned char *CheckSyntax(str)
  237.   unsigned char *str;
  238. {
  239.   int numLP = 0,
  240.       numRP = 0;
  241.  
  242.   if ( (CharInStr("/*^E)",*str)) && (strncmp(str,"EXP",3) != 0) ) {
  243.      if (CharInStr("/*^",*str)) {
  244.     SyntaxErr = MISPLACEDOP;
  245.     return str;
  246.      }
  247.      else if (*str == 'E') {
  248.     SyntaxErr = ILLEGALEXP;
  249.     return str;
  250.      }
  251.      else {
  252.     SyntaxErr = MISSINGLP;
  253.     return str;
  254.      }
  255.   } /* if */
  256.  
  257.   for (;;) {   /* forever */
  258.  
  259.      if (*str == '(') {
  260.     ++numLP;
  261.     ++str;
  262.     if ( (CharInStr("*/^E",*str)) && (strncmp(str,"EXP",3) != 0) ) {
  263.        if (*str == 'E') {
  264.           SyntaxErr = ILLEGALEXP;
  265.           return str;
  266.        }
  267.        else {
  268.           SyntaxErr = MISPLACEDOP;
  269.           return str;
  270.        }
  271.     } /* if */
  272.     if ( (*str == ')') || (*str == NULL) ) {
  273.        SyntaxErr = MISSINGPARM;
  274.        return str;
  275.     }
  276.      } /* if */
  277.  
  278.      else if (*str == ')') {
  279.     ++numRP;
  280.     ++str;
  281.     if (numRP > numLP) {
  282.        SyntaxErr = MISSINGLP;
  283.        return (str-1);
  284.     }
  285.     else if ( (!CharInStr(")+-*/^",*str)) && (*str != NULL) ) {
  286.        SyntaxErr = MISSINGOP;
  287.        return str;
  288.     }
  289.      } /* else if */
  290.  
  291.      else if ( (isdigit(*str)) || (*str == '.') ) {
  292.     char ExitFlag = FALSE,
  293.          OneDecimal = FALSE,
  294.          OneE = FALSE;
  295.  
  296.     if (*str == '.') OneDecimal = TRUE;
  297.  
  298.     ++str;
  299.  
  300.     if ( (OneDecimal == TRUE) && (!isdigit(*str)) ) {
  301.        SyntaxErr = LONEDECIMAL;
  302.        return (str - 1);
  303.     }
  304.  
  305.     while ( ( (isdigit(*str)) || (CharInStr(".E)-+",*str))
  306.         || (*str == NULL) ) && !ExitFlag ) {
  307.  
  308.        if (*str == '.') {
  309.           ++str;
  310.           if (OneE) {
  311.          SyntaxErr = ILLEGALEXP;
  312.          return (str-1);
  313.           }
  314.           else if (OneDecimal) {
  315.          SyntaxErr = EXTRADECIMAL;
  316.          return (str-1);
  317.           }
  318.           else if (strncmp(str,"EXP",3) == 0) {
  319.          SyntaxErr = MISSINGOP;
  320.          return str;
  321.           }
  322.           else if ( (!CharInStr("+-*/^E)",*str)) && (!isdigit(*str)) ) {
  323.          SyntaxErr = ILLEGALCHAR;
  324.          return str;
  325.           }
  326.           else {
  327.          OneDecimal = TRUE;
  328.           }
  329.        } /* if */
  330.  
  331.        else if (*str == 'E') {
  332.           ++str;
  333.           if (OneE) {
  334.          SyntaxErr = EXTRAE;
  335.          return (str-1);
  336.           }
  337.           else if ( (!CharInStr("+-",*str)) && (!isdigit(*str)) ) {
  338.          SyntaxErr = ILLEGALEXP;
  339.          return str;
  340.           }
  341.           else {
  342.          OneE = TRUE;
  343.           }
  344.        } /* else if */
  345.  
  346.        else if (CharInStr("+-",*str)) {
  347.           if ( *(str-1) == 'E' )
  348.          ++str;
  349.           else if ( !OneE || (OneE && isdigit(*(str-1))) )
  350.          ExitFlag = TRUE;
  351.           else {
  352.          SyntaxErr = MISPLACEDOP;
  353.          return str;
  354.           }
  355.        } /* else if */
  356.  
  357.        else if ( (*str == ')') || (*str == NULL) ) {
  358.           if (CharInStr("+-E",*(str-1))) {
  359.          SyntaxErr = ILLEGALEXP;
  360.          return str;
  361.           }
  362.           else {
  363.          ExitFlag = TRUE;
  364.           }
  365.        } /* else if */
  366.  
  367.        else {
  368.           ++str;
  369.        } /* else */
  370.  
  371.     } /* while */
  372.  
  373.     if( !CharInStr("+-*/)", *str) && (*str != NULL) ) {
  374.        SyntaxErr = MISSINGOP;
  375.        return str;
  376.     }
  377.  
  378.      } /* else if */
  379.  
  380.      else if (CharInStr("+-*/^",*str)) {
  381.     ++str;
  382.     if ( (CharInStr(")E+-*/^",*str)) || (*str == NULL) ) {
  383.        if (strncmp(str,"EXP",3) != 0) {
  384.           SyntaxErr = MISPLACEDOP;
  385.           return (str-1);
  386.        }
  387.     }
  388.      } /* else if */
  389.  
  390.      else if (CharInStr("XY",*str)) {
  391.     ++str;
  392.     if ( (!CharInStr(")+-*/^",*str)) && (*str != NULL) ) {
  393.        SyntaxErr = MISSINGOPRP;
  394.        return str;
  395.     }
  396.      } /* else if */
  397.  
  398.      else if (isupper(*str)) {
  399.     if (strncmp(str,"LN",2) == 0) str += 2;
  400.     else if (strncmp(str,"SINH",4) == 0) str += 4;
  401.     else if (strncmp(str,"COSH",4) == 0) str += 4;
  402.     else if (strncmp(str,"TANH",4) == 0) str += 4;
  403.     else if (strncmp(str,"SIN",3) == 0) str += 3;
  404.     else if (strncmp(str,"COS",3) == 0) str += 3;
  405.     else if (strncmp(str,"TAN",3) == 0) str += 3;
  406.     else if (strncmp(str,"EXP",3) == 0) str += 3;
  407.     else if (strncmp(str,"LOG",3) == 0) str += 3;
  408.     else if (strncmp(str,"SQRT",4) == 0) str += 4;
  409.     else if (strncmp(str,"ASIN",4) == 0) str += 4;
  410.     else if (strncmp(str,"ACOS",4) == 0) str += 4;
  411.     else if (strncmp(str,"ATAN",4) == 0) str += 4;
  412.     else {
  413.        SyntaxErr = ILLEGALFUNC;
  414.        return str;
  415.     }
  416.  
  417.     if (*str != '(') {
  418.        SyntaxErr = MISSINGLP;
  419.        return str;
  420.     }
  421.      } /* else if */
  422.  
  423.      else if (*str == NULL) {
  424.     if (numLP < numRP) {
  425.        SyntaxErr = MISSINGLP;
  426.        return str;
  427.     }
  428.     else if (numLP > numRP) {
  429.        SyntaxErr = MISSINGRP;
  430.        return str;
  431.     }
  432.     else {
  433.        SyntaxErr = FALSE;
  434.        return 0L;
  435.     }
  436.      } /* else if */
  437.  
  438.      else {
  439.     SyntaxErr = ILLEGALCHAR;
  440.     return str;
  441.      }
  442.  
  443.   } /* for */
  444.  
  445. } /* CheckSyntax */
  446.  
  447.  
  448. static char ConvertConstants(str)
  449.   unsigned char *str;
  450. {
  451.   unsigned char *ptr;
  452.  
  453.   ptr = str;
  454.   if ( CharInStr("+-",*ptr) ) {
  455.      AddZero(str);
  456.      ptr += 2;
  457.   }
  458.  
  459.   while ( *ptr != NULL ) {
  460.      if ( (CharInStr("+-",*ptr)) && (*(ptr-1) == '(') )
  461.     AddZero(ptr);
  462.  
  463.      ++ptr;
  464.  
  465.   } /* while */
  466.  
  467. #if DEBUG
  468.   printf("\nAddZero: %s\n", str);
  469. #endif
  470.  
  471.   {  /* begin block */
  472.   unsigned long j;
  473.   unsigned char numstr[80];
  474.   double number;
  475.  
  476.   ptr = str;
  477.  
  478.   CurConstant = SYMBASE;
  479.  
  480.   while ( *ptr != NULL) {
  481.      if ( (*ptr == '.') || (isdigit(*ptr)) ) {
  482.     unsigned long lennum = 1;
  483.  
  484.     while ( (CharInStr(".E-+",*(ptr+lennum))) || (isdigit(*(ptr+lennum))) ) {
  485.        if( (CharInStr("-+",*(ptr+lennum))) && (*(ptr+lennum-1) != 'E') )
  486.           break;
  487.        ++lennum;
  488.     }
  489.  
  490.     for (j=0; j<lennum; ++j)
  491.        *(numstr+j) = *(ptr+j);
  492.  
  493.     *(numstr+j) = NULL;
  494.  
  495.     number = atof(numstr);
  496.     Deposit(number);
  497.     Substitute(CurConstant, ptr, lennum);
  498.  
  499.     ++CurConstant;
  500.     if (CurConstant >= SYMBASE+NUMSYM) {
  501.        SyntaxErr = TOOMANYCONST;
  502.        return FALSE;
  503.     }
  504.  
  505.      } /* if */
  506.  
  507.      ++ptr;
  508.  
  509.   } /* while */
  510.  
  511.   }  /* end block */
  512.  
  513.   return TRUE;
  514.  
  515. } /* ConvertConstants */
  516.  
  517.  
  518. static void ConvertFunctions(str)
  519.   unsigned char *str;
  520. {
  521.   while ( *str != NULL ) {
  522.      if ( (isupper(*str)) && (!CharInStr("XY",*str)) ) {
  523.  
  524.     if (strncmp(str,"LN",2) == 0) Substitute(LN,str,2L);
  525.     else if (strncmp(str,"SINH",4) == 0) Substitute(SINH,str,4L);
  526.     else if (strncmp(str,"COSH",4) == 0) Substitute(COSH,str,4L);
  527.     else if (strncmp(str,"TANH",4) == 0) Substitute(TANH,str,4L);
  528.     else if (strncmp(str,"SIN",3) == 0) Substitute(SIN,str,3L);
  529.     else if (strncmp(str,"COS",3) == 0) Substitute(COS,str,3L);
  530.     else if (strncmp(str,"TAN",3) == 0) Substitute(TAN,str,3L);
  531.     else if (strncmp(str,"EXP",3) == 0) Substitute(EXP,str,3L);
  532.     else if (strncmp(str,"LOG",3) == 0) Substitute(LOG,str,3L);
  533.     else if (strncmp(str,"SQRT",4) == 0) Substitute(SQRT,str,4L);
  534.     else if (strncmp(str,"ASIN",4) == 0) Substitute(ASIN,str,4L);
  535.     else if (strncmp(str,"ACOS",4) == 0) Substitute(ACOS,str,4L);
  536.     else if (strncmp(str,"ATAN",4) == 0) Substitute(ATAN,str,4L);
  537.  
  538.      } /* if */
  539.  
  540.      ++str;
  541.  
  542.   } /* while */
  543.  
  544. } /* ConvertFunctions */
  545.  
  546.  
  547. static char InfixToPostfix(str)
  548.   unsigned char *str;
  549. {
  550.   unsigned long i1=0, i2=0;
  551.   unsigned char NextChar, TopSymbol;
  552.  
  553.   cstack.top = 0;    /* Initialize stack */
  554.   NewExpr[0] = NULL;    /* Initialize expression */
  555.  
  556.   while ( *(str+i1) != NULL ) {
  557.  
  558.      NextChar = *(str+i1);
  559.  
  560.      if ( (IsSymbol(NextChar)) || (NextChar == 'X') || (NextChar == 'Y') ) {
  561.     NewExpr[i2] = NextChar;
  562.     ++i2;
  563.      }
  564.      else {
  565.     for (;;) {   /* Forever */
  566.  
  567.        if ( (cstack.top == 0) || (!Precedence(CTopOfStack(),NextChar)) )
  568.           break;
  569.  
  570.        if ((TopSymbol = CPop()) == 0) {
  571.           SyntaxErr = STACKUNDERFLOW;
  572.           return FALSE;
  573.        }
  574.  
  575.        if (cstack.top != 0) {
  576.           if ( (IsFunction( CTopOfStack() )) && (NextChar == ')') ) {
  577.          TopSymbol = CPop();
  578.          NewExpr[i2] = TopSymbol;
  579.          ++i2;
  580.          break;
  581.           } /* if */
  582.        } /* if */
  583.  
  584.        if ( (TopSymbol == '(') && (NextChar == ')') )
  585.           break;
  586.  
  587.        if (TopSymbol != '(') {
  588.           NewExpr[i2] = TopSymbol;
  589.           ++i2;
  590.        }
  591.  
  592.     } /* for */
  593.  
  594.     if (NextChar != ')') {
  595.        if (CPush(NextChar) == FALSE) {
  596.           SyntaxErr = STACKOVERFLOW;
  597.           return FALSE;
  598.        }
  599.     }
  600.  
  601.      } /* if */
  602.  
  603.      ++i1;
  604.  
  605.   } /* while */
  606.  
  607.   while (cstack.top != 0) {
  608.      TopSymbol = CPop();
  609.      if (TopSymbol != '(') {
  610.     NewExpr[i2] = TopSymbol;
  611.     ++i2;
  612.      }
  613.   }
  614.  
  615.   NewExpr[i2] = NULL;
  616.  
  617.   return TRUE;
  618.  
  619. } /* InfixToPostfix */
  620.  
  621.  
  622. static double Calculate(s,n2,n1)
  623.   unsigned char s;
  624.   double n1,n2;
  625. {
  626.   switch (s) {
  627.      case '+':
  628.     return (n1 + n2);
  629.      case '-':
  630.     return (n1 - n2);
  631.      case '*':
  632.     return (n1 * n2);
  633.      case '/':
  634.     return (n1 / n2);
  635.      case '^':
  636.     return ( exp(n2*log(n1)) );
  637.      case SIN:
  638.     return ( sin(n2) );
  639.      case COS:
  640.     return ( cos(n2) );
  641.      case TAN:
  642.     return ( tan(n2) );
  643.      case EXP:
  644.     return ( exp(n2) );
  645.      case SQRT:
  646.     return ( sqrt(n2) );
  647.      case LN:
  648.     return ( log(n2) );
  649.      case LOG:
  650.     return ( log10(n2) );
  651.      case ASIN:
  652.     return ( asin(n2) );
  653.      case ACOS:
  654.     return ( acos(n2) );
  655.      case ATAN:
  656.     return ( atan(n2) );
  657.      case SINH:
  658.     return ( sinh(n2) );
  659.      case COSH:
  660.     return ( cosh(n2) );
  661.      case TANH:
  662.     return ( tanh(n2) );
  663.  
  664.   } /* switch */
  665.  
  666. } /* Calculate */
  667.  
  668.  
  669. unsigned char *Convert(FunctionString)
  670.   unsigned char *FunctionString;
  671. {
  672.   unsigned char fstr[512];
  673.   unsigned char *ptr;
  674.  
  675.   SyntaxErr = FALSE;
  676.  
  677.   RemoveSpaces(FunctionString);
  678.  
  679. #if DEBUG
  680.   printf("\nRemoveSpaces: %s\n", FunctionString);
  681. #endif
  682.  
  683.   strupr(FunctionString);
  684.  
  685. #if DEBUG
  686.   printf("\nstrupr: %s\n", FunctionString);
  687. #endif
  688.  
  689.   if ((ptr = CheckSyntax(FunctionString)) != 0) return ptr;
  690.  
  691.   strcpy(fstr,FunctionString);
  692.  
  693. #if DEBUG
  694.   printf("\nCheckSyntax: %s\n", fstr);
  695. #endif
  696.  
  697.   if (!ConvertConstants(fstr)) return fstr;
  698.  
  699. #if DEBUG
  700.   printf("\nConvertConstants: ");
  701.  
  702.   for(ptr = fstr; *ptr != NULL; ++ptr)
  703.      printf("%d ", *ptr);
  704.  
  705.   printf("\n");
  706. #endif
  707.  
  708.   ConvertFunctions(fstr);
  709.  
  710. #if DEBUG
  711.   printf("\nConvertFunctions: ");
  712.  
  713.   for(ptr = fstr; *ptr != NULL; ++ptr)
  714.      printf("%d ", *ptr);
  715.  
  716.   printf("\n");
  717. #endif
  718.  
  719.   if (!InfixToPostfix(fstr)) return fstr;
  720.  
  721. #if DEBUG
  722.   {
  723.   unsigned char *ptr;
  724.  
  725.   printf("\nInfixToPostfix: ");
  726.  
  727.   for(ptr = NewExpr; *ptr != NULL; ++ptr)
  728.      printf("%d ", *ptr);
  729.  
  730.   printf("\n");
  731.   }
  732. #endif
  733.  
  734.   return NewExpr;
  735.  
  736. } /* Convert */
  737.  
  738.  
  739. double Evaluate(x,y)
  740.   double x, y;
  741. {
  742.   unsigned char symbol;
  743.   long i = 0;
  744.  
  745.   nstack.top = 0;  /* Initialize stack */
  746.  
  747.   while (NewExpr[i] != NULL) {
  748.      symbol = NewExpr[i];
  749.  
  750.      if (symbol == 'X')
  751.     NPush(x);
  752.  
  753.      else if (symbol == 'Y')
  754.     NPush(y);
  755.  
  756.      else if (IsSymbol(symbol)) {
  757.     NPush( Constants[symbol-SYMBASE] );
  758.      }
  759.  
  760.      else if (IsFunction(symbol)) {
  761.     NPush( Calculate(symbol, NPop(), 0.0) );
  762.      }
  763.  
  764.      else {
  765.     NPush( Calculate(symbol, NPop(), NPop()) );
  766.      }
  767.  
  768.      ++i;
  769.  
  770.   } /* while */
  771.  
  772.   return NPop();
  773.  
  774. } /* Evaluate */
  775.