tkcond.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
- /*
- * tkcond.c
- *
- * Eric Youngdale was the original author of xconfig.
- * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
- *
- * This file takes the tokenized statement list and transforms 'if ...'
- * statements. For each simple statement, I find all of the 'if' statements
- * that enclose it, and attach the aggregate conditionals of those 'if'
- * statements to the cond list of the simple statement.
- *
- * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Steam-clean this file. I tested this by generating kconfig.tk for
- * every architecture and comparing it character-for-character against
- * the output of the old tkparse.
- *
- * 07 July 1999, Andrzej M. Krzysztofowicz <ankry@mif.pg.gda.pl>
- * - kvariables removed; all variables are stored in a single table now
- * - some elimination of options non-valid for current architecture
- * implemented.
- * - negation (!) eliminated from conditions
- *
- * TO DO:
- * - xconfig is at the end of its life cycle. Contact <mec@shout.net> if
- * you are interested in working on the replacement.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "tkparse.h"
- /*
- * Mark variables which are defined anywhere.
- */
- static void mark_variables( struct kconfig * scfg )
- {
- struct kconfig * cfg;
- int i;
- for ( i = 1; i <= max_varnum; i++ )
- vartable[i].defined = 0;
- for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
- {
- if ( cfg->token == token_bool
- || cfg->token == token_choice_item
- || cfg->token == token_define_bool
- || cfg->token == token_define_hex
- || cfg->token == token_define_int
- || cfg->token == token_define_string
- || cfg->token == token_define_tristate
- || cfg->token == token_dep_bool
- || cfg->token == token_dep_mbool
- || cfg->token == token_dep_tristate
- || cfg->token == token_hex
- || cfg->token == token_int
- || cfg->token == token_string
- || cfg->token == token_tristate
- || cfg->token == token_unset )
- {
- if ( cfg->nameindex > 0 ) /* paranoid */
- {
- vartable[cfg->nameindex].defined = 1;
- }
- }
- }
- }
- static void free_cond( struct condition *cond )
- {
- struct condition *tmp, *tmp1;
- for ( tmp = cond; tmp; tmp = tmp1 )
- {
- tmp1 = tmp->next;
- free( (void*)tmp );
- }
- }
- /*
- * Remove the bang operator from a condition to avoid priority problems.
- * "!" has different priorities as "test" command argument and in
- * a tk script.
- */
- static struct condition * remove_bang( struct condition * condition )
- {
- struct condition * conda, * condb, * prev = NULL;
- for ( conda = condition; conda; conda = conda->next )
- {
- if ( conda->op == op_bang && conda->next &&
- ( condb = conda->next->next ) )
- {
- if ( condb->op == op_eq || condb->op == op_neq )
- {
- condb->op = (condb->op == op_eq) ? op_neq : op_eq;
- conda->op = op_nuked;
- if ( prev )
- {
- prev->next = conda->next;
- }
- else
- {
- condition = conda->next;
- }
- conda->next = NULL;
- free_cond( conda );
- conda = condb;
- }
- }
- prev = conda;
- }
- return condition;
- }
- /*
- * Make a new condition chain by joining the current condition stack with
- * the "&&" operator for glue.
- */
- static struct condition * join_condition_stack( struct condition * conditions [],
- int depth )
- {
- struct condition * cond_list;
- struct condition * cond_last;
- int i, is_first = 1;
- cond_list = cond_last = NULL;
- for ( i = 0; i < depth; i++ )
- {
- if ( conditions[i]->op == op_false )
- {
- struct condition * cnew;
- /* It is always false condition */
- cnew = malloc( sizeof(*cnew) );
- memset( cnew, 0, sizeof(*cnew) );
- cnew->op = op_false;
- cond_list = cond_last = cnew;
- goto join_done;
- }
- }
- for ( i = 0; i < depth; i++ )
- {
- struct condition * cond;
- struct condition * cnew;
- int add_paren;
- /* omit always true conditions */
- if ( conditions[i]->op == op_true )
- continue;
- /* if i have another condition, add an '&&' operator */
- if ( !is_first )
- {
- cnew = malloc( sizeof(*cnew) );
- memset( cnew, 0, sizeof(*cnew) );
- cnew->op = op_and;
- cond_last->next = cnew;
- cond_last = cnew;
- }
- if ( conditions[i]->op != op_lparen )
- {
- /* add a '(' */
- add_paren = 1;
- cnew = malloc( sizeof(*cnew) );
- memset( cnew, 0, sizeof(*cnew) );
- cnew->op = op_lparen;
- if ( cond_last == NULL )
- { cond_list = cond_last = cnew; }
- else
- { cond_last->next = cnew; cond_last = cnew; }
- }
- else
- {
- add_paren = 0;
- }
- /* duplicate the chain */
- for ( cond = conditions [i]; cond != NULL; cond = cond->next )
- {
- cnew = malloc( sizeof(*cnew) );
- cnew->next = NULL;
- cnew->op = cond->op;
- cnew->str = cond->str ? strdup( cond->str ) : NULL;
- cnew->nameindex = cond->nameindex;
- if ( cond_last == NULL )
- { cond_list = cond_last = cnew; }
- else
- { cond_last->next = cnew; cond_last = cnew; }
- }
- if ( add_paren )
- {
- /* add a ')' */
- cnew = malloc( sizeof(*cnew) );
- memset( cnew, 0, sizeof(*cnew) );
- cnew->op = op_rparen;
- cond_last->next = cnew;
- cond_last = cnew;
- }
- is_first = 0;
- }
- /*
- * Remove duplicate conditions.
- */
- {
- struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f;
- for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next )
- {
- if ( cond1->op == op_lparen )
- {
- cond1b = cond1 ->next; if ( cond1b == NULL ) break;
- cond1c = cond1b->next; if ( cond1c == NULL ) break;
- cond1d = cond1c->next; if ( cond1d == NULL ) break;
- cond1e = cond1d->next; if ( cond1e == NULL ) break;
- cond1f = cond1e->next; if ( cond1f == NULL ) break;
- if ( cond1b->op == op_variable
- && ( cond1c->op == op_eq || cond1c->op == op_neq )
- && cond1d->op == op_constant
- && cond1e->op == op_rparen )
- {
- struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f;
- for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next )
- {
- if ( cond2->op == op_lparen )
- {
- cond2b = cond2 ->next; if ( cond2b == NULL ) break;
- cond2c = cond2b->next; if ( cond2c == NULL ) break;
- cond2d = cond2c->next; if ( cond2d == NULL ) break;
- cond2e = cond2d->next; if ( cond2e == NULL ) break;
- cond2f = cond2e->next;
- /* look for match */
- if ( cond2b->op == op_variable
- && cond2b->nameindex == cond1b->nameindex
- && cond2c->op == cond1c->op
- && cond2d->op == op_constant
- && strcmp( cond2d->str, cond1d->str ) == 0
- && cond2e->op == op_rparen )
- {
- /* one of these must be followed by && */
- if ( cond1f->op == op_and
- || ( cond2f != NULL && cond2f->op == op_and ) )
- {
- /* nuke the first duplicate */
- cond1 ->op = op_nuked;
- cond1b->op = op_nuked;
- cond1c->op = op_nuked;
- cond1d->op = op_nuked;
- cond1e->op = op_nuked;
- if ( cond1f->op == op_and )
- cond1f->op = op_nuked;
- else
- cond2f->op = op_nuked;
- }
- }
- }
- }
- }
- }
- }
- }
- join_done:
- return cond_list;
- }
- static char * current_arch = NULL;
- /*
- * Eliminating conditions with ARCH = <not current>.
- */
- static struct condition *eliminate_other_arch( struct condition *list )
- {
- struct condition *cond1a = list, *cond1b = NULL, *cond1c = NULL, *cond1d = NULL;
- if ( current_arch == NULL )
- current_arch = getenv( "ARCH" );
- if ( current_arch == NULL )
- {
- fprintf( stderr, "error: ARCH undefinedn" );
- exit( 1 );
- }
- if ( cond1a->op == op_variable
- && ! strcmp( vartable[cond1a->nameindex].name, "ARCH" ) )
- {
- cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
- cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
- cond1d = cond1c->next;
- if ( cond1c->op == op_constant && cond1d == NULL )
- {
- if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
- || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
- {
- /* This is for another architecture */
- cond1a->op = op_false;
- cond1a->next = NULL;
- free_cond( cond1b );
- return cond1a;
- }
- else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
- || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
- {
- /* This is for current architecture */
- cond1a->op = op_true;
- cond1a->next = NULL;
- free_cond( cond1b );
- return cond1a;
- }
- }
- else if ( cond1c->op == op_constant && cond1d->op == op_or )
- {
- if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
- || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
- {
- /* This is for another architecture */
- cond1b = cond1d->next;
- cond1d->next = NULL;
- free_cond( cond1a );
- return eliminate_other_arch( cond1b );
- }
- else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
- || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
- {
- /* This is for current architecture */
- cond1a->op = op_true;
- cond1a->next = NULL;
- free_cond( cond1b );
- return cond1a;
- }
- }
- else if ( cond1c->op == op_constant && cond1d->op == op_and )
- {
- if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
- || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
- {
- /* This is for another architecture */
- int l_par = 0;
-
- for ( cond1c = cond1d->next; cond1c; cond1c = cond1c->next )
- {
- if ( cond1c->op == op_lparen )
- l_par++;
- else if ( cond1c->op == op_rparen )
- l_par--;
- else if ( cond1c->op == op_or && l_par == 0 )
- /* Expression too complex - don't touch */
- return cond1a;
- else if ( l_par < 0 )
- {
- fprintf( stderr, "incorrect condition: programming error ?n" );
- exit( 1 );
- }
- }
- cond1a->op = op_false;
- cond1a->next = NULL;
- free_cond( cond1b );
- return cond1a;
- }
- else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
- || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
- {
- /* This is for current architecture */
- cond1b = cond1d->next;
- cond1d->next = NULL;
- free_cond( cond1a );
- return eliminate_other_arch( cond1b );
- }
- }
- }
- if ( cond1a->op == op_variable && ! vartable[cond1a->nameindex].defined )
- {
- cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
- cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
- cond1d = cond1c->next;
- if ( cond1c->op == op_constant
- && ( cond1d == NULL || cond1d->op == op_and ) ) /*???*/
- {
- if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
- {
- cond1a->op = op_false;
- cond1a->next = NULL;
- free_cond( cond1b );
- return cond1a;
- }
- }
- else if ( cond1c->op == op_constant && cond1d->op == op_or )
- {
- if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
- {
- cond1b = cond1d->next;
- cond1d->next = NULL;
- free_cond( cond1a );
- return eliminate_other_arch( cond1b );
- }
- }
- }
- done:
- return list;
- }
- /*
- * This is the main transformation function.
- */
- void fix_conditionals( struct kconfig * scfg )
- {
- struct kconfig * cfg;
- /*
- * Transform op_variable to op_kvariable.
- */
- mark_variables( scfg );
- /*
- * Walk the statement list, maintaining a stack of current conditions.
- * token_if push its condition onto the stack.
- * token_else invert the condition on the top of the stack.
- * token_endif pop the stack.
- *
- * For a simple statement, create a condition chain by joining together
- * all of the conditions on the stack.
- */
- {
- struct condition * cond_stack [32];
- int depth = 0;
- struct kconfig * prev = NULL;
- for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
- {
- int good = 1;
- switch ( cfg->token )
- {
- default:
- break;
- case token_if:
- cond_stack [depth++] =
- remove_bang( eliminate_other_arch( cfg->cond ) );
- cfg->cond = NULL;
- break;
- case token_else:
- {
- /*
- * Invert the condition chain.
- *
- * Be careful to transfrom op_or to op_and1, not op_and.
- * I will need this later in the code that removes
- * duplicate conditions.
- */
- struct condition * cond;
- for ( cond = cond_stack [depth-1];
- cond != NULL;
- cond = cond->next )
- {
- switch( cond->op )
- {
- default: break;
- case op_and: cond->op = op_or; break;
- case op_or: cond->op = op_and1; break;
- case op_neq: cond->op = op_eq; break;
- case op_eq: cond->op = op_neq; break;
- case op_true: cond->op = op_false;break;
- case op_false:cond->op = op_true; break;
- }
- }
- }
- break;
- case token_fi:
- --depth;
- break;
- case token_bool:
- case token_choice_item:
- case token_choice_header:
- case token_comment:
- case token_define_bool:
- case token_define_hex:
- case token_define_int:
- case token_define_string:
- case token_define_tristate:
- case token_endmenu:
- case token_hex:
- case token_int:
- case token_mainmenu_option:
- case token_string:
- case token_tristate:
- case token_unset:
- cfg->cond = join_condition_stack( cond_stack, depth );
- if ( cfg->cond && cfg->cond->op == op_false )
- {
- good = 0;
- if ( prev )
- prev->next = cfg->next;
- else
- scfg = cfg->next;
- }
- break;
- case token_dep_bool:
- case token_dep_mbool:
- case token_dep_tristate:
- /*
- * Same as the other simple statements, plus an additional
- * condition for the dependency.
- */
- if ( cfg->cond )
- {
- cond_stack [depth] = eliminate_other_arch( cfg->cond );
- cfg->cond = join_condition_stack( cond_stack, depth+1 );
- }
- else
- {
- cfg->cond = join_condition_stack( cond_stack, depth );
- }
- if ( cfg->cond && cfg->cond->op == op_false )
- {
- good = 0;
- if ( prev )
- prev->next = cfg->next;
- else
- scfg = cfg->next;
- }
- break;
- }
- if ( good )
- prev = cfg;
- }
- }
- }
- #if 0
- void dump_condition( struct condition *list )
- {
- struct condition *tmp;
- for ( tmp = list; tmp; tmp = tmp->next )
- {
- switch (tmp->op)
- {
- default:
- break;
- case op_variable:
- printf( " %s", vartable[tmp->nameindex].name );
- break;
- case op_constant:
- printf( " %s", tmp->str );
- break;
- case op_eq:
- printf( " =" );
- break;
- case op_bang:
- printf( " !" );
- break;
- case op_neq:
- printf( " !=" );
- break;
- case op_and:
- case op_and1:
- printf( " -a" );
- break;
- case op_or:
- printf( " -o" );
- break;
- case op_true:
- printf( " TRUE" );
- break;
- case op_false:
- printf( " FALSE" );
- break;
- case op_lparen:
- printf( " (" );
- break;
- case op_rparen:
- printf( " )" );
- break;
- }
- }
- printf( "n" );
- }
- #endif