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