ifparser.c

Go to the documentation of this file.
00001 /*
00002  * $XConsortium: ifparser.c /main/10 1996/09/28 16:15:18 rws $
00003  * $XFree86: xc/config/makedepend/ifparser.c,v 3.6 1996/12/30 13:57:55 dawes Exp $
00004  *
00005  * Copyright 1992 Network Computing Devices, Inc.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and its
00008  * documentation for any purpose and without fee is hereby granted, provided
00009  * that the above copyright notice appear in all copies and that both that
00010  * copyright notice and this permission notice appear in supporting
00011  * documentation, and that the name of Network Computing Devices may not be
00012  * used in advertising or publicity pertaining to distribution of the software
00013  * without specific, written prior permission.  Network Computing Devices makes
00014  * no representations about the suitability of this software for any purpose.
00015  * It is provided ``as is'' without express or implied warranty.
00016  *
00017  * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
00018  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
00019  * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
00020  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00021  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00022  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00023  * PERFORMANCE OF THIS SOFTWARE.
00024  *
00025  * Author:  Jim Fulton
00026  *          Network Computing Devices, Inc.
00027  *
00028  * Simple if statement processor
00029  *
00030  * This module can be used to evaluate string representations of C language
00031  * if constructs.  It accepts the following grammar:
00032  *
00033  *     EXPRESSION := VALUE
00034  *     | VALUE  BINOP EXPRESSION
00035  *     | VALUE '?' EXPRESSION ':' EXPRESSION
00036  *
00037  *     VALUE  := '('  EXPRESSION  ')'
00038  *     | '!'  VALUE
00039  *     | '-'  VALUE
00040  *     | '~'  VALUE
00041  *     | 'defined'  '('  variable  ')'
00042  *     | 'defined'  variable
00043  *     | # variable '(' variable-list ')'
00044  *     | variable
00045  *     | number
00046  *
00047  *     BINOP  := '*' |  '/' |  '%'
00048  *     | '+' |  '-'
00049  *     | '<<' |  '>>'
00050  *     | '<' |  '>' |  '<='  |  '>='
00051  *     | '==' |  '!='
00052  *     | '&' |  '^'  |  '|'
00053  *     | '&&' |  '||'
00054  *
00055  * The normal C order of precedence is supported.
00056  *
00057  *
00058  * External Entry Points:
00059  *
00060  *     ParseIfExpression  parse a string for #if
00061  */
00062 
00063 #include "ifparser.h"
00064 #include <ctype.h>
00065 #include <string.h>
00066 
00067 extern long strtol(const char *nptr, char **endptr, int base);
00068 
00069 /****************************************************************************
00070      Internal Macros and Utilities for Parser
00071  ****************************************************************************/
00072 
00073 #define DO(val) if (!(val)) return NULL
00074 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
00075 #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
00076 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
00077 
00078 
00079 static const char *
00080 parse_variable(g, cp, varp)
00081 IfParser *g;
00082 const char *cp;
00083 const char **varp;
00084 {
00085    SKIPSPACE(cp);
00086 
00087    if (!isvarfirstletter(*cp))
00088       return CALLFUNC(g, handle_error)(g, cp, "variable name");
00089 
00090    *varp = cp;
00091    /* EMPTY */
00092    for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
00093    return cp;
00094 }
00095 
00096 
00097 static const char *
00098 parse_number(g, cp, valp)
00099 IfParser *g;
00100 const char *cp;
00101 long *valp;
00102 {
00103    SKIPSPACE(cp);
00104 
00105    if (!isdigit(*cp))
00106       return CALLFUNC(g, handle_error)(g, cp, "number");
00107 
00108    *valp = strtol(cp, &cp, 0);
00109    /* skip trailing qualifiers */
00110    while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++;
00111 #if 0
00112    *valp = atoi(cp);
00113    /* EMPTY */
00114    for (cp++; isdigit(*cp); cp++) ;
00115 #endif
00116    return cp;
00117 }
00118 
00119 static const char *
00120 parse_character(g, cp, valp)
00121 IfParser *g;
00122 const char *cp;
00123 long *valp;
00124 {
00125    char val;
00126    if (g) { }   /* use argument */
00127 
00128    SKIPSPACE(cp);
00129    if (*cp == '\\')
00130       switch (cp[1]) {
00131          case 'n':
00132             val = '\n';
00133             break;
00134          case 't':
00135             val = '\t';
00136             break;
00137          case 'v':
00138             val = '\v';
00139             break;
00140          case 'b':
00141             val = '\b';
00142             break;
00143          case 'r':
00144             val = '\r';
00145             break;
00146          case 'f':
00147             val = '\f';
00148             break;
00149          case 'a':
00150             val = '\a';
00151             break;
00152          case '\\':
00153             val = '\\';
00154             break;
00155          case '?':
00156             val = '\?';
00157             break;
00158          case '\'':
00159             val = '\'';
00160             break;
00161          case '\"':
00162             val = '\"';
00163             break;
00164          case 'x':
00165             val = (char) strtol(cp + 2, NULL, 16);
00166             break;
00167          default:
00168             val = (char) strtol(cp + 1, NULL, 8);
00169             break;
00170       }
00171    else
00172       val = *cp;
00173    while (*cp != '\'') cp++;
00174    *valp = (long) val;
00175    return cp;
00176 }
00177 
00178 static const char *
00179 parse_value(g, cp, valp)
00180 IfParser *g;
00181 const char *cp;
00182 long *valp;
00183 {
00184    const char *var;
00185 
00186    *valp = 0;
00187 
00188    SKIPSPACE(cp);
00189    if (!*cp)
00190       return cp;
00191 
00192    switch (*cp) {
00193       case '(':
00194          DO(cp = ParseIfExpression(g, cp + 1, valp));
00195          SKIPSPACE(cp);
00196          if (*cp != ')')
00197             return CALLFUNC(g, handle_error)(g, cp, ")");
00198 
00199          return cp + 1;   /* skip the right paren */
00200 
00201       case '!':
00202          DO(cp = parse_value(g, cp + 1, valp));
00203          *valp = !(*valp);
00204          return cp;
00205 
00206       case '-':
00207          DO(cp = parse_value(g, cp + 1, valp));
00208          *valp = -(*valp);
00209          return cp;
00210 
00211       case '~':
00212          DO(cp = parse_value(g, cp + 1, valp));
00213          *valp = ~(*valp);
00214          return cp;
00215 
00216       case '#':
00217          DO(cp = parse_variable(g, cp + 1, &var));
00218          SKIPSPACE(cp);
00219          if (*cp != '(')
00220             return CALLFUNC(g, handle_error)(g, cp, "(");
00221          do {
00222             DO(cp = parse_variable(g, cp + 1, &var));
00223             SKIPSPACE(cp);
00224          } while (*cp && *cp != ')');
00225          if (*cp != ')')
00226             return CALLFUNC(g, handle_error)(g, cp, ")");
00227          *valp = 1; /* XXX */
00228          return cp + 1;
00229 
00230       case '\'':
00231          DO(cp = parse_character(g, cp + 1, valp));
00232          if (*cp != '\'')
00233             return CALLFUNC(g, handle_error)(g, cp, "'");
00234          return cp + 1;
00235 
00236       case 'd':
00237          if (strncmp(cp, "defined", 7) == 0 && !isalnum(cp[7])) {
00238             int paren = 0;
00239             int len;
00240 
00241             cp += 7;
00242             SKIPSPACE(cp);
00243             if (*cp == '(') {
00244                paren = 1;
00245                cp++;
00246             }
00247             DO(cp = parse_variable(g, cp, &var));
00248             len = cp - var;
00249             SKIPSPACE(cp);
00250             if (paren && *cp != ')')
00251                return CALLFUNC(g, handle_error)(g, cp, ")");
00252             *valp = (*(g->funcs.eval_defined))(g, var, len);
00253             return cp + paren;  /* skip the right paren */
00254          }
00255          /* fall out */
00256    }
00257 
00258    if (isdigit(*cp)) {
00259       DO(cp = parse_number(g, cp, valp));
00260    } else if (!isvarfirstletter(*cp))
00261       return CALLFUNC(g, handle_error)(g, cp, "variable or number");
00262    else {
00263       DO(cp = parse_variable(g, cp, &var));
00264       *valp = (*(g->funcs.eval_variable))(g, var, cp - var);
00265    }
00266 
00267    return cp;
00268 }
00269 
00270 
00271 
00272 static const char *
00273 parse_product(g, cp, valp)
00274 IfParser *g;
00275 const char *cp;
00276 long *valp;
00277 {
00278    long rightval;
00279 
00280    DO(cp = parse_value(g, cp, valp));
00281    SKIPSPACE(cp);
00282 
00283    switch (*cp) {
00284       case '*':
00285          DO(cp = parse_product(g, cp + 1, &rightval));
00286          *valp = (*valp * rightval);
00287          break;
00288 
00289       case '/':
00290          DO(cp = parse_product(g, cp + 1, &rightval));
00291          if (rightval)
00292             *valp = (*valp / rightval);
00293          break;
00294 
00295       case '%':
00296          DO(cp = parse_product(g, cp + 1, &rightval));
00297          if (rightval)
00298             *valp = (*valp % rightval);
00299          break;
00300    }
00301    return cp;
00302 }
00303 
00304 
00305 static const char *
00306 parse_sum(g, cp, valp)
00307 IfParser *g;
00308 const char *cp;
00309 long *valp;
00310 {
00311    long rightval;
00312 
00313    DO(cp = parse_product(g, cp, valp));
00314    SKIPSPACE(cp);
00315 
00316    switch (*cp) {
00317       case '+':
00318          DO(cp = parse_sum(g, cp + 1, &rightval));
00319          *valp = (*valp + rightval);
00320          break;
00321 
00322       case '-':
00323          DO(cp = parse_sum(g, cp + 1, &rightval));
00324          *valp = (*valp - rightval);
00325          break;
00326    }
00327    return cp;
00328 }
00329 
00330 
00331 static const char *
00332 parse_shift(g, cp, valp)
00333 IfParser *g;
00334 const char *cp;
00335 long *valp;
00336 {
00337    long rightval;
00338 
00339    DO(cp = parse_sum(g, cp, valp));
00340    SKIPSPACE(cp);
00341 
00342    switch (*cp) {
00343       case '<':
00344          if (cp[1] == '<') {
00345             DO(cp = parse_shift(g, cp + 2, &rightval));
00346             *valp = (*valp << rightval);
00347          }
00348          break;
00349 
00350       case '>':
00351          if (cp[1] == '>') {
00352             DO(cp = parse_shift(g, cp + 2, &rightval));
00353             *valp = (*valp >> rightval);
00354          }
00355          break;
00356    }
00357    return cp;
00358 }
00359 
00360 
00361 static const char *
00362 parse_inequality(g, cp, valp)
00363 IfParser *g;
00364 const char *cp;
00365 long *valp;
00366 {
00367    long rightval;
00368 
00369    DO(cp = parse_shift(g, cp, valp));
00370    SKIPSPACE(cp);
00371 
00372    switch (*cp) {
00373       case '<':
00374          if (cp[1] == '=') {
00375             DO(cp = parse_inequality(g, cp + 2, &rightval));
00376             *valp = (*valp <= rightval);
00377          } else {
00378             DO(cp = parse_inequality(g, cp + 1, &rightval));
00379             *valp = (*valp < rightval);
00380          }
00381          break;
00382 
00383       case '>':
00384          if (cp[1] == '=') {
00385             DO(cp = parse_inequality(g, cp + 2, &rightval));
00386             *valp = (*valp >= rightval);
00387          } else {
00388             DO(cp = parse_inequality(g, cp + 1, &rightval));
00389             *valp = (*valp > rightval);
00390          }
00391          break;
00392    }
00393    return cp;
00394 }
00395 
00396 
00397 static const char *
00398 parse_equality(g, cp, valp)
00399 IfParser *g;
00400 const char *cp;
00401 long *valp;
00402 {
00403    long rightval;
00404 
00405    DO(cp = parse_inequality(g, cp, valp));
00406    SKIPSPACE(cp);
00407 
00408    switch (*cp) {
00409       case '=':
00410          if (cp[1] == '=')
00411             cp++;
00412          DO(cp = parse_equality(g, cp + 1, &rightval));
00413          *valp = (*valp == rightval);
00414          break;
00415 
00416       case '!':
00417          if (cp[1] != '=')
00418             break;
00419          DO(cp = parse_equality(g, cp + 2, &rightval));
00420          *valp = (*valp != rightval);
00421          break;
00422    }
00423    return cp;
00424 }
00425 
00426 
00427 static const char *
00428 parse_band(g, cp, valp)
00429 IfParser *g;
00430 const char *cp;
00431 long *valp;
00432 {
00433    long rightval;
00434 
00435    DO(cp = parse_equality(g, cp, valp));
00436    SKIPSPACE(cp);
00437 
00438    switch (*cp) {
00439       case '&':
00440          if (cp[1] != '&') {
00441             DO(cp = parse_band(g, cp + 1, &rightval));
00442             *valp = (*valp & rightval);
00443          }
00444          break;
00445    }
00446    return cp;
00447 }
00448 
00449 
00450 static const char *
00451 parse_bxor(g, cp, valp)
00452 IfParser *g;
00453 const char *cp;
00454 long *valp;
00455 {
00456    long rightval;
00457 
00458    DO(cp = parse_band(g, cp, valp));
00459    SKIPSPACE(cp);
00460 
00461    switch (*cp) {
00462       case '^':
00463          DO(cp = parse_bxor(g, cp + 1, &rightval));
00464          *valp = (*valp ^ rightval);
00465          break;
00466    }
00467    return cp;
00468 }
00469 
00470 
00471 static const char *
00472 parse_bor(g, cp, valp)
00473 IfParser *g;
00474 const char *cp;
00475 long *valp;
00476 {
00477    long rightval;
00478 
00479    DO(cp = parse_bxor(g, cp, valp));
00480    SKIPSPACE(cp);
00481 
00482    switch (*cp) {
00483       case '|':
00484          if (cp[1] != '|') {
00485             DO(cp = parse_bor(g, cp + 1, &rightval));
00486             *valp = (*valp | rightval);
00487          }
00488          break;
00489    }
00490    return cp;
00491 }
00492 
00493 
00494 static const char *
00495 parse_land(g, cp, valp)
00496 IfParser *g;
00497 const char *cp;
00498 long *valp;
00499 {
00500    long rightval;
00501 
00502    DO(cp = parse_bor(g, cp, valp));
00503    SKIPSPACE(cp);
00504 
00505    switch (*cp) {
00506       case '&':
00507          if (cp[1] != '&')
00508             return CALLFUNC(g, handle_error)(g, cp, "&&");
00509          DO(cp = parse_land(g, cp + 2, &rightval));
00510          *valp = (*valp && rightval);
00511          break;
00512    }
00513    return cp;
00514 }
00515 
00516 
00517 static const char *
00518 parse_lor(g, cp, valp)
00519 IfParser *g;
00520 const char *cp;
00521 long *valp;
00522 {
00523    long rightval;
00524 
00525    DO(cp = parse_land(g, cp, valp));
00526    SKIPSPACE(cp);
00527 
00528    switch (*cp) {
00529       case '|':
00530          if (cp[1] != '|')
00531             return CALLFUNC(g, handle_error)(g, cp, "||");
00532          DO(cp = parse_lor(g, cp + 2, &rightval));
00533          *valp = (*valp || rightval);
00534          break;
00535    }
00536    return cp;
00537 }
00538 
00539 
00540 static const char *
00541 parse_cond(g, cp, valp)
00542 IfParser *g;
00543 const char *cp;
00544 long *valp;
00545 {
00546    long trueval, falseval;
00547 
00548    DO(cp = parse_lor(g, cp, valp));
00549    SKIPSPACE(cp);
00550 
00551    switch (*cp) {
00552       case '?':
00553          DO(cp = parse_cond(g, cp + 1, &trueval));
00554          SKIPSPACE(cp);
00555          if (*cp != ':')
00556             return CALLFUNC(g, handle_error)(g, cp, ":");
00557          DO(cp = parse_cond(g, cp + 1, &falseval));
00558          *valp = (*valp ? trueval : falseval);
00559          break;
00560    }
00561    return cp;
00562 }
00563 
00564 
00565 /****************************************************************************
00566         External Entry Points
00567  ****************************************************************************/
00568 
00569 const char *
00570 ParseIfExpression(g, cp, valp)
00571 IfParser *g;
00572 const char *cp;
00573 long *valp;
00574 {
00575    return parse_cond(g, cp, valp);
00576 }

Generated on Tue Jul 5 14:10:17 2011 for ROOT_528-00b_version by  doxygen 1.5.1