forgotten commit. disabled until egl is adapted.
[AROS-Contrib.git] / development / build / makedepend / ifparser.c
blob795ebfba15a012908ba7582abe4d68a5f0bd6f59
1 /*
2 * $Xorg: ifparser.c,v 1.3 2000/08/17 19:41:50 cpqbld Exp $
4 * Copyright 1992 Network Computing Devices, Inc.
5 *
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.
24 * Author: Jim Fulton
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:
32 * EXPRESSION := VALUE
33 * | VALUE BINOP EXPRESSION
34 * | VALUE '?' EXPRESSION ':' EXPRESSION
36 * VALUE := '(' EXPRESSION ')'
37 * | '!' VALUE
38 * | '-' VALUE
39 * | '~' VALUE
40 * | 'defined' '(' variable ')'
41 * | 'defined' variable
42 * | # variable '(' variable-list ')'
43 * | variable
44 * | number
46 * BINOP := '*' | '/' | '%'
47 * | '+' | '-'
48 * | '<<' | '>>'
49 * | '<' | '>' | '<=' | '>='
50 * | '==' | '!='
51 * | '&' | '^' | '|'
52 * | '&&' | '||'
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 $ */
63 #include "ifparser.h"
64 #include <ctype.h>
65 #include <stdlib.h>
66 #include <string.h>
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) == '_')
78 static const char *
79 parse_variable (IfParser *g, const char *cp, const char **varp)
81 SKIPSPACE (cp);
83 if (!isvarfirstletter (*cp))
84 return CALLFUNC(g, handle_error) (g, cp, "variable name");
86 *varp = cp;
87 /* EMPTY */
88 for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
89 return cp;
93 static const char *
94 parse_number (IfParser *g, const char *cp, long *valp)
96 long base = 10;
97 SKIPSPACE (cp);
99 if (!isdigit(*cp))
100 return CALLFUNC(g, handle_error) (g, cp, "number");
102 *valp = 0;
104 if (*cp == '0') {
105 cp++;
106 if ((*cp == 'x') || (*cp == 'X')) {
107 base = 16;
108 cp++;
109 } else {
110 base = 8;
114 /* Ignore overflows and assume ASCII, what source is usually written in */
115 while (1) {
116 int increment = -1;
117 if (base == 8) {
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';
131 if (increment < 0)
132 break;
133 *valp = (*valp * base) + increment;
136 /* Skip trailing qualifiers */
137 while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++;
138 return cp;
141 static const char *
142 parse_character (IfParser *g, const char *cp, long *valp)
144 char val;
146 SKIPSPACE (cp);
147 if (*cp == '\\')
148 switch (cp[1]) {
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;
163 else
164 val = *cp;
165 while (*cp != '\'') cp++;
166 *valp = (long) val;
167 return cp;
170 static const char *
171 parse_value (IfParser *g, const char *cp, long *valp)
173 const char *var;
175 *valp = 0;
177 SKIPSPACE (cp);
178 if (!*cp)
179 return cp;
181 switch (*cp) {
182 case '(':
183 DO (cp = ParseIfExpression (g, cp + 1, valp));
184 SKIPSPACE (cp);
185 if (*cp != ')')
186 return CALLFUNC(g, handle_error) (g, cp, ")");
188 return cp + 1; /* skip the right paren */
190 case '!':
191 DO (cp = parse_value (g, cp + 1, valp));
192 *valp = !(*valp);
193 return cp;
195 case '-':
196 DO (cp = parse_value (g, cp + 1, valp));
197 *valp = -(*valp);
198 return cp;
200 case '~':
201 DO (cp = parse_value (g, cp + 1, valp));
202 *valp = ~(*valp);
203 return cp;
205 case '#':
206 DO (cp = parse_variable (g, cp + 1, &var));
207 SKIPSPACE (cp);
208 if (*cp != '(')
209 return CALLFUNC(g, handle_error) (g, cp, "(");
210 do {
211 DO (cp = parse_variable (g, cp + 1, &var));
212 SKIPSPACE (cp);
213 } while (*cp && *cp != ')');
214 if (*cp != ')')
215 return CALLFUNC(g, handle_error) (g, cp, ")");
216 *valp = 1; /* XXX */
217 return cp + 1;
219 case '\'':
220 DO (cp = parse_character (g, cp + 1, valp));
221 if (*cp != '\'')
222 return CALLFUNC(g, handle_error) (g, cp, "'");
223 return cp + 1;
225 case 'd':
226 if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
227 int paren = 0;
228 int len;
230 cp += 7;
231 SKIPSPACE (cp);
232 if (*cp == '(') {
233 paren = 1;
234 cp++;
236 DO (cp = parse_variable (g, cp, &var));
237 len = cp - var;
238 SKIPSPACE (cp);
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 */
244 /* fall out */
247 if (isdigit(*cp)) {
248 DO (cp = parse_number (g, cp, valp));
249 } else if (!isvarfirstletter(*cp))
250 return CALLFUNC(g, handle_error) (g, cp, "variable or number");
251 else {
252 DO (cp = parse_variable (g, cp, &var));
253 *valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
256 return cp;
261 static const char *
262 parse_product (IfParser *g, const char *cp, long *valp)
264 long rightval;
266 DO (cp = parse_value (g, cp, valp));
267 SKIPSPACE (cp);
269 switch (*cp) {
270 case '*':
271 DO (cp = parse_product (g, cp + 1, &rightval));
272 *valp = (*valp * rightval);
273 break;
275 case '/':
276 DO (cp = parse_product (g, cp + 1, &rightval));
277 *valp = (*valp / rightval);
278 break;
280 case '%':
281 DO (cp = parse_product (g, cp + 1, &rightval));
282 *valp = (*valp % rightval);
283 break;
285 return cp;
289 static const char *
290 parse_sum (IfParser *g, const char *cp, long *valp)
292 long rightval;
294 DO (cp = parse_product (g, cp, valp));
295 SKIPSPACE (cp);
297 switch (*cp) {
298 case '+':
299 DO (cp = parse_sum (g, cp + 1, &rightval));
300 *valp = (*valp + rightval);
301 break;
303 case '-':
304 DO (cp = parse_sum (g, cp + 1, &rightval));
305 *valp = (*valp - rightval);
306 break;
308 return cp;
312 static const char *
313 parse_shift (IfParser *g, const char *cp, long *valp)
315 long rightval;
317 DO (cp = parse_sum (g, cp, valp));
318 SKIPSPACE (cp);
320 switch (*cp) {
321 case '<':
322 if (cp[1] == '<') {
323 DO (cp = parse_shift (g, cp + 2, &rightval));
324 *valp = (*valp << rightval);
326 break;
328 case '>':
329 if (cp[1] == '>') {
330 DO (cp = parse_shift (g, cp + 2, &rightval));
331 *valp = (*valp >> rightval);
333 break;
335 return cp;
339 static const char *
340 parse_inequality (IfParser *g, const char *cp, long *valp)
342 long rightval;
344 DO (cp = parse_shift (g, cp, valp));
345 SKIPSPACE (cp);
347 switch (*cp) {
348 case '<':
349 if (cp[1] == '=') {
350 DO (cp = parse_inequality (g, cp + 2, &rightval));
351 *valp = (*valp <= rightval);
352 } else {
353 DO (cp = parse_inequality (g, cp + 1, &rightval));
354 *valp = (*valp < rightval);
356 break;
358 case '>':
359 if (cp[1] == '=') {
360 DO (cp = parse_inequality (g, cp + 2, &rightval));
361 *valp = (*valp >= rightval);
362 } else {
363 DO (cp = parse_inequality (g, cp + 1, &rightval));
364 *valp = (*valp > rightval);
366 break;
368 return cp;
372 static const char *
373 parse_equality (IfParser *g, const char *cp, long *valp)
375 long rightval;
377 DO (cp = parse_inequality (g, cp, valp));
378 SKIPSPACE (cp);
380 switch (*cp) {
381 case '=':
382 if (cp[1] == '=')
383 cp++;
384 DO (cp = parse_equality (g, cp + 1, &rightval));
385 *valp = (*valp == rightval);
386 break;
388 case '!':
389 if (cp[1] != '=')
390 break;
391 DO (cp = parse_equality (g, cp + 2, &rightval));
392 *valp = (*valp != rightval);
393 break;
395 return cp;
399 static const char *
400 parse_band (IfParser *g, const char *cp, long *valp)
402 long rightval;
404 DO (cp = parse_equality (g, cp, valp));
405 SKIPSPACE (cp);
407 switch (*cp) {
408 case '&':
409 if (cp[1] != '&') {
410 DO (cp = parse_band (g, cp + 1, &rightval));
411 *valp = (*valp & rightval);
413 break;
415 return cp;
419 static const char *
420 parse_bxor (IfParser *g, const char *cp, long *valp)
422 long rightval;
424 DO (cp = parse_band (g, cp, valp));
425 SKIPSPACE (cp);
427 switch (*cp) {
428 case '^':
429 DO (cp = parse_bxor (g, cp + 1, &rightval));
430 *valp = (*valp ^ rightval);
431 break;
433 return cp;
437 static const char *
438 parse_bor (IfParser *g, const char *cp, long *valp)
440 long rightval;
442 DO (cp = parse_bxor (g, cp, valp));
443 SKIPSPACE (cp);
445 switch (*cp) {
446 case '|':
447 if (cp[1] != '|') {
448 DO (cp = parse_bor (g, cp + 1, &rightval));
449 *valp = (*valp | rightval);
451 break;
453 return cp;
457 static const char *
458 parse_land (IfParser *g, const char *cp, long *valp)
460 long rightval;
462 DO (cp = parse_bor (g, cp, valp));
463 SKIPSPACE (cp);
465 switch (*cp) {
466 case '&':
467 if (cp[1] != '&')
468 return CALLFUNC(g, handle_error) (g, cp, "&&");
469 DO (cp = parse_land (g, cp + 2, &rightval));
470 *valp = (*valp && rightval);
471 break;
473 return cp;
477 static const char *
478 parse_lor (IfParser *g, const char *cp, long *valp)
480 long rightval;
482 DO (cp = parse_land (g, cp, valp));
483 SKIPSPACE (cp);
485 switch (*cp) {
486 case '|':
487 if (cp[1] != '|')
488 return CALLFUNC(g, handle_error) (g, cp, "||");
489 DO (cp = parse_lor (g, cp + 2, &rightval));
490 *valp = (*valp || rightval);
491 break;
493 return cp;
497 static const char *
498 parse_cond(IfParser *g, const char *cp, long *valp)
500 long trueval, falseval;
502 DO (cp = parse_lor (g, cp, valp));
503 SKIPSPACE (cp);
505 switch (*cp) {
506 case '?':
507 DO (cp = parse_cond (g, cp + 1, &trueval));
508 SKIPSPACE (cp);
509 if (*cp != ':')
510 return CALLFUNC(g, handle_error) (g, cp, ":");
511 DO (cp = parse_cond (g, cp + 1, &falseval));
512 *valp = (*valp ? trueval : falseval);
513 break;
515 return cp;
519 /****************************************************************************
520 External Entry Points
521 ****************************************************************************/
523 const char *
524 ParseIfExpression (IfParser *g, const char *cp, long *valp)
526 return parse_cond (g, cp, valp);