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.
18 * - xconfig is at the end of its life cycle. Contact <mec@shout.net> if
19 * you are interested in working on the replacement.
31 * Transform op_variable to op_kvariable.
33 * This works, but it's gross, speed-wise. It would benefit greatly
34 * from a simple hash table that maps names to cfg.
36 * Note well: this is actually better than the loop structure xconfig
37 * has been staggering along with for three years, which performs
38 * this whole procedure inside *another* loop on active conditionals.
40 void transform_to_kvariable( struct kconfig
* scfg
)
44 for ( cfg
= scfg
; cfg
!= NULL
; cfg
= cfg
->next
)
46 struct condition
* cond
;
48 for ( cond
= cfg
->cond
; cond
!= NULL
; cond
= cond
->next
)
50 if ( cond
->op
== op_variable
)
52 /* Here's where it gets DISGUSTING. */
53 struct kconfig
* cfg1
;
55 for ( cfg1
= scfg
; cfg1
!= NULL
; cfg1
= cfg1
->next
)
57 if ( cfg1
->token
== token_bool
58 || cfg1
->token
== token_choice_item
59 || cfg1
->token
== token_dep_tristate
60 || cfg1
->token
== token_hex
61 || cfg1
->token
== token_int
62 || cfg1
->token
== token_string
63 || cfg1
->token
== token_tristate
)
65 if ( strcmp( cond
->str
, cfg1
->optionname
) == 0 )
67 cond
->op
= op_kvariable
;
78 * Maybe someday this will be useful, but right now it
79 * gives a lot of false positives on files like
80 * drivers/video/Config.in that are meant for more
81 * than one architecture. Turn it on if you want to play
82 * with it though; it does work. -- mec
84 if ( cond
->op
== op_variable
)
86 if ( strcmp( cond
->str
, "ARCH" ) != 0
87 && strcmp( cond
->str
, "CONSTANT_Y" ) != 0
88 && strcmp( cond
->str
, "CONSTANT_M" ) != 0
89 && strcmp( cond
->str
, "CONSTANT_N" ) != 0 )
91 fprintf( stderr
, "warning: $%s used but not defined\n",
103 * Make a new condition chain by joining the current condition stack with
104 * the "&&" operator for glue.
106 struct condition
* join_condition_stack( struct condition
* conditions
[],
109 struct condition
* cond_list
;
110 struct condition
* cond_last
;
113 cond_list
= cond_last
= NULL
;
114 for ( i
= 0; i
< depth
; i
++ )
116 struct condition
* cond
;
117 struct condition
* cnew
;
120 cnew
= malloc( sizeof(*cnew
) );
121 memset( cnew
, 0, sizeof(*cnew
) );
122 cnew
->op
= op_lparen
;
123 if ( cond_last
== NULL
)
124 { cond_list
= cond_last
= cnew
; }
126 { cond_last
->next
= cnew
; cond_last
= cnew
; }
128 /* duplicate the chain */
129 for ( cond
= conditions
[i
]; cond
!= NULL
; cond
= cond
->next
)
131 cnew
= malloc( sizeof(*cnew
) );
134 cnew
->str
= cond
->str
? strdup( cond
->str
) : NULL
;
135 cnew
->cfg
= cond
->cfg
;
136 cond_last
->next
= cnew
;
141 cnew
= malloc( sizeof(*cnew
) );
142 memset( cnew
, 0, sizeof(*cnew
) );
143 cnew
->op
= op_rparen
;
144 cond_last
->next
= cnew
;
147 /* if i have another condition, add an '&&' operator */
150 cnew
= malloc( sizeof(*cnew
) );
151 memset( cnew
, 0, sizeof(*cnew
) );
153 cond_last
->next
= cnew
;
159 * Remove duplicate conditions.
162 struct condition
*cond1
, *cond1b
, *cond1c
, *cond1d
, *cond1e
, *cond1f
;
164 for ( cond1
= cond_list
; cond1
!= NULL
; cond1
= cond1
->next
)
166 if ( cond1
->op
== op_lparen
)
168 cond1b
= cond1
->next
; if ( cond1b
== NULL
) break;
169 cond1c
= cond1b
->next
; if ( cond1c
== NULL
) break;
170 cond1d
= cond1c
->next
; if ( cond1d
== NULL
) break;
171 cond1e
= cond1d
->next
; if ( cond1e
== NULL
) break;
172 cond1f
= cond1e
->next
; if ( cond1f
== NULL
) break;
174 if ( cond1b
->op
== op_kvariable
175 && ( cond1c
->op
== op_eq
|| cond1c
->op
== op_neq
)
176 && cond1d
->op
== op_constant
177 && cond1e
->op
== op_rparen
)
179 struct condition
*cond2
, *cond2b
, *cond2c
, *cond2d
, *cond2e
, *cond2f
;
181 for ( cond2
= cond1f
->next
; cond2
!= NULL
; cond2
= cond2
->next
)
183 if ( cond2
->op
== op_lparen
)
185 cond2b
= cond2
->next
; if ( cond2b
== NULL
) break;
186 cond2c
= cond2b
->next
; if ( cond2c
== NULL
) break;
187 cond2d
= cond2c
->next
; if ( cond2d
== NULL
) break;
188 cond2e
= cond2d
->next
; if ( cond2e
== NULL
) break;
189 cond2f
= cond2e
->next
;
192 if ( cond2b
->op
== op_kvariable
193 && cond2b
->cfg
== cond1b
->cfg
194 && cond2c
->op
== cond1c
->op
195 && cond2d
->op
== op_constant
196 && strcmp( cond2d
->str
, cond1d
->str
) == 0
197 && cond2e
->op
== op_rparen
)
199 /* one of these must be followed by && */
200 if ( cond1f
->op
== op_and
201 || ( cond2f
!= NULL
&& cond2f
->op
== op_and
) )
203 /* nuke the first duplicate */
204 cond1
->op
= op_nuked
;
205 cond1b
->op
= op_nuked
;
206 cond1c
->op
= op_nuked
;
207 cond1d
->op
= op_nuked
;
208 cond1e
->op
= op_nuked
;
209 if ( cond1f
->op
== op_and
)
210 cond1f
->op
= op_nuked
;
212 cond2f
->op
= op_nuked
;
228 * This is the main transformation function.
230 void fix_conditionals( struct kconfig
* scfg
)
232 struct kconfig
* cfg
;
235 * Transform op_variable to op_kvariable.
237 transform_to_kvariable( scfg
);
240 * Transform conditions that use variables from "choice" statements.
241 * Choice values appear to the user as a collection of booleans, and the
242 * script can test the individual booleans. But internally, all I have is
243 * the N-way value of an unnamed temporary for the whole statement. So I
244 * have to tranform '"$CONFIG_M386" != "y"'
245 * into '"$tmpvar_N" != "CONFIG_M386"'.
247 for ( cfg
= scfg
; cfg
!= NULL
; cfg
= cfg
->next
)
249 struct condition
* cond
;
251 for ( cond
= cfg
->cond
; cond
!= NULL
; cond
= cond
->next
)
253 if ( cond
->op
== op_kvariable
&& cond
->cfg
->token
== token_choice_item
)
256 * Look two more tokens down for the comparison token.
257 * It has to be "y" for this trick to work.
259 * If you get this error, don't even think about relaxing the
260 * strcmp test. You will produce incorrect TK code. Instead,
261 * look for the place in your Config.in script where you are
262 * comparing a 'choice' variable to a value other than 'y',
263 * and rewrite the comparison to be '= "y"' or '!= "y"'.
265 struct condition
* cond2
= cond
->next
->next
;
268 if ( strcmp( cond2
->str
, "y" ) != 0 )
270 fprintf( stderr
, "tkparse choked in fix_choice_cond\n" );
274 label
= cond
->cfg
->label
;
275 cond
->cfg
= cond
->cfg
->cfg_parent
;
276 cond2
->str
= strdup( label
);
282 * Walk the statement list, maintaining a stack of current conditions.
283 * token_if push its condition onto the stack.
284 * token_else invert the condition on the top of the stack.
285 * token_endif pop the stack.
287 * For a simple statement, create a condition chain by joining together
288 * all of the conditions on the stack.
291 struct condition
* cond_stack
[32];
294 for ( cfg
= scfg
; cfg
!= NULL
; cfg
= cfg
->next
)
296 switch ( cfg
->token
)
302 cond_stack
[depth
++] = cfg
->cond
;
309 * Invert the condition chain.
311 * Be careful to transfrom op_or to op_and1, not op_and.
312 * I will need this later in the code that removes
313 * duplicate conditions.
315 struct condition
* cond
;
317 for ( cond
= cond_stack
[depth
-1];
324 case op_and
: cond
->op
= op_or
; break;
325 case op_or
: cond
->op
= op_and1
; break;
326 case op_neq
: cond
->op
= op_eq
; break;
327 case op_eq
: cond
->op
= op_neq
; break;
338 case token_choice_item
:
340 case token_define_bool
:
343 case token_mainmenu_option
:
346 cfg
->cond
= join_condition_stack( cond_stack
, depth
);
349 case token_dep_tristate
:
351 * Same as the other simple statements, plus an additional
352 * condition for the dependency.
354 cond_stack
[depth
] = cfg
->cond
;
355 cfg
->cond
= join_condition_stack( cond_stack
, depth
+1 );