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