1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
17 #include "preprocess.h"
19 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
22 #define DEBUG_PARSE 0x0002
26 static void yyerror(const char *err
);
27 static void zconf_error
(const char *err
, ...
);
28 static bool zconf_endtoken
(const char *tokenname
,
29 const char *expected_tokenname
);
31 struct menu
*current_menu
, *current_entry
, *current_choice
;
38 struct symbol
*symbol
;
41 enum symbol_type type
;
42 enum variable_flavor flavor
;
45 %token
<string> T_HELPTEXT
46 %token
<string> T_WORD
47 %token
<string> T_WORD_QUOTE
81 %token
<string> T_ASSIGN_VAL
85 %left T_EQUAL T_UNEQUAL
86 %left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL
89 %type
<symbol
> nonconst_symbol
91 %type
<type
> type default
95 %type
<menu
> if_entry menu_entry choice_entry
96 %type
<string> assign_val
97 %type
<flavor
> assign_op
100 fprintf
(stderr
, "%s:%d: missing end statement for this entry\n",
101 $$
->filename
, $$
->lineno
);
102 if
(current_menu
== $$
)
104 } if_entry menu_entry choice_entry
107 input: mainmenu_stmt stmt_list | stmt_list
;
111 mainmenu_stmt: T_MAINMENU T_WORD_QUOTE T_EOL
113 menu_add_prompt
(P_MENU
, $2, NULL
);
118 | stmt_list assignment_stmt
119 | stmt_list choice_stmt
120 | stmt_list comment_stmt
121 | stmt_list config_stmt
123 | stmt_list menu_stmt
124 | stmt_list menuconfig_stmt
125 | stmt_list source_stmt
126 | stmt_list T_WORD
error T_EOL
{ zconf_error
("unknown statement \"%s\"", $2); }
127 | stmt_list
error T_EOL
{ zconf_error
("invalid statement"); }
132 | stmt_list_in_choice comment_stmt
133 | stmt_list_in_choice config_stmt
134 | stmt_list_in_choice if_stmt_in_choice
135 | stmt_list_in_choice
error T_EOL
{ zconf_error
("invalid statement"); }
138 /* config/menuconfig entry */
140 config_entry_start: T_CONFIG nonconst_symbol T_EOL
143 printd
(DEBUG_PARSE
, "%s:%d:config %s\n", cur_filename
, cur_lineno
, $2->name
);
146 config_stmt: config_entry_start config_option_list
148 if
(current_choice
) {
149 if
(!current_entry
->prompt
) {
150 fprintf
(stderr
, "%s:%d: error: choice member must have a prompt\n",
151 current_entry
->filename
, current_entry
->lineno
);
155 if
(current_entry
->sym
->type
!= S_BOOLEAN
) {
156 fprintf
(stderr
, "%s:%d: error: choice member must be bool\n",
157 current_entry
->filename
, current_entry
->lineno
);
162 * If the same symbol appears twice in a choice block, the list
163 * node would be added twice, leading to a broken linked list.
164 * list_empty() ensures that this symbol has not yet added.
166 if
(list_empty
(¤t_entry
->sym
->choice_link
))
167 list_add_tail
(¤t_entry
->sym
->choice_link
,
168 ¤t_choice
->choice_members
);
171 printd
(DEBUG_PARSE
, "%s:%d:endconfig\n", cur_filename
, cur_lineno
);
174 menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
177 printd
(DEBUG_PARSE
, "%s:%d:menuconfig %s\n", cur_filename
, cur_lineno
, $2->name
);
180 menuconfig_stmt: menuconfig_entry_start config_option_list
182 if
(current_entry
->prompt
)
183 current_entry
->prompt
->type
= P_MENU
;
185 zconf_error
("menuconfig statement without prompt");
186 printd
(DEBUG_PARSE
, "%s:%d:endconfig\n", cur_filename
, cur_lineno
);
191 | config_option_list config_option
192 | config_option_list depends
193 | config_option_list help
196 config_option: type prompt_stmt_opt T_EOL
199 printd
(DEBUG_PARSE
, "%s:%d:type(%u)\n", cur_filename
, cur_lineno
, $1);
202 config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
204 menu_add_prompt
(P_PROMPT
, $2, $3);
205 printd
(DEBUG_PARSE
, "%s:%d:prompt\n", cur_filename
, cur_lineno
);
208 config_option: default expr if_expr T_EOL
210 menu_add_expr
(P_DEFAULT
, $2, $3);
213 printd
(DEBUG_PARSE
, "%s:%d:default(%u)\n", cur_filename
, cur_lineno
,
217 config_option: T_SELECT nonconst_symbol if_expr T_EOL
219 menu_add_symbol
(P_SELECT
, $2, $3);
220 printd
(DEBUG_PARSE
, "%s:%d:select\n", cur_filename
, cur_lineno
);
223 config_option: T_IMPLY nonconst_symbol if_expr T_EOL
225 menu_add_symbol
(P_IMPLY
, $2, $3);
226 printd
(DEBUG_PARSE
, "%s:%d:imply\n", cur_filename
, cur_lineno
);
229 config_option: T_RANGE symbol symbol if_expr T_EOL
231 menu_add_expr
(P_RANGE
, expr_alloc_comp
(E_RANGE
,$2, $3), $4);
232 printd
(DEBUG_PARSE
, "%s:%d:range\n", cur_filename
, cur_lineno
);
235 config_option: T_MODULES T_EOL
238 zconf_error
("symbol '%s' redefines option 'modules' already defined by symbol '%s'",
239 current_entry
->sym
->name
, modules_sym
->name
);
240 modules_sym
= current_entry
->sym
;
245 choice: T_CHOICE T_EOL
247 struct symbol
*sym
= sym_lookup
(NULL
, 0);
250 menu_set_type
(S_BOOLEAN
);
251 INIT_LIST_HEAD
(¤t_entry
->choice_members
);
253 printd
(DEBUG_PARSE
, "%s:%d:choice\n", cur_filename
, cur_lineno
);
256 choice_entry: choice choice_option_list
258 if
(!current_entry
->prompt
) {
259 fprintf
(stderr
, "%s:%d: error: choice must have a prompt\n",
260 current_entry
->filename
, current_entry
->lineno
);
264 $$
= menu_add_menu
();
266 current_choice
= current_entry
;
271 current_choice
= NULL
;
273 if
(zconf_endtoken
($1, "choice")) {
275 printd
(DEBUG_PARSE
, "%s:%d:endchoice\n", cur_filename
, cur_lineno
);
279 choice_stmt: choice_entry stmt_list_in_choice choice_end
284 | choice_option_list choice_option
285 | choice_option_list depends
286 | choice_option_list help
289 choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
291 menu_add_prompt
(P_PROMPT
, $2, $3);
292 printd
(DEBUG_PARSE
, "%s:%d:prompt\n", cur_filename
, cur_lineno
);
295 choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
297 menu_add_symbol
(P_DEFAULT
, $2, $3);
298 printd
(DEBUG_PARSE
, "%s:%d:default\n", cur_filename
, cur_lineno
);
302 T_BOOL
{ $$
= S_BOOLEAN
; }
303 | T_TRISTATE
{ $$
= S_TRISTATE
; }
304 | T_INT
{ $$
= S_INT
; }
305 | T_HEX
{ $$
= S_HEX
; }
306 | T_STRING
{ $$
= S_STRING
; }
309 T_DEFAULT
{ $$
= S_UNKNOWN
; }
310 | T_DEF_BOOL
{ $$
= S_BOOLEAN
; }
311 | T_DEF_TRISTATE
{ $$
= S_TRISTATE
; }
315 if_entry: T_IF expr T_EOL
317 printd
(DEBUG_PARSE
, "%s:%d:if\n", cur_filename
, cur_lineno
);
318 menu_add_entry
(NULL
);
320 $$
= menu_add_menu
();
325 if
(zconf_endtoken
($1, "if")) {
327 printd
(DEBUG_PARSE
, "%s:%d:endif\n", cur_filename
, cur_lineno
);
331 if_stmt: if_entry stmt_list if_end
334 if_stmt_in_choice: if_entry stmt_list_in_choice if_end
339 menu: T_MENU T_WORD_QUOTE T_EOL
341 menu_add_entry
(NULL
);
342 menu_add_prompt
(P_MENU
, $2, NULL
);
343 printd
(DEBUG_PARSE
, "%s:%d:menu\n", cur_filename
, cur_lineno
);
346 menu_entry: menu menu_option_list
348 $$
= menu_add_menu
();
353 if
(zconf_endtoken
($1, "menu")) {
355 printd
(DEBUG_PARSE
, "%s:%d:endmenu\n", cur_filename
, cur_lineno
);
359 menu_stmt: menu_entry stmt_list menu_end
364 | menu_option_list visible
365 | menu_option_list depends
368 source_stmt: T_SOURCE T_WORD_QUOTE T_EOL
370 printd
(DEBUG_PARSE
, "%s:%d:source %s\n", cur_filename
, cur_lineno
, $2);
377 comment: T_COMMENT T_WORD_QUOTE T_EOL
379 menu_add_entry
(NULL
);
380 menu_add_prompt
(P_COMMENT
, $2, NULL
);
381 printd
(DEBUG_PARSE
, "%s:%d:comment\n", cur_filename
, cur_lineno
);
384 comment_stmt: comment comment_option_list
389 | comment_option_list depends
394 help_start: T_HELP T_EOL
396 printd
(DEBUG_PARSE
, "%s:%d:help\n", cur_filename
, cur_lineno
);
400 help: help_start T_HELPTEXT
402 if
(current_entry
->help
) {
403 free
(current_entry
->help
);
404 zconf_error
("'%s' defined with more than one help text",
405 current_entry
->sym
->name ?
: "<choice>");
408 /* Is the help text empty or all whitespace? */
409 if
($2[strspn
($2, " \f\n\r\t\v")] == '\0')
410 zconf_error
("'%s' defined with blank help text",
411 current_entry
->sym
->name ?
: "<choice>");
413 current_entry
->help
= $2;
418 depends: T_DEPENDS T_ON expr T_EOL
421 printd
(DEBUG_PARSE
, "%s:%d:depends on\n", cur_filename
, cur_lineno
);
424 /* visibility option */
425 visible: T_VISIBLE if_expr T_EOL
427 menu_add_visibility
($2);
430 /* prompt statement */
434 | T_WORD_QUOTE if_expr
436 menu_add_prompt
(P_PROMPT
, $1, $2);
439 end: T_ENDMENU T_EOL
{ $$
= "menu"; }
440 | T_ENDCHOICE T_EOL
{ $$
= "choice"; }
441 | T_ENDIF T_EOL
{ $$
= "if"; }
444 if_expr: /* empty */ { $$
= NULL
; }
445 | T_IF expr
{ $$
= $2; }
448 expr: symbol
{ $$
= expr_alloc_symbol
($1); }
449 | symbol T_LESS symbol
{ $$
= expr_alloc_comp
(E_LTH
, $1, $3); }
450 | symbol T_LESS_EQUAL symbol
{ $$
= expr_alloc_comp
(E_LEQ
, $1, $3); }
451 | symbol T_GREATER symbol
{ $$
= expr_alloc_comp
(E_GTH
, $1, $3); }
452 | symbol T_GREATER_EQUAL symbol
{ $$
= expr_alloc_comp
(E_GEQ
, $1, $3); }
453 | symbol T_EQUAL symbol
{ $$
= expr_alloc_comp
(E_EQUAL
, $1, $3); }
454 | symbol T_UNEQUAL symbol
{ $$
= expr_alloc_comp
(E_UNEQUAL
, $1, $3); }
455 | T_OPEN_PAREN expr T_CLOSE_PAREN
{ $$
= $2; }
456 | T_NOT expr
{ $$
= expr_alloc_one
(E_NOT
, $2); }
457 | expr T_OR expr
{ $$
= expr_alloc_two
(E_OR
, $1, $3); }
458 | expr T_AND expr
{ $$
= expr_alloc_two
(E_AND
, $1, $3); }
461 /* For symbol definitions, selects, etc., where quotes are not accepted */
462 nonconst_symbol: T_WORD
{ $$
= sym_lookup
($1, 0); free
($1); };
464 symbol: nonconst_symbol
465 | T_WORD_QUOTE
{ $$
= sym_lookup
($1, SYMBOL_CONST
); free
($1); }
468 /* assignment statement */
470 assignment_stmt: T_WORD assign_op assign_val T_EOL
{ variable_add
($1, $3, $2); free
($1); free
($3); }
473 T_EQUAL
{ $$
= VAR_RECURSIVE
; }
474 | T_COLON_EQUAL
{ $$
= VAR_SIMPLE
; }
475 | T_PLUS_EQUAL
{ $$
= VAR_APPEND
; }
479 /* empty */ { $$
= xstrdup
(""); };
486 * choice_check_sanity - check sanity of a choice member
488 * @menu: menu of the choice member
490 * Return: -1 if an error is found, 0 otherwise.
492 static int choice_check_sanity
(const struct menu
*menu
)
494 struct property
*prop
;
497 for
(prop
= menu
->sym
->prop
; prop
; prop
= prop
->next
) {
498 if
(prop
->type
== P_DEFAULT
) {
499 fprintf
(stderr
, "%s:%d: error: %s",
500 prop
->filename
, prop
->lineno
,
501 "defaults for choice values not supported\n");
505 if
(prop
->menu
!= menu
&& prop
->type
== P_PROMPT
&&
506 prop
->menu
->parent
!= menu
->parent
) {
507 fprintf
(stderr
, "%s:%d: error: %s",
508 prop
->filename
, prop
->lineno
,
509 "choice value has a prompt outside its choice group\n");
517 void conf_parse
(const char *name
)
521 autoconf_cmd
= str_new
();
523 str_printf
(&autoconf_cmd
, "\ndeps_config := \\\n");
525 zconf_initscan
(name
);
529 if
(getenv
("ZCONF_DEBUG"))
533 str_printf
(&autoconf_cmd
,
535 "$(autoconfig): $(deps_config)\n"
536 "$(deps_config): ;\n");
538 env_write_dep
(&autoconf_cmd
);
540 /* Variables are expanded in the parse phase. We can free them here. */
546 modules_sym
= &symbol_no
;
548 if
(!menu_has_prompt
(&rootmenu
)) {
549 current_entry
= &rootmenu
;
550 menu_add_prompt
(P_MENU
, "Main menu", NULL
);
555 menu_for_each_entry
(menu
) {
558 if
(menu
->sym
&& sym_check_deps
(menu
->sym
))
561 if
(menu
->sym
&& sym_is_choice
(menu
->sym
)) {
562 menu_for_each_sub_entry
(child
, menu
)
563 if
(child
->sym
&& choice_check_sanity
(child
))
570 conf_set_changed
(true
);
573 static bool zconf_endtoken
(const char *tokenname
,
574 const char *expected_tokenname
)
576 if
(strcmp
(tokenname
, expected_tokenname
)) {
577 zconf_error
("unexpected '%s' within %s block",
578 tokenname
, expected_tokenname
);
582 if
(strcmp
(current_menu
->filename
, cur_filename
)) {
583 zconf_error
("'%s' in different file than '%s'",
584 tokenname
, expected_tokenname
);
585 fprintf
(stderr
, "%s:%d: location of the '%s'\n",
586 current_menu
->filename
, current_menu
->lineno
,
594 static void zconf_error
(const char *err
, ...
)
599 fprintf
(stderr
, "%s:%d: ", cur_filename
, cur_lineno
);
601 vfprintf
(stderr
, err
, ap
);
603 fprintf
(stderr
, "\n");
606 static void yyerror(const char *err
)
608 fprintf
(stderr
, "%s:%d: %s\n", cur_filename
, cur_lineno
, err
);
611 static void print_quoted_string
(FILE *out
, const char *str
)
617 while
((p
= strchr
(str
, '"'))) {
620 fprintf
(out
, "%.*s", len
, str
);
628 static void print_symbol
(FILE *out
, const struct menu
*menu
)
630 struct symbol
*sym
= menu
->sym
;
631 struct property
*prop
;
633 if
(sym_is_choice
(sym
))
634 fprintf
(out
, "\nchoice\n");
636 fprintf
(out
, "\nconfig %s\n", sym
->name
);
639 fputs
(" bool\n", out
);
642 fputs
(" tristate\n", out
);
645 fputs
(" string\n", out
);
648 fputs
(" integer\n", out
);
651 fputs
(" hex\n", out
);
654 fputs
(" ???\n", out
);
657 for
(prop
= sym
->prop
; prop
; prop
= prop
->next
) {
658 if
(prop
->menu
!= menu
)
660 switch
(prop
->type
) {
662 fputs
(" prompt ", out
);
663 print_quoted_string
(out
, prop
->text
);
664 if
(!expr_is_yes
(prop
->visible.expr
)) {
666 expr_fprint
(prop
->visible.expr
, out
);
671 fputs
( " default ", out
);
672 expr_fprint
(prop
->expr
, out
);
673 if
(!expr_is_yes
(prop
->visible.expr
)) {
675 expr_fprint
(prop
->visible.expr
, out
);
680 fputs
( " select ", out
);
681 expr_fprint
(prop
->expr
, out
);
685 fputs
( " imply ", out
);
686 expr_fprint
(prop
->expr
, out
);
690 fputs
( " range ", out
);
691 expr_fprint
(prop
->expr
, out
);
695 fputs
( " menu ", out
);
696 print_quoted_string
(out
, prop
->text
);
700 fprintf
(out
, " unknown prop %d!\n", prop
->type
);
705 int len
= strlen
(menu
->help
);
706 while
(menu
->help
[--len
] == '\n')
708 fprintf
(out
, " help\n%s\n", menu
->help
);
712 void zconfdump
(FILE *out
)
714 struct property
*prop
;
718 menu
= rootmenu.list
;
720 if
((sym
= menu
->sym
))
721 print_symbol
(out
, menu
);
722 else if
((prop
= menu
->prompt
)) {
723 switch
(prop
->type
) {
725 fputs
("\ncomment ", out
);
726 print_quoted_string
(out
, prop
->text
);
730 fputs
("\nmenu ", out
);
731 print_quoted_string
(out
, prop
->text
);
737 if
(!expr_is_yes
(prop
->visible.expr
)) {
738 fputs
(" depends ", out
);
739 expr_fprint
(prop
->visible.expr
, out
);
748 else while
((menu
= menu
->parent
)) {
749 if
(menu
->prompt
&& menu
->prompt
->type
== P_MENU
)
750 fputs
("\nendmenu\n", out
);