home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / preproc / evaluate.c < prev    next >
C/C++ Source or Header  |  2001-12-12  |  15KB  |  562 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. static long primary        (struct token **tp, struct token *trigger);
  15. static long unary          (struct token **tp, struct token *trigger);
  16. static long multiplicative (struct token **tp, struct token *trigger);
  17. static long additive       (struct token **tp, struct token *trigger);
  18. static long shift          (struct token **tp, struct token *trigger);
  19. static long relation       (struct token **tp, struct token *trigger);
  20. static long equality       (struct token **tp, struct token *trigger);
  21. static long and            (struct token **tp, struct token *trigger);
  22. static long excl_or        (struct token **tp, struct token *trigger);
  23. static long incl_or        (struct token **tp, struct token *trigger);
  24. static long log_and        (struct token **tp, struct token *trigger);
  25. static long log_or         (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.    /*NOTREACHED*/
  243.    return 0;  /* avoid gcc warning */
  244.    }
  245.  
  246. /*
  247.  * <unary> ::= <primary> |
  248.  *             '+' <unary> |
  249.  *             '-' <unary> |
  250.  *             '~' <unary> |
  251.  *             '!' <unary>
  252.  */
  253. static long unary(tp, trigger)
  254. struct token **tp;
  255. struct token *trigger;
  256.    {
  257.    switch ((*tp)->tok_id) {
  258.       case '+':
  259.          advance_tok(tp);
  260.          return unary(tp, trigger);
  261.       case '-':
  262.          advance_tok(tp);
  263.          return -unary(tp, trigger);
  264.       case '~':
  265.          advance_tok(tp);
  266.          return ~unary(tp, trigger);
  267.       case '!':
  268.          advance_tok(tp);
  269.          return !unary(tp, trigger);
  270.       default:
  271.          return primary(tp, trigger);
  272.       }
  273.    }
  274.  
  275. /*
  276.  * <multiplicative> ::= <unary> |
  277.  *                      <multiplicative> '*' <unary> |
  278.  *                      <multiplicative> '/' <unary> |
  279.  *                      <multiplicative> '%' <unary>
  280.  */
  281. static long multiplicative(tp, trigger)
  282. struct token **tp;
  283. struct token *trigger;
  284.    {
  285.    long e1, e2;
  286.    int tok_id;
  287.  
  288.    e1 = unary(tp, trigger);
  289.    tok_id = (*tp)->tok_id;
  290.    while (tok_id == '*' || tok_id == '/' || tok_id == '%') {
  291.       advance_tok(tp);
  292.       e2 = unary(tp, trigger);
  293.       switch (tok_id) {
  294.          case '*':
  295.             e1 = (e1 * e2);
  296.             break;
  297.          case '/':
  298.             e1 = (e1 / e2);
  299.             break;
  300.          case '%':
  301.             e1 = (e1 % e2);
  302.             break;
  303.          }
  304.       tok_id = (*tp)->tok_id;
  305.       }
  306.    return e1;
  307.    }
  308.  
  309. /*
  310.  * <additive> ::= <multiplicative> |
  311.  *                <additive> '+' <multiplicative> |
  312.  *                <additive> '-' <multiplicative>
  313.  */
  314. static long additive(tp, trigger)
  315. struct token **tp;
  316. struct token *trigger;
  317.    {
  318.    long e1, e2;
  319.    int tok_id;
  320.  
  321.    e1 = multiplicative(tp, trigger);
  322.    tok_id = (*tp)->tok_id;
  323.    while (tok_id == '+' || tok_id == '-') {
  324.       advance_tok(tp);
  325.       e2 = multiplicative(tp, trigger);
  326.       if (tok_id == '+')
  327.          e1 = (e1 + e2);
  328.       else
  329.          e1 = (e1 - e2);
  330.       tok_id = (*tp)->tok_id;
  331.       }
  332.    return e1;
  333.    }
  334.  
  335. /*
  336.  * <shift> ::= <additive> |
  337.  *             <shift> '<<' <additive> |
  338.  *             <shift> '>>' <additive>
  339.  */
  340. static long shift(tp, trigger)
  341. struct token **tp;
  342. struct token *trigger;
  343.    {
  344.    long e1, e2;
  345.    int tok_id;
  346.  
  347.    e1 = additive(tp, trigger);
  348.    tok_id = (*tp)->tok_id;
  349.    while (tok_id == LShft || tok_id == RShft) {
  350.       advance_tok(tp);
  351.       e2 = additive(tp, trigger);
  352.       if (tok_id == LShft)
  353.          e1 = (e1 << e2);
  354.       else
  355.          e1 = (e1 >> e2);
  356.       tok_id = (*tp)->tok_id;
  357.       }
  358.    return e1;
  359.    }
  360.  
  361. /*
  362.  * <relation> ::= <shift> |
  363.  *                <relation> '<' <shift> |
  364.  *                <relation> '<=' <shift> |
  365.  *                <relation> '>' <shift> |
  366.  *                <relation> '>=' <shift>
  367.  */
  368. static long relation(tp, trigger)
  369. struct token **tp;
  370. struct token *trigger;
  371.    {
  372.    long e1, e2;
  373.    int tok_id;
  374.  
  375.    e1 = shift(tp, trigger);
  376.    tok_id = (*tp)->tok_id;
  377.    while (tok_id == '<' || tok_id == Leq || tok_id == '>' || tok_id == Geq) {
  378.       advance_tok(tp);
  379.       e2 = shift(tp, trigger);
  380.       switch (tok_id) {
  381.          case '<':
  382.             e1 = (e1 < e2);
  383.             break;
  384.          case Leq:
  385.             e1 = (e1 <= e2);
  386.             break;
  387.          case '>':
  388.             e1 = (e1 > e2);
  389.             break;
  390.          case Geq:
  391.             e1 = (e1 >= e2);
  392.             break;
  393.          }
  394.       tok_id = (*tp)->tok_id;
  395.       }
  396.    return e1;
  397.    }
  398.  
  399. /*
  400.  * <equality> ::= <relation> |
  401.  *                <equality> '==' <relation> |
  402.  *                <equality> '!=' <relation>
  403.  */
  404. static long equality(tp, trigger)
  405. struct token **tp;
  406. struct token *trigger;
  407.    {
  408.    long e1, e2;
  409.    int tok_id;
  410.  
  411.    e1 = relation(tp, trigger);
  412.    tok_id = (*tp)->tok_id;
  413.    while (tok_id == TokEqual || tok_id == Neq) {
  414.       advance_tok(tp);
  415.       e2 = relation(tp, trigger);
  416.       if (tok_id == TokEqual)
  417.          e1 = (e1 == e2);
  418.       else
  419.          e1 = (e1 != e2);
  420.       tok_id = (*tp)->tok_id;
  421.       }
  422.    return e1;
  423.    }
  424.  
  425. /*
  426.  * <and> ::= <equality> |
  427.  *           <and> '&' <equality>
  428.  */
  429. static long and(tp, trigger)
  430. struct token **tp;
  431. struct token *trigger;
  432.    {
  433.    long e1, e2;
  434.  
  435.    e1 = equality(tp, trigger);
  436.    while ((*tp)->tok_id == '&') {
  437.       advance_tok(tp);
  438.       e2 = equality(tp, trigger);
  439.       e1 = (e1 & e2);
  440.       }
  441.    return e1;
  442.    }
  443.  
  444. /*
  445.  * <excl_or> ::= <and> |
  446.  *               <excl_or> '^' <and>
  447.  */
  448. static long excl_or(tp, trigger)
  449. struct token **tp;
  450. struct token *trigger;
  451.    {
  452.    long e1, e2;
  453.  
  454.    e1 = and(tp, trigger);
  455.    while ((*tp)->tok_id == '^') {
  456.       advance_tok(tp);
  457.       e2 = and(tp, trigger);
  458.       e1 = (e1 ^ e2);
  459.       }
  460.    return e1;
  461.    }
  462.  
  463. /*
  464.  * <incl_or> ::= <excl_or> |
  465.  *               <incl_or> '|' <excl_or>
  466.  */
  467. static long incl_or(tp, trigger)
  468. struct token **tp;
  469. struct token *trigger;
  470.    {
  471.    long e1, e2;
  472.  
  473.    e1 = excl_or(tp, trigger);
  474.    while ((*tp)->tok_id == '|') {
  475.       advance_tok(tp);
  476.       e2 = excl_or(tp, trigger);
  477.       e1 = (e1 | e2);
  478.       }
  479.    return e1;
  480.    }
  481.  
  482. /*
  483.  * <log_and> ::= <incl_or> |
  484.  *               <log_and> '&&' <incl_or>
  485.  */
  486. static long log_and(tp, trigger)
  487. struct token **tp;
  488. struct token *trigger;
  489.    {
  490.    long e1, e2;
  491.  
  492.    e1 = incl_or(tp, trigger);
  493.    while ((*tp)->tok_id == And) {
  494.       advance_tok(tp);
  495.       e2 = incl_or(tp, trigger);
  496.       e1 = (e1 && e2);
  497.       }
  498.    return e1;
  499.    }
  500.  
  501. /*
  502.  * <log_or> ::= <log_and> |
  503.  *              <log_or> '||' <log_and>
  504.  */
  505. static long log_or(tp, trigger)
  506. struct token **tp;
  507. struct token *trigger;
  508.    {
  509.    long e1, e2;
  510.  
  511.    e1 = log_and(tp, trigger);
  512.    while ((*tp)->tok_id == Or) {
  513.       advance_tok(tp);
  514.       e2 = log_and(tp, trigger);
  515.       e1 = (e1 || e2);
  516.       }
  517.    return e1;
  518.    }
  519.  
  520. /*
  521.  * <conditional> ::= <log_or> |
  522.  *                   <log_or> '?' <conditional> ':' <conditional>
  523.  */
  524. long conditional(tp, trigger)
  525. struct token **tp;
  526. struct token *trigger;
  527.    {
  528.    long e1, e2, e3;
  529.  
  530.    e1 = log_or(tp, trigger);
  531.    if ((*tp)->tok_id == '?') {
  532.       advance_tok(tp);
  533.       e2 = conditional(tp, trigger);
  534.       if ((*tp)->tok_id != ':')
  535.          errt2(*tp, "expected ':' in conditional of #", trigger->image);
  536.       advance_tok(tp);
  537.       e3 = conditional(tp, trigger);
  538.       return e1 ? e2 : e3;
  539.       }
  540.    else
  541.       return e1;
  542.    }
  543.  
  544. /*
  545.  * eval - get the tokens for a conditional and evaluate it to 0 or 1.
  546.  *  trigger is the preprocessing directive that triggered the evaluation;
  547.  *  it is used for error messages.
  548.  */
  549. int eval(trigger)
  550. struct token *trigger;
  551.    {
  552.    struct token *t = NULL;
  553.    int result;
  554.  
  555.    advance_tok(&t);
  556.    result = (conditional(&t, trigger) != 0L);
  557.    if (t->tok_id != PpDirEnd)
  558.       errt2(t, "expected end of condition of #", trigger->image);
  559.    free_t(t);
  560.    return result;
  561.    }
  562.