Resolve many build warnings
[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 #include <stdlib.h>
85 #include <string.h>
86 #include <limits.h>
87
88 /****************************************************************************
89                    Internal Macros and Utilities for Parser
90  ****************************************************************************/
91
92 #define DO(val) if (!(val)) return NULL
93 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
94 #define SKIPSPACE(ccc) while (isspace((int)*ccc)) ccc++
95 #define isvarfirstletter(ccc) (isalpha((int)ccc) || (ccc) == '_')
96
97
98 static const char *
99 parse_variable (g, cp, varp)
100     IfParser *g;
101     const char *cp;
102     const char **varp;
103 {
104     SKIPSPACE (cp);
105
106     if (!isvarfirstletter (*cp))
107         return CALLFUNC(g, handle_error) (g, cp, "variable name");
108
109     *varp = cp;
110     /* EMPTY */
111     for (cp++; isalnum((int)*cp) || *cp == '_'; cp++) ;
112     return cp;
113 }
114
115
116 static const char *
117 parse_number (g, cp, valp)
118     IfParser *g;
119     const char *cp;
120     long *valp;
121 {
122     long base = 10;
123     SKIPSPACE (cp);
124
125     if (!isdigit((int)*cp))
126         return CALLFUNC(g, handle_error) (g, cp, "number");
127
128     *valp = 0;
129
130     if (*cp == '0') {
131         cp++;
132         if ((*cp == 'x') || (*cp == 'X')) {
133             base = 16;
134             cp++;
135         } else {
136             base = 8;
137         }
138     }
139
140     /* Ignore overflows and assume ASCII, what source is usually written in */
141     while (1) {
142         int increment = -1;
143         if (base == 8) {
144             if ((*cp >= '0') && (*cp <= '7'))
145                 increment = *cp++ - '0';
146         } else if (base == 16) {
147             if ((*cp >= '0') && (*cp <= '9'))
148                 increment = *cp++ - '0';
149             else if ((*cp >= 'A') &&  (*cp <= 'F'))
150                 increment = *cp++ - ('A' - 10);
151             else if ((*cp >= 'a') && (*cp <= 'f'))
152                 increment = *cp++ - ('a' - 10);
153         } else {        /* Decimal */
154             if ((*cp >= '0') && (*cp <= '9'))
155                 increment = *cp++ - '0';
156         }
157         if (increment < 0)
158             break;
159         *valp = (*valp * base) + increment;
160     }
161
162     /* Skip trailing qualifiers */
163     while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++;
164     return cp;
165 }
166
167 static const char *
168 parse_character (g, cp, valp)
169     IfParser *g;
170     const char *cp;
171     long *valp;
172 {
173     char val;
174
175     SKIPSPACE (cp);
176     if (*cp == '\\')
177         switch (cp[1]) {
178         case 'n': val = '\n'; break;
179         case 't': val = '\t'; break;
180         case 'v': val = '\v'; break;
181         case 'b': val = '\b'; break;
182         case 'r': val = '\r'; break;
183         case 'f': val = '\f'; break;
184         case 'a': val = '\a'; break;
185         case '\\': val = '\\'; break;
186         case '?': val = '\?'; break;
187         case '\'': val = '\''; break;
188         case '\"': val = '\"'; break;
189         case 'x': val = (char) strtol (cp + 2, NULL, 16); break;
190         default: val = (char) strtol (cp + 1, NULL, 8); break;
191         }
192     else
193         val = *cp;
194     while (*cp != '\'') cp++;
195     *valp = (long) val;
196     return cp;
197 }
198
199 static const char *
200 parse_value (g, cp, valp)
201     IfParser *g;
202     const char *cp;
203     long *valp;
204 {
205     const char *var;
206
207     *valp = 0;
208
209     SKIPSPACE (cp);
210     if (!*cp)
211         return cp;
212
213     switch (*cp) {
214       case '(':
215         DO (cp = ParseIfExpression (g, cp + 1, valp));
216         SKIPSPACE (cp);
217         if (*cp != ')') 
218             return CALLFUNC(g, handle_error) (g, cp, ")");
219
220         return cp + 1;                  /* skip the right paren */
221
222       case '!':
223         DO (cp = parse_value (g, cp + 1, valp));
224         *valp = !(*valp);
225         return cp;
226
227       case '-':
228         DO (cp = parse_value (g, cp + 1, valp));
229         *valp = -(*valp);
230         return cp;
231
232       case '#':
233         DO (cp = parse_variable (g, cp + 1, &var));
234         SKIPSPACE (cp);
235         if (*cp != '(')
236             return CALLFUNC(g, handle_error) (g, cp, "(");
237         do {
238             DO (cp = parse_variable (g, cp + 1, &var));
239             SKIPSPACE (cp);
240         } while (*cp && *cp != ')');
241         if (*cp != ')')
242             return CALLFUNC(g, handle_error) (g, cp, ")");
243         *valp = 1; /* XXX */
244         return cp + 1;
245
246       case '\'':
247         DO (cp = parse_character (g, cp + 1, valp));
248         if (*cp != '\'')
249             return CALLFUNC(g, handle_error) (g, cp, "'");
250         return cp + 1;
251
252       case 'd':
253         if (strncmp (cp, "defined", 7) == 0 && !isalnum((int)cp[7])) {
254             int paren = 0;
255             int len;
256
257             cp += 7;
258             SKIPSPACE (cp);
259             if (*cp == '(') {
260                 paren = 1;
261                 cp++;
262             }
263             DO (cp = parse_variable (g, cp, &var));
264             len = cp - var;
265             SKIPSPACE (cp);
266             if (paren && *cp != ')')
267                 return CALLFUNC(g, handle_error) (g, cp, ")");
268             *valp = (*(g->funcs.eval_defined)) (g, var, len);
269             return cp + paren;          /* skip the right paren */
270         }
271         /* fall out */
272     }
273
274     if (isdigit((int)*cp)) {
275         DO (cp = parse_number (g, cp, valp));
276     } else if (!isvarfirstletter(*cp))
277         return CALLFUNC(g, handle_error) (g, cp, "variable or number");
278     else {
279         DO (cp = parse_variable (g, cp, &var));
280         *valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
281     }
282     
283     return cp;
284 }
285
286
287
288 static const char *
289 parse_product (g, cp, valp)
290     IfParser *g;
291     const char *cp;
292     long *valp;
293 {
294     long rightval;
295
296     DO (cp = parse_value (g, cp, valp));
297     SKIPSPACE (cp);
298
299     switch (*cp) {
300       case '*':
301         DO (cp = parse_product (g, cp + 1, &rightval));
302         *valp = (*valp * rightval);
303         break;
304
305       case '/':
306         DO (cp = parse_product (g, cp + 1, &rightval));
307         if (rightval)
308             *valp = (*valp / rightval);
309         else
310             *valp = LONG_MAX;
311         break;
312
313       case '%':
314         DO (cp = parse_product (g, cp + 1, &rightval));
315         *valp = (*valp % rightval);
316         break;
317     }
318     return cp;
319 }
320
321
322 static const char *
323 parse_sum (g, cp, valp)
324     IfParser *g;
325     const char *cp;
326     long *valp;
327 {
328     long rightval;
329
330     DO (cp = parse_product (g, cp, valp));
331     SKIPSPACE (cp);
332
333     switch (*cp) {
334       case '+':
335         DO (cp = parse_sum (g, cp + 1, &rightval));
336         *valp = (*valp + rightval);
337         break;
338
339       case '-':
340         DO (cp = parse_sum (g, cp + 1, &rightval));
341         *valp = (*valp - rightval);
342         break;
343     }
344     return cp;
345 }
346
347
348 static const char *
349 parse_shift (g, cp, valp)
350     IfParser *g;
351     const char *cp;
352     long *valp;
353 {
354     long rightval;
355
356     DO (cp = parse_sum (g, cp, valp));
357     SKIPSPACE (cp);
358
359     switch (*cp) {
360       case '<':
361         if (cp[1] == '<') {
362             DO (cp = parse_shift (g, cp + 2, &rightval));
363             *valp = (*valp << rightval);
364         }
365         break;
366
367       case '>':
368         if (cp[1] == '>') {
369             DO (cp = parse_shift (g, cp + 2, &rightval));
370             *valp = (*valp >> rightval);
371         }
372         break;
373     }
374     return cp;
375 }
376
377
378 static const char *
379 parse_inequality (g, cp, valp)
380     IfParser *g;
381     const char *cp;
382     long *valp;
383 {
384     long rightval;
385
386     DO (cp = parse_shift (g, cp, valp));
387     SKIPSPACE (cp);
388
389     switch (*cp) {
390       case '<':
391         if (cp[1] == '=') {
392             DO (cp = parse_inequality (g, cp + 2, &rightval));
393             *valp = (*valp <= rightval);
394         } else {
395             DO (cp = parse_inequality (g, cp + 1, &rightval));
396             *valp = (*valp < rightval);
397         }
398         break;
399
400       case '>':
401         if (cp[1] == '=') {
402             DO (cp = parse_inequality (g, cp + 2, &rightval));
403             *valp = (*valp >= rightval);
404         } else {
405             DO (cp = parse_inequality (g, cp + 1, &rightval));
406             *valp = (*valp > rightval);
407         }
408         break;
409     }
410     return cp;
411 }
412
413
414 static const char *
415 parse_equality (g, cp, valp)
416     IfParser *g;
417     const char *cp;
418     long *valp;
419 {
420     long rightval;
421
422     DO (cp = parse_inequality (g, cp, valp));
423     SKIPSPACE (cp);
424
425     switch (*cp) {
426       case '=':
427         if (cp[1] == '=')
428             cp++;
429         DO (cp = parse_equality (g, cp + 1, &rightval));
430         *valp = (*valp == rightval);
431         break;
432
433       case '!':
434         if (cp[1] != '=')
435             break;
436         DO (cp = parse_equality (g, cp + 2, &rightval));
437         *valp = (*valp != rightval);
438         break;
439     }
440     return cp;
441 }
442
443
444 static const char *
445 parse_band (g, cp, valp)
446     IfParser *g;
447     const char *cp;
448     long *valp;
449 {
450     long rightval;
451
452     DO (cp = parse_equality (g, cp, valp));
453     SKIPSPACE (cp);
454
455     switch (*cp) {
456       case '&':
457         if (cp[1] != '&') {
458             DO (cp = parse_band (g, cp + 1, &rightval));
459             *valp = (*valp & rightval);
460         }
461         break;
462     }
463     return cp;
464 }
465
466
467 static const char *
468 parse_bor (g, cp, valp)
469     IfParser *g;
470     const char *cp;
471     long *valp;
472 {
473     long rightval;
474
475     DO (cp = parse_band (g, cp, valp));
476     SKIPSPACE (cp);
477
478     switch (*cp) {
479       case '|':
480         if (cp[1] != '|') {
481             DO (cp = parse_bor (g, cp + 1, &rightval));
482             *valp = (*valp | rightval);
483         }
484         break;
485     }
486     return cp;
487 }
488
489
490 static const char *
491 parse_land (g, cp, valp)
492     IfParser *g;
493     const char *cp;
494     long *valp;
495 {
496     long rightval;
497
498     DO (cp = parse_bor (g, cp, valp));
499     SKIPSPACE (cp);
500
501     switch (*cp) {
502       case '&':
503         if (cp[1] != '&')
504             return CALLFUNC(g, handle_error) (g, cp, "&&");
505         DO (cp = parse_land (g, cp + 2, &rightval));
506         *valp = (*valp && rightval);
507         break;
508     }
509     return cp;
510 }
511
512
513 static const char *
514 parse_lor (g, cp, valp)
515     IfParser *g;
516     const char *cp;
517     long *valp;
518 {
519     long rightval;
520
521     DO (cp = parse_land (g, cp, valp));
522     SKIPSPACE (cp);
523
524     switch (*cp) {
525       case '|':
526         if (cp[1] != '|')
527             return CALLFUNC(g, handle_error) (g, cp, "||");
528         DO (cp = parse_lor (g, cp + 2, &rightval));
529         *valp = (*valp || rightval);
530         break;
531     }
532     return cp;
533 }
534
535
536 /****************************************************************************
537                              External Entry Points
538  ****************************************************************************/
539
540 const char *
541 ParseIfExpression (g, cp, valp)
542     IfParser *g;
543     const char *cp;
544     long *valp;
545 {
546     return parse_lor (g, cp, valp);
547 }
548
549