home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 363_01 / eval.c < prev    next >
C/C++ Source or Header  |  1991-09-24  |  15KB  |  498 lines

  1. /***********************************************************************
  2.  *
  3.  *      EVAL.C
  4.  *      Expression Evaluator for 68020 Assembler
  5.  *
  6.  *    Function: eval()
  7.  *      Evaluates a constant expression. The p argument points to the string
  8.  *      to be evaluated, and the function returns a pointer to the first
  9.  *      character beyond the end of the expression. The value of the
  10.  *      expression and an error code are returned via output arguments. The
  11.  *      function handles errors according to the following table:
  12.  *
  13.  *                         Pass1        Pass1   Pass2         Pass2
  14.  *      Condition          Error        *refPtr Error         *refPtr
  15.  *      ----------------   ----------   -----   -----------   -----
  16.  *      Undefined symbol   INCOMPLETE   FALSE   UNDEFINED     FALSE
  17.  *      Division by zero   INCOMPLETE   FALSE   DIV_BY_ZERO   FALSE
  18.  *      Syntax error       SYNTAX       --      SYNTAX        --
  19.  *      Constant error     x_TOO_BIG    T/F     x_TOO_BIG     T/F
  20.  *      No error           OK           T/F     OK            T/F
  21.  *
  22.  *      The char pointed to by refPtr is set to TRUE if all the symbols 
  23.  *      encountered in the expression are backwards references or FALSE if 
  24.  *      at least one symbol is a forward reference.
  25.  *
  26.  *   Usage: char *eval(char *p, long *valuePtr, char *refPtr, int *errorPtr)
  27.  *
  28.  *  Errors: ASCII_TOO_BIG
  29.  *          DIV_BY_ZERO
  30.  *          INCOMPLETE
  31.  *          NUMBER_TOO_BIG
  32.  *          REG_LIST_SPEC
  33.  *          SYNTAX
  34.  *          UNDEFINED
  35.  *
  36.  *      Author: Paul McKee
  37.  *      ECE492    North Carolina State University, 9/24/86
  38.  *
  39.  *      Modified A.E. Romer. Version 1.0
  40.  *          16 March 1991 - converted to ANSI, braces layout.
  41.  *          21 March 1991 - '.' disallowed in symbols except as first char.
  42.  *                          (to allow .w and .l suffixes in absolute
  43.  *                          addressing), '_' allowed as first character.
  44.  *          22 May 1991   - any character that is not valid in an expression
  45.  *                          is now the terminator.
  46.  *          Sept. 1991    - '$' disallowed in symbols.
  47.  ************************************************************************/
  48.  
  49.  
  50. #include <stdio.h>
  51. #include <ctype.h>
  52. #include "asm.h"
  53.  
  54. extern char pass2;
  55.  
  56. /* Largest number that can be represented in an unsigned int
  57.     - MACHINE DEPENDENT */
  58.  
  59. #define     INTLIMIT    0xFFFF
  60. #define     LONGLIMIT   0xFFFFFFFF
  61.  
  62. #define     STACKMAX    5
  63.  
  64.  
  65. char    *evalNumber(char *p, long *numberPtr, char *refPtr, int *errorPtr)
  66.     {
  67.     int status;
  68.     long base;
  69.     long x;
  70.     char name[SIGCHARS+1];
  71.     symbolDef *symbol;
  72.     int i;
  73.     char endFlag;
  74.  
  75.     *refPtr = TRUE;
  76.     if (*p == '-')
  77.         {
  78.         /* Evaluate unary minus operator recursively */
  79.  
  80.         p = evalNumber(++p, &x, refPtr, errorPtr);
  81.         *numberPtr = -x;
  82.         return p;
  83.         }
  84.     else if (*p == '~')
  85.         {
  86.         /* Evaluate one's complement operator recursively */
  87.  
  88.         p = evalNumber(++p, &x, refPtr, errorPtr);
  89.         *numberPtr = ~x;
  90.         return p;
  91.         }
  92.     else if (*p == '(')
  93.         {
  94.         /* Evaluate parenthesized expressions recursively */
  95.  
  96.         p = eval(++p, &x, refPtr, errorPtr);
  97.         if (*errorPtr > SEVERE)
  98.             return NULL;
  99.         else if (*p != ')')
  100.             {
  101.             NEWERROR(*errorPtr, SYNTAX);
  102.             return NULL;
  103.             }
  104.         else
  105.             {
  106.             *numberPtr = x;
  107.             return ++p;
  108.             }
  109.         }
  110.     else if (*p == '$' && isxdigit(*(p+1)))
  111.         {
  112.         /* Convert hex digits until another character is
  113.            found. (At least one hex digit is present.) */
  114.  
  115.         x = 0;
  116.         while (isxdigit(*++p))
  117.             {
  118.             if ((unsigned long)x > (unsigned long)LONGLIMIT/16)
  119.                 NEWERROR(*errorPtr, NUMBER_TOO_BIG);
  120.             if (*p > '9')
  121.                 x = 16 * x + (*p - 'A' + 10);
  122.             else
  123.                 x = 16 * x + (*p - '0');
  124.             }
  125.         *numberPtr = x;
  126.         return p;
  127.         }
  128.     else if (*p == '%' || *p == '@' || isdigit(*p))
  129.         {
  130.         /* Convert digits in the appropriate base (binary,
  131.            octal, or decimal) until an invalid digit is found. */
  132.  
  133.         if (*p == '%')
  134.             {
  135.             base = 2;
  136.             p++;
  137.             }
  138.         else if (*p == '@')
  139.             {
  140.             base = 8;
  141.             p++;
  142.             }
  143.         else base = 10;
  144.  
  145.         /* Check that at least one digit is present */
  146.  
  147.         if (*p < '0' || *p >= '0' + base)
  148.             {
  149.             NEWERROR(*errorPtr, SYNTAX);
  150.             return NULL;
  151.             }
  152.         x = 0;
  153.  
  154.         /* Convert the digits into an integer */
  155.  
  156.         while (*p >= '0' && *p < '0' + base)
  157.             {
  158.             if (x > (LONGLIMIT - (*p - '0')) / base)
  159.                 {
  160.                 NEWERROR(*errorPtr, NUMBER_TOO_BIG);
  161.                 }
  162.             x = (long) ( (long) ((long) base * x) + (long) (*p - '0') );
  163.             p++;
  164.             }
  165.         *numberPtr = x;
  166.         return p;
  167.         }
  168.     else if (*p == CHAR_DELIMITER)
  169.         {
  170.         endFlag = FALSE;
  171.         i = 0;
  172.         x = 0;
  173.         p++;
  174.         while (!endFlag)
  175.             {
  176.             if (*p == CHAR_DELIMITER)
  177.                 if (*(p+1) == CHAR_DELIMITER)
  178.                     {
  179.                     x = (x << 8) + *p;
  180.                     i++;
  181.                     p++;
  182.                     }
  183.                 else
  184.                     endFlag = TRUE;
  185.             else
  186.                 {
  187.                 x = (x << 8) + *p;
  188.                 i++;
  189.                 }
  190.             p++;
  191.             }
  192.         if (i == 0)
  193.             {
  194.             NEWERROR(*errorPtr, SYNTAX);
  195.             return NULL;
  196.             }
  197.         else if (i == 3)
  198.             x = x << 8;
  199.         else if (i > 4)
  200.             NEWERROR(*errorPtr, ASCII_TOO_BIG);
  201.         *numberPtr = x;
  202.         return p;
  203.         }
  204.     else if (isalpha(*p) || *p == '.' || *p == '_')
  205.         {
  206.         /* Determine the value of a symbol */
  207.  
  208.         i = 0;
  209.         /* Collect characters of the symbol's name
  210.            (only SIGCHARS characters are significant) */
  211.  
  212.         do
  213.             {
  214.             if (i < SIGCHARS)
  215.                 name[i++] = *p;
  216.             p++;
  217.             } while (isalnum(*p) || *p == '_' || *p == '$');
  218.         name[i] = '\0';
  219.         /* Look up the name in the symbol table, resulting
  220.            in a pointer to the symbol table entry */
  221.  
  222.         status = OK;
  223.         symbol = lookup(name, &status);
  224.  
  225. /*      printf("EvalNumber: Status from lookup = %04X\n", status); */
  226.  
  227.         if (status == OK)
  228.             /* If symbol was found, and it's not a register
  229.                list symbol, then return its value */
  230.  
  231.             if (!(symbol->flags & REG_LIST_SYM))
  232.                 {
  233.                 *numberPtr = symbol->value;
  234.  
  235. /*              printf("The value of the symbol \"%s\" is %08lX\n",
  236.                     name, *numberPtr); */
  237.  
  238.                 if (pass2)
  239.                     *refPtr = (symbol->flags & BACKREF);
  240.                 }
  241.             else
  242.                 {
  243.                 /* If it is a register list symbol, return error */
  244.  
  245.                 *numberPtr = 0;
  246.                 NEWERROR(*errorPtr, REG_LIST_SPEC);
  247.                 }
  248.         else
  249.             {
  250.             /* Otherwise return an error */
  251.  
  252.             if (pass2)
  253.                 {
  254.                 NEWERROR(*errorPtr, UNDEFINED);
  255.                 }
  256.             else
  257.                 NEWERROR(*errorPtr, INCOMPLETE);
  258.             *refPtr = FALSE;
  259.             }
  260.  
  261. /*      printf("The symbol \"%s\" is%s a backwards reference\n",
  262.             name, (*refPtr) ? "" : " not"); */
  263.  
  264.         return p;
  265.         }
  266.     else
  267.         {
  268.         /* Otherwise, the character was not a valid operand */
  269.  
  270.         NEWERROR(*errorPtr, SYNTAX);
  271.         return NULL;
  272.         }
  273.  
  274.     return NORMAL;
  275.     }
  276.  
  277.  
  278.  
  279. int precedence(char op)
  280.     {
  281.     /* Compute the precedence of an operator. Higher numbers indicate
  282.        higher precedence, e.g., precedence('*') > precedence('+').
  283.        Any character which is not a binary operator will be assigned
  284.        a precedence of zero. */
  285.  
  286.     switch (op)
  287.         {
  288.         case '+' :
  289.         case '-' : return 1;
  290.         case '&' :
  291.         case '!' : return 3;
  292.         case '>' :
  293.         case '<' : return 4;
  294.         case '*' :
  295.         case '/' :
  296.         case '\\': return 2;
  297.         default  : return 0;
  298.         }
  299.  
  300.     return NORMAL;
  301.     }
  302.  
  303.  
  304. int doOp(long val1, long val2, char op, long *result)
  305.     {
  306.  
  307.     /* Performs the operation of the operator on the two operands.
  308.        Returns OK or DIV_BY_ZERO. */
  309.  
  310.     switch (op)
  311.         {
  312.         case '+' : *result = val1 + val2;  return OK;
  313.         case '-' : *result = val1 - val2;  return OK;
  314.         case '&' : *result = val1 & val2;  return OK;
  315.         case '!' : *result = val1 | val2;  return OK;
  316.         case '>' : *result = val1 >> val2; return OK;
  317.         case '<' : *result = val1 << val2; return OK;
  318.         case '*' : *result = val1 * val2;  return OK;
  319.         case '/' : if (val2 != 0)
  320.                         {
  321.                         *result = val1 / val2;
  322.                         return OK;
  323.                         }
  324.                    else
  325.                         return DIV_BY_ZERO;
  326.         case '\\': if (val2 != 0)
  327.                         {
  328.                         *result = val1 % val2;
  329.                         return OK;
  330.                         }
  331.                    else
  332.                         return DIV_BY_ZERO;
  333.         default  : printf("DoOp: Operator error  op = '%c' val1 = %d val2 = %d\n", op, val1, val2);
  334.         }
  335.  
  336.     return NORMAL;
  337. }
  338.  
  339.  
  340. char *eval(char *p, long *valuePtr, char *refPtr, int *errorPtr)
  341.     {
  342.     long    valStack[STACKMAX];
  343.     char    opStack[STACKMAX-1];
  344.     int     valPtr = 0;
  345.     int     opPtr = 0;
  346.     long    t;
  347.     int     prec;
  348.     long    i;
  349.     char    evaluate, backRef;
  350.     int     status;
  351.  
  352. /*  printf("EVAL: Input string is \"%s\"\n", p); */
  353.  
  354.     /* Assume that the expression is to be evaluated,
  355.        at least until an undefined symbol is found */
  356.  
  357.     evaluate = TRUE;
  358.  
  359.     /* Assume initially that all symbols are backwards references */
  360.  
  361.     *refPtr = TRUE;
  362.  
  363.     /* Loop until terminator character is found (loop is exited via return) */
  364.  
  365.     while (TRUE)
  366.         {
  367.         /************************************************
  368.          *                                              *
  369.          *      EXPECT AN OPERAND                       *
  370.          *                                              *
  371.          ************************************************/
  372.         /* Use evalNumber to read in a number or symbol */
  373.  
  374.         status = OK;
  375.         p = evalNumber(p, &t, &backRef, &status);
  376.         NEWERROR(*errorPtr, status);
  377.         if (!backRef && (status > ERROR || status == INCOMPLETE))
  378.                                         /* Stop evaluating the expression */
  379.             {
  380.             evaluate = FALSE;
  381.             *refPtr = FALSE;
  382.             }
  383.         else if (*errorPtr > SEVERE)
  384.                                     /* Pass any other error to the caller */
  385.             return NULL;
  386.         else
  387.                         /* If OK or WARNING, push the value on the stack */
  388.             {
  389.             if (evaluate)
  390.                 valStack[valPtr++] = t;
  391.  
  392.                         /* Set *refPtr to reflect the symbol just parsed */
  393.  
  394.             *refPtr = (char) (*refPtr && backRef);
  395.             }
  396.  
  397. /******************************************
  398.         printf("Operand read - stack contains (bottom to top):\n");
  399.         for (i = 0; i < valPtr || i < opPtr; i++)
  400.             {
  401.             printf("%2d: ", i);
  402.             if (i < valPtr)
  403.                 printf("%10d ", valStack[i]);
  404.             else
  405.                 printf("           ");
  406.             if (i < opPtr)
  407.                 putchar(opStack[i]);
  408.             putchar('\n');
  409.             } *************************************************/
  410.  
  411.         /************************************************
  412.          *                                              *
  413.          *      EXPECT AN OPERATOR                      *
  414.          *                                              *
  415.          ************************************************/
  416.         /* Handle the >> and << operators */
  417.  
  418.         if (*p == '>' || *p == '<')
  419.             {
  420.             p++;
  421.             if (*p != *(p-1))
  422.                 {
  423.                 NEWERROR(*errorPtr, SYNTAX);
  424.                 return NULL;
  425.                 }
  426.             }
  427.         prec = precedence(*p);
  428.  
  429.                             /* Do all stacked operations that are of higher
  430.                              * precedence than the operator just examined. */
  431.  
  432.         while (opPtr && evaluate && (prec <= precedence(opStack[opPtr-1])))
  433.                         /* Pop operands and operator and do the operation */
  434.             {
  435.             t = valStack[--valPtr];
  436.             i = valStack[--valPtr];
  437.             status = doOp(i, t, opStack[--opPtr], &t);
  438.             if (status != OK)
  439.                 {
  440.                 /* Report error from doOp */
  441.  
  442.                 if (pass2)
  443.                     {
  444.                     NEWERROR(*errorPtr, status);
  445.                     }
  446.                 else
  447.                     NEWERROR(*errorPtr, INCOMPLETE);
  448.                 evaluate = FALSE;
  449.                 *refPtr = FALSE;
  450.                 }
  451.             else
  452.                 /* Otherwise push result on the stack */
  453.  
  454.                 valStack[valPtr++] = t;
  455.             }
  456.         if (prec)
  457.             {
  458.             if (evaluate)   /* If operator is valid, push it on the stack */
  459.                 opStack[opPtr++] = *p;
  460.             p++;
  461.             }
  462.         else
  463.                         /* any other character terminates the expression */
  464.             {
  465.                         /* return all the results needed */
  466.             if (evaluate)
  467.                 *valuePtr = valStack[--valPtr];
  468.             else
  469.                 *valuePtr = 0;
  470.  
  471. /*          printf("EVAL: The expression is \"");
  472.  
  473.             while (start < p)
  474.                 putchar(*start++);
  475.             printf("\"\n"); */
  476.             return p;
  477.             }
  478.  
  479. /**********************************************************
  480.         printf("Operator processed - stack contains (bottom to top):\n");
  481.         for (i = 0; i < valPtr || i < opPtr; i++)
  482.             {
  483.             printf("%2d: ", i);
  484.             if (i < valPtr)
  485.                 printf("%10d ", valStack[i]);
  486.             else
  487.                 printf("           ");
  488.             if (i < opPtr)
  489.                 putchar(opStack[i]);
  490.             putchar('\n');
  491.             }
  492. ***********************************************************/
  493.         }
  494.  
  495.     return NORMAL;
  496.     }
  497.  
  498.