home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / preproc / evaluate.c < prev    next >
C/C++ Source or Header  |  1996-03-22  |  15KB  |  560 lines

  1. /*
  2.  * This file contains functions to evaluate constant expressions for
  3.  *  conditional inclusion. These functions are organized as a recursive
  4.  *  decent parser based on the C grammar presented in the ANSI C Standard
  5.  *  document. The function eval() is called from the outside.
  6.  */
  7.  
  8. #include "::preproc:preproc.h"
  9. #include "::preproc:ptoken.h"
  10.  
  11. /*
  12.  * Prototypes for static functions.
  13.  */
  14. hidden long primary        Params((struct token **tp, struct token *trigger));
  15. hidden long unary          Params((struct token **tp, struct token *trigger));
  16. hidden long multiplicative Params((struct token **tp, struct token *trigger));
  17. hidden long additive       Params((struct token **tp, struct token *trigger));
  18. hidden long shift          Params((struct token **tp, struct token *trigger));
  19. hidden long relation       Params((struct token **tp, struct token *trigger));
  20. hidden long equality       Params((struct token **tp, struct token *trigger));
  21. hidden long and            Params((struct token **tp, struct token *trigger));
  22. hidden long excl_or        Params((struct token **tp, struct token *trigger));
  23. hidden long incl_or        Params((struct token **tp, struct token *trigger));
  24. hidden long log_and        Params((struct token **tp, struct token *trigger));
  25. hidden long log_or         Params((struct token **tp, struct token *trigger));
  26.  
  27. #include "::preproc:pproto.h"
  28.  
  29. /*
  30.  * <primary> ::= <identifier>
  31.  *               defined <identifier>
  32.  *               defined '(' <identifier> ')'
  33.  *               <number>
  34.  *               <character-constant>
  35.  *               '(' <conditional> ')'
  36.  */
  37. static long primary(tp, trigger)
  38. struct token **tp;
  39. struct token *trigger;
  40.    {
  41.    struct token *t = NULL;
  42.    struct token *id = NULL;
  43.    long e1;
  44.    int i;
  45.    int is_hex_char;
  46.    char *s;
  47.  
  48.    switch ((*tp)->tok_id) {
  49.       case Identifier:
  50.          /*
  51.           * Check for "defined", it is the only reserved word in this expression
  52.           *  evaluation (See ANSI C Standard).
  53.           */
  54.          if (strcmp((*tp)->image, "defined") == 0) {
  55.             nxt_non_wh(&t);
  56.             if (t->tok_id == '(') {
  57.                nxt_non_wh(&id);
  58.                nxt_non_wh(&t);
  59.                if (t == NULL || t->tok_id != ')')
  60.                   errt1(id, "')' missing in 'defined' expression");
  61.                free_t(t);
  62.                }
  63.             else
  64.                id = t;
  65.             if (id->tok_id != Identifier)
  66.                errt1(id, "'defined' must be followed by an identifier");
  67.             advance_tok(tp);
  68.             if (m_lookup(id) == NULL)
  69.                e1 = 0L;
  70.             else
  71.                e1 = 1L;
  72.             free_t(id);
  73.             }
  74.          else {
  75.             advance_tok(tp);
  76.             e1 = 0L;   /* undefined: all macros have been expanded */
  77.             }
  78.          return e1;
  79.  
  80.       case PpNumber:
  81.          s = (*tp)->image;
  82.          e1 = 0L;
  83.          if (*s == '0') {
  84.             ++s;
  85.             if ((*s == 'x') || (*s == 'X')) {
  86.                /*
  87.                 * Hex constant
  88.                 */
  89.                ++s;
  90.                if (*s == '\0' || *s == 'u' || *s == 'U' || *s == 'l' ||
  91.                     *s == 'L')
  92.                   errt2(*tp, "invalid hex constant in condition of #",
  93.                      trigger->image);
  94.                while (*s != '\0' && *s != 'u' && *s != 'U' && *s != 'l' &&
  95.                     *s != 'L') {
  96.                   e1 <<= 4;
  97.                   if (*s >= '0' && *s <= '9')
  98.                      e1 |= *s - '0';
  99.                   else
  100.                      switch (*s) {
  101.                         case 'a': case 'A': e1 |= 10; break;
  102.                         case 'b': case 'B': e1 |= 11; break;
  103.                         case 'c': case 'C': e1 |= 12; break;
  104.                         case 'd': case 'D': e1 |= 13; break;
  105.                         case 'e': case 'E': e1 |= 14; break;
  106.                         case 'f': case 'F': e1 |= 15; break;
  107.                         default:
  108.                            errt2(*tp, "invalid hex constant in condition of #",
  109.                               trigger->image);
  110.                         }
  111.                   ++s;
  112.                   }
  113.                }
  114.             else {
  115.                /*
  116.                 * Octal constant
  117.                 */
  118.                while (*s != '\0' && *s != 'u' && *s != 'U' && *s != 'l' &&
  119.                     *s != 'L') {
  120.                   if (*s >= '0' && *s <= '7')
  121.                      e1 = (e1 << 3) | (*s - '0');
  122.                   else
  123.                      errt2(*tp, "invalid octal constant in condition of #",
  124.                         trigger->image);
  125.                   ++s;
  126.                   }
  127.                }
  128.             }
  129.          else {
  130.             /*
  131.              * Decimal constant
  132.              */
  133.             while (*s != '\0' && *s != 'u' && *s != 'U' && *s != 'l' &&
  134.                  *s != 'L') {
  135.                if (*s >= '0' && *s <= '9')
  136.                   e1 = e1 * 10 + (*s - '0');
  137.                else
  138.                   errt2(*tp, "invalid decimal constant in condition of #",
  139.                      trigger->image);
  140.                ++s;
  141.                }
  142.             }
  143.             advance_tok(tp);
  144.             /*
  145.              * Check integer suffix for validity
  146.              */
  147.             if (*s == '\0')
  148.                return e1;
  149.             else if (*s == 'u' || *s == 'U') {
  150.                ++s;
  151.                if (*s == '\0')
  152.                   return e1;
  153.                else if ((*s == 'l' || *s == 'L') && *++s == '\0')
  154.                   return e1;
  155.                }
  156.             else if (*s == 'l' || *s == 'L') {
  157.                ++s;
  158.                if (*s == '\0')
  159.                   return e1;
  160.                else if ((*s == 'u' || *s == 'U') && *++s == '\0')
  161.                   return e1;
  162.                }
  163.             errt2(*tp, "invalid integer constant in condition of #",
  164.                trigger->image);
  165.  
  166.       case CharConst:
  167.       case LCharConst:
  168.          /*
  169.           * Wide characters are treated the same as characters. Only the
  170.           *  first byte of a multi-byte character is used.
  171.           */
  172.          s = (*tp)->image;
  173.          if (*s != '\\')
  174.             e1 = (long)*s;
  175.          else {
  176.             /*
  177.              * Escape sequence.
  178.              */
  179.             e1 = 0L;
  180.             ++s;
  181.             if (*s >= '0' && *s <= '7') {
  182.                 for (i = 1; i <= 3 && *s >= '0' && *s <= '7'; ++i, ++s)
  183.                    e1 = (e1 << 3) | (*s - '0');
  184.                 if (e1 != (long)(unsigned char)e1)
  185.                    errt1(*tp, "octal escape sequece larger than a character");
  186.                 e1 = (long)(char)e1;
  187.                 }
  188.             else switch (*s) {
  189.                case '\'': e1 = (long) '\''; break;
  190.                case '"':  e1 = (long) '"';  break;
  191.                case '?':  e1 = (long) '?';  break;
  192.                case '\\': e1 = (long) '\\'; break;
  193.                case 'a':  e1 = (long) Bell; break;
  194.                case 'b':  e1 = (long) '\b'; break;
  195.                case 'f':  e1 = (long) '\f'; break;
  196.                case 'n':  e1 = (long) '\n'; break;
  197.                case 'r':  e1 = (long) '\r'; break;
  198.                case 't':  e1 = (long) '\t'; break;
  199.                case 'v':  e1 = (long) '\v'; break;
  200.    
  201.                case 'x': 
  202.                   ++s;
  203.                   is_hex_char = 1;
  204.                   while (is_hex_char) {
  205.                      if (*s >= '0' && *s <= '9')
  206.                         e1 = (e1 << 4) | (*s - '0');
  207.                      else switch (*s) {
  208.                         case 'a': case 'A': e1 = (e1 << 4) | 10; break;
  209.                         case 'b': case 'B': e1 = (e1 << 4) | 11; break;
  210.                         case 'c': case 'C': e1 = (e1 << 4) | 12; break;
  211.                         case 'd': case 'D': e1 = (e1 << 4) | 13; break;
  212.                         case 'e': case 'E': e1 = (e1 << 4) | 14; break;
  213.                         case 'f': case 'F': e1 = (e1 << 4) | 15; break;
  214.                         default: is_hex_char = 0;
  215.                         }
  216.                      if (is_hex_char)
  217.                         ++s;
  218.                      if (e1 != (long)(unsigned char)e1)
  219.                         errt1(*tp,"hex escape sequece larger than a character");
  220.                      }
  221.                   e1 = (long)(char)e1;
  222.                   break;
  223.    
  224.                default:
  225.                   e1 = (long) *s;
  226.                }
  227.             }
  228.          advance_tok(tp);
  229.          return e1;
  230.  
  231.       case '(':
  232.          advance_tok(tp);
  233.          e1 = conditional(tp, trigger);
  234.          if ((*tp)->tok_id != ')')
  235.             errt2(*tp, "expected ')' in conditional of #", trigger->image);
  236.          advance_tok(tp);
  237.          return e1;
  238.  
  239.       default:
  240.          errt2(*tp, "syntax error in condition of #", trigger->image);
  241.       }
  242.    }
  243.  
  244. /*
  245.  * <unary> ::= <primary> |
  246.  *             '+' <unary> |
  247.  *             '-' <unary> |
  248.  *             '~' <unary> |
  249.  *             '!' <unary>
  250.  */
  251. static long unary(tp, trigger)
  252. struct token **tp;
  253. struct token *trigger;
  254.    {
  255.    switch ((*tp)->tok_id) {
  256.       case '+':
  257.          advance_tok(tp);
  258.          return unary(tp, trigger);
  259.       case '-':
  260.          advance_tok(tp);
  261.          return -unary(tp, trigger);
  262.       case '~':
  263.          advance_tok(tp);
  264.          return ~unary(tp, trigger);
  265.       case '!':
  266.          advance_tok(tp);
  267.          return !unary(tp, trigger);
  268.       default:
  269.          return primary(tp, trigger);
  270.       }
  271.    }
  272.  
  273. /*
  274.  * <multiplicative> ::= <unary> |
  275.  *                      <multiplicative> '*' <unary> |
  276.  *                      <multiplicative> '/' <unary> |
  277.  *                      <multiplicative> '%' <unary>
  278.  */
  279. static long multiplicative(tp, trigger)
  280. struct token **tp;
  281. struct token *trigger;
  282.    {
  283.    long e1, e2;
  284.    int tok_id;
  285.  
  286.    e1 = unary(tp, trigger);
  287.    tok_id = (*tp)->tok_id;
  288.    while (tok_id == '*' || tok_id == '/' || tok_id == '%') {
  289.       advance_tok(tp);
  290.       e2 = unary(tp, trigger);
  291.       switch (tok_id) {
  292.          case '*':
  293.             e1 = (e1 * e2);
  294.             break;
  295.          case '/':
  296.             e1 = (e1 / e2);
  297.             break;
  298.          case '%':
  299.             e1 = (e1 % e2);
  300.             break;
  301.          }
  302.       tok_id = (*tp)->tok_id;
  303.       }
  304.    return e1;
  305.    }
  306.  
  307. /*
  308.  * <additive> ::= <multiplicative> |
  309.  *                <additive> '+' <multiplicative> |
  310.  *                <additive> '-' <multiplicative>
  311.  */
  312. static long additive(tp, trigger)
  313. struct token **tp;
  314. struct token *trigger;
  315.    {
  316.    long e1, e2;
  317.    int tok_id;
  318.  
  319.    e1 = multiplicative(tp, trigger);
  320.    tok_id = (*tp)->tok_id;
  321.    while (tok_id == '+' || tok_id == '-') {
  322.       advance_tok(tp);
  323.       e2 = multiplicative(tp, trigger);
  324.       if (tok_id == '+')
  325.          e1 = (e1 + e2);
  326.       else
  327.          e1 = (e1 - e2);
  328.       tok_id = (*tp)->tok_id;
  329.       }
  330.    return e1;
  331.    }
  332.  
  333. /*
  334.  * <shift> ::= <additive> |
  335.  *             <shift> '<<' <additive> |
  336.  *             <shift> '>>' <additive>
  337.  */
  338. static long shift(tp, trigger)
  339. struct token **tp;
  340. struct token *trigger;
  341.    {
  342.    long e1, e2;
  343.    int tok_id;
  344.  
  345.    e1 = additive(tp, trigger);
  346.    tok_id = (*tp)->tok_id;
  347.    while (tok_id == LShft || tok_id == RShft) {
  348.       advance_tok(tp);
  349.       e2 = additive(tp, trigger);
  350.       if (tok_id == LShft)
  351.          e1 = (e1 << e2);
  352.       else
  353.          e1 = (e1 >> e2);
  354.       tok_id = (*tp)->tok_id;
  355.       }
  356.    return e1;
  357.    }
  358.  
  359. /*
  360.  * <relation> ::= <shift> |
  361.  *                <relation> '<' <shift> |
  362.  *                <relation> '<=' <shift> |
  363.  *                <relation> '>' <shift> |
  364.  *                <relation> '>=' <shift>
  365.  */
  366. static long relation(tp, trigger)
  367. struct token **tp;
  368. struct token *trigger;
  369.    {
  370.    long e1, e2;
  371.    int tok_id;
  372.  
  373.    e1 = shift(tp, trigger);
  374.    tok_id = (*tp)->tok_id;
  375.    while (tok_id == '<' || tok_id == Leq || tok_id == '>' || tok_id == Geq) {
  376.       advance_tok(tp);
  377.       e2 = shift(tp, trigger);
  378.       switch (tok_id) {
  379.          case '<':
  380.             e1 = (e1 < e2);
  381.             break;
  382.          case Leq:
  383.             e1 = (e1 <= e2);
  384.             break;
  385.          case '>':
  386.             e1 = (e1 > e2);
  387.             break;
  388.          case Geq:
  389.             e1 = (e1 >= e2);
  390.             break;
  391.          }
  392.       tok_id = (*tp)->tok_id;
  393.       }
  394.    return e1;
  395.    }
  396.  
  397. /*
  398.  * <equality> ::= <relation> |
  399.  *                <equality> '==' <relation> |
  400.  *                <equality> '!=' <relation>
  401.  */
  402. static long equality(tp, trigger)
  403. struct token **tp;
  404. struct token *trigger;
  405.    {
  406.    long e1, e2;
  407.    int tok_id;
  408.  
  409.    e1 = relation(tp, trigger);
  410.    tok_id = (*tp)->tok_id;
  411.    while (tok_id == Equal || tok_id == Neq) {
  412.       advance_tok(tp);
  413.       e2 = relation(tp, trigger);
  414.       if (tok_id == Equal)
  415.          e1 = (e1 == e2);
  416.       else
  417.          e1 = (e1 != e2);
  418.       tok_id = (*tp)->tok_id;
  419.       }
  420.    return e1;
  421.    }
  422.  
  423. /*
  424.  * <and> ::= <equality> |
  425.  *           <and> '&' <equality>
  426.  */
  427. static long and(tp, trigger)
  428. struct token **tp;
  429. struct token *trigger;
  430.    {
  431.    long e1, e2;
  432.  
  433.    e1 = equality(tp, trigger);
  434.    while ((*tp)->tok_id == '&') {
  435.       advance_tok(tp);
  436.       e2 = equality(tp, trigger);
  437.       e1 = (e1 & e2);
  438.       }
  439.    return e1;
  440.    }
  441.  
  442. /*
  443.  * <excl_or> ::= <and> |
  444.  *               <excl_or> '^' <and>
  445.  */
  446. static long excl_or(tp, trigger)
  447. struct token **tp;
  448. struct token *trigger;
  449.    {
  450.    long e1, e2;
  451.  
  452.    e1 = and(tp, trigger);
  453.    while ((*tp)->tok_id == '^') {
  454.       advance_tok(tp);
  455.       e2 = and(tp, trigger);
  456.       e1 = (e1 ^ e2);
  457.       }
  458.    return e1;
  459.    }
  460.  
  461. /*
  462.  * <incl_or> ::= <excl_or> |
  463.  *               <incl_or> '|' <excl_or>
  464.  */
  465. static long incl_or(tp, trigger)
  466. struct token **tp;
  467. struct token *trigger;
  468.    {
  469.    long e1, e2;
  470.  
  471.    e1 = excl_or(tp, trigger);
  472.    while ((*tp)->tok_id == '|') {
  473.       advance_tok(tp);
  474.       e2 = excl_or(tp, trigger);
  475.       e1 = (e1 | e2);
  476.       }
  477.    return e1;
  478.    }
  479.  
  480. /*
  481.  * <log_and> ::= <incl_or> |
  482.  *               <log_and> '&&' <incl_or>
  483.  */
  484. static long log_and(tp, trigger)
  485. struct token **tp;
  486. struct token *trigger;
  487.    {
  488.    long e1, e2;
  489.  
  490.    e1 = incl_or(tp, trigger);
  491.    while ((*tp)->tok_id == And) {
  492.       advance_tok(tp);
  493.       e2 = incl_or(tp, trigger);
  494.       e1 = (e1 && e2);
  495.       }
  496.    return e1;
  497.    }
  498.  
  499. /*
  500.  * <log_or> ::= <log_and> |
  501.  *              <log_or> '||' <log_and>
  502.  */
  503. static long log_or(tp, trigger)
  504. struct token **tp;
  505. struct token *trigger;
  506.    {
  507.    long e1, e2;
  508.  
  509.    e1 = log_and(tp, trigger);
  510.    while ((*tp)->tok_id == Or) {
  511.       advance_tok(tp);
  512.       e2 = log_and(tp, trigger);
  513.       e1 = (e1 || e2);
  514.       }
  515.    return e1;
  516.    }
  517.  
  518. /*
  519.  * <conditional> ::= <log_or> |
  520.  *                   <log_or> '?' <conditional> ':' <conditional>
  521.  */
  522. long conditional(tp, trigger)
  523. struct token **tp;
  524. struct token *trigger;
  525.    {
  526.    long e1, e2, e3;
  527.  
  528.    e1 = log_or(tp, trigger);
  529.    if ((*tp)->tok_id == '?') {
  530.       advance_tok(tp);
  531.       e2 = conditional(tp, trigger);
  532.       if ((*tp)->tok_id != ':')
  533.          errt2(*tp, "expected ':' in conditional of #", trigger->image);
  534.       advance_tok(tp);
  535.       e3 = conditional(tp, trigger);
  536.       return e1 ? e2 : e3;
  537.       }
  538.    else
  539.       return e1;
  540.    }
  541.  
  542. /*
  543.  * eval - get the tokens for a conditional and evaluate it to 0 or 1.
  544.  *  trigger is the preprocessing directive that triggered the evaluation;
  545.  *  it is used for error messages.
  546.  */
  547. int eval(trigger)
  548. struct token *trigger;
  549.    {
  550.    struct token *t = NULL;
  551.    int result;
  552.  
  553.    advance_tok(&t);
  554.    result = (conditional(&t, trigger) != 0L);
  555.    if (t->tok_id != PpDirEnd)
  556.       errt2(t, "expected end of condition of #", trigger->image);
  557.    free_t(t);
  558.    return result;
  559.    }
  560.