home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mdepsrc.zip / ifparser.c < prev    next >
C/C++ Source or Header  |  1996-12-10  |  9KB  |  452 lines

  1. /*
  2.  * $XConsortium: ifparser.c,v 1.7 94/01/18 21:30:50 rws 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.         cp += 7;
  164.         SKIPSPACE (cp);
  165.         if (*cp == '(') {
  166.         paren = 1;
  167.         cp++;
  168.         }
  169.         DO (cp = parse_variable (g, cp, &var));
  170.         SKIPSPACE (cp);
  171.         if (paren && *cp != ')')
  172.         return CALLFUNC(g, handle_error) (g, cp, ")");
  173.         *valp = (*(g->funcs.eval_defined)) (g, var, cp - var);
  174.         return cp + paren;        /* skip the right paren */
  175.     }
  176.     /* fall out */
  177.     }
  178.  
  179.     if (isdigit(*cp)) {
  180.     DO (cp = parse_number (g, cp, valp));
  181.     } else if (!isvarfirstletter(*cp))
  182.     return CALLFUNC(g, handle_error) (g, cp, "variable or number");
  183.     else {
  184.     DO (cp = parse_variable (g, cp, &var));
  185.     *valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
  186.     }
  187.     
  188.     return cp;
  189. }
  190.  
  191.  
  192.  
  193. static const char *
  194. parse_product (g, cp, valp)
  195.     IfParser *g;
  196.     const char *cp;
  197.     int *valp;
  198. {
  199.     int rightval;
  200.  
  201.     DO (cp = parse_value (g, cp, valp));
  202.     SKIPSPACE (cp);
  203.  
  204.     switch (*cp) {
  205.       case '*':
  206.     DO (cp = parse_product (g, cp + 1, &rightval));
  207.     *valp = (*valp * rightval);
  208.     break;
  209.  
  210.       case '/':
  211.     DO (cp = parse_product (g, cp + 1, &rightval));
  212.     *valp = (*valp / rightval);
  213.     break;
  214.  
  215.       case '%':
  216.     DO (cp = parse_product (g, cp + 1, &rightval));
  217.     *valp = (*valp % rightval);
  218.     break;
  219.     }
  220.     return cp;
  221. }
  222.  
  223.  
  224. static const char *
  225. parse_sum (g, cp, valp)
  226.     IfParser *g;
  227.     const char *cp;
  228.     int *valp;
  229. {
  230.     int rightval;
  231.  
  232.     DO (cp = parse_product (g, cp, valp));
  233.     SKIPSPACE (cp);
  234.  
  235.     switch (*cp) {
  236.       case '+':
  237.     DO (cp = parse_sum (g, cp + 1, &rightval));
  238.     *valp = (*valp + rightval);
  239.     break;
  240.  
  241.       case '-':
  242.     DO (cp = parse_sum (g, cp + 1, &rightval));
  243.     *valp = (*valp - rightval);
  244.     break;
  245.     }
  246.     return cp;
  247. }
  248.  
  249.  
  250. static const char *
  251. parse_shift (g, cp, valp)
  252.     IfParser *g;
  253.     const char *cp;
  254.     int *valp;
  255. {
  256.     int rightval;
  257.  
  258.     DO (cp = parse_sum (g, cp, valp));
  259.     SKIPSPACE (cp);
  260.  
  261.     switch (*cp) {
  262.       case '<':
  263.     if (cp[1] == '<') {
  264.         DO (cp = parse_shift (g, cp + 2, &rightval));
  265.         *valp = (*valp << rightval);
  266.     }
  267.     break;
  268.  
  269.       case '>':
  270.     if (cp[1] == '>') {
  271.         DO (cp = parse_shift (g, cp + 2, &rightval));
  272.         *valp = (*valp >> rightval);
  273.     }
  274.     break;
  275.     }
  276.     return cp;
  277. }
  278.  
  279.  
  280. static const char *
  281. parse_inequality (g, cp, valp)
  282.     IfParser *g;
  283.     const char *cp;
  284.     int *valp;
  285. {
  286.     int rightval;
  287.  
  288.     DO (cp = parse_shift (g, cp, valp));
  289.     SKIPSPACE (cp);
  290.  
  291.     switch (*cp) {
  292.       case '<':
  293.     if (cp[1] == '=') {
  294.         DO (cp = parse_inequality (g, cp + 2, &rightval));
  295.         *valp = (*valp <= rightval);
  296.     } else {
  297.         DO (cp = parse_inequality (g, cp + 1, &rightval));
  298.         *valp = (*valp < rightval);
  299.     }
  300.     break;
  301.  
  302.       case '>':
  303.     if (cp[1] == '=') {
  304.         DO (cp = parse_inequality (g, cp + 2, &rightval));
  305.         *valp = (*valp >= rightval);
  306.     } else {
  307.         DO (cp = parse_inequality (g, cp + 1, &rightval));
  308.         *valp = (*valp > rightval);
  309.     }
  310.     break;
  311.     }
  312.     return cp;
  313. }
  314.  
  315.  
  316. static const char *
  317. parse_equality (g, cp, valp)
  318.     IfParser *g;
  319.     const char *cp;
  320.     int *valp;
  321. {
  322.     int rightval;
  323.  
  324.     DO (cp = parse_inequality (g, cp, valp));
  325.     SKIPSPACE (cp);
  326.  
  327.     switch (*cp) {
  328.       case '=':
  329.     if (cp[1] == '=')
  330.         cp++;
  331.     DO (cp = parse_equality (g, cp + 1, &rightval));
  332.     *valp = (*valp == rightval);
  333.     break;
  334.  
  335.       case '!':
  336.     if (cp[1] != '=')
  337.         break;
  338.     DO (cp = parse_equality (g, cp + 2, &rightval));
  339.     *valp = (*valp != rightval);
  340.     break;
  341.     }
  342.     return cp;
  343. }
  344.  
  345.  
  346. static const char *
  347. parse_band (g, cp, valp)
  348.     IfParser *g;
  349.     const char *cp;
  350.     int *valp;
  351. {
  352.     int rightval;
  353.  
  354.     DO (cp = parse_equality (g, cp, valp));
  355.     SKIPSPACE (cp);
  356.  
  357.     switch (*cp) {
  358.       case '&':
  359.     if (cp[1] != '&') {
  360.         DO (cp = parse_band (g, cp + 1, &rightval));
  361.         *valp = (*valp & rightval);
  362.     }
  363.     break;
  364.     }
  365.     return cp;
  366. }
  367.  
  368.  
  369. static const char *
  370. parse_bor (g, cp, valp)
  371.     IfParser *g;
  372.     const char *cp;
  373.     int *valp;
  374. {
  375.     int rightval;
  376.  
  377.     DO (cp = parse_band (g, cp, valp));
  378.     SKIPSPACE (cp);
  379.  
  380.     switch (*cp) {
  381.       case '|':
  382.     if (cp[1] != '|') {
  383.         DO (cp = parse_bor (g, cp + 1, &rightval));
  384.         *valp = (*valp | rightval);
  385.     }
  386.     break;
  387.     }
  388.     return cp;
  389. }
  390.  
  391.  
  392. static const char *
  393. parse_land (g, cp, valp)
  394.     IfParser *g;
  395.     const char *cp;
  396.     int *valp;
  397. {
  398.     int rightval;
  399.  
  400.     DO (cp = parse_bor (g, cp, valp));
  401.     SKIPSPACE (cp);
  402.  
  403.     switch (*cp) {
  404.       case '&':
  405.     if (cp[1] != '&')
  406.         return CALLFUNC(g, handle_error) (g, cp, "&&");
  407.     DO (cp = parse_land (g, cp + 2, &rightval));
  408.     *valp = (*valp && rightval);
  409.     break;
  410.     }
  411.     return cp;
  412. }
  413.  
  414.  
  415. static const char *
  416. parse_lor (g, cp, valp)
  417.     IfParser *g;
  418.     const char *cp;
  419.     int *valp;
  420. {
  421.     int rightval;
  422.  
  423.     DO (cp = parse_land (g, cp, valp));
  424.     SKIPSPACE (cp);
  425.  
  426.     switch (*cp) {
  427.       case '|':
  428.     if (cp[1] != '|')
  429.         return CALLFUNC(g, handle_error) (g, cp, "||");
  430.     DO (cp = parse_lor (g, cp + 2, &rightval));
  431.     *valp = (*valp || rightval);
  432.     break;
  433.     }
  434.     return cp;
  435. }
  436.  
  437.  
  438. /****************************************************************************
  439.                  External Entry Points
  440.  ****************************************************************************/
  441.  
  442. const char *
  443. ParseIfExpression (g, cp, valp)
  444.     IfParser *g;
  445.     const char *cp;
  446.     int *valp;
  447. {
  448.     return parse_lor (g, cp, valp);
  449. }
  450.  
  451.  
  452.