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 ')'
41 * | 'defined' '(' variable ')'
42 * | 'defined' variable
43 * | # variable '(' variable-list ')'
47 * BINOP := '*' | '/' | '%'
50 * | '<' | '>' | '<=' | '>='
55 * The normal C order of precedence is supported.
58 * External Entry Points:
60 * ParseIfExpression parse a string for #if
62 /* $XFree86: xc/config/makedepend/ifparser.c,v 3.11 2002/09/23 01:48:08 tsi Exp $ */
69 /****************************************************************************
70 Internal Macros and Utilities for Parser
71 ****************************************************************************/
73 #define DO(val) if (!(val)) return NULL
74 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
75 #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
76 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
80 parse_variable (IfParser
*g
, const char *cp
, const char **varp
)
84 if (!isvarfirstletter (*cp
))
85 return CALLFUNC(g
, handle_error
) (g
, cp
, "variable name");
89 for (cp
++; isalnum(*cp
) || *cp
== '_'; cp
++) ;
95 parse_number (IfParser
*g
, const char *cp
, long *valp
)
101 return CALLFUNC(g
, handle_error
) (g
, cp
, "number");
107 if ((*cp
== 'x') || (*cp
== 'X')) {
115 /* Ignore overflows and assume ASCII, what source is usually written in */
119 if ((*cp
>= '0') && (*cp
<= '7'))
120 increment
= *cp
++ - '0';
121 } else if (base
== 16) {
122 if ((*cp
>= '0') && (*cp
<= '9'))
123 increment
= *cp
++ - '0';
124 else if ((*cp
>= 'A') && (*cp
<= 'F'))
125 increment
= *cp
++ - ('A' - 10);
126 else if ((*cp
>= 'a') && (*cp
<= 'f'))
127 increment
= *cp
++ - ('a' - 10);
128 } else { /* Decimal */
129 if ((*cp
>= '0') && (*cp
<= '9'))
130 increment
= *cp
++ - '0';
134 *valp
= (*valp
* base
) + increment
;
137 /* Skip trailing qualifiers */
138 while (*cp
== 'U' || *cp
== 'u' || *cp
== 'L' || *cp
== 'l') cp
++;
143 parse_character (IfParser
*g
, const char *cp
, long *valp
)
150 case 'n': val
= '\n'; break;
151 case 't': val
= '\t'; break;
152 case 'v': val
= '\v'; break;
153 case 'b': val
= '\b'; break;
154 case 'r': val
= '\r'; break;
155 case 'f': val
= '\f'; break;
156 case 'a': val
= '\a'; break;
157 case '\\': val
= '\\'; break;
158 case '?': val
= '\?'; break;
159 case '\'': val
= '\''; break;
160 case '\"': val
= '\"'; break;
161 case 'x': val
= (char) strtol (cp
+ 2, NULL
, 16); break;
162 default: val
= (char) strtol (cp
+ 1, NULL
, 8); break;
166 while (*cp
!= '\'') cp
++;
172 parse_value (IfParser
*g
, const char *cp
, long *valp
)
174 const char *var
, *varend
;
184 DO (cp
= ParseIfExpression (g
, cp
+ 1, valp
));
187 return CALLFUNC(g
, handle_error
) (g
, cp
, ")");
189 return cp
+ 1; /* skip the right paren */
192 DO (cp
= parse_value (g
, cp
+ 1, valp
));
197 DO (cp
= parse_value (g
, cp
+ 1, valp
));
202 DO (cp
= parse_value (g
, cp
+ 1, valp
));
206 DO (cp
= parse_value (g
, cp
+ 1, valp
));
211 DO (cp
= parse_variable (g
, cp
+ 1, &var
));
214 return CALLFUNC(g
, handle_error
) (g
, cp
, "(");
216 DO (cp
= parse_variable (g
, cp
+ 1, &var
));
218 } while (*cp
&& *cp
!= ')');
220 return CALLFUNC(g
, handle_error
) (g
, cp
, ")");
225 DO (cp
= parse_character (g
, cp
+ 1, valp
));
227 return CALLFUNC(g
, handle_error
) (g
, cp
, "'");
231 if (strncmp (cp
, "defined", 7) == 0 && !isalnum(cp
[7])) {
241 DO (cp
= parse_variable (g
, cp
, &var
));
244 if (paren
&& *cp
!= ')')
245 return CALLFUNC(g
, handle_error
) (g
, cp
, ")");
246 *valp
= (*(g
->funcs
.eval_defined
)) (g
, var
, len
);
247 return cp
+ paren
; /* skip the right paren */
253 DO (cp
= parse_number (g
, cp
, valp
));
254 } else if (!isvarfirstletter(*cp
))
255 return CALLFUNC(g
, handle_error
) (g
, cp
, "variable or number");
257 DO (cp
= parse_variable (g
, cp
, &var
));
261 *valp
= (*(g
->funcs
.eval_variable
)) (g
, var
, varend
- var
);
265 DO (cp
= ParseIfExpression (g
, cp
+ 1, &dummy
));
270 return CALLFUNC(g
, handle_error
) (g
, cp
, ",");
284 parse_product (IfParser
*g
, const char *cp
, long *valp
)
288 DO (cp
= parse_value (g
, cp
, valp
));
293 DO (cp
= parse_product (g
, cp
+ 1, &rightval
));
294 *valp
= (*valp
* rightval
);
298 DO (cp
= parse_product (g
, cp
+ 1, &rightval
));
299 *valp
= (*valp
/ rightval
);
303 DO (cp
= parse_product (g
, cp
+ 1, &rightval
));
304 *valp
= (*valp
% rightval
);
312 parse_sum (IfParser
*g
, const char *cp
, long *valp
)
316 DO (cp
= parse_product (g
, cp
, valp
));
321 DO (cp
= parse_sum (g
, cp
+ 1, &rightval
));
322 *valp
= (*valp
+ rightval
);
326 DO (cp
= parse_sum (g
, cp
+ 1, &rightval
));
327 *valp
= (*valp
- rightval
);
335 parse_shift (IfParser
*g
, const char *cp
, long *valp
)
339 DO (cp
= parse_sum (g
, cp
, valp
));
345 DO (cp
= parse_shift (g
, cp
+ 2, &rightval
));
346 *valp
= (*valp
<< rightval
);
352 DO (cp
= parse_shift (g
, cp
+ 2, &rightval
));
353 *valp
= (*valp
>> rightval
);
362 parse_inequality (IfParser
*g
, const char *cp
, long *valp
)
366 DO (cp
= parse_shift (g
, cp
, valp
));
372 DO (cp
= parse_inequality (g
, cp
+ 2, &rightval
));
373 *valp
= (*valp
<= rightval
);
375 DO (cp
= parse_inequality (g
, cp
+ 1, &rightval
));
376 *valp
= (*valp
< rightval
);
382 DO (cp
= parse_inequality (g
, cp
+ 2, &rightval
));
383 *valp
= (*valp
>= rightval
);
385 DO (cp
= parse_inequality (g
, cp
+ 1, &rightval
));
386 *valp
= (*valp
> rightval
);
395 parse_equality (IfParser
*g
, const char *cp
, long *valp
)
399 DO (cp
= parse_inequality (g
, cp
, valp
));
406 DO (cp
= parse_equality (g
, cp
+ 1, &rightval
));
407 *valp
= (*valp
== rightval
);
413 DO (cp
= parse_equality (g
, cp
+ 2, &rightval
));
414 *valp
= (*valp
!= rightval
);
422 parse_band (IfParser
*g
, const char *cp
, long *valp
)
426 DO (cp
= parse_equality (g
, cp
, valp
));
432 DO (cp
= parse_band (g
, cp
+ 1, &rightval
));
433 *valp
= (*valp
& rightval
);
442 parse_bxor (IfParser
*g
, const char *cp
, long *valp
)
446 DO (cp
= parse_band (g
, cp
, valp
));
451 DO (cp
= parse_bxor (g
, cp
+ 1, &rightval
));
452 *valp
= (*valp
^ rightval
);
460 parse_bor (IfParser
*g
, const char *cp
, long *valp
)
464 DO (cp
= parse_bxor (g
, cp
, valp
));
470 DO (cp
= parse_bor (g
, cp
+ 1, &rightval
));
471 *valp
= (*valp
| rightval
);
480 parse_land (IfParser
*g
, const char *cp
, long *valp
)
484 DO (cp
= parse_bor (g
, cp
, valp
));
490 return CALLFUNC(g
, handle_error
) (g
, cp
, "&&");
491 DO (cp
= parse_land (g
, cp
+ 2, &rightval
));
492 *valp
= (*valp
&& rightval
);
500 parse_lor (IfParser
*g
, const char *cp
, long *valp
)
504 DO (cp
= parse_land (g
, cp
, valp
));
510 return CALLFUNC(g
, handle_error
) (g
, cp
, "||");
511 DO (cp
= parse_lor (g
, cp
+ 2, &rightval
));
512 *valp
= (*valp
|| rightval
);
520 parse_cond(IfParser
*g
, const char *cp
, long *valp
)
522 long trueval
, falseval
;
524 DO (cp
= parse_lor (g
, cp
, valp
));
529 DO (cp
= parse_cond (g
, cp
+ 1, &trueval
));
532 return CALLFUNC(g
, handle_error
) (g
, cp
, ":");
533 DO (cp
= parse_cond (g
, cp
+ 1, &falseval
));
534 *valp
= (*valp
? trueval
: falseval
);
541 /****************************************************************************
542 External Entry Points
543 ****************************************************************************/
546 ParseIfExpression (IfParser
*g
, const char *cp
, long *valp
)
548 return parse_cond (g
, cp
, valp
);