ifparser.cpp

Go to the documentation of this file.
00001 /*
00002  * $XConsortium: ifparser.c,v 1.7 94/01/18 21:30:50 rws Exp $
00003  *
00004  * Copyright 1992 Network Computing Devices, Inc.
00005  * 
00006  * Permission to use, copy, modify, and distribute this software and its
00007  * documentation for any purpose and without fee is hereby granted, provided
00008  * that the above copyright notice appear in all copies and that both that
00009  * copyright notice and this permission notice appear in supporting
00010  * documentation, and that the name of Network Computing Devices may not be
00011  * used in advertising or publicity pertaining to distribution of the software
00012  * without specific, written prior permission.  Network Computing Devices makes
00013  * no representations about the suitability of this software for any purpose.
00014  * It is provided ``as is'' without express or implied warranty.
00015  * 
00016  * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
00017  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
00018  * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
00019  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00020  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00021  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00022  * PERFORMANCE OF THIS SOFTWARE.
00023  * 
00024  * Author:  Jim Fulton
00025  *          Network Computing Devices, Inc.
00026  * 
00027  * Simple if statement processor
00028  *
00029  * This module can be used to evaluate string representations of C language
00030  * if constructs.  It accepts the following grammar:
00031  * 
00032  *     EXPRESSION :=  VALUE
00033  *       |  VALUE  BINOP  EXPRESSION
00034  * 
00035  *     VALUE    :=  '('  EXPRESSION  ')'
00036  *       |  '!'  VALUE
00037  *       |  '-'  VALUE
00038  *       |  'defined'  '('  variable  ')'
00039  *       |  'defined'  variable
00040  *       |  # variable '(' variable-list ')'
00041  *       |  variable
00042  *       |  number
00043  * 
00044  *     BINOP    :=  '*' |  '/'  |  '%'
00045  *       |  '+' |  '-'
00046  *       |  '<<'  |  '>>'
00047  *       |  '<' |  '>'  |  '<='  |  '>='
00048  *       |  '=='  |  '!='
00049  *       |  '&' |  '|'
00050  *       |  '&&'  |  '||'
00051  * 
00052  * The normal C order of precidence is supported.
00053  * 
00054  * 
00055  * External Entry Points:
00056  * 
00057  *     ParseIfExpression    parse a string for #if
00058  */
00059 
00060 #ifdef __WIN32__
00061   #pragma warning(disable : 4996)
00062 #endif
00063 
00064 #include "ifparser.h"
00065 
00066 #include <ctype.h>
00067 #include <stdlib.h>
00068 #include <string.h>
00069 
00070 /****************************************************************************
00071        Internal Macros and Utilities for Parser
00072  ****************************************************************************/
00073 
00074 #define DO(val) if (!(val)) return NULL
00075 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
00076 #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
00077 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
00078 
00079 
00080 static const char *parse_variable(IfParser *g, const char *cp,
00081     const char **varp)
00082 {
00083     SKIPSPACE (cp);
00084 
00085     if (!isvarfirstletter (*cp))
00086   return CALLFUNC(g, handle_error) (g, cp, "variable name");
00087 
00088     *varp = cp;
00089     /* EMPTY */
00090     for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
00091     return cp;
00092 }
00093 
00094 
00095 static const char *parse_number(IfParser *g, const char *cp, int *valp)
00096 {
00097     SKIPSPACE (cp);
00098 
00099     if (!isdigit(*cp))
00100   return CALLFUNC(g, handle_error) (g, cp, "number");
00101 
00102 #ifdef WIN32
00103     char *hold_result;
00104     *valp = strtol(cp, &hold_result, 0);
00105     cp = hold_result;
00106 #else
00107     *valp = atoi (cp);
00108     /* EMPTY */
00109     for (cp++; isdigit(*cp); cp++) ;
00110 #endif
00111     return cp;
00112 }
00113 
00114 
00115 static const char *parse_value(IfParser *g, const char *cp, int *valp)
00116 {
00117     const char *var;
00118 
00119     *valp = 0;
00120 
00121     SKIPSPACE (cp);
00122     if (!*cp)
00123   return cp;
00124 
00125     switch (*cp) {
00126       case '(':
00127   DO (cp = ParseIfExpression (g, cp + 1, valp));
00128   SKIPSPACE (cp);
00129   if (*cp != ')') 
00130       return CALLFUNC(g, handle_error) (g, cp, ")");
00131 
00132   return cp + 1;      /* skip the right paren */
00133 
00134       case '!':
00135   DO (cp = parse_value (g, cp + 1, valp));
00136   *valp = !(*valp);
00137   return cp;
00138 
00139       case '-':
00140   DO (cp = parse_value (g, cp + 1, valp));
00141   *valp = -(*valp);
00142   return cp;
00143 
00144       case '#':
00145   DO (cp = parse_variable (g, cp + 1, &var));
00146   SKIPSPACE (cp);
00147   if (*cp != '(')
00148       return CALLFUNC(g, handle_error) (g, cp, "(");
00149   do {
00150       DO (cp = parse_variable (g, cp + 1, &var));
00151       SKIPSPACE (cp);
00152   } while (*cp && *cp != ')');
00153   if (*cp != ')')
00154       return CALLFUNC(g, handle_error) (g, cp, ")");
00155   *valp = 1; /* XXX */
00156   return cp + 1;
00157 
00158       case 'd':
00159   if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
00160       int paren = 0;
00161       cp += 7;
00162       SKIPSPACE (cp);
00163       if (*cp == '(') {
00164     paren = 1;
00165     cp++;
00166       }
00167       DO (cp = parse_variable (g, cp, &var));
00168       SKIPSPACE (cp);
00169       if (paren && *cp != ')')
00170     return CALLFUNC(g, handle_error) (g, cp, ")");
00171       *valp = (*(g->funcs.eval_defined)) (g, var, int(cp - var));
00172       return cp + paren;    /* skip the right paren */
00173   }
00174   /* fall out */
00175     }
00176 
00177     if (isdigit(*cp)) {
00178   DO (cp = parse_number (g, cp, valp));
00179     } else if (!isvarfirstletter(*cp))
00180   return CALLFUNC(g, handle_error) (g, cp, "variable or number");
00181     else {
00182   DO (cp = parse_variable (g, cp, &var));
00183   *valp = (*(g->funcs.eval_variable)) (g, var, int(cp - var));
00184     }
00185     
00186     return cp;
00187 }
00188 
00189 static const char *parse_product(IfParser *g, const char *cp, int *valp)
00190 {
00191     int rightval;
00192 
00193     DO (cp = parse_value (g, cp, valp));
00194     SKIPSPACE (cp);
00195 
00196     switch (*cp) {
00197       case '*':
00198   DO (cp = parse_product (g, cp + 1, &rightval));
00199   *valp = (*valp * rightval);
00200   break;
00201 
00202       case '/':
00203   DO (cp = parse_product (g, cp + 1, &rightval));
00204   *valp = (*valp / rightval);
00205   break;
00206 
00207       case '%':
00208   DO (cp = parse_product (g, cp + 1, &rightval));
00209   *valp = (*valp % rightval);
00210   break;
00211     }
00212     return cp;
00213 }
00214 
00215 static const char *parse_sum(IfParser *g, const char *cp, int *valp)
00216 {
00217     int rightval;
00218 
00219     DO (cp = parse_product (g, cp, valp));
00220     SKIPSPACE (cp);
00221 
00222     switch (*cp) {
00223       case '+':
00224   DO (cp = parse_sum (g, cp + 1, &rightval));
00225   *valp = (*valp + rightval);
00226   break;
00227 
00228       case '-':
00229   DO (cp = parse_sum (g, cp + 1, &rightval));
00230   *valp = (*valp - rightval);
00231   break;
00232     }
00233     return cp;
00234 }
00235 
00236 
00237 static const char *parse_shift(IfParser *g, const char *cp, int *valp)
00238 {
00239     int rightval;
00240 
00241     DO (cp = parse_sum (g, cp, valp));
00242     SKIPSPACE (cp);
00243 
00244     switch (*cp) {
00245       case '<':
00246   if (cp[1] == '<') {
00247       DO (cp = parse_shift (g, cp + 2, &rightval));
00248       *valp = (*valp << rightval);
00249   }
00250   break;
00251 
00252       case '>':
00253   if (cp[1] == '>') {
00254       DO (cp = parse_shift (g, cp + 2, &rightval));
00255       *valp = (*valp >> rightval);
00256   }
00257   break;
00258     }
00259     return cp;
00260 }
00261 
00262 static const char *parse_inequality(IfParser *g, const char *cp, int *valp)
00263 {
00264     int rightval;
00265 
00266     DO (cp = parse_shift (g, cp, valp));
00267     SKIPSPACE (cp);
00268 
00269     switch (*cp) {
00270       case '<':
00271   if (cp[1] == '=') {
00272       DO (cp = parse_inequality (g, cp + 2, &rightval));
00273       *valp = (*valp <= rightval);
00274   } else {
00275       DO (cp = parse_inequality (g, cp + 1, &rightval));
00276       *valp = (*valp < rightval);
00277   }
00278   break;
00279 
00280       case '>':
00281   if (cp[1] == '=') {
00282       DO (cp = parse_inequality (g, cp + 2, &rightval));
00283       *valp = (*valp >= rightval);
00284   } else {
00285       DO (cp = parse_inequality (g, cp + 1, &rightval));
00286       *valp = (*valp > rightval);
00287   }
00288   break;
00289     }
00290     return cp;
00291 }
00292 
00293 static const char *parse_equality(IfParser *g, const char *cp, int *valp)
00294 {
00295     int rightval;
00296 
00297     DO (cp = parse_inequality (g, cp, valp));
00298     SKIPSPACE (cp);
00299 
00300     switch (*cp) {
00301       case '=':
00302   if (cp[1] == '=')
00303       cp++;
00304   DO (cp = parse_equality (g, cp + 1, &rightval));
00305   *valp = (*valp == rightval);
00306   break;
00307 
00308       case '!':
00309   if (cp[1] != '=')
00310       break;
00311   DO (cp = parse_equality (g, cp + 2, &rightval));
00312   *valp = (*valp != rightval);
00313   break;
00314     }
00315     return cp;
00316 }
00317 
00318 static const char *parse_band(IfParser *g, const char *cp, int *valp)
00319 {
00320     int rightval;
00321 
00322     DO (cp = parse_equality (g, cp, valp));
00323     SKIPSPACE (cp);
00324 
00325     switch (*cp) {
00326       case '&':
00327   if (cp[1] != '&') {
00328       DO (cp = parse_band (g, cp + 1, &rightval));
00329       *valp = (*valp & rightval);
00330   }
00331   break;
00332     }
00333     return cp;
00334 }
00335 
00336 
00337 static const char *parse_bor(IfParser *g, const char *cp, int *valp)
00338 {
00339     int rightval;
00340 
00341     DO (cp = parse_band (g, cp, valp));
00342     SKIPSPACE (cp);
00343 
00344     switch (*cp) {
00345       case '|':
00346   if (cp[1] != '|') {
00347       DO (cp = parse_bor (g, cp + 1, &rightval));
00348       *valp = (*valp | rightval);
00349   }
00350   break;
00351     }
00352     return cp;
00353 }
00354 
00355 static const char *parse_land(IfParser *g, const char *cp, int *valp)
00356 {
00357     int rightval;
00358 
00359     DO (cp = parse_bor (g, cp, valp));
00360     SKIPSPACE (cp);
00361 
00362     switch (*cp) {
00363       case '&':
00364   if (cp[1] != '&')
00365       return CALLFUNC(g, handle_error) (g, cp, "&&");
00366   DO (cp = parse_land (g, cp + 2, &rightval));
00367   *valp = (*valp && rightval);
00368   break;
00369     }
00370     return cp;
00371 }
00372 
00373 static const char *parse_lor(IfParser *g, const char *cp, int *valp)
00374 {
00375     int rightval;
00376 
00377     DO (cp = parse_land (g, cp, valp));
00378     SKIPSPACE (cp);
00379 
00380     switch (*cp) {
00381       case '|':
00382   if (cp[1] != '|')
00383       return CALLFUNC(g, handle_error) (g, cp, "||");
00384   DO (cp = parse_lor (g, cp + 2, &rightval));
00385   *valp = (*valp || rightval);
00386   break;
00387     }
00388     return cp;
00389 }
00390 
00391 
00392 /****************************************************************************
00393            External Entry Points
00394  ****************************************************************************/
00395 
00396 const char *ParseIfExpression(IfParser *g, const char *cp, int *valp)
00397 {
00398     return parse_lor (g, cp, valp);
00399 }
00400 
00401 
Generated on Sat Jan 28 04:22:39 2012 for hoople2 project by  doxygen 1.6.3