first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / tools / dependency_tool / ifparser.cpp
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  * 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 #ifdef __WIN32__
61   #pragma warning(disable : 4996)
62 #endif
63
64 #include "ifparser.h"
65
66 #include <ctype.h>
67 #include <stdlib.h>
68 #include <string.h>
69
70 /****************************************************************************
71                    Internal Macros and Utilities for Parser
72  ****************************************************************************/
73
74 #define DO(val) if (!(val)) return NULL
75 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
76 #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
77 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
78
79
80 static const char *parse_variable(IfParser *g, const char *cp,
81     const char **varp)
82 {
83     SKIPSPACE (cp);
84
85     if (!isvarfirstletter (*cp))
86         return CALLFUNC(g, handle_error) (g, cp, "variable name");
87
88     *varp = cp;
89     /* EMPTY */
90     for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
91     return cp;
92 }
93
94
95 static const char *parse_number(IfParser *g, const char *cp, 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     char *hold_result;
104     *valp = strtol(cp, &hold_result, 0);
105     cp = hold_result;
106 #else
107     *valp = atoi (cp);
108     /* EMPTY */
109     for (cp++; isdigit(*cp); cp++) ;
110 #endif
111     return cp;
112 }
113
114
115 static const char *parse_value(IfParser *g, const char *cp, int *valp)
116 {
117     const char *var;
118
119     *valp = 0;
120
121     SKIPSPACE (cp);
122     if (!*cp)
123         return cp;
124
125     switch (*cp) {
126       case '(':
127         DO (cp = ParseIfExpression (g, cp + 1, valp));
128         SKIPSPACE (cp);
129         if (*cp != ')') 
130             return CALLFUNC(g, handle_error) (g, cp, ")");
131
132         return cp + 1;                  /* skip the right paren */
133
134       case '!':
135         DO (cp = parse_value (g, cp + 1, valp));
136         *valp = !(*valp);
137         return cp;
138
139       case '-':
140         DO (cp = parse_value (g, cp + 1, valp));
141         *valp = -(*valp);
142         return cp;
143
144       case '#':
145         DO (cp = parse_variable (g, cp + 1, &var));
146         SKIPSPACE (cp);
147         if (*cp != '(')
148             return CALLFUNC(g, handle_error) (g, cp, "(");
149         do {
150             DO (cp = parse_variable (g, cp + 1, &var));
151             SKIPSPACE (cp);
152         } while (*cp && *cp != ')');
153         if (*cp != ')')
154             return CALLFUNC(g, handle_error) (g, cp, ")");
155         *valp = 1; /* XXX */
156         return cp + 1;
157
158       case 'd':
159         if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
160             int paren = 0;
161             cp += 7;
162             SKIPSPACE (cp);
163             if (*cp == '(') {
164                 paren = 1;
165                 cp++;
166             }
167             DO (cp = parse_variable (g, cp, &var));
168             SKIPSPACE (cp);
169             if (paren && *cp != ')')
170                 return CALLFUNC(g, handle_error) (g, cp, ")");
171             *valp = (*(g->funcs.eval_defined)) (g, var, int(cp - var));
172             return cp + paren;          /* skip the right paren */
173         }
174         /* fall out */
175     }
176
177     if (isdigit(*cp)) {
178         DO (cp = parse_number (g, cp, valp));
179     } else if (!isvarfirstletter(*cp))
180         return CALLFUNC(g, handle_error) (g, cp, "variable or number");
181     else {
182         DO (cp = parse_variable (g, cp, &var));
183         *valp = (*(g->funcs.eval_variable)) (g, var, int(cp - var));
184     }
185     
186     return cp;
187 }
188
189 static const char *parse_product(IfParser *g, const char *cp, int *valp)
190 {
191     int rightval;
192
193     DO (cp = parse_value (g, cp, valp));
194     SKIPSPACE (cp);
195
196     switch (*cp) {
197       case '*':
198         DO (cp = parse_product (g, cp + 1, &rightval));
199         *valp = (*valp * rightval);
200         break;
201
202       case '/':
203         DO (cp = parse_product (g, cp + 1, &rightval));
204         *valp = (*valp / rightval);
205         break;
206
207       case '%':
208         DO (cp = parse_product (g, cp + 1, &rightval));
209         *valp = (*valp % rightval);
210         break;
211     }
212     return cp;
213 }
214
215 static const char *parse_sum(IfParser *g, const char *cp, int *valp)
216 {
217     int rightval;
218
219     DO (cp = parse_product (g, cp, valp));
220     SKIPSPACE (cp);
221
222     switch (*cp) {
223       case '+':
224         DO (cp = parse_sum (g, cp + 1, &rightval));
225         *valp = (*valp + rightval);
226         break;
227
228       case '-':
229         DO (cp = parse_sum (g, cp + 1, &rightval));
230         *valp = (*valp - rightval);
231         break;
232     }
233     return cp;
234 }
235
236
237 static const char *parse_shift(IfParser *g, const char *cp, int *valp)
238 {
239     int rightval;
240
241     DO (cp = parse_sum (g, cp, valp));
242     SKIPSPACE (cp);
243
244     switch (*cp) {
245       case '<':
246         if (cp[1] == '<') {
247             DO (cp = parse_shift (g, cp + 2, &rightval));
248             *valp = (*valp << rightval);
249         }
250         break;
251
252       case '>':
253         if (cp[1] == '>') {
254             DO (cp = parse_shift (g, cp + 2, &rightval));
255             *valp = (*valp >> rightval);
256         }
257         break;
258     }
259     return cp;
260 }
261
262 static const char *parse_inequality(IfParser *g, const char *cp, int *valp)
263 {
264     int rightval;
265
266     DO (cp = parse_shift (g, cp, valp));
267     SKIPSPACE (cp);
268
269     switch (*cp) {
270       case '<':
271         if (cp[1] == '=') {
272             DO (cp = parse_inequality (g, cp + 2, &rightval));
273             *valp = (*valp <= rightval);
274         } else {
275             DO (cp = parse_inequality (g, cp + 1, &rightval));
276             *valp = (*valp < rightval);
277         }
278         break;
279
280       case '>':
281         if (cp[1] == '=') {
282             DO (cp = parse_inequality (g, cp + 2, &rightval));
283             *valp = (*valp >= rightval);
284         } else {
285             DO (cp = parse_inequality (g, cp + 1, &rightval));
286             *valp = (*valp > rightval);
287         }
288         break;
289     }
290     return cp;
291 }
292
293 static const char *parse_equality(IfParser *g, const char *cp, int *valp)
294 {
295     int rightval;
296
297     DO (cp = parse_inequality (g, cp, valp));
298     SKIPSPACE (cp);
299
300     switch (*cp) {
301       case '=':
302         if (cp[1] == '=')
303             cp++;
304         DO (cp = parse_equality (g, cp + 1, &rightval));
305         *valp = (*valp == rightval);
306         break;
307
308       case '!':
309         if (cp[1] != '=')
310             break;
311         DO (cp = parse_equality (g, cp + 2, &rightval));
312         *valp = (*valp != rightval);
313         break;
314     }
315     return cp;
316 }
317
318 static const char *parse_band(IfParser *g, const char *cp, int *valp)
319 {
320     int rightval;
321
322     DO (cp = parse_equality (g, cp, valp));
323     SKIPSPACE (cp);
324
325     switch (*cp) {
326       case '&':
327         if (cp[1] != '&') {
328             DO (cp = parse_band (g, cp + 1, &rightval));
329             *valp = (*valp & rightval);
330         }
331         break;
332     }
333     return cp;
334 }
335
336
337 static const char *parse_bor(IfParser *g, const char *cp, int *valp)
338 {
339     int rightval;
340
341     DO (cp = parse_band (g, cp, valp));
342     SKIPSPACE (cp);
343
344     switch (*cp) {
345       case '|':
346         if (cp[1] != '|') {
347             DO (cp = parse_bor (g, cp + 1, &rightval));
348             *valp = (*valp | rightval);
349         }
350         break;
351     }
352     return cp;
353 }
354
355 static const char *parse_land(IfParser *g, const char *cp, int *valp)
356 {
357     int rightval;
358
359     DO (cp = parse_bor (g, cp, valp));
360     SKIPSPACE (cp);
361
362     switch (*cp) {
363       case '&':
364         if (cp[1] != '&')
365             return CALLFUNC(g, handle_error) (g, cp, "&&");
366         DO (cp = parse_land (g, cp + 2, &rightval));
367         *valp = (*valp && rightval);
368         break;
369     }
370     return cp;
371 }
372
373 static const char *parse_lor(IfParser *g, const char *cp, int *valp)
374 {
375     int rightval;
376
377     DO (cp = parse_land (g, cp, valp));
378     SKIPSPACE (cp);
379
380     switch (*cp) {
381       case '|':
382         if (cp[1] != '|')
383             return CALLFUNC(g, handle_error) (g, cp, "||");
384         DO (cp = parse_lor (g, cp + 2, &rightval));
385         *valp = (*valp || rightval);
386         break;
387     }
388     return cp;
389 }
390
391
392 /****************************************************************************
393                              External Entry Points
394  ****************************************************************************/
395
396 const char *ParseIfExpression(IfParser *g, const char *cp, int *valp)
397 {
398     return parse_lor (g, cp, valp);
399 }
400
401