added a lot of printk output to ease writing of emulator
[linux-2.4.21-pre4.git] / scripts / tkcond.c
1 /*
2  * tkcond.c
3  *
4  * Eric Youngdale was the original author of xconfig.
5  * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
6  *
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.
11  *
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.
16  *
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
20  *   implemented.
21  * - negation (!) eliminated from conditions
22  *
23  * TO DO:
24  * - xconfig is at the end of its life cycle.  Contact <mec@shout.net> if
25  *   you are interested in working on the replacement.
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "tkparse.h"
33
34
35
36 /*
37  * Mark variables which are defined anywhere.
38  */
39 static void mark_variables( struct kconfig * scfg )
40 {
41     struct kconfig * cfg;
42     int i;
43
44     for ( i = 1; i <= max_varnum; i++ )
45         vartable[i].defined = 0;
46     for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
47     {
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 )
63         {
64             if ( cfg->nameindex > 0 )   /* paranoid */
65             {
66                 vartable[cfg->nameindex].defined = 1;
67             }
68         }
69     }
70 }
71
72
73
74 static void free_cond( struct condition *cond )
75 {
76     struct condition *tmp, *tmp1;
77     for ( tmp = cond; tmp; tmp = tmp1 )
78     {
79         tmp1 = tmp->next;
80         free( (void*)tmp );
81     }
82 }
83
84
85
86 /*
87  * Remove the bang operator from a condition to avoid priority problems.
88  * "!" has different priorities as "test" command argument and in 
89  * a tk script.
90  */
91 static struct condition * remove_bang( struct condition * condition )
92 {
93     struct condition * conda, * condb, * prev = NULL;
94
95     for ( conda = condition; conda; conda = conda->next )
96     {
97         if ( conda->op == op_bang && conda->next &&
98            ( condb = conda->next->next ) )
99         {
100             if ( condb->op == op_eq || condb->op == op_neq )
101             {
102                 condb->op = (condb->op == op_eq) ? op_neq : op_eq;
103                 conda->op = op_nuked;
104                 if ( prev )
105                 {
106                     prev->next = conda->next;
107                 }
108                 else
109                 {
110                     condition = conda->next;
111                 }
112                 conda->next = NULL;
113                 free_cond( conda );
114                 conda = condb;
115             }
116         }
117         prev = conda;
118     }
119     return condition;
120 }
121
122
123
124 /*
125  * Make a new condition chain by joining the current condition stack with
126  * the "&&" operator for glue.
127  */
128 static struct condition * join_condition_stack( struct condition * conditions [],
129     int depth )
130 {
131     struct condition * cond_list;
132     struct condition * cond_last;
133     int i, is_first = 1;
134
135     cond_list = cond_last = NULL;
136
137     for ( i = 0; i < depth; i++ )
138     {
139         if ( conditions[i]->op == op_false )
140         {
141             struct condition * cnew;
142
143             /* It is always false condition */
144             cnew = malloc( sizeof(*cnew) );
145             memset( cnew, 0, sizeof(*cnew) );
146             cnew->op = op_false;
147             cond_list = cond_last = cnew;
148             goto join_done;
149         }
150     }
151     for ( i = 0; i < depth; i++ )
152     {
153         struct condition * cond;
154         struct condition * cnew;
155         int add_paren;
156
157         /* omit always true conditions */
158         if ( conditions[i]->op == op_true )
159             continue;
160
161         /* if i have another condition, add an '&&' operator */
162         if ( !is_first )
163         {
164             cnew = malloc( sizeof(*cnew) );
165             memset( cnew, 0, sizeof(*cnew) );
166             cnew->op = op_and;
167             cond_last->next = cnew;
168             cond_last = cnew;
169         }
170
171         if ( conditions[i]->op != op_lparen )
172         {
173             /* add a '(' */
174             add_paren = 1;
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; }
180             else
181                 { cond_last->next = cnew; cond_last = cnew; }
182         }
183         else
184         {
185             add_paren = 0;
186         }
187
188         /* duplicate the chain */
189         for ( cond = conditions [i]; cond != NULL; cond = cond->next )
190         {
191             cnew            = malloc( sizeof(*cnew) );
192             cnew->next      = NULL;
193             cnew->op        = cond->op;
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; }
198             else
199                 { cond_last->next = cnew; cond_last = cnew; }
200         }
201
202         if ( add_paren )
203         {
204             /* add a ')' */
205             cnew = malloc( sizeof(*cnew) );
206             memset( cnew, 0, sizeof(*cnew) );
207             cnew->op = op_rparen;
208             cond_last->next = cnew;
209             cond_last = cnew;
210         }
211         is_first = 0;
212     }
213
214     /*
215      * Remove duplicate conditions.
216      */
217     {
218         struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f;
219
220         for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next )
221         {
222             if ( cond1->op == op_lparen )
223             {
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;
229
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 )
234                 {
235                     struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f;
236
237                     for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next )
238                     {
239                         if ( cond2->op == op_lparen )
240                         {
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;
246
247                             /* look for match */
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 )
254                             {
255                                 /* one of these must be followed by && */
256                                 if ( cond1f->op == op_and
257                                 || ( cond2f != NULL && cond2f->op == op_and ) )
258                                 {
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;
267                                     else
268                                         cond2f->op = op_nuked;
269                                 }
270                             }
271                         }
272                     }
273                 }
274             }
275         }
276     }
277
278 join_done:
279     return cond_list;
280 }
281
282
283
284 static char * current_arch = NULL;
285
286 /*
287  * Eliminating conditions with ARCH = <not current>.
288  */
289 static struct condition *eliminate_other_arch( struct condition *list )
290 {
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 )
295     {
296         fprintf( stderr, "error: ARCH undefined\n" );
297         exit( 1 );
298     }
299     if ( cond1a->op == op_variable
300     && ! strcmp( vartable[cond1a->nameindex].name, "ARCH" ) )
301     {
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 )
306         {
307             if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
308             ||   (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
309             {
310                 /* This is for another architecture */ 
311                 cond1a->op = op_false;
312                 cond1a->next = NULL;
313                 free_cond( cond1b );
314                 return cond1a;
315             }
316             else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
317                  ||   (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
318             {
319                 /* This is for current architecture */
320                 cond1a->op = op_true;
321                 cond1a->next = NULL;
322                 free_cond( cond1b );
323                 return cond1a;
324             }
325         }
326         else if ( cond1c->op == op_constant && cond1d->op == op_or )
327         {
328             if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
329             ||   (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
330             {
331                 /* This is for another architecture */ 
332                 cond1b = cond1d->next;
333                 cond1d->next = NULL;
334                 free_cond( cond1a );
335                 return eliminate_other_arch( cond1b );
336             }
337             else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
338                  || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
339             {
340                 /* This is for current architecture */
341                 cond1a->op = op_true;
342                 cond1a->next = NULL;
343                 free_cond( cond1b );
344                 return cond1a;
345             }
346         }
347         else if ( cond1c->op == op_constant && cond1d->op == op_and )
348         {
349             if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
350             ||   (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
351             {
352                 /* This is for another architecture */
353                 int l_par = 0;
354                 
355                 for ( cond1c = cond1d->next; cond1c; cond1c = cond1c->next )
356                 {
357                     if ( cond1c->op == op_lparen )
358                         l_par++;
359                     else if ( cond1c->op == op_rparen )
360                         l_par--;
361                     else if ( cond1c->op == op_or && l_par == 0 )
362                     /* Expression too complex - don't touch */
363                         return cond1a;
364                     else if ( l_par < 0 )
365                     {
366                         fprintf( stderr, "incorrect condition: programming error ?\n" );
367                         exit( 1 );
368                     }
369                 }
370                 cond1a->op = op_false;
371                 cond1a->next = NULL;
372                 free_cond( cond1b );
373                 return cond1a;
374             }
375             else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
376                  || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
377             {
378                 /* This is for current architecture */
379                 cond1b = cond1d->next;
380                 cond1d->next = NULL;
381                 free_cond( cond1a );
382                 return eliminate_other_arch( cond1b );
383             }
384         }
385     }
386     if ( cond1a->op == op_variable && ! vartable[cond1a->nameindex].defined )
387     {
388         cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
389         cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
390         cond1d = cond1c->next;
391
392         if ( cond1c->op == op_constant
393         && ( cond1d == NULL || cond1d->op == op_and ) ) /*???*/
394         {
395             if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
396             {
397                 cond1a->op = op_false;
398                 cond1a->next = NULL;
399                 free_cond( cond1b );
400                 return cond1a;
401             }
402         }
403         else if ( cond1c->op == op_constant && cond1d->op == op_or )
404         {
405             if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
406             {
407                 cond1b = cond1d->next;
408                 cond1d->next = NULL;
409                 free_cond( cond1a );
410                 return eliminate_other_arch( cond1b );
411             }
412         }
413     }
414 done:
415     return list;
416 }
417
418
419
420 /*
421  * This is the main transformation function.
422  */
423 void fix_conditionals( struct kconfig * scfg )
424 {
425     struct kconfig * cfg;
426
427     /*
428      * Transform op_variable to op_kvariable.
429      */
430     mark_variables( scfg );
431
432     /*
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.
437      *
438      * For a simple statement, create a condition chain by joining together
439      * all of the conditions on the stack.
440      */
441     {
442         struct condition * cond_stack [32];
443         int depth = 0;
444         struct kconfig * prev = NULL;
445
446         for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
447         {
448             int good = 1;
449             switch ( cfg->token )
450             {
451             default:
452                 break;
453
454             case token_if:
455                 cond_stack [depth++] =
456                     remove_bang( eliminate_other_arch( cfg->cond ) );
457                 cfg->cond = NULL;
458                 break;
459
460             case token_else:
461                 {
462                     /*
463                      * Invert the condition chain.
464                      *
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.
468                      */
469                     struct condition * cond;
470
471                     for ( cond  = cond_stack [depth-1];
472                           cond != NULL;
473                           cond  = cond->next )
474                     {
475                         switch( cond->op )
476                         {
477                         default:     break;
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;
484                         }
485                     }
486                 }
487                 break;
488
489             case token_fi:
490                 --depth;
491                 break;
492
493             case token_bool:
494             case token_choice_item:
495             case token_choice_header:
496             case token_comment:
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:
502             case token_endmenu:
503             case token_hex:
504             case token_int:
505             case token_mainmenu_option:
506             case token_string:
507             case token_tristate:
508             case token_unset:
509                 cfg->cond = join_condition_stack( cond_stack, depth );
510                 if ( cfg->cond && cfg->cond->op == op_false )
511                 {
512                     good = 0;
513                     if ( prev )
514                         prev->next = cfg->next;
515                     else
516                         scfg = cfg->next;
517                 }
518                 break;
519
520             case token_dep_bool:
521             case token_dep_mbool:
522             case token_dep_tristate:
523                 /*
524                  * Same as the other simple statements, plus an additional
525                  * condition for the dependency.
526                  */
527                 if ( cfg->cond )
528                 {
529                     cond_stack [depth] = eliminate_other_arch( cfg->cond );
530                     cfg->cond = join_condition_stack( cond_stack, depth+1 );
531                 }
532                 else
533                 {
534                     cfg->cond = join_condition_stack( cond_stack, depth );
535                 }
536                 if ( cfg->cond && cfg->cond->op == op_false )
537                 {
538                     good = 0;
539                     if ( prev )
540                         prev->next = cfg->next;
541                     else
542                         scfg = cfg->next;
543                 }
544                 break;
545             }
546             if ( good )
547                 prev = cfg;
548         }
549     }
550 }
551
552
553
554 #if 0
555 void dump_condition( struct condition *list )
556 {
557     struct condition *tmp;
558     for ( tmp = list; tmp; tmp = tmp->next )
559     {
560         switch (tmp->op)
561         {
562         default:
563             break;
564         case op_variable:
565             printf( " %s", vartable[tmp->nameindex].name );
566             break;
567         case op_constant: 
568             printf( " %s", tmp->str );
569             break;
570         case op_eq:
571             printf( " =" );
572             break;
573         case op_bang:
574             printf( " !" );
575             break;
576         case op_neq:
577             printf( " !=" );
578             break;
579         case op_and:
580         case op_and1:
581             printf( " -a" );
582             break;
583         case op_or:
584             printf( " -o" );
585             break;
586         case op_true:
587             printf( " TRUE" );
588             break;
589         case op_false:
590             printf( " FALSE" );
591             break;
592         case op_lparen:
593             printf( " (" );
594             break;
595         case op_rparen:
596             printf( " )" );
597             break;
598         }
599     }
600     printf( "\n" );
601 }
602 #endif