root/trunk/freewrt/tools/config/zconf.y

Revision 3223, 14.5 kB (checked in by tg, 5 years ago)

implement "select !FOO", everything including cosmetics from me,
except rev_dep_inv+deselected stuff, which is from nbd@openwrt –
thanks

selected symbols are now shown as “-+-” (on) or “_ _” (off)

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