mirror of
https://github.com/lcbcFoo/ReonV.git
synced 2025-04-22 12:37:06 -04:00
602 lines
14 KiB
C
602 lines
14 KiB
C
/*
|
|
* 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 arch_sparc[] = "sparc";
|
|
static char * current_arch = arch_sparc;
|
|
|
|
/*
|
|
* 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 undefined\n" );
|
|
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
|