[PATCH] kconfig: use gperf for kconfig keywords
[linux-2.6.git] / scripts / kconfig / 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 #include "zconf.hash.c"
18
19 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
20
21 #define PRINTD          0x0001
22 #define DEBUG_PARSE     0x0002
23
24 int cdebug = PRINTD;
25
26 extern int zconflex(void);
27 static void zconfprint(const char *err, ...);
28 static void zconferror(const char *err);
29 static bool zconf_endtoken(int token, int starttoken, int endtoken);
30
31 struct symbol *symbol_hash[257];
32
33 static 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
96 %%
97 input:    /* empty */
98         | input block
99 ;
100
101 block:    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
111 common_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
123 config_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
131 config_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
137 menuconfig_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
145 menuconfig_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
155 config_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
163 config_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
169 config_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
176 config_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
182 config_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
189 config_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
195 config_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
201 config_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
207 config_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
213 config_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
219 config_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
225 config_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
233 choice: 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
242 choice_entry: choice choice_option_list
243 {
244         menu_end_entry();
245         menu_add_menu();
246 };
247
248 choice_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
256 choice_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
264 choice_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
272 choice_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
278 choice_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
284 choice_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
290 choice_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
296 choice_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
302 choice_block:
303           /* empty */
304         | choice_block common_block
305 ;
306
307 /* if entry */
308
309 if: 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
318 if_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
326 if_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
334 if_block:
335           /* empty */
336         | if_block common_block
337         | if_block menu_stmt
338         | if_block choice_stmt
339 ;
340
341 /* menu entry */
342
343 menu: T_MENU prompt T_EOL
344 {
345         menu_add_entry(NULL);
346         menu_add_prompt(P_MENU, $2, NULL);
347         printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
348 };
349
350 menu_entry: menu depends_list
351 {
352         menu_end_entry();
353         menu_add_menu();
354 };
355
356 menu_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
364 menu_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
372 menu_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
380 source: T_SOURCE prompt T_EOL
381 {
382         $$ = $2;
383         printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
384 };
385
386 source_stmt: source
387 {
388         zconf_nextfile($1);
389 };
390
391 /* comment entry */
392
393 comment: T_COMMENT prompt T_EOL
394 {
395         menu_add_entry(NULL);
396         menu_add_prompt(P_COMMENT, $2, NULL);
397         printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
398 };
399
400 comment_stmt: comment depends_list
401 {
402         menu_end_entry();
403 };
404
405 /* help option */
406
407 help_start: T_HELP T_EOL
408 {
409         printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
410         zconf_starthelp();
411 };
412
413 help: help_start T_HELPTEXT
414 {
415         current_entry->sym->help = $2;
416 };
417
418 /* depends option */
419
420 depends_list:     /* empty */
421                 | depends_list depends
422                 | depends_list T_EOL
423 ;
424
425 depends: 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
443 prompt_stmt_opt:
444           /* empty */
445         | prompt if_expr
446 {
447         menu_add_prompt(P_PROMPT, $1, $2);
448 };
449
450 prompt:   T_WORD
451         | T_WORD_QUOTE
452 ;
453
454 end:      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
459 nl_or_eof:
460         T_EOL | T_EOF;
461
462 if_expr:  /* empty */                   { $$ = NULL; }
463         | T_IF expr                     { $$ = $2; }
464 ;
465
466 expr:     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
475 symbol:   T_WORD        { $$ = sym_lookup($1, 0); free($1); }
476         | T_WORD_QUOTE  { $$ = sym_lookup($1, 1); free($1); }
477 ;
478
479 %%
480
481 void 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);
491         rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
492
493         //zconfdebug = 1;
494         zconfparse();
495         if (zconfnerrs)
496                 exit(1);
497         menu_finalize(&rootmenu);
498         for_all_symbols(i, sym) {
499                 sym_check_deps(sym);
500         }
501
502         sym_change_count = 1;
503 }
504
505 const 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
518 static 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
534 static 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
545 static void zconferror(const char *err)
546 {
547         fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
548 }
549
550 void 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
567 void 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
635 void 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"