Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / config / makedepend / ifparser.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  * $XConsortium: ifparser.c /main/10 1996/09/28 16:15:18 rws $
25  *
26  * Copyright 1992 Network Computing Devices, Inc.
27  * 
28  * Permission to use, copy, modify, and distribute this software and its
29  * documentation for any purpose and without fee is hereby granted, provided
30  * that the above copyright notice appear in all copies and that both that
31  * copyright notice and this permission notice appear in supporting
32  * documentation, and that the name of Network Computing Devices may not be
33  * used in advertising or publicity pertaining to distribution of the software
34  * without specific, written prior permission.  Network Computing Devices makes
35  * no representations about the suitability of this software for any purpose.
36  * It is provided ``as is'' without express or implied warranty.
37  * 
38  * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
39  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
40  * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
41  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
42  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
43  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
44  * PERFORMANCE OF THIS SOFTWARE.
45  * 
46  * Author:  Jim Fulton
47  *          Network Computing Devices, Inc.
48  * 
49  * Simple if statement processor
50  *
51  * This module can be used to evaluate string representations of C language
52  * if constructs.  It accepts the following grammar:
53  * 
54  *     EXPRESSION       :=      VALUE
55  *                       |      VALUE  BINOP    EXPRESSION
56  * 
57  *     VALUE            :=      '('  EXPRESSION  ')'
58  *                       |      '!'  VALUE
59  *                       |      '-'  VALUE
60  *                       |      'defined'  '('  variable  ')'
61  *                       |      'defined'  variable
62  *                       |      # variable '(' variable-list ')'
63  *                       |      variable
64  *                       |      number
65  * 
66  *     BINOP            :=      '*'     |  '/'  |  '%'
67  *                       |      '+'     |  '-'
68  *                       |      '<<'    |  '>>'
69  *                       |      '<'     |  '>'  |  '<='  |  '>='
70  *                       |      '=='    |  '!='
71  *                       |      '&'     |  '|'
72  *                       |      '&&'    |  '||'
73  * 
74  * The normal C order of precidence is supported.
75  * 
76  * 
77  * External Entry Points:
78  * 
79  *     ParseIfExpression                parse a string for #if
80  */
81
82 #include "ifparser.h"
83 #include <ctype.h>
84
85 /****************************************************************************
86                    Internal Macros and Utilities for Parser
87  ****************************************************************************/
88
89 #define DO(val) if (!(val)) return NULL
90 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
91 #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
92 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
93
94
95 static const char *
96 parse_variable (g, cp, varp)
97     IfParser *g;
98     const char *cp;
99     const char **varp;
100 {
101     SKIPSPACE (cp);
102
103     if (!isvarfirstletter (*cp))
104         return CALLFUNC(g, handle_error) (g, cp, "variable name");
105
106     *varp = cp;
107     /* EMPTY */
108     for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
109     return cp;
110 }
111
112
113 static const char *
114 parse_number (g, cp, valp)
115     IfParser *g;
116     const char *cp;
117     long *valp;
118 {
119     SKIPSPACE (cp);
120
121     if (!isdigit(*cp))
122         return CALLFUNC(g, handle_error) (g, cp, "number");
123
124     *valp = strtol(cp, &cp, 0);
125     /* skip trailing qualifiers */
126     while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++;
127 #if 0
128     *valp = atoi (cp);
129     /* EMPTY */
130     for (cp++; isdigit(*cp); cp++) ;
131 #endif
132     return cp;
133 }
134
135 static const char *
136 parse_character (g, cp, valp)
137     IfParser *g;
138     const char *cp;
139     long *valp;
140 {
141     char val;
142
143     SKIPSPACE (cp);
144     if (*cp == '\\')
145         switch (cp[1]) {
146         case 'n': val = '\n'; break;
147         case 't': val = '\t'; break;
148         case 'v': val = '\v'; break;
149         case 'b': val = '\b'; break;
150         case 'r': val = '\r'; break;
151         case 'f': val = '\f'; break;
152         case 'a': val = '\a'; break;
153         case '\\': val = '\\'; break;
154         case '?': val = '\?'; break;
155         case '\'': val = '\''; break;
156         case '\"': val = '\"'; break;
157         case 'x': val = (char) strtol (cp + 2, NULL, 16); break;
158         default: val = (char) strtol (cp + 1, NULL, 8); break;
159         }
160     else
161         val = *cp;
162     while (*cp != '\'') cp++;
163     *valp = (long) val;
164     return cp;
165 }
166
167 static const char *
168 parse_value (g, cp, valp)
169     IfParser *g;
170     const char *cp;
171     long *valp;
172 {
173     const char *var;
174
175     *valp = 0;
176
177     SKIPSPACE (cp);
178     if (!*cp)
179         return cp;
180
181     switch (*cp) {
182       case '(':
183         DO (cp = ParseIfExpression (g, cp + 1, valp));
184         SKIPSPACE (cp);
185         if (*cp != ')') 
186             return CALLFUNC(g, handle_error) (g, cp, ")");
187
188         return cp + 1;                  /* skip the right paren */
189
190       case '!':
191         DO (cp = parse_value (g, cp + 1, valp));
192         *valp = !(*valp);
193         return cp;
194
195       case '-':
196         DO (cp = parse_value (g, cp + 1, valp));
197         *valp = -(*valp);
198         return cp;
199
200       case '#':
201         DO (cp = parse_variable (g, cp + 1, &var));
202         SKIPSPACE (cp);
203         if (*cp != '(')
204             return CALLFUNC(g, handle_error) (g, cp, "(");
205         do {
206             DO (cp = parse_variable (g, cp + 1, &var));
207             SKIPSPACE (cp);
208         } while (*cp && *cp != ')');
209         if (*cp != ')')
210             return CALLFUNC(g, handle_error) (g, cp, ")");
211         *valp = 1; /* XXX */
212         return cp + 1;
213
214       case '\'':
215         DO (cp = parse_character (g, cp + 1, valp));
216         if (*cp != '\'')
217             return CALLFUNC(g, handle_error) (g, cp, "'");
218         return cp + 1;
219
220       case 'd':
221         if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
222             int paren = 0;
223             int len;
224
225             cp += 7;
226             SKIPSPACE (cp);
227             if (*cp == '(') {
228                 paren = 1;
229                 cp++;
230             }
231             DO (cp = parse_variable (g, cp, &var));
232             len = cp - var;
233             SKIPSPACE (cp);
234             if (paren && *cp != ')')
235                 return CALLFUNC(g, handle_error) (g, cp, ")");
236             *valp = (*(g->funcs.eval_defined)) (g, var, len);
237             return cp + paren;          /* skip the right paren */
238         }
239         /* fall out */
240     }
241
242     if (isdigit(*cp)) {
243         DO (cp = parse_number (g, cp, valp));
244     } else if (!isvarfirstletter(*cp))
245         return CALLFUNC(g, handle_error) (g, cp, "variable or number");
246     else {
247         DO (cp = parse_variable (g, cp, &var));
248         *valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
249     }
250     
251     return cp;
252 }
253
254
255
256 static const char *
257 parse_product (g, cp, valp)
258     IfParser *g;
259     const char *cp;
260     long *valp;
261 {
262     long rightval;
263
264     DO (cp = parse_value (g, cp, valp));
265     SKIPSPACE (cp);
266
267     switch (*cp) {
268       case '*':
269         DO (cp = parse_product (g, cp + 1, &rightval));
270         *valp = (*valp * rightval);
271         break;
272
273       case '/':
274         DO (cp = parse_product (g, cp + 1, &rightval));
275         *valp = (*valp / rightval);
276         break;
277
278       case '%':
279         DO (cp = parse_product (g, cp + 1, &rightval));
280         *valp = (*valp % rightval);
281         break;
282     }
283     return cp;
284 }
285
286
287 static const char *
288 parse_sum (g, cp, valp)
289     IfParser *g;
290     const char *cp;
291     long *valp;
292 {
293     long rightval;
294
295     DO (cp = parse_product (g, cp, valp));
296     SKIPSPACE (cp);
297
298     switch (*cp) {
299       case '+':
300         DO (cp = parse_sum (g, cp + 1, &rightval));
301         *valp = (*valp + rightval);
302         break;
303
304       case '-':
305         DO (cp = parse_sum (g, cp + 1, &rightval));
306         *valp = (*valp - rightval);
307         break;
308     }
309     return cp;
310 }
311
312
313 static const char *
314 parse_shift (g, cp, valp)
315     IfParser *g;
316     const char *cp;
317     long *valp;
318 {
319     long rightval;
320
321     DO (cp = parse_sum (g, cp, valp));
322     SKIPSPACE (cp);
323
324     switch (*cp) {
325       case '<':
326         if (cp[1] == '<') {
327             DO (cp = parse_shift (g, cp + 2, &rightval));
328             *valp = (*valp << rightval);
329         }
330         break;
331
332       case '>':
333         if (cp[1] == '>') {
334             DO (cp = parse_shift (g, cp + 2, &rightval));
335             *valp = (*valp >> rightval);
336         }
337         break;
338     }
339     return cp;
340 }
341
342
343 static const char *
344 parse_inequality (g, cp, valp)
345     IfParser *g;
346     const char *cp;
347     long *valp;
348 {
349     long rightval;
350
351     DO (cp = parse_shift (g, cp, valp));
352     SKIPSPACE (cp);
353
354     switch (*cp) {
355       case '<':
356         if (cp[1] == '=') {
357             DO (cp = parse_inequality (g, cp + 2, &rightval));
358             *valp = (*valp <= rightval);
359         } else {
360             DO (cp = parse_inequality (g, cp + 1, &rightval));
361             *valp = (*valp < rightval);
362         }
363         break;
364
365       case '>':
366         if (cp[1] == '=') {
367             DO (cp = parse_inequality (g, cp + 2, &rightval));
368             *valp = (*valp >= rightval);
369         } else {
370             DO (cp = parse_inequality (g, cp + 1, &rightval));
371             *valp = (*valp > rightval);
372         }
373         break;
374     }
375     return cp;
376 }
377
378
379 static const char *
380 parse_equality (g, cp, valp)
381     IfParser *g;
382     const char *cp;
383     long *valp;
384 {
385     long rightval;
386
387     DO (cp = parse_inequality (g, cp, valp));
388     SKIPSPACE (cp);
389
390     switch (*cp) {
391       case '=':
392         if (cp[1] == '=')
393             cp++;
394         DO (cp = parse_equality (g, cp + 1, &rightval));
395         *valp = (*valp == rightval);
396         break;
397
398       case '!':
399         if (cp[1] != '=')
400             break;
401         DO (cp = parse_equality (g, cp + 2, &rightval));
402         *valp = (*valp != rightval);
403         break;
404     }
405     return cp;
406 }
407
408
409 static const char *
410 parse_band (g, cp, valp)
411     IfParser *g;
412     const char *cp;
413     long *valp;
414 {
415     long rightval;
416
417     DO (cp = parse_equality (g, cp, valp));
418     SKIPSPACE (cp);
419
420     switch (*cp) {
421       case '&':
422         if (cp[1] != '&') {
423             DO (cp = parse_band (g, cp + 1, &rightval));
424             *valp = (*valp & rightval);
425         }
426         break;
427     }
428     return cp;
429 }
430
431
432 static const char *
433 parse_bor (g, cp, valp)
434     IfParser *g;
435     const char *cp;
436     long *valp;
437 {
438     long rightval;
439
440     DO (cp = parse_band (g, cp, valp));
441     SKIPSPACE (cp);
442
443     switch (*cp) {
444       case '|':
445         if (cp[1] != '|') {
446             DO (cp = parse_bor (g, cp + 1, &rightval));
447             *valp = (*valp | rightval);
448         }
449         break;
450     }
451     return cp;
452 }
453
454
455 static const char *
456 parse_land (g, cp, valp)
457     IfParser *g;
458     const char *cp;
459     long *valp;
460 {
461     long rightval;
462
463     DO (cp = parse_bor (g, cp, valp));
464     SKIPSPACE (cp);
465
466     switch (*cp) {
467       case '&':
468         if (cp[1] != '&')
469             return CALLFUNC(g, handle_error) (g, cp, "&&");
470         DO (cp = parse_land (g, cp + 2, &rightval));
471         *valp = (*valp && rightval);
472         break;
473     }
474     return cp;
475 }
476
477
478 static const char *
479 parse_lor (g, cp, valp)
480     IfParser *g;
481     const char *cp;
482     long *valp;
483 {
484     long rightval;
485
486     DO (cp = parse_land (g, cp, valp));
487     SKIPSPACE (cp);
488
489     switch (*cp) {
490       case '|':
491         if (cp[1] != '|')
492             return CALLFUNC(g, handle_error) (g, cp, "||");
493         DO (cp = parse_lor (g, cp + 2, &rightval));
494         *valp = (*valp || rightval);
495         break;
496     }
497     return cp;
498 }
499
500
501 /****************************************************************************
502                              External Entry Points
503  ****************************************************************************/
504
505 const char *
506 ParseIfExpression (g, cp, valp)
507     IfParser *g;
508     const char *cp;
509     long *valp;
510 {
511     return parse_lor (g, cp, valp);
512 }
513
514