xref: /AOO41X/main/soltools/mkdepend/parse.c (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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 
find_includes(filep,file,file_red,recursion,failOK,incCollection,symbols)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 
gobble(filep,file,file_red,symbols)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  */
deftype(line,filep,file_red,file,parse_it,symbols)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         strcpy (line, p);
350         break;
351     case ELSE:
352     case ENDIF:
353     case ELIF:
354     case PRAGMA:
355     case ERROR:
356     case IDENT:
357     case SCCS:
358     case EJECT:
359         debug(0,("%s, line %d: #%s\n",
360             file->i_file, filep->f_line, directives[ret]));
361         /*
362          * nothing to do.
363          */
364         break;
365     }
366     return(ret);
367 }
368 
369 /*
370  * HACK! - so that we do not have to introduce 'symbols' in each cppsetup.c
371  * function...  It's safe, functions from cppsetup.c don't return here.
372  */
373 struct symhash *global_symbols = NULL;
374 
isdefined(symbol)375 char * isdefined( symbol )
376     register char *symbol;
377 {
378     return hash_lookup( symbol, global_symbols );
379 }
380 
381 /*
382  * Return type based on if the #if expression evaluates to 0
383  */
zero_value(exp,filep,file_red,symbols)384 int zero_value(exp, filep, file_red, symbols)
385     register char   *exp;
386     register struct filepointer *filep;
387     register struct inclist *file_red;
388     register struct symhash *symbols;
389 {
390     global_symbols = symbols; /* HACK! see above */
391     if (cppsetup(exp, filep, file_red))
392         return(IFFALSE);
393     else
394         return(IF);
395 }
396 
define(def,symbols)397 void define( def, symbols )
398     char            *def;
399     struct symhash **symbols;
400 {
401     char *val;
402 
403     /* Separate symbol name and its value */
404     val = def;
405     while (isalnum(*val) || *val == '_')
406     val++;
407     if (*val)
408     *val++ = '\0';
409     while (*val == ' ' || *val == '\t')
410     val++;
411 
412     if (!*val)
413     val = "1";
414     hash_define( def, val, symbols );
415 }
416 
hash(str)417 static int hash( str )
418     register char *str;
419 {
420     /* Hash (Kernighan and Ritchie) */
421     register unsigned int hashval = 0;
422     //char *s = str;
423 
424     for ( ; *str; str++ )
425     {
426         hashval = ( hashval * SYMHASHSEED ) + ( *str );
427     }
428 
429     //fprintf( stderr, "hash: %s, %d\n", s, hashval & ( SYMHASHMEMBERS - 1 ) );
430     return hashval & ( SYMHASHMEMBERS - 1 );
431 }
432 
hash_copy(symbols)433 struct symhash *hash_copy( symbols )
434     struct symhash *symbols;
435 {
436     int i;
437     struct symhash *newsym;
438     if ( !symbols )
439         return NULL;
440 
441     newsym = (struct symhash *) malloc( sizeof( struct symhash ) );
442 
443     for ( i = 0; i < SYMHASHMEMBERS; ++i )
444     {
445         if ( !symbols->s_pairs[ i ] )
446             newsym->s_pairs[ i ] = NULL;
447         else
448         {
449             struct pair *it = symbols->s_pairs[ i ];
450             struct pair *nw = newsym->s_pairs[ i ] = (struct pair*) malloc( sizeof( struct pair ) );
451             nw->p_name = it->p_name;
452             nw->p_value = it->p_value;
453             nw->p_next = NULL;
454 
455             while ( it->p_next )
456             {
457                 nw->p_next = (struct pair*) malloc( sizeof( struct pair ) );
458                 it = it->p_next;
459                 nw = nw->p_next;
460                 nw->p_name = it->p_name;
461                 nw->p_value = it->p_value;
462                 nw->p_next = NULL;
463             }
464         }
465     }
466     return newsym;
467 }
468 
hash_free(symbols)469 void hash_free( symbols )
470     struct symhash *symbols;
471 {
472     int i;
473 
474     if ( !symbols )
475         return;
476 
477     for ( i = 0; i < SYMHASHMEMBERS; ++i )
478     {
479         struct pair *it = symbols->s_pairs[ i ];
480         struct pair *next;
481         while ( it )
482         {
483             next = it->p_next;
484             free( it );
485             it = next;
486         }
487     }
488     free( symbols->s_pairs );
489 }
490 
hash_define(name,val,symbols)491 void hash_define( name, val, symbols )
492     char            *name, *val;
493     struct symhash **symbols;
494 {
495     int hashval;
496     struct pair *it;
497 
498     if ( !symbols )
499         return;
500 
501     /* Make space if it's needed */
502     if ( *symbols == NULL )
503     {
504         int i;
505 
506         *symbols = (struct symhash *) malloc( sizeof( struct symhash ) );
507         if ( *symbols == NULL )
508             fatalerr( "malloc()/realloc() failure in insert_defn()\n" );
509 
510         for ( i = 0; i < SYMHASHMEMBERS; ++i )
511             (*symbols)->s_pairs[i] = NULL;
512     }
513 
514     hashval = hash( name );
515     it = (*symbols)->s_pairs[ hashval ];
516 
517     /* Replace/insert the symbol */
518     if ( it == NULL )
519     {
520         it = (*symbols)->s_pairs[ hashval ] = (struct pair*) malloc( sizeof( struct pair ) );
521         it->p_name = copy( name );
522         it->p_value = copy( val );
523         it->p_next = NULL;
524     }
525     else if ( strcmp( it->p_name, name ) == 0 )
526     {
527         it->p_value = copy( val );
528     }
529     else
530     {
531         while ( it->p_next && ( strcmp( it->p_next->p_name, name ) != 0 ) )
532         {
533             it = it->p_next;
534         }
535         if ( it->p_next )
536             it->p_next->p_name = copy( name );
537         else
538         {
539             it->p_next = (struct pair*) malloc( sizeof( struct pair ) );
540             it->p_next->p_name = copy( name );
541             it->p_next->p_value = copy( val );
542             it->p_next->p_next = NULL;
543         }
544     }
545 }
546 
hash_lookup(symbol,symbols)547 char *hash_lookup( symbol, symbols )
548     char           *symbol;
549     struct symhash *symbols;
550 {
551     struct pair *it;
552 
553     if ( !symbols )
554         return NULL;
555 
556     it = symbols->s_pairs[ hash( symbol ) ];
557 
558     while ( it && ( strcmp( it->p_name, symbol ) != 0 ) )
559     {
560         it = it->p_next;
561     }
562     if ( it )
563         return it->p_value;
564 
565     return NULL;
566 }
567 
hash_undefine(symbol,symbols)568 void hash_undefine( symbol, symbols )
569     char           *symbol;
570     struct symhash *symbols;
571 {
572     int hashval;
573     struct pair *it;
574 
575     if ( !symbols )
576         return;
577 
578     hashval = hash( symbol );
579     it = symbols->s_pairs[ hashval ];
580 
581     /* Replace/insert the symbol */
582     if ( it == NULL )
583         return;
584     else if ( strcmp( it->p_name, symbol ) == 0 )
585     {
586         if ( it->p_next )
587         {
588             struct pair *tmp;
589             it->p_name = it->p_next->p_name;
590             it->p_value = it->p_next->p_value;
591             tmp = it->p_next->p_next;
592             free( it->p_next );
593             it->p_next = tmp;
594         }
595         else
596         {
597             free( it );
598             symbols->s_pairs[ hashval ] = NULL;
599         }
600     }
601     else
602     {
603         while ( it->p_next && ( strcmp( it->p_next->p_name, symbol ) != 0 ) )
604         {
605             it = it->p_next;
606         }
607         if ( it->p_next )
608         {
609             struct pair *tmp = it->p_next;
610             it->p_next = it->p_next->p_next;
611             free( tmp );
612         }
613     }
614 }
615