4 * Eric Youngdale was the original author of xconfig.
5 * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
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.
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.
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
21 * - negation (!) eliminated from conditions
24 * - xconfig is at the end of its life cycle. Contact <mec@shout.net> if
25 * you are interested in working on the replacement.
37 * Mark variables which are defined anywhere.
39 static void mark_variables( struct kconfig * scfg )
44 for ( i = 1; i <= max_varnum; i++ )
45 vartable[i].defined = 0;
46 for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
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 )
64 if ( cfg->nameindex > 0 ) /* paranoid */
66 vartable[cfg->nameindex].defined = 1;
74 static void free_cond( struct condition *cond )
76 struct condition *tmp, *tmp1;
77 for ( tmp = cond; tmp; tmp = tmp1 )
87 * Remove the bang operator from a condition to avoid priority problems.
88 * "!" has different priorities as "test" command argument and in
91 static struct condition * remove_bang( struct condition * condition )
93 struct condition * conda, * condb, * prev = NULL;
95 for ( conda = condition; conda; conda = conda->next )
97 if ( conda->op == op_bang && conda->next &&
98 ( condb = conda->next->next ) )
100 if ( condb->op == op_eq || condb->op == op_neq )
102 condb->op = (condb->op == op_eq) ? op_neq : op_eq;
103 conda->op = op_nuked;
106 prev->next = conda->next;
110 condition = conda->next;
125 * Make a new condition chain by joining the current condition stack with
126 * the "&&" operator for glue.
128 static struct condition * join_condition_stack( struct condition * conditions [],
131 struct condition * cond_list;
132 struct condition * cond_last;
135 cond_list = cond_last = NULL;
137 for ( i = 0; i < depth; i++ )
139 if ( conditions[i]->op == op_false )
141 struct condition * cnew;
143 /* It is always false condition */
144 cnew = malloc( sizeof(*cnew) );
145 memset( cnew, 0, sizeof(*cnew) );
147 cond_list = cond_last = cnew;
151 for ( i = 0; i < depth; i++ )
153 struct condition * cond;
154 struct condition * cnew;
157 /* omit always true conditions */
158 if ( conditions[i]->op == op_true )
161 /* if i have another condition, add an '&&' operator */
164 cnew = malloc( sizeof(*cnew) );
165 memset( cnew, 0, sizeof(*cnew) );
167 cond_last->next = cnew;
171 if ( conditions[i]->op != op_lparen )
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; }
181 { cond_last->next = cnew; cond_last = cnew; }
188 /* duplicate the chain */
189 for ( cond = conditions [i]; cond != NULL; cond = cond->next )
191 cnew = malloc( sizeof(*cnew) );
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; }
199 { cond_last->next = cnew; cond_last = cnew; }
205 cnew = malloc( sizeof(*cnew) );
206 memset( cnew, 0, sizeof(*cnew) );
207 cnew->op = op_rparen;
208 cond_last->next = cnew;
215 * Remove duplicate conditions.
218 struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f;
220 for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next )
222 if ( cond1->op == op_lparen )
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;
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 )
235 struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f;
237 for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next )
239 if ( cond2->op == op_lparen )
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;
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 )
255 /* one of these must be followed by && */
256 if ( cond1f->op == op_and
257 || ( cond2f != NULL && cond2f->op == op_and ) )
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;
268 cond2f->op = op_nuked;
284 static char * current_arch = NULL;
287 * Eliminating conditions with ARCH = <not current>.
289 static struct condition *eliminate_other_arch( struct condition *list )
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 )
296 fprintf( stderr, "error: ARCH undefined\n" );
299 if ( cond1a->op == op_variable
300 && ! strcmp( vartable[cond1a->nameindex].name, "ARCH" ) )
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 )
307 if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
308 || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
310 /* This is for another architecture */
311 cond1a->op = op_false;
316 else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
317 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
319 /* This is for current architecture */
320 cond1a->op = op_true;
326 else if ( cond1c->op == op_constant && cond1d->op == op_or )
328 if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
329 || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
331 /* This is for another architecture */
332 cond1b = cond1d->next;
335 return eliminate_other_arch( cond1b );
337 else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
338 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
340 /* This is for current architecture */
341 cond1a->op = op_true;
347 else if ( cond1c->op == op_constant && cond1d->op == op_and )
349 if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
350 || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
352 /* This is for another architecture */
355 for ( cond1c = cond1d->next; cond1c; cond1c = cond1c->next )
357 if ( cond1c->op == op_lparen )
359 else if ( cond1c->op == op_rparen )
361 else if ( cond1c->op == op_or && l_par == 0 )
362 /* Expression too complex - don't touch */
364 else if ( l_par < 0 )
366 fprintf( stderr, "incorrect condition: programming error ?\n" );
370 cond1a->op = op_false;
375 else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
376 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
378 /* This is for current architecture */
379 cond1b = cond1d->next;
382 return eliminate_other_arch( cond1b );
386 if ( cond1a->op == op_variable && ! vartable[cond1a->nameindex].defined )
388 cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
389 cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
390 cond1d = cond1c->next;
392 if ( cond1c->op == op_constant
393 && ( cond1d == NULL || cond1d->op == op_and ) ) /*???*/
395 if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
397 cond1a->op = op_false;
403 else if ( cond1c->op == op_constant && cond1d->op == op_or )
405 if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
407 cond1b = cond1d->next;
410 return eliminate_other_arch( cond1b );
421 * This is the main transformation function.
423 void fix_conditionals( struct kconfig * scfg )
425 struct kconfig * cfg;
428 * Transform op_variable to op_kvariable.
430 mark_variables( scfg );
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.
438 * For a simple statement, create a condition chain by joining together
439 * all of the conditions on the stack.
442 struct condition * cond_stack [32];
444 struct kconfig * prev = NULL;
446 for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
449 switch ( cfg->token )
455 cond_stack [depth++] =
456 remove_bang( eliminate_other_arch( cfg->cond ) );
463 * Invert the condition chain.
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.
469 struct condition * cond;
471 for ( cond = cond_stack [depth-1];
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;
494 case token_choice_item:
495 case token_choice_header:
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:
505 case token_mainmenu_option:
509 cfg->cond = join_condition_stack( cond_stack, depth );
510 if ( cfg->cond && cfg->cond->op == op_false )
514 prev->next = cfg->next;
521 case token_dep_mbool:
522 case token_dep_tristate:
524 * Same as the other simple statements, plus an additional
525 * condition for the dependency.
529 cond_stack [depth] = eliminate_other_arch( cfg->cond );
530 cfg->cond = join_condition_stack( cond_stack, depth+1 );
534 cfg->cond = join_condition_stack( cond_stack, depth );
536 if ( cfg->cond && cfg->cond->op == op_false )
540 prev->next = cfg->next;
555 void dump_condition( struct condition *list )
557 struct condition *tmp;
558 for ( tmp = list; tmp; tmp = tmp->next )
565 printf( " %s", vartable[tmp->nameindex].name );
568 printf( " %s", tmp->str );