xref: /trunk/main/soltools/mkdepend/parse.c (revision cf6516809c57e1bb0a940545cca99cdad54d4ce2)
1 /* $XConsortium: parse.c,v 1.30 94/04/17 20:10:38 gildea Exp $ */
2 /*
3 
4 Copyright (c) 1993, 1994  X Consortium
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 
23 Except as contained in this notice, the name of the X Consortium shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the X Consortium.
26 
27 */
28 
29 #include "def.h"
30 char *hash_lookup( char *symbol, struct symhash *symbols );
31 void hash_undefine( char *symbol, struct symhash *symbols );
32 int gobble( register struct filepointer *filep, struct inclist *file,
33     struct inclist *file_red, struct symhash *symbols );
34 int deftype ( register char *line, register struct filepointer *filep,
35     register struct inclist *file_red, register struct inclist *file,
36     int parse_it, struct symhash *symbols);
37 int zero_value(register char *exp, register struct filepointer *filep,
38     register struct inclist *file_red, register struct symhash *symbols);
39 
40 extern char *directives[];
41 extern struct symhash *maininclist;
42 
43 int find_includes(filep, file, file_red, recursion, failOK, incCollection, symbols)
44     struct filepointer  *filep;
45     struct inclist      *file, *file_red;
46     int         recursion;
47     boolean         failOK;
48     struct IncludesCollection* incCollection;
49     struct symhash      *symbols;
50 {
51     register char   *line;
52     register int    type;
53     boolean recfailOK;
54 
55     while ((line = get_line(filep))) {
56         switch(type = deftype(line, filep, file_red, file, TRUE, symbols)) {
57         case IF:
58         doif:
59             type = find_includes(filep, file,
60                 file_red, recursion+1, failOK, incCollection, symbols);
61             while ((type == ELIF) || (type == ELIFFALSE) ||
62                    (type == ELIFGUESSFALSE))
63                 type = gobble(filep, file, file_red, symbols);
64             if (type == ELSE)
65                 gobble(filep, file, file_red, symbols);
66             break;
67         case IFFALSE:
68         case IFGUESSFALSE:
69             doiffalse:
70             if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
71                 recfailOK = TRUE;
72             else
73                 recfailOK = failOK;
74             type = gobble(filep, file, file_red, symbols);
75             if (type == ELSE)
76                 find_includes(filep, file,
77                       file_red, recursion+1, recfailOK, incCollection, symbols);
78             else
79             if (type == ELIF)
80                 goto doif;
81             else
82             if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
83                 goto doiffalse;
84             break;
85         case IFDEF:
86         case IFNDEF:
87             if ((type == IFDEF && hash_lookup(line, symbols))
88              || (type == IFNDEF && !hash_lookup(line, symbols))) {
89                 debug(1,(type == IFNDEF ?
90                     "line %d: %s !def'd in %s via %s%s\n" : "",
91                     filep->f_line, line,
92                     file->i_file, file_red->i_file, ": doit"));
93                 type = find_includes(filep, file,
94                     file_red, recursion+1, failOK, incCollection, symbols);
95                 while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
96                     type = gobble(filep, file, file_red, symbols);
97                 if (type == ELSE)
98                     gobble(filep, file, file_red, symbols);
99             }
100             else {
101                 debug(1,(type == IFDEF ?
102                     "line %d: %s !def'd in %s via %s%s\n" : "",
103                     filep->f_line, line,
104                     file->i_file, file_red->i_file, ": gobble"));
105                 type = gobble(filep, file, file_red, symbols);
106                 if (type == ELSE)
107                     find_includes(filep, file,
108                         file_red, recursion + 1, failOK, incCollection, symbols);
109                 else if (type == ELIF)
110                         goto doif;
111                 else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
112                         goto doiffalse;
113             }
114             break;
115         case ELSE:
116         case ELIFFALSE:
117         case ELIFGUESSFALSE:
118         case ELIF:
119             if (!recursion)
120                 gobble(filep, file, file_red, symbols);
121         case ENDIF:
122             if (recursion)
123                 return(type);
124         case DEFINE:
125             define(line, &symbols);
126             break;
127         case UNDEF:
128             if (!*line) {
129                 warning("%s, line %d: incomplete undef == \"%s\"\n",
130                 file_red->i_file, filep->f_line, line);
131                 break;
132             }
133             hash_undefine(line, symbols);
134             break;
135         case INCLUDE:
136             add_include(filep, file, file_red, line, FALSE, failOK, incCollection, symbols);
137             break;
138         case INCLUDEDOT:
139             add_include(filep, file, file_red, line, TRUE, failOK, incCollection, symbols);
140             break;
141         case ERROR:
142                 warning("%s: %d: %s\n", file_red->i_file,
143                  filep->f_line, line);
144                 break;
145 
146         case PRAGMA:
147         case IDENT:
148         case SCCS:
149         case EJECT:
150             break;
151         case -1:
152             warning("%s", file_red->i_file);
153             if (file_red != file)
154                 warning1(" (reading %s)", file->i_file);
155             warning1(", line %d: unknown directive == \"%s\"\n",
156                  filep->f_line, line);
157             break;
158         case -2:
159             warning("%s", file_red->i_file);
160             if (file_red != file)
161                 warning1(" (reading %s)", file->i_file);
162             warning1(", line %d: incomplete include == \"%s\"\n",
163                  filep->f_line, line);
164             break;
165         }
166     }
167     return(-1);
168 }
169 
170 int gobble(filep, file, file_red, symbols)
171     register struct filepointer *filep;
172     struct inclist      *file, *file_red;
173     struct symhash      *symbols;
174 {
175     register char   *line;
176     register int    type;
177 
178     while ((line = get_line(filep))) {
179         switch(type = deftype(line, filep, file_red, file, FALSE, symbols)) {
180         case IF:
181         case IFFALSE:
182         case IFGUESSFALSE:
183         case IFDEF:
184         case IFNDEF:
185             type = gobble(filep, file, file_red, symbols);
186             while ((type == ELIF) || (type == ELIFFALSE) ||
187                    (type == ELIFGUESSFALSE))
188                 type = gobble(filep, file, file_red, symbols);
189             if (type == ELSE)
190                     (void)gobble(filep, file, file_red, symbols);
191             break;
192         case ELSE:
193         case ENDIF:
194             debug(0,("%s, line %d: #%s\n",
195                 file->i_file, filep->f_line,
196                 directives[type]));
197             return(type);
198         case DEFINE:
199         case UNDEF:
200         case INCLUDE:
201         case INCLUDEDOT:
202         case PRAGMA:
203         case ERROR:
204         case IDENT:
205         case SCCS:
206         case EJECT:
207             break;
208         case ELIF:
209         case ELIFFALSE:
210         case ELIFGUESSFALSE:
211             return(type);
212         case -1:
213             warning("%s, line %d: unknown directive == \"%s\"\n",
214                 file_red->i_file, filep->f_line, line);
215             break;
216         }
217     }
218     return(-1);
219 }
220 
221 /*
222  * Decide what type of # directive this line is.
223  */
224 int deftype (line, filep, file_red, file, parse_it, symbols)
225     register char   *line;
226     register struct filepointer *filep;
227     register struct inclist *file_red, *file;
228     int parse_it;
229     struct symhash  *symbols;
230 {
231     register char   *p;
232     char    *directive, savechar;
233     register int    ret;
234 
235     /*
236      * Parse the directive...
237      */
238     directive=line+1;
239     while (*directive == ' ' || *directive == '\t')
240         directive++;
241 
242     p = directive;
243     while (*p >= 'a' && *p <= 'z')
244         p++;
245     savechar = *p;
246     *p = '\0';
247     ret = match(directive, directives);
248     *p = savechar;
249 
250     /* If we don't recognize this compiler directive or we happen to just
251      * be gobbling up text while waiting for an #endif or #elif or #else
252      * in the case of an #elif we must check the zero_value and return an
253      * ELIF or an ELIFFALSE.
254      */
255 
256     if (ret == ELIF && !parse_it)
257     {
258         while (*p == ' ' || *p == '\t')
259         p++;
260         /*
261          * parse an expression.
262          */
263         debug(0,("%s, line %d: #elif %s ",
264            file->i_file, filep->f_line, p));
265         ret = zero_value(p, filep, file_red, symbols);
266         if (ret != IF)
267         {
268         debug(0,("false...\n"));
269         if (ret == IFFALSE)
270             return(ELIFFALSE);
271         else
272             return(ELIFGUESSFALSE);
273         }
274         else
275         {
276         debug(0,("true...\n"));
277         return(ELIF);
278         }
279     }
280 
281     if (ret < 0 || ! parse_it)
282         return(ret);
283 
284     /*
285      * now decide how to parse the directive, and do it.
286      */
287     while (*p == ' ' || *p == '\t')
288         p++;
289     switch (ret) {
290     case IF:
291         /*
292          * parse an expression.
293          */
294         ret = zero_value(p, filep, file_red, symbols);
295         debug(0,("%s, line %d: %s #if %s\n",
296              file->i_file, filep->f_line, ret?"false":"true", p));
297         break;
298     case IFDEF:
299     case IFNDEF:
300         debug(0,("%s, line %d: #%s %s\n",
301             file->i_file, filep->f_line, directives[ret], p));
302     case UNDEF:
303         /*
304          * separate the name of a single symbol.
305          */
306         while (isalnum(*p) || *p == '_')
307             *line++ = *p++;
308         *line = '\0';
309         break;
310     case INCLUDE:
311         debug(2,("%s, line %d: #include %s\n",
312             file->i_file, filep->f_line, p));
313 
314         /* Support ANSI macro substitution */
315         {
316             char *sym = hash_lookup(p, symbols);
317             while (sym)
318             {
319                 p = sym;
320                 debug(3,("%s : #includes SYMBOL %s\n",
321                             file->i_incstring,
322                             sym));
323                 /* mark file as having included a 'soft include' */
324                 file->i_included_sym = TRUE;
325                 sym = hash_lookup(p, symbols);
326             }
327         }
328 
329         /*
330          * Separate the name of the include file.
331          */
332         while (*p && *p != '"' && *p != '<')
333             p++;
334         if (! *p)
335             return(-2);
336         if (*p++ == '"') {
337             ret = INCLUDEDOT;
338             while (*p && *p != '"')
339                 *line++ = *p++;
340         } else
341             while (*p && *p != '>')
342                 *line++ = *p++;
343         *line = '\0';
344         break;
345     case DEFINE:
346         /*
347          * copy the definition back to the beginning of the line.
348          */
349         {
350             int lenl = strlen(line);
351             int lenp = strlen(p);
352             memmove ( line, p, (lenl < lenp) ? lenl : lenp );
353             line[ (lenl < lenp) ? lenl : lenp ] = '\0'; /* belts and braces */
354         }
355         break;
356     case ELSE:
357     case ENDIF:
358     case ELIF:
359     case PRAGMA:
360     case ERROR:
361     case IDENT:
362     case SCCS:
363     case EJECT:
364         debug(0,("%s, line %d: #%s\n",
365             file->i_file, filep->f_line, directives[ret]));
366         /*
367          * nothing to do.
368          */
369         break;
370     }
371     return(ret);
372 }
373 
374 /*
375  * HACK! - so that we do not have to introduce 'symbols' in each cppsetup.c
376  * function...  It's safe, functions from cppsetup.c don't return here.
377  */
378 struct symhash *global_symbols = NULL;
379 
380 char * isdefined( symbol )
381     register char *symbol;
382 {
383     return hash_lookup( symbol, global_symbols );
384 }
385 
386 /*
387  * Return type based on if the #if expression evaluates to 0
388  */
389 int zero_value(exp, filep, file_red, symbols)
390     register char   *exp;
391     register struct filepointer *filep;
392     register struct inclist *file_red;
393     register struct symhash *symbols;
394 {
395     global_symbols = symbols; /* HACK! see above */
396     if (cppsetup(exp, filep, file_red))
397         return(IFFALSE);
398     else
399         return(IF);
400 }
401 
402 void define( def, symbols )
403     char            *def;
404     struct symhash **symbols;
405 {
406     char *val;
407 
408     /* Separate symbol name and its value */
409     val = def;
410     while (isalnum(*val) || *val == '_')
411     val++;
412     if (*val)
413     *val++ = '\0';
414     while (*val == ' ' || *val == '\t')
415     val++;
416 
417     if (!*val)
418     val = "1";
419     hash_define( def, val, symbols );
420 }
421 
422 static int hash( str )
423     register char *str;
424 {
425     /* Hash (Kernighan and Ritchie) */
426     register unsigned int hashval = 0;
427     //char *s = str;
428 
429     for ( ; *str; str++ )
430     {
431         hashval = ( hashval * SYMHASHSEED ) + ( *str );
432     }
433 
434     //fprintf( stderr, "hash: %s, %d\n", s, hashval & ( SYMHASHMEMBERS - 1 ) );
435     return hashval & ( SYMHASHMEMBERS - 1 );
436 }
437 
438 struct symhash *hash_copy( symbols )
439     struct symhash *symbols;
440 {
441     int i;
442     struct symhash *newsym;
443     if ( !symbols )
444         return NULL;
445 
446     newsym = (struct symhash *) malloc( sizeof( struct symhash ) );
447 
448     for ( i = 0; i < SYMHASHMEMBERS; ++i )
449     {
450         if ( !symbols->s_pairs[ i ] )
451             newsym->s_pairs[ i ] = NULL;
452         else
453         {
454             struct pair *it = symbols->s_pairs[ i ];
455             struct pair *nw = newsym->s_pairs[ i ] = (struct pair*) malloc( sizeof( struct pair ) );
456             nw->p_name = it->p_name;
457             nw->p_value = it->p_value;
458             nw->p_next = NULL;
459 
460             while ( it->p_next )
461             {
462                 nw->p_next = (struct pair*) malloc( sizeof( struct pair ) );
463                 it = it->p_next;
464                 nw = nw->p_next;
465                 nw->p_name = it->p_name;
466                 nw->p_value = it->p_value;
467                 nw->p_next = NULL;
468             }
469         }
470     }
471     return newsym;
472 }
473 
474 void hash_free( symbols )
475     struct symhash *symbols;
476 {
477     int i;
478 
479     if ( !symbols )
480         return;
481 
482     for ( i = 0; i < SYMHASHMEMBERS; ++i )
483     {
484         struct pair *it = symbols->s_pairs[ i ];
485         struct pair *next;
486         while ( it )
487         {
488             next = it->p_next;
489             free( it );
490             it = next;
491         }
492     }
493     free( symbols->s_pairs );
494 }
495 
496 void hash_define( name, val, symbols )
497     char            *name, *val;
498     struct symhash **symbols;
499 {
500     int hashval;
501     struct pair *it;
502 
503     if ( !symbols )
504         return;
505 
506     /* Make space if it's needed */
507     if ( *symbols == NULL )
508     {
509         int i;
510 
511         *symbols = (struct symhash *) malloc( sizeof( struct symhash ) );
512         if ( *symbols == NULL )
513             fatalerr( "malloc()/realloc() failure in insert_defn()\n" );
514 
515         for ( i = 0; i < SYMHASHMEMBERS; ++i )
516             (*symbols)->s_pairs[i] = NULL;
517     }
518 
519     hashval = hash( name );
520     it = (*symbols)->s_pairs[ hashval ];
521 
522     /* Replace/insert the symbol */
523     if ( it == NULL )
524     {
525         it = (*symbols)->s_pairs[ hashval ] = (struct pair*) malloc( sizeof( struct pair ) );
526         it->p_name = copy( name );
527         it->p_value = copy( val );
528         it->p_next = NULL;
529     }
530     else if ( strcmp( it->p_name, name ) == 0 )
531     {
532         it->p_value = copy( val );
533     }
534     else
535     {
536         while ( it->p_next && ( strcmp( it->p_next->p_name, name ) != 0 ) )
537         {
538             it = it->p_next;
539         }
540         if ( it->p_next )
541             it->p_next->p_name = copy( name );
542         else
543         {
544             it->p_next = (struct pair*) malloc( sizeof( struct pair ) );
545             it->p_next->p_name = copy( name );
546             it->p_next->p_value = copy( val );
547             it->p_next->p_next = NULL;
548         }
549     }
550 }
551 
552 char *hash_lookup( symbol, symbols )
553     char           *symbol;
554     struct symhash *symbols;
555 {
556     struct pair *it;
557 
558     if ( !symbols )
559         return NULL;
560 
561     it = symbols->s_pairs[ hash( symbol ) ];
562 
563     while ( it && ( strcmp( it->p_name, symbol ) != 0 ) )
564     {
565         it = it->p_next;
566     }
567     if ( it )
568         return it->p_value;
569 
570     return NULL;
571 }
572 
573 void hash_undefine( symbol, symbols )
574     char           *symbol;
575     struct symhash *symbols;
576 {
577     int hashval;
578     struct pair *it;
579 
580     if ( !symbols )
581         return;
582 
583     hashval = hash( symbol );
584     it = symbols->s_pairs[ hashval ];
585 
586     /* Replace/insert the symbol */
587     if ( it == NULL )
588         return;
589     else if ( strcmp( it->p_name, symbol ) == 0 )
590     {
591         if ( it->p_next )
592         {
593             struct pair *tmp;
594             it->p_name = it->p_next->p_name;
595             it->p_value = it->p_next->p_value;
596             tmp = it->p_next->p_next;
597             free( it->p_next );
598             it->p_next = tmp;
599         }
600         else
601         {
602             free( it );
603             symbols->s_pairs[ hashval ] = NULL;
604         }
605     }
606     else
607     {
608         while ( it->p_next && ( strcmp( it->p_next->p_name, symbol ) != 0 ) )
609         {
610             it = it->p_next;
611         }
612         if ( it->p_next )
613         {
614             struct pair *tmp = it->p_next;
615             it->p_next = it->p_next->p_next;
616             free( tmp );
617         }
618     }
619 }
620