2 * $XConsortium: ifparser.c,v 1.7 94/01/18 21:30:50 rws Exp $
4 * Copyright 1992 Network Computing Devices, Inc.
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.
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.
25 * Network Computing Devices, Inc.
27 * Simple if statement processor
29 * This module can be used to evaluate string representations of C language
30 * if constructs. It accepts the following grammar:
33 * | VALUE BINOP EXPRESSION
35 * VALUE := '(' EXPRESSION ')'
38 * | 'defined' '(' variable ')'
39 * | 'defined' variable
40 * | # variable '(' variable-list ')'
44 * BINOP := '*' | '/' | '%'
47 * | '<' | '>' | '<=' | '>='
52 * The normal C order of precidence is supported.
55 * External Entry Points:
57 * ParseIfExpression parse a string for #if
61 #pragma warning(disable : 4996)
70 /****************************************************************************
71 Internal Macros and Utilities for Parser
72 ****************************************************************************/
74 #define DO(val) if (!(val)) return NULL
75 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
76 #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
77 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
80 static const char *parse_variable(IfParser *g, const char *cp,
85 if (!isvarfirstletter (*cp))
86 return CALLFUNC(g, handle_error) (g, cp, "variable name");
90 for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
95 static const char *parse_number(IfParser *g, const char *cp, int *valp)
100 return CALLFUNC(g, handle_error) (g, cp, "number");
104 *valp = strtol(cp, &hold_result, 0);
109 for (cp++; isdigit(*cp); cp++) ;
115 static const char *parse_value(IfParser *g, const char *cp, int *valp)
127 DO (cp = ParseIfExpression (g, cp + 1, valp));
130 return CALLFUNC(g, handle_error) (g, cp, ")");
132 return cp + 1; /* skip the right paren */
135 DO (cp = parse_value (g, cp + 1, valp));
140 DO (cp = parse_value (g, cp + 1, valp));
145 DO (cp = parse_variable (g, cp + 1, &var));
148 return CALLFUNC(g, handle_error) (g, cp, "(");
150 DO (cp = parse_variable (g, cp + 1, &var));
152 } while (*cp && *cp != ')');
154 return CALLFUNC(g, handle_error) (g, cp, ")");
159 if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
167 DO (cp = parse_variable (g, cp, &var));
169 if (paren && *cp != ')')
170 return CALLFUNC(g, handle_error) (g, cp, ")");
171 *valp = (*(g->funcs.eval_defined)) (g, var, int(cp - var));
172 return cp + paren; /* skip the right paren */
179 DO (cp = parse_number (g, cp, valp));
180 } else if (!isvarfirstletter(*cp))
181 return CALLFUNC(g, handle_error) (g, cp, "variable or number");
183 DO (cp = parse_variable (g, cp, &var));
184 *valp = (*(g->funcs.eval_variable)) (g, var, int(cp - var));
190 static const char *parse_product(IfParser *g, const char *cp, int *valp)
194 DO (cp = parse_value (g, cp, valp));
199 DO (cp = parse_product (g, cp + 1, &rightval));
200 *valp = (*valp * rightval);
204 DO (cp = parse_product (g, cp + 1, &rightval));
205 *valp = (*valp / rightval);
209 DO (cp = parse_product (g, cp + 1, &rightval));
210 *valp = (*valp % rightval);
216 static const char *parse_sum(IfParser *g, const char *cp, int *valp)
220 DO (cp = parse_product (g, cp, valp));
225 DO (cp = parse_sum (g, cp + 1, &rightval));
226 *valp = (*valp + rightval);
230 DO (cp = parse_sum (g, cp + 1, &rightval));
231 *valp = (*valp - rightval);
238 static const char *parse_shift(IfParser *g, const char *cp, int *valp)
242 DO (cp = parse_sum (g, cp, valp));
248 DO (cp = parse_shift (g, cp + 2, &rightval));
249 *valp = (*valp << rightval);
255 DO (cp = parse_shift (g, cp + 2, &rightval));
256 *valp = (*valp >> rightval);
263 static const char *parse_inequality(IfParser *g, const char *cp, int *valp)
267 DO (cp = parse_shift (g, cp, valp));
273 DO (cp = parse_inequality (g, cp + 2, &rightval));
274 *valp = (*valp <= rightval);
276 DO (cp = parse_inequality (g, cp + 1, &rightval));
277 *valp = (*valp < rightval);
283 DO (cp = parse_inequality (g, cp + 2, &rightval));
284 *valp = (*valp >= rightval);
286 DO (cp = parse_inequality (g, cp + 1, &rightval));
287 *valp = (*valp > rightval);
294 static const char *parse_equality(IfParser *g, const char *cp, int *valp)
298 DO (cp = parse_inequality (g, cp, valp));
305 DO (cp = parse_equality (g, cp + 1, &rightval));
306 *valp = (*valp == rightval);
312 DO (cp = parse_equality (g, cp + 2, &rightval));
313 *valp = (*valp != rightval);
319 static const char *parse_band(IfParser *g, const char *cp, int *valp)
323 DO (cp = parse_equality (g, cp, valp));
329 DO (cp = parse_band (g, cp + 1, &rightval));
330 *valp = (*valp & rightval);
338 static const char *parse_bor(IfParser *g, const char *cp, int *valp)
342 DO (cp = parse_band (g, cp, valp));
348 DO (cp = parse_bor (g, cp + 1, &rightval));
349 *valp = (*valp | rightval);
356 static const char *parse_land(IfParser *g, const char *cp, int *valp)
360 DO (cp = parse_bor (g, cp, valp));
366 return CALLFUNC(g, handle_error) (g, cp, "&&");
367 DO (cp = parse_land (g, cp + 2, &rightval));
368 *valp = (*valp && rightval);
374 static const char *parse_lor(IfParser *g, const char *cp, int *valp)
378 DO (cp = parse_land (g, cp, valp));
384 return CALLFUNC(g, handle_error) (g, cp, "||");
385 DO (cp = parse_lor (g, cp + 2, &rightval));
386 *valp = (*valp || rightval);
393 /****************************************************************************
394 External Entry Points
395 ****************************************************************************/
397 const char *ParseIfExpression(IfParser *g, const char *cp, int *valp)
399 return parse_lor (g, cp, valp);