home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / config / mkdepend / ifparser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  9.8 KB  |  459 lines

  1. /*
  2.  * $XConsortium: ifparser.c,v 1.8 95/06/03 00:01:41 gildea Exp $
  3.  *
  4.  * Copyright 1992 Network Computing Devices, Inc.
  5.  * 
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for any purpose and without fee is hereby granted, provided
  8.  * that the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of Network Computing Devices may not be
  11.  * used in advertising or publicity pertaining to distribution of the software
  12.  * without specific, written prior permission.  Network Computing Devices makes
  13.  * no representations about the suitability of this software for any purpose.
  14.  * It is provided ``as is'' without express or implied warranty.
  15.  * 
  16.  * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  17.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  18.  * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
  19.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  20.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  21.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  22.  * PERFORMANCE OF THIS SOFTWARE.
  23.  * 
  24.  * Author:  Jim Fulton
  25.  *          Network Computing Devices, Inc.
  26.  * 
  27.  * Simple if statement processor
  28.  *
  29.  * This module can be used to evaluate string representations of C language
  30.  * if constructs.  It accepts the following grammar:
  31.  * 
  32.  *     EXPRESSION    :=    VALUE
  33.  *              |    VALUE  BINOP    EXPRESSION
  34.  * 
  35.  *     VALUE        :=    '('  EXPRESSION  ')'
  36.  *              |    '!'  VALUE
  37.  *              |    '-'  VALUE
  38.  *              |    'defined'  '('  variable  ')'
  39.  *              |    'defined'  variable
  40.  *             |    # variable '(' variable-list ')'
  41.  *              |    variable
  42.  *              |    number
  43.  * 
  44.  *     BINOP        :=    '*'    |  '/'    |  '%'
  45.  *              |    '+'    |  '-'
  46.  *              |    '<<'    |  '>>'
  47.  *              |    '<'    |  '>'    |  '<='  |  '>='
  48.  *              |    '=='    |  '!='
  49.  *              |    '&'    |  '|'
  50.  *              |    '&&'    |  '||'
  51.  * 
  52.  * The normal C order of precidence is supported.
  53.  * 
  54.  * 
  55.  * External Entry Points:
  56.  * 
  57.  *     ParseIfExpression        parse a string for #if
  58.  */
  59.  
  60. #include "ifparser.h"
  61. #include <ctype.h>
  62.  
  63. /****************************************************************************
  64.            Internal Macros and Utilities for Parser
  65.  ****************************************************************************/
  66.  
  67. #define DO(val) if (!(val)) return NULL
  68. #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
  69. #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
  70. #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
  71.  
  72.  
  73. static const char *
  74. parse_variable (g, cp, varp)
  75.     IfParser *g;
  76.     const char *cp;
  77.     const char **varp;
  78. {
  79.     SKIPSPACE (cp);
  80.  
  81.     if (!isvarfirstletter (*cp))
  82.     return CALLFUNC(g, handle_error) (g, cp, "variable name");
  83.  
  84.     *varp = cp;
  85.     /* EMPTY */
  86.     for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
  87.     return cp;
  88. }
  89.  
  90.  
  91. static const char *
  92. parse_number (g, cp, valp)
  93.     IfParser *g;
  94.     const char *cp;
  95.     int *valp;
  96. {
  97.     SKIPSPACE (cp);
  98.  
  99.     if (!isdigit(*cp))
  100.     return CALLFUNC(g, handle_error) (g, cp, "number");
  101.  
  102. #ifdef WIN32
  103.     *valp = strtol(cp, &cp, 0);
  104. #else
  105.     *valp = atoi (cp);
  106.     /* EMPTY */
  107.     for (cp++; isdigit(*cp); cp++) ;
  108. #endif
  109.     return cp;
  110. }
  111.  
  112.  
  113. static const char *
  114. parse_value (g, cp, valp)
  115.     IfParser *g;
  116.     const char *cp;
  117.     int *valp;
  118. {
  119.     const char *var;
  120.  
  121.     *valp = 0;
  122.  
  123.     SKIPSPACE (cp);
  124.     if (!*cp)
  125.     return cp;
  126.  
  127.     switch (*cp) {
  128.       case '(':
  129.     DO (cp = ParseIfExpression (g, cp + 1, valp));
  130.     SKIPSPACE (cp);
  131.     if (*cp != ')') 
  132.         return CALLFUNC(g, handle_error) (g, cp, ")");
  133.  
  134.     return cp + 1;            /* skip the right paren */
  135.  
  136.       case '!':
  137.     DO (cp = parse_value (g, cp + 1, valp));
  138.     *valp = !(*valp);
  139.     return cp;
  140.  
  141.       case '-':
  142.     DO (cp = parse_value (g, cp + 1, valp));
  143.     *valp = -(*valp);
  144.     return cp;
  145.  
  146.       case '#':
  147.     DO (cp = parse_variable (g, cp + 1, &var));
  148.     SKIPSPACE (cp);
  149.     if (*cp != '(')
  150.         return CALLFUNC(g, handle_error) (g, cp, "(");
  151.     do {
  152.         DO (cp = parse_variable (g, cp + 1, &var));
  153.         SKIPSPACE (cp);
  154.     } while (*cp && *cp != ')');
  155.     if (*cp != ')')
  156.         return CALLFUNC(g, handle_error) (g, cp, ")");
  157.     *valp = 1; /* XXX */
  158.     return cp + 1;
  159.  
  160.       case 'd':
  161.     if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
  162.         int paren = 0;
  163.         int len;
  164.  
  165.         cp += 7;
  166.         SKIPSPACE (cp);
  167.         if (*cp == '(') {
  168.         paren = 1;
  169.         cp++;
  170.         }
  171.         DO (cp = parse_variable (g, cp, &var));
  172.         len = cp - var;
  173.         SKIPSPACE (cp);
  174.         if (paren && *cp != ')')
  175.         return CALLFUNC(g, handle_error) (g, cp, ")");
  176.         *valp = (*(g->funcs.eval_defined)) (g, var, len);
  177.         return cp + paren;        /* skip the right paren */
  178.     }
  179.     /* fall out */
  180.     }
  181.  
  182.     if (isdigit(*cp)) {
  183.     DO (cp = parse_number (g, cp, valp));
  184.     } else if (!isvarfirstletter(*cp))
  185.     return CALLFUNC(g, handle_error) (g, cp, "variable or number");
  186.     else {
  187.     DO (cp = parse_variable (g, cp, &var));
  188.     *valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
  189.     }
  190.     
  191.     return cp;
  192. }
  193.  
  194.  
  195.  
  196. static const char *
  197. parse_product (g, cp, valp)
  198.     IfParser *g;
  199.     const char *cp;
  200.     int *valp;
  201. {
  202.     int rightval;
  203.  
  204.     DO (cp = parse_value (g, cp, valp));
  205.     SKIPSPACE (cp);
  206.  
  207.     switch (*cp) {
  208.       case '*':
  209.     DO (cp = parse_product (g, cp + 1, &rightval));
  210.     *valp = (*valp * rightval);
  211.     break;
  212.  
  213.       case '/':
  214.     DO (cp = parse_product (g, cp + 1, &rightval));
  215.  
  216.     /* Do nothing in the divide-by-zero case. */
  217.     if (rightval) {
  218.         *valp = (*valp / rightval);
  219.     }
  220.     break;
  221.  
  222.       case '%':
  223.     DO (cp = parse_product (g, cp + 1, &rightval));
  224.     *valp = (*valp % rightval);
  225.     break;
  226.     }
  227.     return cp;
  228. }
  229.  
  230.  
  231. static const char *
  232. parse_sum (g, cp, valp)
  233.     IfParser *g;
  234.     const char *cp;
  235.     int *valp;
  236. {
  237.     int rightval;
  238.  
  239.     DO (cp = parse_product (g, cp, valp));
  240.     SKIPSPACE (cp);
  241.  
  242.     switch (*cp) {
  243.       case '+':
  244.     DO (cp = parse_sum (g, cp + 1, &rightval));
  245.     *valp = (*valp + rightval);
  246.     break;
  247.  
  248.       case '-':
  249.     DO (cp = parse_sum (g, cp + 1, &rightval));
  250.     *valp = (*valp - rightval);
  251.     break;
  252.     }
  253.     return cp;
  254. }
  255.  
  256.  
  257. static const char *
  258. parse_shift (g, cp, valp)
  259.     IfParser *g;
  260.     const char *cp;
  261.     int *valp;
  262. {
  263.     int rightval;
  264.  
  265.     DO (cp = parse_sum (g, cp, valp));
  266.     SKIPSPACE (cp);
  267.  
  268.     switch (*cp) {
  269.       case '<':
  270.     if (cp[1] == '<') {
  271.         DO (cp = parse_shift (g, cp + 2, &rightval));
  272.         *valp = (*valp << rightval);
  273.     }
  274.     break;
  275.  
  276.       case '>':
  277.     if (cp[1] == '>') {
  278.         DO (cp = parse_shift (g, cp + 2, &rightval));
  279.         *valp = (*valp >> rightval);
  280.     }
  281.     break;
  282.     }
  283.     return cp;
  284. }
  285.  
  286.  
  287. static const char *
  288. parse_inequality (g, cp, valp)
  289.     IfParser *g;
  290.     const char *cp;
  291.     int *valp;
  292. {
  293.     int rightval;
  294.  
  295.     DO (cp = parse_shift (g, cp, valp));
  296.     SKIPSPACE (cp);
  297.  
  298.     switch (*cp) {
  299.       case '<':
  300.     if (cp[1] == '=') {
  301.         DO (cp = parse_inequality (g, cp + 2, &rightval));
  302.         *valp = (*valp <= rightval);
  303.     } else {
  304.         DO (cp = parse_inequality (g, cp + 1, &rightval));
  305.         *valp = (*valp < rightval);
  306.     }
  307.     break;
  308.  
  309.       case '>':
  310.     if (cp[1] == '=') {
  311.         DO (cp = parse_inequality (g, cp + 2, &rightval));
  312.         *valp = (*valp >= rightval);
  313.     } else {
  314.         DO (cp = parse_inequality (g, cp + 1, &rightval));
  315.         *valp = (*valp > rightval);
  316.     }
  317.     break;
  318.     }
  319.     return cp;
  320. }
  321.  
  322.  
  323. static const char *
  324. parse_equality (g, cp, valp)
  325.     IfParser *g;
  326.     const char *cp;
  327.     int *valp;
  328. {
  329.     int rightval;
  330.  
  331.     DO (cp = parse_inequality (g, cp, valp));
  332.     SKIPSPACE (cp);
  333.  
  334.     switch (*cp) {
  335.       case '=':
  336.     if (cp[1] == '=')
  337.         cp++;
  338.     DO (cp = parse_equality (g, cp + 1, &rightval));
  339.     *valp = (*valp == rightval);
  340.     break;
  341.  
  342.       case '!':
  343.     if (cp[1] != '=')
  344.         break;
  345.     DO (cp = parse_equality (g, cp + 2, &rightval));
  346.     *valp = (*valp != rightval);
  347.     break;
  348.     }
  349.     return cp;
  350. }
  351.  
  352.  
  353. static const char *
  354. parse_band (g, cp, valp)
  355.     IfParser *g;
  356.     const char *cp;
  357.     int *valp;
  358. {
  359.     int rightval;
  360.  
  361.     DO (cp = parse_equality (g, cp, valp));
  362.     SKIPSPACE (cp);
  363.  
  364.     switch (*cp) {
  365.       case '&':
  366.     if (cp[1] != '&') {
  367.         DO (cp = parse_band (g, cp + 1, &rightval));
  368.         *valp = (*valp & rightval);
  369.     }
  370.     break;
  371.     }
  372.     return cp;
  373. }
  374.  
  375.  
  376. static const char *
  377. parse_bor (g, cp, valp)
  378.     IfParser *g;
  379.     const char *cp;
  380.     int *valp;
  381. {
  382.     int rightval;
  383.  
  384.     DO (cp = parse_band (g, cp, valp));
  385.     SKIPSPACE (cp);
  386.  
  387.     switch (*cp) {
  388.       case '|':
  389.     if (cp[1] != '|') {
  390.         DO (cp = parse_bor (g, cp + 1, &rightval));
  391.         *valp = (*valp | rightval);
  392.     }
  393.     break;
  394.     }
  395.     return cp;
  396. }
  397.  
  398.  
  399. static const char *
  400. parse_land (g, cp, valp)
  401.     IfParser *g;
  402.     const char *cp;
  403.     int *valp;
  404. {
  405.     int rightval;
  406.  
  407.     DO (cp = parse_bor (g, cp, valp));
  408.     SKIPSPACE (cp);
  409.  
  410.     switch (*cp) {
  411.       case '&':
  412.     if (cp[1] != '&')
  413.         return CALLFUNC(g, handle_error) (g, cp, "&&");
  414.     DO (cp = parse_land (g, cp + 2, &rightval));
  415.     *valp = (*valp && rightval);
  416.     break;
  417.     }
  418.     return cp;
  419. }
  420.  
  421.  
  422. static const char *
  423. parse_lor (g, cp, valp)
  424.     IfParser *g;
  425.     const char *cp;
  426.     int *valp;
  427. {
  428.     int rightval;
  429.  
  430.     DO (cp = parse_land (g, cp, valp));
  431.     SKIPSPACE (cp);
  432.  
  433.     switch (*cp) {
  434.       case '|':
  435.     if (cp[1] != '|')
  436.         return CALLFUNC(g, handle_error) (g, cp, "||");
  437.     DO (cp = parse_lor (g, cp + 2, &rightval));
  438.     *valp = (*valp || rightval);
  439.     break;
  440.     }
  441.     return cp;
  442. }
  443.  
  444.  
  445. /****************************************************************************
  446.                  External Entry Points
  447.  ****************************************************************************/
  448.  
  449. const char *
  450. ParseIfExpression (g, cp, valp)
  451.     IfParser *g;
  452.     const char *cp;
  453.     int *valp;
  454. {
  455.     return parse_lor (g, cp, valp);
  456. }
  457.  
  458.  
  459.