Fix warnings on FreeBSD
[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 libraries 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, *varend;
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_value (g, cp + 1, valp));
234         *valp = +(*valp);
235         return cp;
236
237       case '~':
238         DO (cp = parse_value (g, cp + 1, valp));
239         *valp = ~(*valp);
240         return cp;
241
242       case '#':
243         DO (cp = parse_variable (g, cp + 1, &var));
244         SKIPSPACE (cp);
245         if (*cp != '(')
246             return CALLFUNC(g, handle_error) (g, cp, "(");
247         do {
248             DO (cp = parse_variable (g, cp + 1, &var));
249             SKIPSPACE (cp);
250         } while (*cp && *cp != ')');
251         if (*cp != ')')
252             return CALLFUNC(g, handle_error) (g, cp, ")");
253         *valp = 1; /* XXX */
254         return cp + 1;
255
256       case '\'':
257         DO (cp = parse_character (g, cp + 1, valp));
258         if (*cp != '\'')
259             return CALLFUNC(g, handle_error) (g, cp, "'");
260         return cp + 1;
261
262       case 'd':
263         if (strncmp (cp, "defined", 7) == 0 && !isalnum((int)cp[7])) {
264             int paren = 0;
265             int len;
266
267             cp += 7;
268             SKIPSPACE (cp);
269             if (*cp == '(') {
270                 paren = 1;
271                 cp++;
272             }
273             DO (cp = parse_variable (g, cp, &var));
274             len = cp - var;
275             SKIPSPACE (cp);
276             if (paren && *cp != ')')
277                 return CALLFUNC(g, handle_error) (g, cp, ")");
278             *valp = (*(g->funcs.eval_defined)) (g, var, len);
279             return cp + paren;          /* skip the right paren */
280         }
281         /* fall out */
282     }
283
284     if (isdigit((int)*cp)) {
285         DO (cp = parse_number (g, cp, valp));
286     } else if (!isvarfirstletter(*cp))
287         return CALLFUNC(g, handle_error) (g, cp, "variable or number");
288     else {
289         DO (cp = parse_variable (g, cp, &var));
290         varend = cp;
291         SKIPSPACE(cp);
292         if (*cp != '(') {
293             *valp = (*(g->funcs.eval_variable)) (g, var, varend - var);
294         } else {
295             do {
296                 long dummy;
297                 DO (cp = ParseIfExpression (g, cp + 1, &dummy));
298                 SKIPSPACE(cp);
299                 if (*cp == ')')
300                     break;
301                 if (*cp != ',')
302                     return CALLFUNC(g, handle_error) (g, cp, ",");
303             } while (1);
304
305             *valp = 1;  /* XXX */
306             cp++;
307         }
308     }
309     
310     return cp;
311 }
312
313
314
315 static const char *
316 parse_product (g, cp, valp)
317     IfParser *g;
318     const char *cp;
319     long *valp;
320 {
321     long rightval;
322
323     DO (cp = parse_value (g, cp, valp));
324     SKIPSPACE (cp);
325
326     switch (*cp) {
327       case '*':
328         DO (cp = parse_product (g, cp + 1, &rightval));
329         *valp = (*valp * rightval);
330         break;
331
332       case '/':
333         DO (cp = parse_product (g, cp + 1, &rightval));
334         if (rightval)
335             *valp = (*valp / rightval);
336         else
337             *valp = LONG_MAX;
338         break;
339
340       case '%':
341         DO (cp = parse_product (g, cp + 1, &rightval));
342         *valp = (*valp % rightval);
343         break;
344     }
345     return cp;
346 }
347
348
349 static const char *
350 parse_sum (g, cp, valp)
351     IfParser *g;
352     const char *cp;
353     long *valp;
354 {
355     long rightval;
356
357     DO (cp = parse_product (g, cp, valp));
358     SKIPSPACE (cp);
359
360     switch (*cp) {
361       case '+':
362         DO (cp = parse_sum (g, cp + 1, &rightval));
363         *valp = (*valp + rightval);
364         break;
365
366       case '-':
367         DO (cp = parse_sum (g, cp + 1, &rightval));
368         *valp = (*valp - rightval);
369         break;
370     }
371     return cp;
372 }
373
374
375 static const char *
376 parse_shift (g, cp, valp)
377     IfParser *g;
378     const char *cp;
379     long *valp;
380 {
381     long rightval;
382
383     DO (cp = parse_sum (g, cp, valp));
384     SKIPSPACE (cp);
385
386     switch (*cp) {
387       case '<':
388         if (cp[1] == '<') {
389             DO (cp = parse_shift (g, cp + 2, &rightval));
390             *valp = (*valp << rightval);
391         }
392         break;
393
394       case '>':
395         if (cp[1] == '>') {
396             DO (cp = parse_shift (g, cp + 2, &rightval));
397             *valp = (*valp >> rightval);
398         }
399         break;
400     }
401     return cp;
402 }
403
404
405 static const char *
406 parse_inequality (g, cp, valp)
407     IfParser *g;
408     const char *cp;
409     long *valp;
410 {
411     long rightval;
412
413     DO (cp = parse_shift (g, cp, valp));
414     SKIPSPACE (cp);
415
416     switch (*cp) {
417       case '<':
418         if (cp[1] == '=') {
419             DO (cp = parse_inequality (g, cp + 2, &rightval));
420             *valp = (*valp <= rightval);
421         } else {
422             DO (cp = parse_inequality (g, cp + 1, &rightval));
423             *valp = (*valp < rightval);
424         }
425         break;
426
427       case '>':
428         if (cp[1] == '=') {
429             DO (cp = parse_inequality (g, cp + 2, &rightval));
430             *valp = (*valp >= rightval);
431         } else {
432             DO (cp = parse_inequality (g, cp + 1, &rightval));
433             *valp = (*valp > rightval);
434         }
435         break;
436     }
437     return cp;
438 }
439
440
441 static const char *
442 parse_equality (g, cp, valp)
443     IfParser *g;
444     const char *cp;
445     long *valp;
446 {
447     long rightval;
448
449     DO (cp = parse_inequality (g, cp, valp));
450     SKIPSPACE (cp);
451
452     switch (*cp) {
453       case '=':
454         if (cp[1] == '=')
455             cp++;
456         DO (cp = parse_equality (g, cp + 1, &rightval));
457         *valp = (*valp == rightval);
458         break;
459
460       case '!':
461         if (cp[1] != '=')
462             break;
463         DO (cp = parse_equality (g, cp + 2, &rightval));
464         *valp = (*valp != rightval);
465         break;
466     }
467     return cp;
468 }
469
470
471 static const char *
472 parse_band (g, cp, valp)
473     IfParser *g;
474     const char *cp;
475     long *valp;
476 {
477     long rightval;
478
479     DO (cp = parse_equality (g, cp, valp));
480     SKIPSPACE (cp);
481
482     switch (*cp) {
483       case '&':
484         if (cp[1] != '&') {
485             DO (cp = parse_band (g, cp + 1, &rightval));
486             *valp = (*valp & rightval);
487         }
488         break;
489     }
490     return cp;
491 }
492
493
494 static const char *
495 parse_bxor (g, cp, valp)
496     IfParser *g;
497     const char *cp;
498     long *valp;
499 {
500     long rightval;
501
502     DO (cp = parse_band (g, cp, valp));
503     SKIPSPACE (cp);
504
505     switch (*cp) {
506       case '^':
507         DO (cp = parse_bxor (g, cp + 1, &rightval));
508         *valp = (*valp ^ rightval);
509         break;
510     }
511     return cp;
512 }
513
514
515 static const char *
516 parse_bor (g, cp, valp)
517     IfParser *g;
518     const char *cp;
519     long *valp;
520 {
521     long rightval;
522
523     DO (cp = parse_bxor (g, cp, valp));
524     SKIPSPACE (cp);
525
526     switch (*cp) {
527       case '|':
528         if (cp[1] != '|') {
529             DO (cp = parse_bor (g, cp + 1, &rightval));
530             *valp = (*valp | rightval);
531         }
532         break;
533     }
534     return cp;
535 }
536
537
538 static const char *
539 parse_land (g, cp, valp)
540     IfParser *g;
541     const char *cp;
542     long *valp;
543 {
544     long rightval;
545
546     DO (cp = parse_bor (g, cp, valp));
547     SKIPSPACE (cp);
548
549     switch (*cp) {
550       case '&':
551         if (cp[1] != '&')
552             return CALLFUNC(g, handle_error) (g, cp, "&&");
553         DO (cp = parse_land (g, cp + 2, &rightval));
554         *valp = (*valp && rightval);
555         break;
556     }
557     return cp;
558 }
559
560
561 static const char *
562 parse_lor (g, cp, valp)
563     IfParser *g;
564     const char *cp;
565     long *valp;
566 {
567     long rightval;
568
569     DO (cp = parse_land (g, cp, valp));
570     SKIPSPACE (cp);
571
572     switch (*cp) {
573       case '|':
574         if (cp[1] != '|')
575             return CALLFUNC(g, handle_error) (g, cp, "||");
576         DO (cp = parse_lor (g, cp + 2, &rightval));
577         *valp = (*valp || rightval);
578         break;
579     }
580     return cp;
581 }
582
583
584 /****************************************************************************
585                              External Entry Points
586  ****************************************************************************/
587
588 const char *
589 ParseIfExpression (g, cp, valp)
590     IfParser *g;
591     const char *cp;
592     long *valp;
593 {
594     return parse_lor (g, cp, valp);
595 }
596
597