1/* 2 * tkcond.c 3 * 4 * Eric Youngdale was the original author of xconfig. 5 * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer. 6 * 7 * This file takes the tokenized statement list and transforms 'if ...' 8 * statements. For each simple statement, I find all of the 'if' statements 9 * that enclose it, and attach the aggregate conditionals of those 'if' 10 * statements to the cond list of the simple statement. 11 * 12 * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net> 13 * - Steam-clean this file. I tested this by generating kconfig.tk for 14 * every architecture and comparing it character-for-character against 15 * the output of the old tkparse. 16 * 17 * 07 July 1999, Andrzej M. Krzysztofowicz <ankry@mif.pg.gda.pl> 18 * - kvariables removed; all variables are stored in a single table now 19 * - some elimination of options non-valid for current architecture 20 * implemented. 21 * - negation (!) eliminated from conditions 22 * 23 * TO DO: 24 * - xconfig is at the end of its life cycle. Contact <mec@shout.net> if 25 * you are interested in working on the replacement. 26 */ 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31 32#include "tkparse.h" 33 34 35 36/* 37 * Mark variables which are defined anywhere. 38 */ 39static void mark_variables( struct kconfig * scfg ) 40{ 41 struct kconfig * cfg; 42 int i; 43 44 for ( i = 1; i <= max_varnum; i++ ) 45 vartable[i].defined = 0; 46 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 47 { 48 if ( cfg->token == token_bool 49 || cfg->token == token_choice_item 50 || cfg->token == token_define_bool 51 || cfg->token == token_define_hex 52 || cfg->token == token_define_int 53 || cfg->token == token_define_string 54 || cfg->token == token_define_tristate 55 || cfg->token == token_dep_bool 56 || cfg->token == token_dep_mbool 57 || cfg->token == token_dep_tristate 58 || cfg->token == token_hex 59 || cfg->token == token_int 60 || cfg->token == token_string 61 || cfg->token == token_tristate 62 || cfg->token == token_unset ) 63 { 64 if ( cfg->nameindex > 0 ) /* paranoid */ 65 { 66 vartable[cfg->nameindex].defined = 1; 67 } 68 } 69 } 70} 71 72 73 74static void free_cond( struct condition *cond ) 75{ 76 struct condition *tmp, *tmp1; 77 for ( tmp = cond; tmp; tmp = tmp1 ) 78 { 79 tmp1 = tmp->next; 80 free( (void*)tmp ); 81 } 82} 83 84 85 86/* 87 * Remove the bang operator from a condition to avoid priority problems. 88 * "!" has different priorities as "test" command argument and in 89 * a tk script. 90 */ 91static struct condition * remove_bang( struct condition * condition ) 92{ 93 struct condition * conda, * condb, * prev = NULL; 94 95 for ( conda = condition; conda; conda = conda->next ) 96 { 97 if ( conda->op == op_bang && conda->next && 98 ( condb = conda->next->next ) ) 99 { 100 if ( condb->op == op_eq || condb->op == op_neq ) 101 { 102 condb->op = (condb->op == op_eq) ? op_neq : op_eq; 103 conda->op = op_nuked; 104 if ( prev ) 105 { 106 prev->next = conda->next; 107 } 108 else 109 { 110 condition = conda->next; 111 } 112 conda->next = NULL; 113 free_cond( conda ); 114 conda = condb; 115 } 116 } 117 prev = conda; 118 } 119 return condition; 120} 121 122 123 124/* 125 * Make a new condition chain by joining the current condition stack with 126 * the "&&" operator for glue. 127 */ 128static struct condition * join_condition_stack( struct condition * conditions [], 129 int depth ) 130{ 131 struct condition * cond_list; 132 struct condition * cond_last; 133 int i, is_first = 1; 134 135 cond_list = cond_last = NULL; 136 137 for ( i = 0; i < depth; i++ ) 138 { 139 if ( conditions[i]->op == op_false ) 140 { 141 struct condition * cnew; 142 143 /* It is always false condition */ 144 cnew = malloc( sizeof(*cnew) ); 145 memset( cnew, 0, sizeof(*cnew) ); 146 cnew->op = op_false; 147 cond_list = cond_last = cnew; 148 goto join_done; 149 } 150 } 151 for ( i = 0; i < depth; i++ ) 152 { 153 struct condition * cond; 154 struct condition * cnew; 155 int add_paren; 156 157 /* omit always true conditions */ 158 if ( conditions[i]->op == op_true ) 159 continue; 160 161 /* if i have another condition, add an '&&' operator */ 162 if ( !is_first ) 163 { 164 cnew = malloc( sizeof(*cnew) ); 165 memset( cnew, 0, sizeof(*cnew) ); 166 cnew->op = op_and; 167 cond_last->next = cnew; 168 cond_last = cnew; 169 } 170 171 if ( conditions[i]->op != op_lparen ) 172 { 173 /* add a '(' */ 174 add_paren = 1; 175 cnew = malloc( sizeof(*cnew) ); 176 memset( cnew, 0, sizeof(*cnew) ); 177 cnew->op = op_lparen; 178 if ( cond_last == NULL ) 179 { cond_list = cond_last = cnew; } 180 else 181 { cond_last->next = cnew; cond_last = cnew; } 182 } 183 else 184 { 185 add_paren = 0; 186 } 187 188 /* duplicate the chain */ 189 for ( cond = conditions [i]; cond != NULL; cond = cond->next ) 190 { 191 cnew = malloc( sizeof(*cnew) ); 192 cnew->next = NULL; 193 cnew->op = cond->op; 194 cnew->str = cond->str ? strdup( cond->str ) : NULL; 195 cnew->nameindex = cond->nameindex; 196 if ( cond_last == NULL ) 197 { cond_list = cond_last = cnew; } 198 else 199 { cond_last->next = cnew; cond_last = cnew; } 200 } 201 202 if ( add_paren ) 203 { 204 /* add a ')' */ 205 cnew = malloc( sizeof(*cnew) ); 206 memset( cnew, 0, sizeof(*cnew) ); 207 cnew->op = op_rparen; 208 cond_last->next = cnew; 209 cond_last = cnew; 210 } 211 is_first = 0; 212 } 213 214 /* 215 * Remove duplicate conditions. 216 */ 217 { 218 struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f; 219 220 for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next ) 221 { 222 if ( cond1->op == op_lparen ) 223 { 224 cond1b = cond1 ->next; if ( cond1b == NULL ) break; 225 cond1c = cond1b->next; if ( cond1c == NULL ) break; 226 cond1d = cond1c->next; if ( cond1d == NULL ) break; 227 cond1e = cond1d->next; if ( cond1e == NULL ) break; 228 cond1f = cond1e->next; if ( cond1f == NULL ) break; 229 230 if ( cond1b->op == op_variable 231 && ( cond1c->op == op_eq || cond1c->op == op_neq ) 232 && cond1d->op == op_constant 233 && cond1e->op == op_rparen ) 234 { 235 struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f; 236 237 for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next ) 238 { 239 if ( cond2->op == op_lparen ) 240 { 241 cond2b = cond2 ->next; if ( cond2b == NULL ) break; 242 cond2c = cond2b->next; if ( cond2c == NULL ) break; 243 cond2d = cond2c->next; if ( cond2d == NULL ) break; 244 cond2e = cond2d->next; if ( cond2e == NULL ) break; 245 cond2f = cond2e->next; 246 247 /* look for match */ 248 if ( cond2b->op == op_variable 249 && cond2b->nameindex == cond1b->nameindex 250 && cond2c->op == cond1c->op 251 && cond2d->op == op_constant 252 && strcmp( cond2d->str, cond1d->str ) == 0 253 && cond2e->op == op_rparen ) 254 { 255 /* one of these must be followed by && */ 256 if ( cond1f->op == op_and 257 || ( cond2f != NULL && cond2f->op == op_and ) ) 258 { 259 /* nuke the first duplicate */ 260 cond1 ->op = op_nuked; 261 cond1b->op = op_nuked; 262 cond1c->op = op_nuked; 263 cond1d->op = op_nuked; 264 cond1e->op = op_nuked; 265 if ( cond1f->op == op_and ) 266 cond1f->op = op_nuked; 267 else 268 cond2f->op = op_nuked; 269 } 270 } 271 } 272 } 273 } 274 } 275 } 276 } 277 278join_done: 279 return cond_list; 280} 281 282 283 284static char * current_arch = NULL; 285 286/* 287 * Eliminating conditions with ARCH = <not current>. 288 */ 289static struct condition *eliminate_other_arch( struct condition *list ) 290{ 291 struct condition *cond1a = list, *cond1b = NULL, *cond1c = NULL, *cond1d = NULL; 292 if ( current_arch == NULL ) 293 current_arch = getenv( "ARCH" ); 294 if ( current_arch == NULL ) 295 { 296 fprintf( stderr, "error: ARCH undefined\n" ); 297 exit( 1 ); 298 } 299 if ( cond1a->op == op_variable 300 && ! strcmp( vartable[cond1a->nameindex].name, "ARCH" ) ) 301 { 302 cond1b = cond1a->next; if ( cond1b == NULL ) goto done; 303 cond1c = cond1b->next; if ( cond1c == NULL ) goto done; 304 cond1d = cond1c->next; 305 if ( cond1c->op == op_constant && cond1d == NULL ) 306 { 307 if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch )) 308 || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) ) 309 { 310 /* This is for another architecture */ 311 cond1a->op = op_false; 312 cond1a->next = NULL; 313 free_cond( cond1b ); 314 return cond1a; 315 } 316 else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch )) 317 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) ) 318 { 319 /* This is for current architecture */ 320 cond1a->op = op_true; 321 cond1a->next = NULL; 322 free_cond( cond1b ); 323 return cond1a; 324 } 325 } 326 else if ( cond1c->op == op_constant && cond1d->op == op_or ) 327 { 328 if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch )) 329 || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) ) 330 { 331 /* This is for another architecture */ 332 cond1b = cond1d->next; 333 cond1d->next = NULL; 334 free_cond( cond1a ); 335 return eliminate_other_arch( cond1b ); 336 } 337 else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch )) 338 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) ) 339 { 340 /* This is for current architecture */ 341 cond1a->op = op_true; 342 cond1a->next = NULL; 343 free_cond( cond1b ); 344 return cond1a; 345 } 346 } 347 else if ( cond1c->op == op_constant && cond1d->op == op_and ) 348 { 349 if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch )) 350 || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) ) 351 { 352 /* This is for another architecture */ 353 int l_par = 0; 354 355 for ( cond1c = cond1d->next; cond1c; cond1c = cond1c->next ) 356 { 357 if ( cond1c->op == op_lparen ) 358 l_par++; 359 else if ( cond1c->op == op_rparen ) 360 l_par--; 361 else if ( cond1c->op == op_or && l_par == 0 ) 362 /* Expression too complex - don't touch */ 363 return cond1a; 364 else if ( l_par < 0 ) 365 { 366 fprintf( stderr, "incorrect condition: programming error ?\n" ); 367 exit( 1 ); 368 } 369 } 370 cond1a->op = op_false; 371 cond1a->next = NULL; 372 free_cond( cond1b ); 373 return cond1a; 374 } 375 else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch )) 376 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) ) 377 { 378 /* This is for current architecture */ 379 cond1b = cond1d->next; 380 cond1d->next = NULL; 381 free_cond( cond1a ); 382 return eliminate_other_arch( cond1b ); 383 } 384 } 385 } 386 if ( cond1a->op == op_variable && ! vartable[cond1a->nameindex].defined ) 387 { 388 cond1b = cond1a->next; if ( cond1b == NULL ) goto done; 389 cond1c = cond1b->next; if ( cond1c == NULL ) goto done; 390 cond1d = cond1c->next; 391 392 if ( cond1c->op == op_constant 393 && ( cond1d == NULL || cond1d->op == op_and ) ) /*???*/ 394 { 395 if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) ) 396 { 397 cond1a->op = op_false; 398 cond1a->next = NULL; 399 free_cond( cond1b ); 400 return cond1a; 401 } 402 } 403 else if ( cond1c->op == op_constant && cond1d->op == op_or ) 404 { 405 if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) ) 406 { 407 cond1b = cond1d->next; 408 cond1d->next = NULL; 409 free_cond( cond1a ); 410 return eliminate_other_arch( cond1b ); 411 } 412 } 413 } 414done: 415 return list; 416} 417 418 419 420/* 421 * This is the main transformation function. 422 */ 423void fix_conditionals( struct kconfig * scfg ) 424{ 425 struct kconfig * cfg; 426 427 /* 428 * Transform op_variable to op_kvariable. 429 */ 430 mark_variables( scfg ); 431 432 /* 433 * Walk the statement list, maintaining a stack of current conditions. 434 * token_if push its condition onto the stack. 435 * token_else invert the condition on the top of the stack. 436 * token_endif pop the stack. 437 * 438 * For a simple statement, create a condition chain by joining together 439 * all of the conditions on the stack. 440 */ 441 { 442 struct condition * cond_stack [32]; 443 int depth = 0; 444 struct kconfig * prev = NULL; 445 446 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 447 { 448 int good = 1; 449 switch ( cfg->token ) 450 { 451 default: 452 break; 453 454 case token_if: 455 cond_stack [depth++] = 456 remove_bang( eliminate_other_arch( cfg->cond ) ); 457 cfg->cond = NULL; 458 break; 459 460 case token_else: 461 { 462 /* 463 * Invert the condition chain. 464 * 465 * Be careful to transfrom op_or to op_and1, not op_and. 466 * I will need this later in the code that removes 467 * duplicate conditions. 468 */ 469 struct condition * cond; 470 471 for ( cond = cond_stack [depth-1]; 472 cond != NULL; 473 cond = cond->next ) 474 { 475 switch( cond->op ) 476 { 477 default: break; 478 case op_and: cond->op = op_or; break; 479 case op_or: cond->op = op_and1; break; 480 case op_neq: cond->op = op_eq; break; 481 case op_eq: cond->op = op_neq; break; 482 case op_true: cond->op = op_false;break; 483 case op_false:cond->op = op_true; break; 484 } 485 } 486 } 487 break; 488 489 case token_fi: 490 --depth; 491 break; 492 493 case token_bool: 494 case token_choice_item: 495 case token_choice_header: 496 case token_comment: 497 case token_define_bool: 498 case token_define_hex: 499 case token_define_int: 500 case token_define_string: 501 case token_define_tristate: 502 case token_endmenu: 503 case token_hex: 504 case token_int: 505 case token_mainmenu_option: 506 case token_string: 507 case token_tristate: 508 case token_unset: 509 cfg->cond = join_condition_stack( cond_stack, depth ); 510 if ( cfg->cond && cfg->cond->op == op_false ) 511 { 512 good = 0; 513 if ( prev ) 514 prev->next = cfg->next; 515 else 516 scfg = cfg->next; 517 } 518 break; 519 520 case token_dep_bool: 521 case token_dep_mbool: 522 case token_dep_tristate: 523 /* 524 * Same as the other simple statements, plus an additional 525 * condition for the dependency. 526 */ 527 if ( cfg->cond ) 528 { 529 cond_stack [depth] = eliminate_other_arch( cfg->cond ); 530 cfg->cond = join_condition_stack( cond_stack, depth+1 ); 531 } 532 else 533 { 534 cfg->cond = join_condition_stack( cond_stack, depth ); 535 } 536 if ( cfg->cond && cfg->cond->op == op_false ) 537 { 538 good = 0; 539 if ( prev ) 540 prev->next = cfg->next; 541 else 542 scfg = cfg->next; 543 } 544 break; 545 } 546 if ( good ) 547 prev = cfg; 548 } 549 } 550} 551 552 553 554