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