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