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