carl9170 firmware: import 1.7.0
[carl9170fw.git] / config / zconf.y
1 %{
2 /*
3  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
4  * Released under the terms of the GNU GPL v2.0.
5  */
6
7 #include <ctype.h>
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdbool.h>
13
14 #define LKC_DIRECT_LINK
15 #include "lkc.h"
16
17 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
18
19 #define PRINTD          0x0001
20 #define DEBUG_PARSE     0x0002
21
22 int cdebug = PRINTD;
23
24 extern int zconflex(void);
25 static void zconfprint(const char *err, ...);
26 static void zconf_error(const char *err, ...);
27 static void zconferror(const char *err);
28 static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
29
30 struct symbol *symbol_hash[257];
31
32 static struct menu *current_menu, *current_entry;
33
34 #define YYDEBUG 0
35 #if YYDEBUG
36 #define YYERROR_VERBOSE
37 #endif
38 %}
39 %expect 26
40
41 %union
42 {
43         char *string;
44         struct file *file;
45         struct symbol *symbol;
46         struct expr *expr;
47         struct menu *menu;
48         struct kconf_id *id;
49 }
50
51 %token <id>T_MAINMENU
52 %token <id>T_MENU
53 %token <id>T_ENDMENU
54 %token <id>T_SOURCE
55 %token <id>T_CHOICE
56 %token <id>T_ENDCHOICE
57 %token <id>T_COMMENT
58 %token <id>T_CONFIG
59 %token <id>T_MENUCONFIG
60 %token <id>T_HELP
61 %token <string> T_HELPTEXT
62 %token <id>T_IF
63 %token <id>T_ENDIF
64 %token <id>T_DEPENDS
65 %token <id>T_OPTIONAL
66 %token <id>T_PROMPT
67 %token <id>T_TYPE
68 %token <id>T_DEFAULT
69 %token <id>T_SELECT
70 %token <id>T_RANGE
71 %token <id>T_OPTION
72 %token <id>T_ON
73 %token <string> T_WORD
74 %token <string> T_WORD_QUOTE
75 %token T_UNEQUAL
76 %token T_CLOSE_PAREN
77 %token T_OPEN_PAREN
78 %token T_EOL
79
80 %left T_OR
81 %left T_AND
82 %left T_EQUAL T_UNEQUAL
83 %nonassoc T_NOT
84
85 %type <string> prompt
86 %type <symbol> symbol
87 %type <expr> expr
88 %type <expr> if_expr
89 %type <id> end
90 %type <id> option_name
91 %type <menu> if_entry menu_entry choice_entry
92 %type <string> symbol_option_arg word_opt
93
94 %destructor {
95         fprintf(stderr, "%s:%d: missing end statement for this entry\n",
96                 $$->file->name, $$->lineno);
97         if (current_menu == $$)
98                 menu_end_menu();
99 } if_entry menu_entry choice_entry
100
101 %{
102 /* Include zconf.hash.c here so it can see the token constants. */
103 #include "zconf.hash.c"
104 %}
105
106 %%
107 input: stmt_list;
108
109 stmt_list:
110           /* empty */
111         | stmt_list common_stmt
112         | stmt_list choice_stmt
113         | stmt_list menu_stmt
114         | stmt_list T_MAINMENU prompt nl
115         | stmt_list end                 { zconf_error("unexpected end statement"); }
116         | stmt_list T_WORD error T_EOL  { zconf_error("unknown statement \"%s\"", $2); }
117         | stmt_list option_name error T_EOL
118 {
119         zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
120 }
121         | stmt_list error T_EOL         { zconf_error("invalid statement"); }
122 ;
123
124 option_name:
125         T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT
126 ;
127
128 common_stmt:
129           T_EOL
130         | if_stmt
131         | comment_stmt
132         | config_stmt
133         | menuconfig_stmt
134         | source_stmt
135 ;
136
137 option_error:
138           T_WORD error T_EOL            { zconf_error("unknown option \"%s\"", $1); }
139         | error T_EOL                   { zconf_error("invalid option"); }
140 ;
141
142
143 /* config/menuconfig entry */
144
145 config_entry_start: T_CONFIG T_WORD T_EOL
146 {
147         struct symbol *sym = sym_lookup($2, 0);
148         sym->flags |= SYMBOL_OPTIONAL;
149         menu_add_entry(sym);
150         printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
151 };
152
153 config_stmt: config_entry_start config_option_list
154 {
155         menu_end_entry();
156         printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
157 };
158
159 menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
160 {
161         struct symbol *sym = sym_lookup($2, 0);
162         sym->flags |= SYMBOL_OPTIONAL;
163         menu_add_entry(sym);
164         printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
165 };
166
167 menuconfig_stmt: menuconfig_entry_start config_option_list
168 {
169         if (current_entry->prompt)
170                 current_entry->prompt->type = P_MENU;
171         else
172                 zconfprint("warning: menuconfig statement without prompt");
173         menu_end_entry();
174         printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
175 };
176
177 config_option_list:
178           /* empty */
179         | config_option_list config_option
180         | config_option_list symbol_option
181         | config_option_list depends
182         | config_option_list help
183         | config_option_list option_error
184         | config_option_list T_EOL
185 ;
186
187 config_option: T_TYPE prompt_stmt_opt T_EOL
188 {
189         menu_set_type($1->stype);
190         printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
191                 zconf_curname(), zconf_lineno(),
192                 $1->stype);
193 };
194
195 config_option: T_PROMPT prompt if_expr T_EOL
196 {
197         menu_add_prompt(P_PROMPT, $2, $3);
198         printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
199 };
200
201 config_option: T_DEFAULT expr if_expr T_EOL
202 {
203         menu_add_expr(P_DEFAULT, $2, $3);
204         if ($1->stype != S_UNKNOWN)
205                 menu_set_type($1->stype);
206         printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
207                 zconf_curname(), zconf_lineno(),
208                 $1->stype);
209 };
210
211 config_option: T_SELECT T_WORD if_expr T_EOL
212 {
213         menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
214         printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
215 };
216
217 config_option: T_RANGE symbol symbol if_expr T_EOL
218 {
219         menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
220         printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
221 };
222
223 symbol_option: T_OPTION symbol_option_list T_EOL
224 ;
225
226 symbol_option_list:
227           /* empty */
228         | symbol_option_list T_WORD symbol_option_arg
229 {
230         struct kconf_id *id = kconf_id_lookup($2, strlen($2));
231         if (id && id->flags & TF_OPTION)
232                 menu_add_option(id->token, $3);
233         else
234                 zconfprint("warning: ignoring unknown option %s", $2);
235         free($2);
236 };
237
238 symbol_option_arg:
239           /* empty */           { $$ = NULL; }
240         | T_EQUAL prompt        { $$ = $2; }
241 ;
242
243 /* choice entry */
244
245 choice: T_CHOICE word_opt T_EOL
246 {
247         struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
248         sym->flags |= SYMBOL_AUTO;
249         menu_add_entry(sym);
250         menu_add_expr(P_CHOICE, NULL, NULL);
251         printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
252 };
253
254 choice_entry: choice choice_option_list
255 {
256         $$ = menu_add_menu();
257 };
258
259 choice_end: end
260 {
261         if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
262                 menu_end_menu();
263                 printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
264         }
265 };
266
267 choice_stmt: choice_entry choice_block choice_end
268 ;
269
270 choice_option_list:
271           /* empty */
272         | choice_option_list choice_option
273         | choice_option_list depends
274         | choice_option_list help
275         | choice_option_list T_EOL
276         | choice_option_list option_error
277 ;
278
279 choice_option: T_PROMPT prompt if_expr T_EOL
280 {
281         menu_add_prompt(P_PROMPT, $2, $3);
282         printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
283 };
284
285 choice_option: T_TYPE prompt_stmt_opt T_EOL
286 {
287         if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
288                 menu_set_type($1->stype);
289                 printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
290                         zconf_curname(), zconf_lineno(),
291                         $1->stype);
292         } else
293                 YYERROR;
294 };
295
296 choice_option: T_OPTIONAL T_EOL
297 {
298         current_entry->sym->flags |= SYMBOL_OPTIONAL;
299         printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
300 };
301
302 choice_option: T_DEFAULT T_WORD if_expr T_EOL
303 {
304         if ($1->stype == S_UNKNOWN) {
305                 menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
306                 printd(DEBUG_PARSE, "%s:%d:default\n",
307                         zconf_curname(), zconf_lineno());
308         } else
309                 YYERROR;
310 };
311
312 choice_block:
313           /* empty */
314         | choice_block common_stmt
315 ;
316
317 /* if entry */
318
319 if_entry: T_IF expr nl
320 {
321         printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
322         menu_add_entry(NULL);
323         menu_add_dep($2);
324         $$ = menu_add_menu();
325 };
326
327 if_end: end
328 {
329         if (zconf_endtoken($1, T_IF, T_ENDIF)) {
330                 menu_end_menu();
331                 printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
332         }
333 };
334
335 if_stmt: if_entry if_block if_end
336 ;
337
338 if_block:
339           /* empty */
340         | if_block common_stmt
341         | if_block menu_stmt
342         | if_block choice_stmt
343 ;
344
345 /* menu entry */
346
347 menu: T_MENU prompt T_EOL
348 {
349         menu_add_entry(NULL);
350         menu_add_prompt(P_MENU, $2, NULL);
351         printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
352 };
353
354 menu_entry: menu depends_list
355 {
356         $$ = menu_add_menu();
357 };
358
359 menu_end: end
360 {
361         if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
362                 menu_end_menu();
363                 printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
364         }
365 };
366
367 menu_stmt: menu_entry menu_block menu_end
368 ;
369
370 menu_block:
371           /* empty */
372         | menu_block common_stmt
373         | menu_block menu_stmt
374         | menu_block choice_stmt
375 ;
376
377 source_stmt: T_SOURCE prompt T_EOL
378 {
379         printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
380         zconf_nextfile($2);
381 };
382
383 /* comment entry */
384
385 comment: T_COMMENT prompt T_EOL
386 {
387         menu_add_entry(NULL);
388         menu_add_prompt(P_COMMENT, $2, NULL);
389         printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
390 };
391
392 comment_stmt: comment depends_list
393 {
394         menu_end_entry();
395 };
396
397 /* help option */
398
399 help_start: T_HELP T_EOL
400 {
401         printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
402         zconf_starthelp();
403 };
404
405 help: help_start T_HELPTEXT
406 {
407         current_entry->help = $2;
408 };
409
410 /* depends option */
411
412 depends_list:
413           /* empty */
414         | depends_list depends
415         | depends_list T_EOL
416         | depends_list option_error
417 ;
418
419 depends: T_DEPENDS T_ON expr T_EOL
420 {
421         menu_add_dep($3);
422         printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
423 };
424
425 /* prompt statement */
426
427 prompt_stmt_opt:
428           /* empty */
429         | prompt if_expr
430 {
431         menu_add_prompt(P_PROMPT, $1, $2);
432 };
433
434 prompt:   T_WORD
435         | T_WORD_QUOTE
436 ;
437
438 end:      T_ENDMENU T_EOL       { $$ = $1; }
439         | T_ENDCHOICE T_EOL     { $$ = $1; }
440         | T_ENDIF T_EOL         { $$ = $1; }
441 ;
442
443 nl:
444           T_EOL
445         | nl T_EOL
446 ;
447
448 if_expr:  /* empty */                   { $$ = NULL; }
449         | T_IF expr                     { $$ = $2; }
450 ;
451
452 expr:     symbol                                { $$ = expr_alloc_symbol($1); }
453         | symbol T_EQUAL symbol                 { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
454         | symbol T_UNEQUAL symbol               { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
455         | T_OPEN_PAREN expr T_CLOSE_PAREN       { $$ = $2; }
456         | T_NOT expr                            { $$ = expr_alloc_one(E_NOT, $2); }
457         | expr T_OR expr                        { $$ = expr_alloc_two(E_OR, $1, $3); }
458         | expr T_AND expr                       { $$ = expr_alloc_two(E_AND, $1, $3); }
459 ;
460
461 symbol:   T_WORD        { $$ = sym_lookup($1, 0); free($1); }
462         | T_WORD_QUOTE  { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
463 ;
464
465 word_opt: /* empty */                   { $$ = NULL; }
466         | T_WORD
467
468 %%
469
470 void conf_parse(const char *name)
471 {
472         struct symbol *sym;
473         int i;
474
475         zconf_initscan(name);
476
477         sym_init();
478         menu_init();
479         modules_sym = sym_lookup(NULL, 0);
480         modules_sym->type = S_BOOLEAN;
481         modules_sym->flags |= SYMBOL_AUTO;
482         rootmenu.prompt = menu_add_prompt(P_MENU, "CARL9170 Firmware Configuration", NULL);
483
484 #if YYDEBUG
485         if (getenv("ZCONF_DEBUG"))
486                 zconfdebug = 1;
487 #endif
488         zconfparse();
489         if (zconfnerrs)
490                 exit(1);
491         if (!modules_sym->prop) {
492                 struct property *prop;
493
494                 prop = prop_alloc(P_DEFAULT, modules_sym);
495                 prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
496         }
497         menu_finalize(&rootmenu);
498         for_all_symbols(i, sym) {
499                 if (sym_check_deps(sym))
500                         zconfnerrs++;
501         }
502         if (zconfnerrs)
503                 exit(1);
504         sym_set_change_count(1);
505 }
506
507 static const char *zconf_tokenname(int token)
508 {
509         switch (token) {
510         case T_MENU:            return "menu";
511         case T_ENDMENU:         return "endmenu";
512         case T_CHOICE:          return "choice";
513         case T_ENDCHOICE:       return "endchoice";
514         case T_IF:              return "if";
515         case T_ENDIF:           return "endif";
516         case T_DEPENDS:         return "depends";
517         }
518         return "<token>";
519 }
520
521 static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
522 {
523         if (id->token != endtoken) {
524                 zconf_error("unexpected '%s' within %s block",
525                         kconf_id_strings + id->name, zconf_tokenname(starttoken));
526                 zconfnerrs++;
527                 return false;
528         }
529         if (current_menu->file != current_file) {
530                 zconf_error("'%s' in different file than '%s'",
531                         kconf_id_strings + id->name, zconf_tokenname(starttoken));
532                 fprintf(stderr, "%s:%d: location of the '%s'\n",
533                         current_menu->file->name, current_menu->lineno,
534                         zconf_tokenname(starttoken));
535                 zconfnerrs++;
536                 return false;
537         }
538         return true;
539 }
540
541 static void zconfprint(const char *err, ...)
542 {
543         va_list ap;
544
545         fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
546         va_start(ap, err);
547         vfprintf(stderr, err, ap);
548         va_end(ap);
549         fprintf(stderr, "\n");
550 }
551
552 static void zconf_error(const char *err, ...)
553 {
554         va_list ap;
555
556         zconfnerrs++;
557         fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
558         va_start(ap, err);
559         vfprintf(stderr, err, ap);
560         va_end(ap);
561         fprintf(stderr, "\n");
562 }
563
564 static void zconferror(const char *err)
565 {
566 #if YYDEBUG
567         fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
568 #endif
569 }
570
571 static void print_quoted_string(FILE *out, const char *str)
572 {
573         const char *p;
574         int len;
575
576         putc('"', out);
577         while ((p = strchr(str, '"'))) {
578                 len = p - str;
579                 if (len)
580                         fprintf(out, "%.*s", len, str);
581                 fputs("\\\"", out);
582                 str = p + 1;
583         }
584         fputs(str, out);
585         putc('"', out);
586 }
587
588 static void print_symbol(FILE *out, struct menu *menu)
589 {
590         struct symbol *sym = menu->sym;
591         struct property *prop;
592
593         if (sym_is_choice(sym))
594                 fprintf(out, "choice\n");
595         else
596                 fprintf(out, "config %s\n", sym->name);
597         switch (sym->type) {
598         case S_BOOLEAN:
599                 fputs("  boolean\n", out);
600                 break;
601         case S_TRISTATE:
602                 fputs("  tristate\n", out);
603                 break;
604         case S_STRING:
605                 fputs("  string\n", out);
606                 break;
607         case S_INT:
608                 fputs("  integer\n", out);
609                 break;
610         case S_HEX:
611                 fputs("  hex\n", out);
612                 break;
613         default:
614                 fputs("  ???\n", out);
615                 break;
616         }
617         for (prop = sym->prop; prop; prop = prop->next) {
618                 if (prop->menu != menu)
619                         continue;
620                 switch (prop->type) {
621                 case P_PROMPT:
622                         fputs("  prompt ", out);
623                         print_quoted_string(out, prop->text);
624                         if (!expr_is_yes(prop->visible.expr)) {
625                                 fputs(" if ", out);
626                                 expr_fprint(prop->visible.expr, out);
627                         }
628                         fputc('\n', out);
629                         break;
630                 case P_DEFAULT:
631                         fputs( "  default ", out);
632                         expr_fprint(prop->expr, out);
633                         if (!expr_is_yes(prop->visible.expr)) {
634                                 fputs(" if ", out);
635                                 expr_fprint(prop->visible.expr, out);
636                         }
637                         fputc('\n', out);
638                         break;
639                 case P_CHOICE:
640                         fputs("  #choice value\n", out);
641                         break;
642                 default:
643                         fprintf(out, "  unknown prop %d!\n", prop->type);
644                         break;
645                 }
646         }
647         if (menu->help) {
648                 int len = strlen(menu->help);
649                 while (menu->help[--len] == '\n')
650                         menu->help[len] = 0;
651                 fprintf(out, "  help\n%s\n", menu->help);
652         }
653         fputc('\n', out);
654 }
655
656 void zconfdump(FILE *out)
657 {
658         struct property *prop;
659         struct symbol *sym;
660         struct menu *menu;
661
662         menu = rootmenu.list;
663         while (menu) {
664                 if ((sym = menu->sym))
665                         print_symbol(out, menu);
666                 else if ((prop = menu->prompt)) {
667                         switch (prop->type) {
668                         case P_COMMENT:
669                                 fputs("\ncomment ", out);
670                                 print_quoted_string(out, prop->text);
671                                 fputs("\n", out);
672                                 break;
673                         case P_MENU:
674                                 fputs("\nmenu ", out);
675                                 print_quoted_string(out, prop->text);
676                                 fputs("\n", out);
677                                 break;
678                         default:
679                                 ;
680                         }
681                         if (!expr_is_yes(prop->visible.expr)) {
682                                 fputs("  depends ", out);
683                                 expr_fprint(prop->visible.expr, out);
684                                 fputc('\n', out);
685                         }
686                         fputs("\n", out);
687                 }
688
689                 if (menu->list)
690                         menu = menu->list;
691                 else if (menu->next)
692                         menu = menu->next;
693                 else while ((menu = menu->parent)) {
694                         if (menu->prompt && menu->prompt->type == P_MENU)
695                                 fputs("\nendmenu\n", out);
696                         if (menu->next) {
697                                 menu = menu->next;
698                                 break;
699                         }
700                 }
701         }
702 }
703
704 #include "lex.zconf.c"
705 #include "util.c"
706 #include "confdata.c"
707 #include "expr.c"
708 #include "symbol.c"
709 #include "menu.c"