Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * $XConsortium: ifparser.c /main/9 1995/08/09 14:10:57 kaleb $
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
 
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
    /* 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
    long *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
    /* skip trailing qualifiers */
104
    while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++;
105
#if 0
106
    *valp = atoi (cp);
107
    /* EMPTY */
108
    for (cp++; isdigit(*cp); cp++) ;
109
#endif
110
    return cp;
111
}
112
 
113
static const char *
114
parse_character (g, cp, valp)
115
    IfParser *g;
116
    const char *cp;
117
    long *valp;
118
{
119
    char val;
120
 
121
    (void) g;
122
    SKIPSPACE (cp);
123
    if (*cp == '\\')
124
	switch (cp[1]) {
125
	case 'n':  val = '\n'; break;
126
	case 't':  val = '\t'; break;
127
	case 'v':  val = '\v'; break;
128
	case 'b':  val = '\b'; break;
129
	case 'r':  val = '\r'; break;
130
	case 'f':  val = '\f'; break;
131
	case 'a':  val = '\a'; break;
132
	case '\\': val = '\\'; break;
133
	case '?':  val = '\?'; break;
134
	case '\'': val = '\''; break;
135
	case '\"': val = '\"'; break;
136
	case 'x':  val = (char) strtol (cp + 2, NULL, 16); break;
137
	default:   val = (char) strtol (cp + 1, NULL, 8); break;
138
	}
139
    else
140
	val = *cp;
141
    while (*cp != '\'') cp++;
142
    *valp = (long) val;
143
    return cp;
144
}
145
 
146
static const char *
147
parse_value (g, cp, valp)
148
    IfParser *g;
149
    const char *cp;
150
    long *valp;
151
{
152
    const char *var;
153
 
154
    *valp = 0;
155
 
156
    SKIPSPACE (cp);
157
    if (!*cp)
158
	return cp;
159
 
160
    switch (*cp) {
161
      case '(':
162
	DO (cp = ParseIfExpression (g, cp + 1, valp));
163
	SKIPSPACE (cp);
164
	if (*cp != ')') 
165
	    return CALLFUNC(g, handle_error) (g, cp, ")");
166
 
167
	return cp + 1;			/* skip the right paren */
168
 
169
      case '!':
170
	DO (cp = parse_value (g, cp + 1, valp));
171
	*valp = !(*valp);
172
	return cp;
173
 
174
      case '-':
175
	DO (cp = parse_value (g, cp + 1, valp));
176
	*valp = -(*valp);
177
	return cp;
178
 
179
      case '#':
180
	DO (cp = parse_variable (g, cp + 1, &var));
181
	SKIPSPACE (cp);
182
	if (*cp != '(')
183
	    return CALLFUNC(g, handle_error) (g, cp, "(");
184
	do {
185
	    DO (cp = parse_variable (g, cp + 1, &var));
186
	    SKIPSPACE (cp);
187
	} while (*cp && *cp != ')');
188
	if (*cp != ')')
189
	    return CALLFUNC(g, handle_error) (g, cp, ")");
190
	*valp = 1; /* XXX */
191
	return cp + 1;
192
 
193
      case '\'':
194
	DO (cp = parse_character (g, cp + 1, valp));
195
	if (*cp != '\'')
196
	    return CALLFUNC(g, handle_error) (g, cp, "'");
197
	return cp + 1;
198
 
199
      case 'd':
200
	if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
201
	    int paren = 0;
202
	    int len;
203
 
204
	    cp += 7;
205
	    SKIPSPACE (cp);
206
	    if (*cp == '(') {
207
		paren = 1;
208
		cp++;
209
	    }
210
	    DO (cp = parse_variable (g, cp, &var));
211
	    len = cp - var;
212
	    SKIPSPACE (cp);
213
	    if (paren && *cp != ')')
214
		return CALLFUNC(g, handle_error) (g, cp, ")");
215
	    *valp = (*(g->funcs.eval_defined)) (g, var, len);
216
	    return cp + paren;		/* skip the right paren */
217
	}
218
	/* fall out */
219
    }
220
 
221
    if (isdigit(*cp)) {
222
	DO (cp = parse_number (g, cp, valp));
223
    } else if (!isvarfirstletter(*cp))
224
	return CALLFUNC(g, handle_error) (g, cp, "variable or number");
225
    else {
226
	DO (cp = parse_variable (g, cp, &var));
227
	*valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
228
    }
229
 
230
    return cp;
231
}
232
 
233
 
234
 
235
static const char *
236
parse_product (g, cp, valp)
237
    IfParser *g;
238
    const char *cp;
239
    long *valp;
240
{
241
    long rightval;
242
 
243
    DO (cp = parse_value (g, cp, valp));
244
    SKIPSPACE (cp);
245
 
246
    switch (*cp) {
247
      case '*':
248
	DO (cp = parse_product (g, cp + 1, &rightval));
249
	*valp = (*valp * rightval);
250
	break;
251
 
252
      case '/':
253
	DO (cp = parse_product (g, cp + 1, &rightval));
254
	*valp = (*valp / rightval);
255
	break;
256
 
257
      case '%':
258
	DO (cp = parse_product (g, cp + 1, &rightval));
259
	*valp = (*valp % rightval);
260
	break;
261
    }
262
    return cp;
263
}
264
 
265
 
266
static const char *
267
parse_sum (g, cp, valp)
268
    IfParser *g;
269
    const char *cp;
270
    long *valp;
271
{
272
    long rightval;
273
 
274
    DO (cp = parse_product (g, cp, valp));
275
    SKIPSPACE (cp);
276
 
277
    switch (*cp) {
278
      case '+':
279
	DO (cp = parse_sum (g, cp + 1, &rightval));
280
	*valp = (*valp + rightval);
281
	break;
282
 
283
      case '-':
284
	DO (cp = parse_sum (g, cp + 1, &rightval));
285
	*valp = (*valp - rightval);
286
	break;
287
    }
288
    return cp;
289
}
290
 
291
 
292
static const char *
293
parse_shift (g, cp, valp)
294
    IfParser *g;
295
    const char *cp;
296
    long *valp;
297
{
298
    long rightval;
299
 
300
    DO (cp = parse_sum (g, cp, valp));
301
    SKIPSPACE (cp);
302
 
303
    switch (*cp) {
304
      case '<':
305
	if (cp[1] == '<') {
306
	    DO (cp = parse_shift (g, cp + 2, &rightval));
307
	    *valp = (*valp << rightval);
308
	}
309
	break;
310
 
311
      case '>':
312
	if (cp[1] == '>') {
313
	    DO (cp = parse_shift (g, cp + 2, &rightval));
314
	    *valp = (*valp >> rightval);
315
	}
316
	break;
317
    }
318
    return cp;
319
}
320
 
321
 
322
static const char *
323
parse_inequality (g, cp, valp)
324
    IfParser *g;
325
    const char *cp;
326
    long *valp;
327
{
328
    long rightval;
329
 
330
    DO (cp = parse_shift (g, cp, valp));
331
    SKIPSPACE (cp);
332
 
333
    switch (*cp) {
334
      case '<':
335
	if (cp[1] == '=') {
336
	    DO (cp = parse_inequality (g, cp + 2, &rightval));
337
	    *valp = (*valp <= rightval);
338
	} else {
339
	    DO (cp = parse_inequality (g, cp + 1, &rightval));
340
	    *valp = (*valp < rightval);
341
	}
342
	break;
343
 
344
      case '>':
345
	if (cp[1] == '=') {
346
	    DO (cp = parse_inequality (g, cp + 2, &rightval));
347
	    *valp = (*valp >= rightval);
348
	} else {
349
	    DO (cp = parse_inequality (g, cp + 1, &rightval));
350
	    *valp = (*valp > rightval);
351
	}
352
	break;
353
    }
354
    return cp;
355
}
356
 
357
 
358
static const char *
359
parse_equality (g, cp, valp)
360
    IfParser *g;
361
    const char *cp;
362
    long *valp;
363
{
364
    long rightval;
365
 
366
    DO (cp = parse_inequality (g, cp, valp));
367
    SKIPSPACE (cp);
368
 
369
    switch (*cp) {
370
      case '=':
371
	if (cp[1] == '=')
372
	    cp++;
373
	DO (cp = parse_equality (g, cp + 1, &rightval));
374
	*valp = (*valp == rightval);
375
	break;
376
 
377
      case '!':
378
	if (cp[1] != '=')
379
	    break;
380
	DO (cp = parse_equality (g, cp + 2, &rightval));
381
	*valp = (*valp != rightval);
382
	break;
383
    }
384
    return cp;
385
}
386
 
387
 
388
static const char *
389
parse_band (g, cp, valp)
390
    IfParser *g;
391
    const char *cp;
392
    long *valp;
393
{
394
    long rightval;
395
 
396
    DO (cp = parse_equality (g, cp, valp));
397
    SKIPSPACE (cp);
398
 
399
    switch (*cp) {
400
      case '&':
401
	if (cp[1] != '&') {
402
	    DO (cp = parse_band (g, cp + 1, &rightval));
403
	    *valp = (*valp & rightval);
404
	}
405
	break;
406
    }
407
    return cp;
408
}
409
 
410
 
411
static const char *
412
parse_bor (g, cp, valp)
413
    IfParser *g;
414
    const char *cp;
415
    long *valp;
416
{
417
    long rightval;
418
 
419
    DO (cp = parse_band (g, cp, valp));
420
    SKIPSPACE (cp);
421
 
422
    switch (*cp) {
423
      case '|':
424
	if (cp[1] != '|') {
425
	    DO (cp = parse_bor (g, cp + 1, &rightval));
426
	    *valp = (*valp | rightval);
427
	}
428
	break;
429
    }
430
    return cp;
431
}
432
 
433
 
434
static const char *
435
parse_land (g, cp, valp)
436
    IfParser *g;
437
    const char *cp;
438
    long *valp;
439
{
440
    long rightval;
441
 
442
    DO (cp = parse_bor (g, cp, valp));
443
    SKIPSPACE (cp);
444
 
445
    switch (*cp) {
446
      case '&':
447
	if (cp[1] != '&')
448
	    return CALLFUNC(g, handle_error) (g, cp, "&&");
449
	DO (cp = parse_land (g, cp + 2, &rightval));
450
	*valp = (*valp && rightval);
451
	break;
452
    }
453
    return cp;
454
}
455
 
456
 
457
static const char *
458
parse_lor (g, cp, valp)
459
    IfParser *g;
460
    const char *cp;
461
    long *valp;
462
{
463
    long rightval;
464
 
465
    DO (cp = parse_land (g, cp, valp));
466
    SKIPSPACE (cp);
467
 
468
    switch (*cp) {
469
      case '|':
470
	if (cp[1] != '|')
471
	    return CALLFUNC(g, handle_error) (g, cp, "||");
472
	DO (cp = parse_lor (g, cp + 2, &rightval));
473
	*valp = (*valp || rightval);
474
	break;
475
    }
476
    return cp;
477
}
478
 
479
 
480
/****************************************************************************
481
			     External Entry Points
482
 ****************************************************************************/
483
 
484
const char *
485
ParseIfExpression (g, cp, valp)
486
    IfParser *g;
487
    const char *cp;
488
    long *valp;
489
{
490
    return parse_lor (g, cp, valp);
491
}
492
 
493