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