bringing in testkit tools
[feisty_meow.git] / nucleus / 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         break;
175         /* fall out */
176     }
177
178     if (isdigit(*cp)) {
179         DO (cp = parse_number (g, cp, valp));
180     } else if (!isvarfirstletter(*cp))
181         return CALLFUNC(g, handle_error) (g, cp, "variable or number");
182     else {
183         DO (cp = parse_variable (g, cp, &var));
184         *valp = (*(g->funcs.eval_variable)) (g, var, int(cp - var));
185     }
186     
187     return cp;
188 }
189
190 static const char *parse_product(IfParser *g, const char *cp, int *valp)
191 {
192     int rightval;
193
194     DO (cp = parse_value (g, cp, valp));
195     SKIPSPACE (cp);
196
197     switch (*cp) {
198       case '*':
199         DO (cp = parse_product (g, cp + 1, &rightval));
200         *valp = (*valp * rightval);
201         break;
202
203       case '/':
204         DO (cp = parse_product (g, cp + 1, &rightval));
205         *valp = (*valp / rightval);
206         break;
207
208       case '%':
209         DO (cp = parse_product (g, cp + 1, &rightval));
210         *valp = (*valp % rightval);
211         break;
212     }
213     return cp;
214 }
215
216 static const char *parse_sum(IfParser *g, const char *cp, int *valp)
217 {
218     int rightval;
219
220     DO (cp = parse_product (g, cp, valp));
221     SKIPSPACE (cp);
222
223     switch (*cp) {
224       case '+':
225         DO (cp = parse_sum (g, cp + 1, &rightval));
226         *valp = (*valp + rightval);
227         break;
228
229       case '-':
230         DO (cp = parse_sum (g, cp + 1, &rightval));
231         *valp = (*valp - rightval);
232         break;
233     }
234     return cp;
235 }
236
237
238 static const char *parse_shift(IfParser *g, const char *cp, int *valp)
239 {
240     int rightval;
241
242     DO (cp = parse_sum (g, cp, valp));
243     SKIPSPACE (cp);
244
245     switch (*cp) {
246       case '<':
247         if (cp[1] == '<') {
248             DO (cp = parse_shift (g, cp + 2, &rightval));
249             *valp = (*valp << rightval);
250         }
251         break;
252
253       case '>':
254         if (cp[1] == '>') {
255             DO (cp = parse_shift (g, cp + 2, &rightval));
256             *valp = (*valp >> rightval);
257         }
258         break;
259     }
260     return cp;
261 }
262
263 static const char *parse_inequality(IfParser *g, const char *cp, int *valp)
264 {
265     int rightval;
266
267     DO (cp = parse_shift (g, cp, valp));
268     SKIPSPACE (cp);
269
270     switch (*cp) {
271       case '<':
272         if (cp[1] == '=') {
273             DO (cp = parse_inequality (g, cp + 2, &rightval));
274             *valp = (*valp <= rightval);
275         } else {
276             DO (cp = parse_inequality (g, cp + 1, &rightval));
277             *valp = (*valp < rightval);
278         }
279         break;
280
281       case '>':
282         if (cp[1] == '=') {
283             DO (cp = parse_inequality (g, cp + 2, &rightval));
284             *valp = (*valp >= rightval);
285         } else {
286             DO (cp = parse_inequality (g, cp + 1, &rightval));
287             *valp = (*valp > rightval);
288         }
289         break;
290     }
291     return cp;
292 }
293
294 static const char *parse_equality(IfParser *g, const char *cp, int *valp)
295 {
296     int rightval;
297
298     DO (cp = parse_inequality (g, cp, valp));
299     SKIPSPACE (cp);
300
301     switch (*cp) {
302       case '=':
303         if (cp[1] == '=')
304             cp++;
305         DO (cp = parse_equality (g, cp + 1, &rightval));
306         *valp = (*valp == rightval);
307         break;
308
309       case '!':
310         if (cp[1] != '=')
311             break;
312         DO (cp = parse_equality (g, cp + 2, &rightval));
313         *valp = (*valp != rightval);
314         break;
315     }
316     return cp;
317 }
318
319 static const char *parse_band(IfParser *g, const char *cp, int *valp)
320 {
321     int rightval;
322
323     DO (cp = parse_equality (g, cp, valp));
324     SKIPSPACE (cp);
325
326     switch (*cp) {
327       case '&':
328         if (cp[1] != '&') {
329             DO (cp = parse_band (g, cp + 1, &rightval));
330             *valp = (*valp & rightval);
331         }
332         break;
333     }
334     return cp;
335 }
336
337
338 static const char *parse_bor(IfParser *g, const char *cp, int *valp)
339 {
340     int rightval;
341
342     DO (cp = parse_band (g, cp, valp));
343     SKIPSPACE (cp);
344
345     switch (*cp) {
346       case '|':
347         if (cp[1] != '|') {
348             DO (cp = parse_bor (g, cp + 1, &rightval));
349             *valp = (*valp | rightval);
350         }
351         break;
352     }
353     return cp;
354 }
355
356 static const char *parse_land(IfParser *g, const char *cp, int *valp)
357 {
358     int rightval;
359
360     DO (cp = parse_bor (g, cp, valp));
361     SKIPSPACE (cp);
362
363     switch (*cp) {
364       case '&':
365         if (cp[1] != '&')
366             return CALLFUNC(g, handle_error) (g, cp, "&&");
367         DO (cp = parse_land (g, cp + 2, &rightval));
368         *valp = (*valp && rightval);
369         break;
370     }
371     return cp;
372 }
373
374 static const char *parse_lor(IfParser *g, const char *cp, int *valp)
375 {
376     int rightval;
377
378     DO (cp = parse_land (g, cp, valp));
379     SKIPSPACE (cp);
380
381     switch (*cp) {
382       case '|':
383         if (cp[1] != '|')
384             return CALLFUNC(g, handle_error) (g, cp, "||");
385         DO (cp = parse_lor (g, cp + 2, &rightval));
386         *valp = (*valp || rightval);
387         break;
388     }
389     return cp;
390 }
391
392
393 /****************************************************************************
394                              External Entry Points
395  ****************************************************************************/
396
397 const char *ParseIfExpression(IfParser *g, const char *cp, int *valp)
398 {
399     return parse_lor (g, cp, valp);
400 }
401
402