2 * $Xorg: ifparser.c,v 1.3 2000/08/17 19:41:50 cpqbld 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
34 * | VALUE '?' EXPRESSION ':' EXPRESSION
36 * VALUE := '(' EXPRESSION ')'
40 * | 'defined' '(' variable ')'
41 * | 'defined' variable
42 * | # variable '(' variable-list ')'
46 * BINOP := '*' | '/' | '%'
49 * | '<' | '>' | '<=' | '>='
54 * The normal C order of precedence is supported.
57 * External Entry Points:
59 * ParseIfExpression parse a string for #if
61 /* $XFree86: xc/config/makedepend/ifparser.c,v 3.9 2001/04/29 23:25:02 tsi Exp $ */
68 /****************************************************************************
69 Internal Macros and Utilities for Parser
70 ****************************************************************************/
72 #define DO(val) if (!(val)) return NULL
73 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
74 #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
75 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
79 parse_variable (IfParser
*g
, const char *cp
, const char **varp
)
83 if (!isvarfirstletter (*cp
))
84 return CALLFUNC(g
, handle_error
) (g
, cp
, "variable name");
88 for (cp
++; isalnum(*cp
) || *cp
== '_'; cp
++) ;
94 parse_number (IfParser
*g
, const char *cp
, long *valp
)
100 return CALLFUNC(g
, handle_error
) (g
, cp
, "number");
106 if ((*cp
== 'x') || (*cp
== 'X')) {
114 /* Ignore overflows and assume ASCII, what source is usually written in */
118 if ((*cp
>= '0') && (*cp
<= '7'))
119 increment
= *cp
++ - '0';
120 } else if (base
== 16) {
121 if ((*cp
>= '0') && (*cp
<= '9'))
122 increment
= *cp
++ - '0';
123 else if ((*cp
>= 'A') && (*cp
<= 'F'))
124 increment
= *cp
++ - ('A' - 10);
125 else if ((*cp
>= 'a') && (*cp
<= 'f'))
126 increment
= *cp
++ - ('a' - 10);
127 } else { /* Decimal */
128 if ((*cp
>= '0') && (*cp
<= '9'))
129 increment
= *cp
++ - '0';
133 *valp
= (*valp
* base
) + increment
;
136 /* Skip trailing qualifiers */
137 while (*cp
== 'U' || *cp
== 'u' || *cp
== 'L' || *cp
== 'l') cp
++;
142 parse_character (IfParser
*g
, const char *cp
, long *valp
)
149 case 'n': val
= '\n'; break;
150 case 't': val
= '\t'; break;
151 case 'v': val
= '\v'; break;
152 case 'b': val
= '\b'; break;
153 case 'r': val
= '\r'; break;
154 case 'f': val
= '\f'; break;
155 case 'a': val
= '\a'; break;
156 case '\\': val
= '\\'; break;
157 case '?': val
= '\?'; break;
158 case '\'': val
= '\''; break;
159 case '\"': val
= '\"'; break;
160 case 'x': val
= (char) strtol (cp
+ 2, NULL
, 16); break;
161 default: val
= (char) strtol (cp
+ 1, NULL
, 8); break;
165 while (*cp
!= '\'') cp
++;
171 parse_value (IfParser
*g
, const char *cp
, long *valp
)
183 DO (cp
= ParseIfExpression (g
, cp
+ 1, valp
));
186 return CALLFUNC(g
, handle_error
) (g
, cp
, ")");
188 return cp
+ 1; /* skip the right paren */
191 DO (cp
= parse_value (g
, cp
+ 1, valp
));
196 DO (cp
= parse_value (g
, cp
+ 1, valp
));
201 DO (cp
= parse_value (g
, cp
+ 1, valp
));
206 DO (cp
= parse_variable (g
, cp
+ 1, &var
));
209 return CALLFUNC(g
, handle_error
) (g
, cp
, "(");
211 DO (cp
= parse_variable (g
, cp
+ 1, &var
));
213 } while (*cp
&& *cp
!= ')');
215 return CALLFUNC(g
, handle_error
) (g
, cp
, ")");
220 DO (cp
= parse_character (g
, cp
+ 1, valp
));
222 return CALLFUNC(g
, handle_error
) (g
, cp
, "'");
226 if (strncmp (cp
, "defined", 7) == 0 && !isalnum(cp
[7])) {
236 DO (cp
= parse_variable (g
, cp
, &var
));
239 if (paren
&& *cp
!= ')')
240 return CALLFUNC(g
, handle_error
) (g
, cp
, ")");
241 *valp
= (*(g
->funcs
.eval_defined
)) (g
, var
, len
);
242 return cp
+ paren
; /* skip the right paren */
248 DO (cp
= parse_number (g
, cp
, valp
));
249 } else if (!isvarfirstletter(*cp
))
250 return CALLFUNC(g
, handle_error
) (g
, cp
, "variable or number");
252 DO (cp
= parse_variable (g
, cp
, &var
));
253 *valp
= (*(g
->funcs
.eval_variable
)) (g
, var
, cp
- var
);
262 parse_product (IfParser
*g
, const char *cp
, long *valp
)
266 DO (cp
= parse_value (g
, cp
, valp
));
271 DO (cp
= parse_product (g
, cp
+ 1, &rightval
));
272 *valp
= (*valp
* rightval
);
276 DO (cp
= parse_product (g
, cp
+ 1, &rightval
));
277 *valp
= (*valp
/ rightval
);
281 DO (cp
= parse_product (g
, cp
+ 1, &rightval
));
282 *valp
= (*valp
% rightval
);
290 parse_sum (IfParser
*g
, const char *cp
, long *valp
)
294 DO (cp
= parse_product (g
, cp
, valp
));
299 DO (cp
= parse_sum (g
, cp
+ 1, &rightval
));
300 *valp
= (*valp
+ rightval
);
304 DO (cp
= parse_sum (g
, cp
+ 1, &rightval
));
305 *valp
= (*valp
- rightval
);
313 parse_shift (IfParser
*g
, const char *cp
, long *valp
)
317 DO (cp
= parse_sum (g
, cp
, valp
));
323 DO (cp
= parse_shift (g
, cp
+ 2, &rightval
));
324 *valp
= (*valp
<< rightval
);
330 DO (cp
= parse_shift (g
, cp
+ 2, &rightval
));
331 *valp
= (*valp
>> rightval
);
340 parse_inequality (IfParser
*g
, const char *cp
, long *valp
)
344 DO (cp
= parse_shift (g
, cp
, valp
));
350 DO (cp
= parse_inequality (g
, cp
+ 2, &rightval
));
351 *valp
= (*valp
<= rightval
);
353 DO (cp
= parse_inequality (g
, cp
+ 1, &rightval
));
354 *valp
= (*valp
< rightval
);
360 DO (cp
= parse_inequality (g
, cp
+ 2, &rightval
));
361 *valp
= (*valp
>= rightval
);
363 DO (cp
= parse_inequality (g
, cp
+ 1, &rightval
));
364 *valp
= (*valp
> rightval
);
373 parse_equality (IfParser
*g
, const char *cp
, long *valp
)
377 DO (cp
= parse_inequality (g
, cp
, valp
));
384 DO (cp
= parse_equality (g
, cp
+ 1, &rightval
));
385 *valp
= (*valp
== rightval
);
391 DO (cp
= parse_equality (g
, cp
+ 2, &rightval
));
392 *valp
= (*valp
!= rightval
);
400 parse_band (IfParser
*g
, const char *cp
, long *valp
)
404 DO (cp
= parse_equality (g
, cp
, valp
));
410 DO (cp
= parse_band (g
, cp
+ 1, &rightval
));
411 *valp
= (*valp
& rightval
);
420 parse_bxor (IfParser
*g
, const char *cp
, long *valp
)
424 DO (cp
= parse_band (g
, cp
, valp
));
429 DO (cp
= parse_bxor (g
, cp
+ 1, &rightval
));
430 *valp
= (*valp
^ rightval
);
438 parse_bor (IfParser
*g
, const char *cp
, long *valp
)
442 DO (cp
= parse_bxor (g
, cp
, valp
));
448 DO (cp
= parse_bor (g
, cp
+ 1, &rightval
));
449 *valp
= (*valp
| rightval
);
458 parse_land (IfParser
*g
, const char *cp
, long *valp
)
462 DO (cp
= parse_bor (g
, cp
, valp
));
468 return CALLFUNC(g
, handle_error
) (g
, cp
, "&&");
469 DO (cp
= parse_land (g
, cp
+ 2, &rightval
));
470 *valp
= (*valp
&& rightval
);
478 parse_lor (IfParser
*g
, const char *cp
, long *valp
)
482 DO (cp
= parse_land (g
, cp
, valp
));
488 return CALLFUNC(g
, handle_error
) (g
, cp
, "||");
489 DO (cp
= parse_lor (g
, cp
+ 2, &rightval
));
490 *valp
= (*valp
|| rightval
);
498 parse_cond(IfParser
*g
, const char *cp
, long *valp
)
500 long trueval
, falseval
;
502 DO (cp
= parse_lor (g
, cp
, valp
));
507 DO (cp
= parse_cond (g
, cp
+ 1, &trueval
));
510 return CALLFUNC(g
, handle_error
) (g
, cp
, ":");
511 DO (cp
= parse_cond (g
, cp
+ 1, &falseval
));
512 *valp
= (*valp
? trueval
: falseval
);
519 /****************************************************************************
520 External Entry Points
521 ****************************************************************************/
524 ParseIfExpression (IfParser
*g
, const char *cp
, long *valp
)
526 return parse_cond (g
, cp
, valp
);