OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [scripts/] [tkcond.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1629 jcastillo
/* parser config.in
2
 *
3
 * Version 1.0
4
 * Eric Youngdale
5
 * 10/95
6
 *
7
 * The general idea here is that we want to parse a config.in file and
8
 * from this, we generate a wish script which gives us effectively the
9
 * same functionality that the original config.in script provided.
10
 *
11
 * This task is split roughly into 3 parts.  The first parse is the parse
12
 * of the input file itself.  The second part is where we analyze the
13
 * #ifdef clauses, and attach a linked list of tokens to each of the
14
 * menu items.  In this way, each menu item has a complete list of
15
 * dependencies that are used to enable/disable the options.
16
 * The third part is to take the configuration database we have build,
17
 * and build the actual wish script.
18
 *
19
 * This file contains the code to further process the conditions from
20
 * the "ifdef" clauses.
21
 *
22
 * The conditions are assumed to be one of the following formats
23
 *
24
 * simple_condition:= "$VARIABLE" == y/n/m
25
 * simple_condition:= "$VARIABLE != y/n/m
26
 *
27
 * simple_condition -a simple_condition
28
 *
29
 * If the input condition contains '(' or ')' it would screw us up, but for now
30
 * this is not a problem.
31
 */
32
#include <stdlib.h>
33
#include <stdio.h>
34
#include <string.h>
35
#include "tkparse.h"
36
 
37
 
38
/*
39
 * Walk a condition chain and invert it so that the logical result is
40
 * inverted.
41
 */
42
static void invert_condition(struct condition * cnd)
43
{
44
  /*
45
   * This is simple.  Just walk through the list, and invert
46
   * all of the operators.
47
   */
48
  for(;cnd; cnd = cnd->next)
49
    {
50
      switch(cnd->op)
51
        {
52
        case op_and:
53
          cnd->op = op_or;
54
          break;
55
        case op_or:
56
          /*
57
           * This is not turned into op_and - we need to keep track
58
           * of what operators were used here since we have an optimization
59
           * later on to remove duplicate conditions, and having
60
           * inverted ors in there would make it harder if we did not
61
           * distinguish an inverted or from an and we inserted because
62
           * of nested ifs.
63
           */
64
          cnd->op = op_and1;
65
          break;
66
        case op_neq:
67
          cnd->op = op_eq;
68
          break;
69
        case op_eq:
70
          cnd->op = op_neq;
71
          break;
72
        default:
73
          break;
74
        }
75
    }
76
}
77
 
78
/*
79
 * Walk a condition chain, and free the memory associated with it.
80
 */
81
static void free_condition(struct condition * cnd)
82
{
83
  struct condition * next;
84
  for(;cnd; cnd = next)
85
    {
86
      next = cnd->next;
87
 
88
      if( cnd->variable.str != NULL )
89
        free(cnd->variable.str);
90
 
91
      free(cnd);
92
    }
93
}
94
 
95
/*
96
 * Walk all of the conditions, and look for choice values.  Convert
97
 * the tokens into something more digestible.
98
 */
99
void fix_choice_cond()
100
{
101
  struct condition * cond;
102
  struct condition * cond2;
103
  struct kconfig * cfg;
104
  char tmpbuf[10];
105
 
106
  for(cfg = config;cfg != NULL; cfg = cfg->next)
107
    {
108
      if( cfg->cond == NULL )
109
        {
110
          continue;
111
        }
112
 
113
      for(cond = cfg->cond; cond != NULL; cond = cond->next)
114
        {
115
          if( cond->op != op_kvariable )
116
            continue;
117
 
118
          if( cond->variable.cfg->tok != tok_choice )
119
            continue;
120
 
121
          /*
122
           * Look ahead for what we are comparing this to.  There should
123
           * be one operator in between.
124
           */
125
          cond2 = cond->next->next;
126
          strcpy(tmpbuf, cond->variable.cfg->label);
127
 
128
          if( strcmp(cond2->variable.str, "y") == 0 )
129
            {
130
              cond->variable.cfg = cond->variable.cfg->choice_label;
131
              cond2->variable.str = strdup(tmpbuf);
132
            }
133
          else
134
            {
135
              fprintf(stderr,"Ooops\n");
136
              exit(0);
137
            }
138
        }
139
 
140
    }
141
}
142
 
143
/*
144
 * Walk the stack of conditions, and clone all of them with "&&" operators
145
 * gluing them together.  The conditions from each level of the stack
146
 * are wrapped in parenthesis so as to guarantee that the results
147
 * are logically correct.
148
 */
149
struct condition * get_token_cond(struct condition ** cond, int depth)
150
{
151
  int i;
152
  struct condition * newcond;
153
  struct condition * tail;
154
  struct condition * new;
155
  struct condition * ocond;
156
  struct kconfig * cfg;
157
 
158
  newcond = tail = NULL;
159
  for(i=0; i<depth; i++, cond++)
160
    {
161
      /*
162
       * First insert the left parenthesis
163
       */
164
      new = (struct condition *) malloc(sizeof(struct condition));
165
      memset(new, 0, sizeof(*new));
166
      new->op = op_lparen;
167
      if( tail == NULL )
168
        {
169
          newcond = tail = new;
170
        }
171
      else
172
        {
173
          tail->next = new;
174
          tail = new;
175
        }
176
 
177
      /*
178
       * Now duplicate the chain.
179
       */
180
      ocond = *cond;
181
      for(;ocond != NULL; ocond = ocond->next)
182
        {
183
          new = (struct condition *) malloc(sizeof(struct condition));
184
          memset(new, 0, sizeof(*new));
185
          new->op = ocond->op;
186
          if( ocond->variable.str != NULL )
187
            {
188
              if( ocond->op == op_variable )
189
                {
190
                  /*
191
                   * Search for structure to insert here.
192
                   */
193
                  for(cfg = config;cfg != NULL; cfg = cfg->next)
194
                    {
195
                      if( cfg->tok != tok_bool
196
                         && cfg->tok != tok_int
197
                         && cfg->tok != tok_hex
198
                         && cfg->tok != tok_tristate
199
                         && cfg->tok != tok_choice
200
                         && cfg->tok != tok_dep_tristate)
201
                        {
202
                          continue;
203
                        }
204
                      if( strcmp(cfg->optionname, ocond->variable.str) == 0)
205
                        {
206
                          new->variable.cfg = cfg;
207
                          new->op = op_kvariable;
208
                          break;
209
                        }
210
                    }
211
                  if( cfg == NULL )
212
                    {
213
                      new->variable.str = strdup(ocond->variable.str);
214
                    }
215
                }
216
              else
217
                {
218
                  new->variable.str = strdup(ocond->variable.str);
219
                }
220
            }
221
          tail->next = new;
222
          tail = new;
223
        }
224
 
225
      /*
226
       * Next insert the left parenthesis
227
       */
228
      new = (struct condition *) malloc(sizeof(struct condition));
229
      memset(new, 0, sizeof(*new));
230
      new->op = op_rparen;
231
      tail->next = new;
232
      tail = new;
233
 
234
      /*
235
       * Insert an and operator, if we have another condition.
236
       */
237
      if( i < depth - 1 )
238
        {
239
          new = (struct condition *) malloc(sizeof(struct condition));
240
          memset(new, 0, sizeof(*new));
241
          new->op = op_and;
242
          tail->next = new;
243
          tail = new;
244
        }
245
 
246
    }
247
 
248
  return newcond;
249
}
250
 
251
/*
252
 * Walk a single chain of conditions and clone it.  These are assumed
253
 * to be created/processed by  get_token_cond in a previous pass.
254
 */
255
struct condition * get_token_cond_frag(struct condition * cond,
256
                                       struct condition ** last)
257
{
258
  struct condition * newcond;
259
  struct condition * tail;
260
  struct condition * new;
261
  struct condition * ocond;
262
 
263
  newcond = tail = NULL;
264
 
265
  /*
266
   * Now duplicate the chain.
267
   */
268
  for(ocond = cond;ocond != NULL; ocond = ocond->next)
269
    {
270
      new = (struct condition *) malloc(sizeof(struct condition));
271
      memset(new, 0, sizeof(*new));
272
      new->op = ocond->op;
273
      new->variable.cfg = ocond->variable.cfg;
274
      if( tail == NULL )
275
        {
276
          newcond = tail = new;
277
        }
278
      else
279
        {
280
          tail->next = new;
281
          tail = new;
282
        }
283
    }
284
 
285
  new = (struct condition *) malloc(sizeof(struct condition));
286
  memset(new, 0, sizeof(*new));
287
  new->op = op_and;
288
  tail->next = new;
289
  tail = new;
290
 
291
  *last = tail;
292
  return newcond;
293
}
294
 
295
/*
296
 * Walk through the if conditionals and maintain a chain.
297
 */
298
void fix_conditionals(struct kconfig * scfg)
299
{
300
  int depth = 0;
301
  int i;
302
  struct kconfig * cfg;
303
  struct kconfig * cfg1;
304
  struct condition * conditions[25];
305
  struct condition * cnd;
306
  struct condition * cnd1;
307
  struct condition * cnd2;
308
  struct condition * cnd3;
309
  struct condition * newcond;
310
  struct condition * last;
311
 
312
  /*
313
   * Start by walking the chain.  Every time we see an ifdef, push
314
   * the condition chain on the stack.  When we see an "else", we invert
315
   * the condition at the top of the stack, and when we see an "endif"
316
   * we free all of the memory for the condition at the top of the stack
317
   * and remove the condition from the top of the stack.
318
   *
319
   * For any other type of token (i.e. a bool), we clone a new condition chain
320
   * by anding together all of the conditions that are currently stored on
321
   * the stack.  In this way, we have a correct representation of whatever
322
   * conditions govern the usage of each option.
323
   */
324
  memset(conditions, 0, sizeof(conditions));
325
  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
326
    {
327
      switch(cfg->tok)
328
        {
329
        case tok_if:
330
          /*
331
           * Push this condition on the stack, and nuke the token
332
           * representing the ifdef, since we no longer need it.
333
           */
334
          conditions[depth] = cfg->cond;
335
          depth++;
336
          cfg->tok = tok_nop;
337
          cfg->cond =  NULL;
338
          break;
339
        case tok_else:
340
          /*
341
           * For an else, we just invert the condition at the top of
342
           * the stack.  This is done in place with no reallocation
343
           * of memory taking place.
344
           */
345
          invert_condition(conditions[depth-1]);
346
          cfg->tok = tok_nop;
347
          break;
348
        case tok_fi:
349
          depth--;
350
          free_condition(conditions[depth]);
351
          conditions[depth] = NULL;
352
          cfg->tok = tok_nop;
353
          break;
354
        case tok_comment:
355
        case tok_define:
356
        case tok_menuoption:
357
        case tok_bool:
358
        case tok_tristate:
359
        case tok_int:
360
        case tok_hex:
361
        case tok_choice:
362
        case tok_make:
363
          /*
364
           * We need to duplicate the chain of conditions and attach them to
365
           * this token.
366
           */
367
          cfg->cond = get_token_cond(&conditions[0], depth);
368
          break;
369
        case tok_dep_tristate:
370
          /*
371
           * Same as tok_tristate et al except we have a temporary
372
           * conditional. (Sort of a hybrid tok_if, tok_tristate, tok_fi
373
           * option)
374
           */
375
          conditions[depth] = cfg->cond;
376
          depth++;
377
          cfg->cond = get_token_cond(&conditions[0], depth);
378
          depth--;
379
          free_condition(conditions[depth]);
380
          conditions[depth] = NULL;
381
        default:
382
          break;
383
        }
384
    }
385
 
386
  /*
387
   * Fix any conditions involving the "choice" operator.
388
   */
389
  fix_choice_cond();
390
 
391
  /*
392
   * Walk through and see if there are multiple options that control the
393
   * same kvariable.  If there are we need to treat them a little bit
394
   * special.
395
   */
396
  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
397
    {
398
      switch(cfg->tok)
399
        {
400
        case tok_bool:
401
        case tok_tristate:
402
        case tok_dep_tristate:
403
        case tok_int:
404
        case tok_hex:
405
          for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
406
            {
407
              switch(cfg1->tok)
408
                {
409
                case tok_define:
410
                case tok_bool:
411
                case tok_tristate:
412
                case tok_dep_tristate:
413
                case tok_int:
414
                case tok_hex:
415
                  if( strcmp(cfg->optionname, cfg1->optionname) == 0)
416
                    {
417
                      cfg->flags |= CFG_DUP;
418
                      cfg1->flags |= CFG_DUP;
419
                    }
420
                  break;
421
                default:
422
                  break;
423
                }
424
            }
425
          break;
426
        default:
427
          break;
428
        }
429
    }
430
 
431
  /*
432
   * Now go through the list, and every time we see a kvariable, check
433
   * to see whether it also has some dependencies.  If so, then
434
   * append it to our list.  The reason we do this is that we might have
435
   * option CONFIG_FOO which is only used if CONFIG_BAR is set.  It may
436
   * turn out that in config.in that the default value for CONFIG_BAR is
437
   * set to "y", but that CONFIG_BAR is not enabled because CONFIG_XYZZY
438
   * is not set.  The current condition chain does not reflect this, but
439
   * we can fix this by searching for the tokens that this option depends
440
   * upon and cloning the conditions and merging them with the list.
441
   */
442
  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
443
    {
444
      /*
445
       * Search for a token that has a condition list.
446
       */
447
      if(cfg->cond == NULL) continue;
448
      for(cnd = cfg->cond; cnd; cnd=cnd->next)
449
        {
450
          /*
451
           * Now search the condition list for a known configuration variable
452
           * that has conditions of its own.
453
           */
454
          if(cnd->op != op_kvariable) continue;
455
          if(cnd->variable.cfg->cond == NULL) continue;
456
 
457
          if(cnd->variable.cfg->flags & CFG_DUP) continue;
458
          /*
459
           * OK, we have some conditions to append to cfg.  Make  a clone
460
           * of the conditions,
461
           */
462
          newcond = get_token_cond_frag(cnd->variable.cfg->cond, &last);
463
 
464
          /*
465
           * Finally, we splice it into our list.
466
           */
467
          last->next = cfg->cond;
468
          cfg->cond = newcond;
469
 
470
        }
471
    }
472
 
473
  /*
474
   * There is a strong possibility that we have duplicate conditions
475
   * in here.  It would make the script more efficient and readable to
476
   * remove these.  Here is where we assume here that there are no
477
   * parenthesis in the input script.
478
   */
479
  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
480
    {
481
      /*
482
       * Search for configuration options that have conditions.
483
       */
484
      if(cfg->cond == NULL) continue;
485
      for(cnd = cfg->cond; cnd; cnd=cnd->next)
486
        {
487
          /*
488
           * Search for a left parenthesis.
489
           */
490
          if(cnd->op != op_lparen) continue;
491
          for(cnd1 = cnd->next; cnd1; cnd1=cnd1->next)
492
            {
493
              /*
494
               * Search after the previous left parenthesis, and try
495
               * and find a second left parenthesis.
496
               */
497
              if(cnd1->op != op_lparen) continue;
498
 
499
              /*
500
               * Now compare the next 5 tokens to see if they are
501
               * identical.  We are looking for two chains that
502
               * are like: '(' $VARIABLE operator constant ')'.
503
               */
504
              cnd2 = cnd;
505
              cnd3 = cnd1;
506
              for(i=0; i<5; i++, cnd2=cnd2->next, cnd3=cnd3->next)
507
                {
508
                  if(!cnd2 || !cnd3) break;
509
                  if(cnd2->op != cnd3->op) break;
510
                  if(i == 1 && (cnd2->op != op_kvariable
511
                     || cnd2->variable.cfg != cnd3->variable.cfg) ) break;
512
                  if(i==2 && cnd2->op != op_eq && cnd2->op != op_neq) break;
513
                  if(i == 3 && cnd2->op != op_constant &&
514
                     strcmp(cnd2->variable.str, cnd3->variable.str) != 0)
515
                    break;
516
                  if(i==4 && cnd2->op != op_rparen) break;
517
                }
518
              /*
519
               * If these match, and there is an and gluing these together,
520
               * then we can nuke the second one.
521
               */
522
              if(i==5 && ((cnd3 && cnd3->op == op_and)
523
                          ||(cnd2 && cnd2->op == op_and)))
524
                {
525
                  /*
526
                   * We have a duplicate.  Nuke 5 ops.
527
                   */
528
                  cnd3 = cnd1;
529
                  for(i=0; i<5; i++, cnd3=cnd3->next)
530
                    {
531
                      cnd3->op = op_nuked;
532
                    }
533
                  /*
534
                   * Nuke the and that glues the conditions together.
535
                   */
536
                  if(cnd3 && cnd3->op == op_and) cnd3->op = op_nuked;
537
                  else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
538
                }
539
            }
540
        }
541
    }
542
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.