blob: 60740bcca67f8b7b656f7be37edbefa48da5c86e [file] [log] [blame]
Adam Tkacfded0782008-03-22 11:20:54 +00001/*
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 * 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 *
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 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
73static const char *
74parse_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 /* EMPTY */
86 for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
87 return cp;
88}
89
90
91static const char *
92parse_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 *valp = strtol(cp, &cp, 0);
103 return cp;
104}
105
106
107static const char *
108parse_value (g, cp, valp)
109 IfParser *g;
110 const char *cp;
111 int *valp;
112{
113 const char *var;
114
115 *valp = 0;
116
117 SKIPSPACE (cp);
118 if (!*cp)
119 return cp;
120
121 switch (*cp) {
122 case '(':
123 DO (cp = ParseIfExpression (g, cp + 1, valp));
124 SKIPSPACE (cp);
125 if (*cp != ')')
126 return CALLFUNC(g, handle_error) (g, cp, ")");
127
128 return cp + 1; /* skip the right paren */
129
130 case '!':
131 DO (cp = parse_value (g, cp + 1, valp));
132 *valp = !(*valp);
133 return cp;
134
135 case '-':
136 DO (cp = parse_value (g, cp + 1, valp));
137 *valp = -(*valp);
138 return cp;
139
140 case '#':
141 DO (cp = parse_variable (g, cp + 1, &var));
142 SKIPSPACE (cp);
143 if (*cp != '(')
144 return CALLFUNC(g, handle_error) (g, cp, "(");
145 do {
146 DO (cp = parse_variable (g, cp + 1, &var));
147 SKIPSPACE (cp);
148 } while (*cp && *cp != ')');
149 if (*cp != ')')
150 return CALLFUNC(g, handle_error) (g, cp, ")");
151 *valp = 1; /* XXX */
152 return cp + 1;
153
154 case 'd':
155 if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
156 int paren = 0;
157 cp += 7;
158 SKIPSPACE (cp);
159 if (*cp == '(') {
160 paren = 1;
161 cp++;
162 }
163 DO (cp = parse_variable (g, cp, &var));
164 SKIPSPACE (cp);
165 if (paren && *cp != ')')
166 return CALLFUNC(g, handle_error) (g, cp, ")");
167 *valp = (*(g->funcs.eval_defined)) (g, var, cp - var);
168 return cp + paren; /* skip the right paren */
169 }
170 /* fall out */
171 }
172
173 if (isdigit(*cp)) {
174 DO (cp = parse_number (g, cp, valp));
175 } else if (!isvarfirstletter(*cp))
176 return CALLFUNC(g, handle_error) (g, cp, "variable or number");
177 else {
178 DO (cp = parse_variable (g, cp, &var));
179 *valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
180 }
181
182 return cp;
183}
184
185
186
187static const char *
188parse_product (g, cp, valp)
189 IfParser *g;
190 const char *cp;
191 int *valp;
192{
193 int rightval;
194
195 DO (cp = parse_value (g, cp, valp));
196 SKIPSPACE (cp);
197
198 switch (*cp) {
199 case '*':
200 DO (cp = parse_product (g, cp + 1, &rightval));
201 *valp = (*valp * rightval);
202 break;
203
204 case '/':
205 DO (cp = parse_product (g, cp + 1, &rightval));
206 *valp = (*valp / rightval);
207 break;
208
209 case '%':
210 DO (cp = parse_product (g, cp + 1, &rightval));
211 *valp = (*valp % rightval);
212 break;
213 }
214 return cp;
215}
216
217
218static const char *
219parse_sum (g, cp, valp)
220 IfParser *g;
221 const char *cp;
222 int *valp;
223{
224 int rightval;
225
226 DO (cp = parse_product (g, cp, valp));
227 SKIPSPACE (cp);
228
229 switch (*cp) {
230 case '+':
231 DO (cp = parse_sum (g, cp + 1, &rightval));
232 *valp = (*valp + rightval);
233 break;
234
235 case '-':
236 DO (cp = parse_sum (g, cp + 1, &rightval));
237 *valp = (*valp - rightval);
238 break;
239 }
240 return cp;
241}
242
243
244static const char *
245parse_shift (g, cp, valp)
246 IfParser *g;
247 const char *cp;
248 int *valp;
249{
250 int rightval;
251
252 DO (cp = parse_sum (g, cp, valp));
253 SKIPSPACE (cp);
254
255 switch (*cp) {
256 case '<':
257 if (cp[1] == '<') {
258 DO (cp = parse_shift (g, cp + 2, &rightval));
259 *valp = (*valp << rightval);
260 }
261 break;
262
263 case '>':
264 if (cp[1] == '>') {
265 DO (cp = parse_shift (g, cp + 2, &rightval));
266 *valp = (*valp >> rightval);
267 }
268 break;
269 }
270 return cp;
271}
272
273
274static const char *
275parse_inequality (g, cp, valp)
276 IfParser *g;
277 const char *cp;
278 int *valp;
279{
280 int rightval;
281
282 DO (cp = parse_shift (g, cp, valp));
283 SKIPSPACE (cp);
284
285 switch (*cp) {
286 case '<':
287 if (cp[1] == '=') {
288 DO (cp = parse_inequality (g, cp + 2, &rightval));
289 *valp = (*valp <= rightval);
290 } else {
291 DO (cp = parse_inequality (g, cp + 1, &rightval));
292 *valp = (*valp < rightval);
293 }
294 break;
295
296 case '>':
297 if (cp[1] == '=') {
298 DO (cp = parse_inequality (g, cp + 2, &rightval));
299 *valp = (*valp >= rightval);
300 } else {
301 DO (cp = parse_inequality (g, cp + 1, &rightval));
302 *valp = (*valp > rightval);
303 }
304 break;
305 }
306 return cp;
307}
308
309
310static const char *
311parse_equality (g, cp, valp)
312 IfParser *g;
313 const char *cp;
314 int *valp;
315{
316 int rightval;
317
318 DO (cp = parse_inequality (g, cp, valp));
319 SKIPSPACE (cp);
320
321 switch (*cp) {
322 case '=':
323 if (cp[1] == '=')
324 cp++;
325 DO (cp = parse_equality (g, cp + 1, &rightval));
326 *valp = (*valp == rightval);
327 break;
328
329 case '!':
330 if (cp[1] != '=')
331 break;
332 DO (cp = parse_equality (g, cp + 2, &rightval));
333 *valp = (*valp != rightval);
334 break;
335 }
336 return cp;
337}
338
339
340static const char *
341parse_band (g, cp, valp)
342 IfParser *g;
343 const char *cp;
344 int *valp;
345{
346 int rightval;
347
348 DO (cp = parse_equality (g, cp, valp));
349 SKIPSPACE (cp);
350
351 switch (*cp) {
352 case '&':
353 if (cp[1] != '&') {
354 DO (cp = parse_band (g, cp + 1, &rightval));
355 *valp = (*valp & rightval);
356 }
357 break;
358 }
359 return cp;
360}
361
362
363static const char *
364parse_bor (g, cp, valp)
365 IfParser *g;
366 const char *cp;
367 int *valp;
368{
369 int rightval;
370
371 DO (cp = parse_band (g, cp, valp));
372 SKIPSPACE (cp);
373
374 switch (*cp) {
375 case '|':
376 if (cp[1] != '|') {
377 DO (cp = parse_bor (g, cp + 1, &rightval));
378 *valp = (*valp | rightval);
379 }
380 break;
381 }
382 return cp;
383}
384
385
386static const char *
387parse_land (g, cp, valp)
388 IfParser *g;
389 const char *cp;
390 int *valp;
391{
392 int rightval;
393
394 DO (cp = parse_bor (g, cp, valp));
395 SKIPSPACE (cp);
396
397 switch (*cp) {
398 case '&':
399 if (cp[1] != '&')
400 return CALLFUNC(g, handle_error) (g, cp, "&&");
401 DO (cp = parse_land (g, cp + 2, &rightval));
402 *valp = (*valp && rightval);
403 break;
404 }
405 return cp;
406}
407
408
409static const char *
410parse_lor (g, cp, valp)
411 IfParser *g;
412 const char *cp;
413 int *valp;
414{
415 int rightval;
416
417 DO (cp = parse_land (g, cp, valp));
418 SKIPSPACE (cp);
419
420 switch (*cp) {
421 case '|':
422 if (cp[1] != '|')
423 return CALLFUNC(g, handle_error) (g, cp, "||");
424 DO (cp = parse_lor (g, cp + 2, &rightval));
425 *valp = (*valp || rightval);
426 break;
427 }
428 return cp;
429}
430
431
432/****************************************************************************
433 External Entry Points
434 ****************************************************************************/
435
436const char *
437ParseIfExpression (g, cp, valp)
438 IfParser *g;
439 const char *cp;
440 int *valp;
441{
442 return parse_lor (g, cp, valp);
443}
444
445