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
);