1 dawes 1.1 /*
|
2 dawes 3.8 * $Xorg: ifparser.c,v 1.3 2000/08/17 19:41:50 cpqbld Exp $
|
3 dawes 1.1 *
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.
15 *
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.
23 *
24 dawes 1.1 * Author: Jim Fulton
25 * Network Computing Devices, Inc.
26 *
27 * Simple if statement processor
28 *
29 * This module can be used to evaluate string representations of C language
30 * if constructs. It accepts the following grammar:
31 *
32 * EXPRESSION := VALUE
33 * | VALUE BINOP EXPRESSION
|
34 dawes 3.6 * | VALUE '?' EXPRESSION ':' EXPRESSION
|
35 dawes 1.1 *
36 * VALUE := '(' EXPRESSION ')'
37 * | '!' VALUE
38 * | '-' VALUE
|
39 dawes 3.10 * | '+' VALUE
|
40 dawes 3.6 * | '~' VALUE
|
41 dawes 1.1 * | 'defined' '(' variable ')'
42 * | 'defined' variable
43 * | # variable '(' variable-list ')'
44 * | variable
45 * | number
46 *
47 * BINOP := '*' | '/' | '%'
48 * | '+' | '-'
49 * | '<<' | '>>'
50 * | '<' | '>' | '<=' | '>='
51 * | '==' | '!='
|
52 dawes 3.6 * | '&' | '^' | '|'
|
53 dawes 1.1 * | '&&' | '||'
54 *
|
55 dawes 3.6 * The normal C order of precedence is supported.
|
56 dawes 1.1 *
57 *
58 * External Entry Points:
59 *
60 * ParseIfExpression parse a string for #if
61 */
|
62 tsi 3.11 /* $XFree86: xc/config/makedepend/ifparser.c,v 3.10tsi Exp $ */
|
63 dawes 1.1
64 #include "ifparser.h"
65 #include <ctype.h>
|
66 dawes 3.7 #include <stdlib.h>
67 #include <string.h>
|
68 dawes 1.1
69 /****************************************************************************
70 Internal Macros and Utilities for Parser
71 ****************************************************************************/
72
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) == '_')
77
78
79 static const char *
|
80 dawes 3.7 parse_variable (IfParser *g, const char *cp, const char **varp)
|
81 dawes 1.1 {
82 SKIPSPACE (cp);
83
84 if (!isvarfirstletter (*cp))
85 return CALLFUNC(g, handle_error) (g, cp, "variable name");
86
87 *varp = cp;
88 /* EMPTY */
89 for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
90 return cp;
91 }
92
93
94 static const char *
|
95 dawes 3.7 parse_number (IfParser *g, const char *cp, long *valp)
|
96 dawes 1.1 {
|
97 tsi 3.9 long base = 10;
|
98 dawes 1.1 SKIPSPACE (cp);
99
100 if (!isdigit(*cp))
101 return CALLFUNC(g, handle_error) (g, cp, "number");
102
|
103 tsi 3.9 *valp = 0;
104
105 if (*cp == '0') {
106 cp++;
107 if ((*cp == 'x') || (*cp == 'X')) {
108 base = 16;
109 cp++;
110 } else {
111 base = 8;
112 }
113 }
114
115 /* Ignore overflows and assume ASCII, what source is usually written in */
116 while (1) {
117 int increment = -1;
118 if (base == 8) {
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 tsi 3.9 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';
131 }
132 if (increment < 0)
133 break;
134 *valp = (*valp * base) + increment;
135 }
136
137 /* Skip trailing qualifiers */
|
138 dawes 3.1 while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++;
|
139 dawes 1.1 return cp;
140 }
141
|
142 dawes 3.1 static const char *
|
143 dawes 3.7 parse_character (IfParser *g, const char *cp, long *valp)
|
144 dawes 3.1 {
145 char val;
146
147 SKIPSPACE (cp);
148 if (*cp == '\\')
149 switch (cp[1]) {
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;
163 }
164 else
165 dawes 3.1 val = *cp;
166 while (*cp != '\'') cp++;
167 *valp = (long) val;
168 return cp;
169 }
|
170 dawes 1.1
171 static const char *
|
172 dawes 3.7 parse_value (IfParser *g, const char *cp, long *valp)
|
173 dawes 1.1 {
|
174 tsi 3.11 const char *var, *varend;
|
175 dawes 1.1
176 *valp = 0;
177
178 SKIPSPACE (cp);
179 if (!*cp)
180 return cp;
181
182 switch (*cp) {
183 case '(':
184 DO (cp = ParseIfExpression (g, cp + 1, valp));
185 SKIPSPACE (cp);
186 if (*cp != ')')
187 return CALLFUNC(g, handle_error) (g, cp, ")");
188
189 return cp + 1; /* skip the right paren */
190
191 case '!':
192 DO (cp = parse_value (g, cp + 1, valp));
193 *valp = !(*valp);
194 return cp;
195
196 dawes 1.1 case '-':
197 DO (cp = parse_value (g, cp + 1, valp));
198 *valp = -(*valp);
|
199 dawes 3.10 return cp;
200
201 case '+':
202 DO (cp = parse_value (g, cp + 1, valp));
|
203 dawes 1.1 return cp;
204
|
205 dawes 3.2 case '~':
206 DO (cp = parse_value (g, cp + 1, valp));
207 *valp = ~(*valp);
208 return cp;
209
|
210 dawes 1.1 case '#':
211 DO (cp = parse_variable (g, cp + 1, &var));
212 SKIPSPACE (cp);
213 if (*cp != '(')
214 return CALLFUNC(g, handle_error) (g, cp, "(");
215 do {
216 DO (cp = parse_variable (g, cp + 1, &var));
217 SKIPSPACE (cp);
218 } while (*cp && *cp != ')');
219 if (*cp != ')')
220 return CALLFUNC(g, handle_error) (g, cp, ")");
221 *valp = 1; /* XXX */
222 return cp + 1;
223
|
224 dawes 3.1 case '\'':
225 DO (cp = parse_character (g, cp + 1, valp));
226 if (*cp != '\'')
227 return CALLFUNC(g, handle_error) (g, cp, "'");
228 return cp + 1;
229
|
230 dawes 1.1 case 'd':
231 if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
232 int paren = 0;
|
233 dawes 3.0 int len;
234
|
235 dawes 1.1 cp += 7;
236 SKIPSPACE (cp);
237 if (*cp == '(') {
238 paren = 1;
239 cp++;
240 }
241 DO (cp = parse_variable (g, cp, &var));
|
242 dawes 3.0 len = cp - var;
|
243 dawes 1.1 SKIPSPACE (cp);
244 if (paren && *cp != ')')
245 return CALLFUNC(g, handle_error) (g, cp, ")");
|
246 dawes 3.0 *valp = (*(g->funcs.eval_defined)) (g, var, len);
|
247 dawes 1.1 return cp + paren; /* skip the right paren */
248 }
249 /* fall out */
250 }
251
252 if (isdigit(*cp)) {
253 DO (cp = parse_number (g, cp, valp));
254 } else if (!isvarfirstletter(*cp))
255 return CALLFUNC(g, handle_error) (g, cp, "variable or number");
256 else {
257 DO (cp = parse_variable (g, cp, &var));
|
258 tsi 3.11 varend = cp;
259 SKIPSPACE(cp);
260 if (*cp != '(') {
261 *valp = (*(g->funcs.eval_variable)) (g, var, varend - var);
262 } else {
263 do {
264 long dummy;
265 DO (cp = ParseIfExpression (g, cp + 1, &dummy));
266 SKIPSPACE(cp);
267 if (*cp == ')')
268 break;
269 if (*cp != ',')
270 return CALLFUNC(g, handle_error) (g, cp, ",");
271 } while (1);
272
273 *valp = 1; /* XXX */
274 cp++;
275 }
|
276 dawes 1.1 }
277
278 return cp;
279 }
280
281
282
283 static const char *
|
284 dawes 3.7 parse_product (IfParser *g, const char *cp, long *valp)
|
285 dawes 1.1 {
|
286 dawes 3.1 long rightval;
|
287 dawes 1.1
288 DO (cp = parse_value (g, cp, valp));
289 SKIPSPACE (cp);
290
291 switch (*cp) {
292 case '*':
293 DO (cp = parse_product (g, cp + 1, &rightval));
294 *valp = (*valp * rightval);
295 break;
296
297 case '/':
298 DO (cp = parse_product (g, cp + 1, &rightval));
299 *valp = (*valp / rightval);
300 break;
301
302 case '%':
303 DO (cp = parse_product (g, cp + 1, &rightval));
304 *valp = (*valp % rightval);
305 break;
306 }
307 return cp;
308 dawes 1.1 }
309
310
311 static const char *
|
312 dawes 3.7 parse_sum (IfParser *g, const char *cp, long *valp)
|
313 dawes 1.1 {
|
314 dawes 3.1 long rightval;
|
315 dawes 1.1
316 DO (cp = parse_product (g, cp, valp));
317 SKIPSPACE (cp);
318
319 switch (*cp) {
320 case '+':
321 DO (cp = parse_sum (g, cp + 1, &rightval));
322 *valp = (*valp + rightval);
323 break;
324
325 case '-':
326 DO (cp = parse_sum (g, cp + 1, &rightval));
327 *valp = (*valp - rightval);
328 break;
329 }
330 return cp;
331 }
332
333
334 static const char *
|
335 dawes 3.7 parse_shift (IfParser *g, const char *cp, long *valp)
|
336 dawes 1.1 {
|
337 dawes 3.1 long rightval;
|
338 dawes 1.1
339 DO (cp = parse_sum (g, cp, valp));
340 SKIPSPACE (cp);
341
342 switch (*cp) {
343 case '<':
344 if (cp[1] == '<') {
345 DO (cp = parse_shift (g, cp + 2, &rightval));
346 *valp = (*valp << rightval);
347 }
348 break;
349
350 case '>':
351 if (cp[1] == '>') {
352 DO (cp = parse_shift (g, cp + 2, &rightval));
353 *valp = (*valp >> rightval);
354 }
355 break;
356 }
357 return cp;
358 }
359 dawes 1.1
360
361 static const char *
|
362 dawes 3.7 parse_inequality (IfParser *g, const char *cp, long *valp)
|
363 dawes 1.1 {
|
364 dawes 3.1 long rightval;
|
365 dawes 1.1
366 DO (cp = parse_shift (g, cp, valp));
367 SKIPSPACE (cp);
368
369 switch (*cp) {
370 case '<':
371 if (cp[1] == '=') {
372 DO (cp = parse_inequality (g, cp + 2, &rightval));
373 *valp = (*valp <= rightval);
374 } else {
375 DO (cp = parse_inequality (g, cp + 1, &rightval));
376 *valp = (*valp < rightval);
377 }
378 break;
379
380 case '>':
381 if (cp[1] == '=') {
382 DO (cp = parse_inequality (g, cp + 2, &rightval));
383 *valp = (*valp >= rightval);
384 } else {
385 DO (cp = parse_inequality (g, cp + 1, &rightval));
386 dawes 1.1 *valp = (*valp > rightval);
387 }
388 break;
389 }
390 return cp;
391 }
392
393
394 static const char *
|
395 dawes 3.7 parse_equality (IfParser *g, const char *cp, long *valp)
|
396 dawes 1.1 {
|
397 dawes 3.1 long rightval;
|
398 dawes 1.1
399 DO (cp = parse_inequality (g, cp, valp));
400 SKIPSPACE (cp);
401
402 switch (*cp) {
403 case '=':
404 if (cp[1] == '=')
405 cp++;
406 DO (cp = parse_equality (g, cp + 1, &rightval));
407 *valp = (*valp == rightval);
408 break;
409
410 case '!':
411 if (cp[1] != '=')
412 break;
413 DO (cp = parse_equality (g, cp + 2, &rightval));
414 *valp = (*valp != rightval);
415 break;
416 }
417 return cp;
418 }
419 dawes 1.1
420
421 static const char *
|
422 dawes 3.7 parse_band (IfParser *g, const char *cp, long *valp)
|
423 dawes 1.1 {
|
424 dawes 3.1 long rightval;
|
425 dawes 1.1
426 DO (cp = parse_equality (g, cp, valp));
427 SKIPSPACE (cp);
428
429 switch (*cp) {
430 case '&':
431 if (cp[1] != '&') {
432 DO (cp = parse_band (g, cp + 1, &rightval));
433 *valp = (*valp & rightval);
434 }
435 break;
436 }
437 return cp;
438 }
439
440
441 static const char *
|
442 dawes 3.7 parse_bxor (IfParser *g, const char *cp, long *valp)
|
443 dawes 3.6 {
444 long rightval;
445
446 DO (cp = parse_band (g, cp, valp));
447 SKIPSPACE (cp);
448
449 switch (*cp) {
450 case '^':
451 DO (cp = parse_bxor (g, cp + 1, &rightval));
452 *valp = (*valp ^ rightval);
453 break;
454 }
455 return cp;
456 }
457
458
459 static const char *
|
460 dawes 3.7 parse_bor (IfParser *g, const char *cp, long *valp)
|
461 dawes 1.1 {
|
462 dawes 3.1 long rightval;
|
463 dawes 1.1
|
464 dawes 3.6 DO (cp = parse_bxor (g, cp, valp));
|
465 dawes 1.1 SKIPSPACE (cp);
466
467 switch (*cp) {
468 case '|':
469 if (cp[1] != '|') {
470 DO (cp = parse_bor (g, cp + 1, &rightval));
471 *valp = (*valp | rightval);
472 }
473 break;
474 }
475 return cp;
476 }
477
478
479 static const char *
|
480 dawes 3.7 parse_land (IfParser *g, const char *cp, long *valp)
|
481 dawes 1.1 {
|
482 dawes 3.1 long rightval;
|
483 dawes 1.1
484 DO (cp = parse_bor (g, cp, valp));
485 SKIPSPACE (cp);
486
487 switch (*cp) {
488 case '&':
489 if (cp[1] != '&')
490 return CALLFUNC(g, handle_error) (g, cp, "&&");
491 DO (cp = parse_land (g, cp + 2, &rightval));
492 *valp = (*valp && rightval);
493 break;
494 }
495 return cp;
496 }
497
498
499 static const char *
|
500 dawes 3.7 parse_lor (IfParser *g, const char *cp, long *valp)
|
501 dawes 1.1 {
|
502 dawes 3.1 long rightval;
|
503 dawes 1.1
504 DO (cp = parse_land (g, cp, valp));
505 SKIPSPACE (cp);
506
507 switch (*cp) {
508 case '|':
509 if (cp[1] != '|')
510 return CALLFUNC(g, handle_error) (g, cp, "||");
511 DO (cp = parse_lor (g, cp + 2, &rightval));
512 *valp = (*valp || rightval);
513 break;
514 }
515 return cp;
516 }
517
518
|
519 dawes 3.6 static const char *
|
520 dawes 3.7 parse_cond(IfParser *g, const char *cp, long *valp)
|
521 dawes 3.6 {
522 long trueval, falseval;
523
524 DO (cp = parse_lor (g, cp, valp));
525 SKIPSPACE (cp);
526
527 switch (*cp) {
528 case '?':
529 DO (cp = parse_cond (g, cp + 1, &trueval));
530 SKIPSPACE (cp);
531 if (*cp != ':')
532 return CALLFUNC(g, handle_error) (g, cp, ":");
533 DO (cp = parse_cond (g, cp + 1, &falseval));
534 *valp = (*valp ? trueval : falseval);
535 break;
536 }
537 return cp;
538 }
539
540
|
541 dawes 1.1 /****************************************************************************
542 External Entry Points
543 ****************************************************************************/
544
545 const char *
|
546 dawes 3.7 ParseIfExpression (IfParser *g, const char *cp, long *valp)
|
547 dawes 1.1 {
|
548 dawes 3.6 return parse_cond (g, cp, valp);
|
549 dawes 1.1 }
|