Subversion Repositories DevTools

Rev

Rev 333 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
333 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));
5995 dpurdie 254
    if (rightval == 0)
255
    {
256
        *valp = 0;
257
        return CALLFUNC(g, handle_error) (g, cp, "Divide by zero. Set result to zero.");
258
    }
259
    else
260
    {
261
        *valp = (*valp / rightval); 
262
    }
333 dpurdie 263
	break;
264
 
265
      case '%':
266
	DO (cp = parse_product (g, cp + 1, &rightval));
5995 dpurdie 267
    if (rightval == 0)
268
    {
269
        *valp = 0;
270
        return CALLFUNC(g, handle_error) (g, cp, "Mod by zero. Set result to zero.");
271
    }
272
    else
273
    {
274
        *valp = (*valp % rightval); 
275
    }
333 dpurdie 276
	break;
277
    }
278
    return cp;
279
}
280
 
281
 
282
static const char *
283
parse_sum (g, cp, valp)
284
    IfParser *g;
285
    const char *cp;
286
    long *valp;
287
{
288
    long rightval;
289
 
290
    DO (cp = parse_product (g, cp, valp));
291
    SKIPSPACE (cp);
292
 
293
    switch (*cp) {
294
      case '+':
295
	DO (cp = parse_sum (g, cp + 1, &rightval));
296
	*valp = (*valp + rightval);
297
	break;
298
 
299
      case '-':
300
	DO (cp = parse_sum (g, cp + 1, &rightval));
301
	*valp = (*valp - rightval);
302
	break;
303
    }
304
    return cp;
305
}
306
 
307
 
308
static const char *
309
parse_shift (g, cp, valp)
310
    IfParser *g;
311
    const char *cp;
312
    long *valp;
313
{
314
    long rightval;
315
 
316
    DO (cp = parse_sum (g, cp, valp));
317
    SKIPSPACE (cp);
318
 
319
    switch (*cp) {
320
      case '<':
321
	if (cp[1] == '<') {
322
	    DO (cp = parse_shift (g, cp + 2, &rightval));
323
	    *valp = (*valp << rightval);
324
	}
325
	break;
326
 
327
      case '>':
328
	if (cp[1] == '>') {
329
	    DO (cp = parse_shift (g, cp + 2, &rightval));
330
	    *valp = (*valp >> rightval);
331
	}
332
	break;
333
    }
334
    return cp;
335
}
336
 
337
 
338
static const char *
339
parse_inequality (g, cp, valp)
340
    IfParser *g;
341
    const char *cp;
342
    long *valp;
343
{
344
    long rightval;
345
 
346
    DO (cp = parse_shift (g, cp, valp));
347
    SKIPSPACE (cp);
348
 
349
    switch (*cp) {
350
      case '<':
351
	if (cp[1] == '=') {
352
	    DO (cp = parse_inequality (g, cp + 2, &rightval));
353
	    *valp = (*valp <= rightval);
354
	} else {
355
	    DO (cp = parse_inequality (g, cp + 1, &rightval));
356
	    *valp = (*valp < rightval);
357
	}
358
	break;
359
 
360
      case '>':
361
	if (cp[1] == '=') {
362
	    DO (cp = parse_inequality (g, cp + 2, &rightval));
363
	    *valp = (*valp >= rightval);
364
	} else {
365
	    DO (cp = parse_inequality (g, cp + 1, &rightval));
366
	    *valp = (*valp > rightval);
367
	}
368
	break;
369
    }
370
    return cp;
371
}
372
 
373
 
374
static const char *
375
parse_equality (g, cp, valp)
376
    IfParser *g;
377
    const char *cp;
378
    long *valp;
379
{
380
    long rightval;
381
 
382
    DO (cp = parse_inequality (g, cp, valp));
383
    SKIPSPACE (cp);
384
 
385
    switch (*cp) {
386
      case '=':
387
	if (cp[1] == '=')
388
	    cp++;
389
	DO (cp = parse_equality (g, cp + 1, &rightval));
390
	*valp = (*valp == rightval);
391
	break;
392
 
393
      case '!':
394
	if (cp[1] != '=')
395
	    break;
396
	DO (cp = parse_equality (g, cp + 2, &rightval));
397
	*valp = (*valp != rightval);
398
	break;
399
    }
400
    return cp;
401
}
402
 
403
 
404
static const char *
405
parse_band (g, cp, valp)
406
    IfParser *g;
407
    const char *cp;
408
    long *valp;
409
{
410
    long rightval;
411
 
412
    DO (cp = parse_equality (g, cp, valp));
413
    SKIPSPACE (cp);
414
 
415
    switch (*cp) {
416
      case '&':
417
	if (cp[1] != '&') {
418
	    DO (cp = parse_band (g, cp + 1, &rightval));
419
	    *valp = (*valp & rightval);
420
	}
421
	break;
422
    }
423
    return cp;
424
}
425
 
426
 
427
static const char *
428
parse_bor (g, cp, valp)
429
    IfParser *g;
430
    const char *cp;
431
    long *valp;
432
{
433
    long rightval;
434
 
435
    DO (cp = parse_band (g, cp, valp));
436
    SKIPSPACE (cp);
437
 
438
    switch (*cp) {
439
      case '|':
440
	if (cp[1] != '|') {
441
	    DO (cp = parse_bor (g, cp + 1, &rightval));
442
	    *valp = (*valp | rightval);
443
	}
444
	break;
445
    }
446
    return cp;
447
}
448
 
449
 
450
static const char *
451
parse_land (g, cp, valp)
452
    IfParser *g;
453
    const char *cp;
454
    long *valp;
455
{
456
    long rightval;
457
 
458
    DO (cp = parse_bor (g, cp, valp));
459
    SKIPSPACE (cp);
460
 
461
    switch (*cp) {
462
      case '&':
463
	if (cp[1] != '&')
464
	    return CALLFUNC(g, handle_error) (g, cp, "&&");
465
	DO (cp = parse_land (g, cp + 2, &rightval));
466
	*valp = (*valp && rightval);
467
	break;
468
    }
469
    return cp;
470
}
471
 
472
 
473
static const char *
474
parse_lor (g, cp, valp)
475
    IfParser *g;
476
    const char *cp;
477
    long *valp;
478
{
479
    long rightval;
480
 
481
    DO (cp = parse_land (g, cp, valp));
482
    SKIPSPACE (cp);
483
 
484
    switch (*cp) {
485
      case '|':
486
	if (cp[1] != '|')
487
	    return CALLFUNC(g, handle_error) (g, cp, "||");
488
	DO (cp = parse_lor (g, cp + 2, &rightval));
489
	*valp = (*valp || rightval);
490
	break;
491
    }
492
    return cp;
493
}
494
 
495
 
496
/****************************************************************************
497
			     External Entry Points
498
 ****************************************************************************/
499
 
500
const char *
501
ParseIfExpression (g, cp, valp)
502
    IfParser *g;
503
    const char *cp;
504
    long *valp;
505
{
506
    return parse_lor (g, cp, valp);
507
}
508
 
509