home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / EVAL.C < prev    next >
C/C++ Source or Header  |  1997-07-05  |  14KB  |  472 lines

  1. /* +++Date last modified: 05-Jul-1997 */
  2.  
  3. /************************************************************************/
  4. /*                                                                      */
  5. /*  EVAL.C - A simple mathematical expression evaluator in C            */
  6. /*                                                                      */
  7. /*  operators supported: Operator               Precedence              */
  8. /*                                                                      */
  9. /*                         (                     Lowest                 */
  10. /*                         )                     Highest                */
  11. /*                         +   (addition)        Low                    */
  12. /*                         -   (subtraction)     Low                    */
  13. /*                         *   (multiplication)  Medium                 */
  14. /*                         /   (division)        Medium                 */
  15. /*                         \   (modulus)         High                   */
  16. /*                         ^   (exponentiation)  High                   */
  17. /*                         sin(                  Lowest                 */
  18. /*                         cos(                  Lowest                 */
  19. /*                         atan(                 Lowest                 */
  20. /*                         abs(                  Lowest                 */
  21. /*                         sqrt(                 Lowest                 */
  22. /*                         ln(                   Lowest                 */
  23. /*                         exp(                  Lowest                 */
  24. /*                                                                      */
  25. /*  constants supported: pi                                             */
  26. /*                                                                      */
  27. /*  Original Copyright 1991-93 by Robert B. Stout as part of            */
  28. /*  the MicroFirm Function Library (MFL)                                */
  29. /*                                                                      */
  30. /*  The user is granted a free limited license to use this source file  */
  31. /*  to create royalty-free programs, subject to the terms of the        */
  32. /*  license restrictions specified in the LICENSE.MFL file.             */
  33. /*                                                                      */
  34. /*  Requires RMALLWS.C, also in SNIPPETS.                               */
  35. /*                                                                      */
  36. /************************************************************************/
  37.  
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include <math.h>
  42. #include "sniptype.h"
  43. #include "snip_str.h"                     /* For rmallws(), strupr()    */
  44. #include "snipmath.h"
  45. #include "numcnvrt.h"
  46.  
  47. /*
  48. **  Other SNIPPETS functions
  49. */
  50.  
  51. char *rmallws(char *);
  52. char *strupr(char *);
  53.  
  54.  
  55. struct operator {
  56.       char        token;
  57.       char       *tag;
  58.       size_t      taglen;
  59.       int         precedence;
  60. };
  61.  
  62. static struct operator verbs[] = {
  63.       {'+',  "+",       1, 2 },
  64.       {'-',  "-",       1, 3 },
  65.       {'*',  "*",       1, 4 },
  66.       {'/',  "/",       1, 5 },
  67.       {'\\', "\\",      1, 5 },
  68.       {'^',  "^",       1, 6 },
  69.       {'(',  "(",       1, 0 },
  70.       {')',  ")",       1, 99},
  71.       {'S',  "SIN(",    4, 0 },
  72.       {'C',  "COS(",    4, 0 },
  73.       {'A',  "ABS(",    4, 0 },
  74.       {'L',  "LN(",     3, 0 },
  75.       {'E',  "EXP(",    4, 0 },
  76.       {'t',  "ATAN(",   5, 0 },
  77.       {'s',  "SQRT(",   5, 0 },
  78.       {NUL,  NULL,      0, 0 }
  79. };
  80.  
  81. static char   op_stack[256];                    /* Operator stack       */
  82. static double arg_stack[256];                   /* Argument stack       */
  83. static char   token[256];                       /* Token buffer         */
  84. static int    op_sptr,                          /* op_stack pointer     */
  85.               arg_sptr,                         /* arg_stack pointer    */
  86.               parens,                           /* Nesting level        */
  87.               state;                            /* 0 = Awaiting expression
  88.                                                    1 = Awaiting operator
  89.                                                 */
  90. const double Pi = 3.14159265358979323846;
  91.  
  92. static int              do_op(void);
  93. static int              do_paren(void);
  94. static void             push_op(char);
  95. static void             push_arg(double);
  96. static int              pop_arg(double *);
  97. static int              pop_op(int *);
  98. static char            *get_exp(char *);
  99. static struct operator *get_op(char *);
  100. static int              getprec(char);
  101. static int              getTOSprec(void);
  102.  
  103. /************************************************************************/
  104. /*                                                                      */
  105. /*  evaluate()                                                          */
  106. /*                                                                      */
  107. /*  Evaluates an ASCII mathematical expression.                         */
  108. /*                                                                      */
  109. /*  Arguments: 1 - String to evaluate                                   */
  110. /*             2 - Storage to receive double result                     */
  111. /*                                                                      */
  112. /*  Returns: Success_ if successful                                     */
  113. /*           Error_ if syntax error                                     */
  114. /*           R_ERROR if runtime error                                   */
  115. /*                                                                      */
  116. /*  Side effects: Removes all whitespace from the string and converts   */
  117. /*                it to U.C.                                            */
  118. /*                                                                      */
  119. /************************************************************************/
  120.  
  121. int evaluate(char *line, double *val)
  122. {
  123.       double arg;
  124.       char *ptr = line, *str, *endptr;
  125.       int ercode;
  126.       struct operator *op;
  127.  
  128.       strupr(line);
  129.       rmallws(line);
  130.       state = op_sptr = arg_sptr = parens = 0;
  131.  
  132.       while (*ptr)
  133.       {
  134.             switch (state)
  135.             {
  136.             case 0:
  137.                   if (NULL != (str = get_exp(ptr)))
  138.                   {
  139.                         if (NULL != (op = get_op(str)) &&
  140.                               strlen(str) == op->taglen)
  141.                         {
  142.                               push_op(op->token);
  143.                               ptr += op->taglen;
  144.                               break;
  145.                         }
  146.  
  147.                         if (Success_ == strcmp(str, "-"))
  148.                         {
  149.                               push_op(*str);
  150.                               ++ptr;
  151.                               break;
  152.                         }
  153.  
  154.                         if (Success_ == strcmp(str, "PI"))
  155.                               push_arg(Pi);
  156.  
  157.                         else
  158.                         {
  159.                               if (0.0 == (arg = strtod(str, &endptr)) &&
  160.                                     NULL == strchr(str, '0'))
  161.                               {
  162.                                     return Error_;
  163.                               }
  164.                               push_arg(arg);
  165.                         }
  166.                         ptr += strlen(str);
  167.                   }
  168.                   else  return Error_;
  169.  
  170.                   state = 1;
  171.                   break;
  172.  
  173.             case 1:
  174.                   if (NULL != (op = get_op(ptr)))
  175.                   {
  176.                         if (')' == *ptr)
  177.                         {
  178.                               if (Success_ > (ercode = do_paren()))
  179.                                     return ercode;
  180.                         }
  181.                         else
  182.                         {
  183.                               while (op_sptr &&
  184.                                     op->precedence <= getTOSprec())
  185.                               {
  186.                                     do_op();
  187.                               }
  188.                               push_op(op->token);
  189.                               state = 0;
  190.                         }
  191.  
  192.                         ptr += op->taglen;
  193.                   }
  194.                   else  return Error_;
  195.  
  196.                   break;
  197.             }
  198.       }
  199.  
  200.       while (1 < arg_sptr)
  201.       {
  202.             if (Success_ > (ercode = do_op()))
  203.                   return ercode;
  204.       }
  205.       if (!op_sptr)
  206.             return pop_arg(val);
  207.       else  return Error_;
  208. }
  209.  
  210. /*
  211. **  Evaluate stacked arguments and operands
  212. */
  213.  
  214. static int do_op(void)
  215. {
  216.       double arg1, arg2;
  217.       int op;
  218.  
  219.       if (Error_ == pop_op(&op))
  220.             return Error_;
  221.  
  222.       pop_arg(&arg1);
  223.       pop_arg(&arg2);
  224.  
  225.       switch (op)
  226.       {
  227.       case '+':
  228.             push_arg(arg2 + arg1);
  229.             break;
  230.  
  231.       case '-':
  232.             push_arg(arg2 - arg1);
  233.             break;
  234.  
  235.       case '*':
  236.             push_arg(arg2 * arg1);
  237.             break;
  238.  
  239.       case '/':
  240.             if (0.0 == arg1)
  241.                   return R_ERROR;
  242.             push_arg(arg2 / arg1);
  243.             break;
  244.  
  245.       case '\\':
  246.             if (0.0 == arg1)
  247.                   return R_ERROR;
  248.             push_arg(fmod(arg2, arg1));
  249.             break;
  250.  
  251.       case '^':
  252.             push_arg(pow(arg2, arg1));
  253.             break;
  254.  
  255.       case 't':
  256.             ++arg_sptr;
  257.             push_arg(atan(arg1));
  258.             break;
  259.  
  260.       case 'S':
  261.             ++arg_sptr;
  262.             push_arg(sin(arg1));
  263.             break;
  264.  
  265.       case 's':
  266.             if (0.0 > arg2)
  267.                   return R_ERROR;
  268.             ++arg_sptr;
  269.             push_arg(sqrt(arg1));
  270.             break;
  271.  
  272.       case 'C':
  273.             ++arg_sptr;
  274.             push_arg(cos(arg1));
  275.             break;
  276.  
  277.       case 'A':
  278.             ++arg_sptr;
  279.             push_arg(fabs(arg1));
  280.             break;
  281.  
  282.       case 'L':
  283.             if (0.0 < arg1)
  284.             {
  285.                   ++arg_sptr;
  286.                   push_arg(log(arg1));
  287.                   break;
  288.             }
  289.             else  return R_ERROR;
  290.  
  291.       case 'E':
  292.             ++arg_sptr;
  293.             push_arg(exp(arg1));
  294.             break;
  295.  
  296.       case '(':
  297.             arg_sptr += 2;
  298.             break;
  299.  
  300.       default:
  301.             return Error_;
  302.       }
  303.       if (1 > arg_sptr)
  304.             return Error_;
  305.       else  return op;
  306. }
  307.  
  308. /*
  309. **  Evaluate one level
  310. */
  311.  
  312. static int do_paren(void)
  313. {
  314.       int op;
  315.  
  316.       if (1 > parens--)
  317.             return Error_;
  318.       do
  319.       {
  320.             if (Success_ > (op = do_op()))
  321.                   break;
  322.       } while (getprec((char)op));
  323.       return op;
  324. }
  325.  
  326. /*
  327. **  Stack operations
  328. */
  329.  
  330. static void push_op(char op)
  331. {
  332.       if (!getprec(op))
  333.             ++parens;
  334.       op_stack[op_sptr++] = op;
  335. }
  336.  
  337. static void push_arg(double arg)
  338. {
  339.       arg_stack[arg_sptr++] = arg;
  340. }
  341.  
  342. static int pop_arg(double *arg)
  343. {
  344.       *arg = arg_stack[--arg_sptr];
  345.       if (0 > arg_sptr)
  346.             return Error_;
  347.       else  return Success_;
  348. }
  349.  
  350. static int pop_op(int *op)
  351. {
  352.       if (!op_sptr)
  353.             return Error_;
  354.       *op = op_stack[--op_sptr];
  355.       return Success_;
  356. }
  357.  
  358. /*
  359. **  Get an expression
  360. */
  361.  
  362. static char * get_exp(char *str)
  363. {
  364.       char *ptr = str, *tptr = token;
  365.       struct operator *op;
  366.  
  367.       if (Success_ == strncmp(str, "PI", 2))
  368.             return strcpy(token, "PI");
  369.  
  370.  
  371.       while (*ptr)
  372.       {
  373.             if (NULL != (op = get_op(ptr)))
  374.             {
  375.                   if ('-' == *ptr)
  376.                   {
  377.                         if (str != ptr && 'E' != ptr[-1])
  378.                               break;
  379.                         if (str == ptr && !isdigit(ptr[1]) && '.' != ptr[1])
  380.                         {
  381.                               push_arg(0.0);
  382.                               strcpy(token, op->tag);
  383.                               return token;
  384.                         }
  385.                   }
  386.  
  387.                   else if (str == ptr)
  388.                   {
  389.                         strcpy(token, op->tag);
  390.                         return token;
  391.                   }
  392.  
  393.                   else break;
  394.             }
  395.  
  396.             *tptr++ = *ptr++;
  397.       }
  398.       *tptr = NUL;
  399.  
  400.       return token;
  401. }
  402.  
  403. /*
  404. **  Get an operator
  405. */
  406.  
  407. static struct operator * get_op(char *str)
  408. {
  409.       struct operator *op;
  410.  
  411.       for (op = verbs; op->token; ++op)
  412.       {
  413.             if (Success_ == strncmp(str, op->tag, op->taglen))
  414.                   return op;
  415.       }
  416.       return NULL;
  417. }
  418.  
  419. /*
  420. **  Get precedence of a token
  421. */
  422.  
  423. static int getprec(char token)
  424. {
  425.       struct operator *op;
  426.  
  427.       for (op = verbs; op->token; ++op)
  428.       {
  429.             if (token == op->token)
  430.                   break;
  431.       }
  432.       if (op->token)
  433.             return op->precedence;
  434.       else  return 0;
  435. }
  436.  
  437. /*
  438. **  Get precedence of TOS token
  439. */
  440.  
  441. static int getTOSprec(void)
  442. {
  443.       if (!op_sptr)
  444.             return 0;
  445.       return getprec(op_stack[op_sptr - 1]);
  446. }
  447.  
  448. #ifdef TEST
  449.  
  450. #include <stdio.h>
  451.  
  452. #ifdef __WATCOMC__
  453.  #pragma off (unreferenced);
  454. #endif
  455. #ifdef __TURBOC__
  456.  #pragma argsused
  457. #endif
  458.  
  459. main(int argc, char *argv[])
  460. {
  461.       int retval;
  462.       double val;
  463.  
  464.       printf("evaluate(%s) ", argv[1]);
  465.       printf("returned %d\n", retval = evaluate(argv[1], &val));
  466.       if (0 == retval)
  467.             printf("val = %f\n", val);
  468.       return 0;
  469. }
  470.  
  471. #endif /* TEST */
  472.