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