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