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 {
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
isdefined(symbol)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 */
zero_value(exp,filep,file_red,symbols)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
define(def,symbols)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
hash(str)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
hash_copy(symbols)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
hash_free(symbols)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
hash_define(name,val,symbols)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
hash_lookup(symbol,symbols)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
hash_undefine(symbol,symbols)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