1 dawes 1.1 /*
2 * $XConsortium: ifparser.c,v 1.7 94/01/18 21:30:50 rws Exp $
3 *
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 dawes 1.1 * PERFORMANCE OF THIS SOFTWARE.
23 *
24 * 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 *
35 * VALUE := '(' EXPRESSION ')'
36 * | '!' VALUE
37 * | '-' VALUE
38 * | 'defined' '(' variable ')'
39 * | 'defined' variable
40 * | # variable '(' variable-list ')'
41 * | variable
42 * | number
43 dawes 1.1 *
44 * BINOP := '*' | '/' | '%'
45 * | '+' | '-'
46 * | '<<' | '>>'
47 * | '<' | '>' | '<=' | '>='
48 * | '==' | '!='
49 * | '&' | '|'
50 * | '&&' | '||'
51 *
52 * The normal C order of precidence is supported.
53 *
54 *
55 * External Entry Points:
56 *
57 * ParseIfExpression parse a string for #if
58 */
59
60 #include "ifparser.h"
61 #include <ctype.h>
62
63 /****************************************************************************
64 dawes 1.1 Internal Macros and Utilities for Parser
65 ****************************************************************************/
66
67 #define DO(val) if (!(val)) return NULL
68 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
69 #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
70 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
71
72
73 static const char *
74 parse_variable (g, cp, varp)
75 IfParser *g;
76 const char *cp;
77 const char **varp;
78 {
79 SKIPSPACE (cp);
80
81 if (!isvarfirstletter (*cp))
82 return CALLFUNC(g, handle_error) (g, cp, "variable name");
83
84 *varp = cp;
85 dawes 1.1 /* EMPTY */
86 for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
87 return cp;
88 }
89
90
91 static const char *
92 parse_number (g, cp, valp)
93 IfParser *g;
94 const char *cp;
95 int *valp;
96 {
97 SKIPSPACE (cp);
98
99 if (!isdigit(*cp))
100 return CALLFUNC(g, handle_error) (g, cp, "number");
101
102 #ifdef WIN32
103 *valp = strtol(cp, &cp, 0);
104 #else
105 *valp = atoi (cp);
106 dawes 1.1 /* EMPTY */
107 for (cp++; isdigit(*cp); cp++) ;
108 #endif
109 return cp;
110 }
111
112
113 static const char *
114 parse_value (g, cp, valp)
115 IfParser *g;
116 const char *cp;
117 int *valp;
118 {
119 const char *var;
120
121 *valp = 0;
122
123 SKIPSPACE (cp);
124 if (!*cp)
125 return cp;
126
127 dawes 1.1 switch (*cp) {
128 case '(':
129 DO (cp = ParseIfExpression (g, cp + 1, valp));
130 SKIPSPACE (cp);
131 if (*cp != ')')
132 return CALLFUNC(g, handle_error) (g, cp, ")");
133
134 return cp + 1; /* skip the right paren */
135
136 case '!':
137 DO (cp = parse_value (g, cp + 1, valp));
138 *valp = !(*valp);
139 return cp;
140
141 case '-':
142 DO (cp = parse_value (g, cp + 1, valp));
143 *valp = -(*valp);
144 return cp;
145
146 case '#':
147 DO (cp = parse_variable (g, cp + 1, &var));
148 dawes 1.1 SKIPSPACE (cp);
149 if (*cp != '(')
150 return CALLFUNC(g, handle_error) (g, cp, "(");
151 do {
152 DO (cp = parse_variable (g, cp + 1, &var));
153 SKIPSPACE (cp);
154 } while (*cp && *cp != ')');
155 if (*cp != ')')
156 return CALLFUNC(g, handle_error) (g, cp, ")");
157 *valp = 1; /* XXX */
158 return cp + 1;
159
160 case 'd':
161 if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
162 int paren = 0;
163 cp += 7;
164 SKIPSPACE (cp);
165 if (*cp == '(') {
166 paren = 1;
167 cp++;
168 }
169 dawes 1.1 DO (cp = parse_variable (g, cp, &var));
170 SKIPSPACE (cp);
171 if (paren && *cp != ')')
172 return CALLFUNC(g, handle_error) (g, cp, ")");
173 *valp = (*(g->funcs.eval_defined)) (g, var, cp - var);
174 return cp + paren; /* skip the right paren */
175 }
176 /* fall out */
177 }
178
179 if (isdigit(*cp)) {
180 DO (cp = parse_number (g, cp, valp));
181 } else if (!isvarfirstletter(*cp))
182 return CALLFUNC(g, handle_error) (g, cp, "variable or number");
183 else {
184 DO (cp = parse_variable (g, cp, &var));
185 *valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
186 }
187
188 return cp;
189 }
190 dawes 1.1
191
192
193 static const char *
194 parse_product (g, cp, valp)
195 IfParser *g;
196 const char *cp;
197 int *valp;
198 {
199 int rightval;
200
201 DO (cp = parse_value (g, cp, valp));
202 SKIPSPACE (cp);
203
204 switch (*cp) {
205 case '*':
206 DO (cp = parse_product (g, cp + 1, &rightval));
207 *valp = (*valp * rightval);
208 break;
209
210 case '/':
211 dawes 1.1 DO (cp = parse_product (g, cp + 1, &rightval));
212 *valp = (*valp / rightval);
213 break;
214
215 case '%':
216 DO (cp = parse_product (g, cp + 1, &rightval));
217 *valp = (*valp % rightval);
218 break;
219 }
220 return cp;
221 }
222
223
224 static const char *
225 parse_sum (g, cp, valp)
226 IfParser *g;
227 const char *cp;
228 int *valp;
229 {
230 int rightval;
231
232 dawes 1.1 DO (cp = parse_product (g, cp, valp));
233 SKIPSPACE (cp);
234
235 switch (*cp) {
236 case '+':
237 DO (cp = parse_sum (g, cp + 1, &rightval));
238 *valp = (*valp + rightval);
239 break;
240
241 case '-':
242 DO (cp = parse_sum (g, cp + 1, &rightval));
243 *valp = (*valp - rightval);
244 break;
245 }
246 return cp;
247 }
248
249
250 static const char *
251 parse_shift (g, cp, valp)
252 IfParser *g;
253 dawes 1.1 const char *cp;
254 int *valp;
255 {
256 int rightval;
257
258 DO (cp = parse_sum (g, cp, valp));
259 SKIPSPACE (cp);
260
261 switch (*cp) {
262 case '<':
263 if (cp[1] == '<') {
264 DO (cp = parse_shift (g, cp + 2, &rightval));
265 *valp = (*valp << rightval);
266 }
267 break;
268
269 case '>':
270 if (cp[1] == '>') {
271 DO (cp = parse_shift (g, cp + 2, &rightval));
272 *valp = (*valp >> rightval);
273 }
274 dawes 1.1 break;
275 }
276 return cp;
277 }
278
279
280 static const char *
281 parse_inequality (g, cp, valp)
282 IfParser *g;
283 const char *cp;
284 int *valp;
285 {
286 int rightval;
287
288 DO (cp = parse_shift (g, cp, valp));
289 SKIPSPACE (cp);
290
291 switch (*cp) {
292 case '<':
293 if (cp[1] == '=') {
294 DO (cp = parse_inequality (g, cp + 2, &rightval));
295 dawes 1.1 *valp = (*valp <= rightval);
296 } else {
297 DO (cp = parse_inequality (g, cp + 1, &rightval));
298 *valp = (*valp < rightval);
299 }
300 break;
301
302 case '>':
303 if (cp[1] == '=') {
304 DO (cp = parse_inequality (g, cp + 2, &rightval));
305 *valp = (*valp >= rightval);
306 } else {
307 DO (cp = parse_inequality (g, cp + 1, &rightval));
308 *valp = (*valp > rightval);
309 }
310 break;
311 }
312 return cp;
313 }
314
315
316 dawes 1.1 static const char *
317 parse_equality (g, cp, valp)
318 IfParser *g;
319 const char *cp;
320 int *valp;
321 {
322 int rightval;
323
324 DO (cp = parse_inequality (g, cp, valp));
325 SKIPSPACE (cp);
326
327 switch (*cp) {
328 case '=':
329 if (cp[1] == '=')
330 cp++;
331 DO (cp = parse_equality (g, cp + 1, &rightval));
332 *valp = (*valp == rightval);
333 break;
334
335 case '!':
336 if (cp[1] != '=')
337 dawes 1.1 break;
338 DO (cp = parse_equality (g, cp + 2, &rightval));
339 *valp = (*valp != rightval);
340 break;
341 }
342 return cp;
343 }
344
345
346 static const char *
347 parse_band (g, cp, valp)
348 IfParser *g;
349 const char *cp;
350 int *valp;
351 {
352 int rightval;
353
354 DO (cp = parse_equality (g, cp, valp));
355 SKIPSPACE (cp);
356
357 switch (*cp) {
358 dawes 1.1 case '&':
359 if (cp[1] != '&') {
360 DO (cp = parse_band (g, cp + 1, &rightval));
361 *valp = (*valp & rightval);
362 }
363 break;
364 }
365 return cp;
366 }
367
368
369 static const char *
370 parse_bor (g, cp, valp)
371 IfParser *g;
372 const char *cp;
373 int *valp;
374 {
375 int rightval;
376
377 DO (cp = parse_band (g, cp, valp));
378 SKIPSPACE (cp);
379 dawes 1.1
380 switch (*cp) {
381 case '|':
382 if (cp[1] != '|') {
383 DO (cp = parse_bor (g, cp + 1, &rightval));
384 *valp = (*valp | rightval);
385 }
386 break;
387 }
388 return cp;
389 }
390
391
392 static const char *
393 parse_land (g, cp, valp)
394 IfParser *g;
395 const char *cp;
396 int *valp;
397 {
398 int rightval;
399
400 dawes 1.1 DO (cp = parse_bor (g, cp, valp));
401 SKIPSPACE (cp);
402
403 switch (*cp) {
404 case '&':
405 if (cp[1] != '&')
406 return CALLFUNC(g, handle_error) (g, cp, "&&");
407 DO (cp = parse_land (g, cp + 2, &rightval));
408 *valp = (*valp && rightval);
409 break;
410 }
411 return cp;
412 }
413
414
415 static const char *
416 parse_lor (g, cp, valp)
417 IfParser *g;
418 const char *cp;
419 int *valp;
420 {
421 dawes 1.1 int rightval;
422
423 DO (cp = parse_land (g, cp, valp));
424 SKIPSPACE (cp);
425
426 switch (*cp) {
427 case '|':
428 if (cp[1] != '|')
429 return CALLFUNC(g, handle_error) (g, cp, "||");
430 DO (cp = parse_lor (g, cp + 2, &rightval));
431 *valp = (*valp || rightval);
432 break;
433 }
434 return cp;
435 }
436
437
438 /****************************************************************************
439 External Entry Points
440 ****************************************************************************/
441
442 dawes 1.1 const char *
443 ParseIfExpression (g, cp, valp)
444 IfParser *g;
445 const char *cp;
446 int *valp;
447 {
448 return parse_lor (g, cp, valp);
449 }
450
451
|