Tomato 1.26 beta(1766)
[tomato/tomato-null.git] / release / src / router / config / zconf.y
blob41a675c52d9105d79f6eb502f4f8566648fd25a0
1 %{
2 /*
3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
4 * Released under the terms of the GNU GPL v2.0.
5 */
7 #include <ctype.h>
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdbool.h>
14 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
16 #define PRINTD 0x0001
17 #define DEBUG_PARSE 0x0002
19 int cdebug = PRINTD;
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);
26 struct symbol *symbol_hash[257];
28 #define YYERROR_VERBOSE
30 %expect 36
32 %union
34 int token;
35 char *string;
36 struct symbol *symbol;
37 struct expr *expr;
38 struct menu *menu;
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_HELP
50 %token <string> T_HELPTEXT
51 %token T_IF
52 %token T_ENDIF
53 %token T_DEPENDS
54 %token T_REQUIRES
55 %token T_OPTIONAL
56 %token T_PROMPT
57 %token T_DEFAULT
58 %token T_TRISTATE
59 %token T_BOOLEAN
60 %token T_INT
61 %token T_HEX
62 %token <string> T_WORD
63 %token <string> T_STRING
64 %token T_UNEQUAL
65 %token T_EOF
66 %token T_EOL
67 %token T_CLOSE_PAREN
68 %token T_OPEN_PAREN
69 %token T_ON
71 %left T_OR
72 %left T_AND
73 %left T_EQUAL T_UNEQUAL
74 %nonassoc T_NOT
76 %type <string> prompt
77 %type <string> source
78 %type <symbol> symbol
79 %type <expr> expr
80 %type <expr> if_expr
81 %type <token> end
84 #define LKC_DIRECT_LINK
85 #include "lkc.h"
88 input: /* empty */
89 | input block
92 block: common_block
93 | choice_stmt
94 | menu_stmt
95 | T_MAINMENU prompt nl_or_eof
96 | T_ENDMENU { zconfprint("unexpected 'endmenu' statement"); }
97 | T_ENDIF { zconfprint("unexpected 'endif' statement"); }
98 | T_ENDCHOICE { zconfprint("unexpected 'endchoice' statement"); }
99 | error nl_or_eof { zconfprint("syntax error"); yyerrok; }
102 common_block:
103 if_stmt
104 | comment_stmt
105 | config_stmt
106 | source_stmt
107 | nl_or_eof
111 /* config entry */
113 config_entry_start: T_CONFIG T_WORD
115 struct symbol *sym = sym_lookup($2, 0);
116 sym->flags |= SYMBOL_OPTIONAL;
117 menu_add_entry(sym);
118 printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
121 config_stmt: config_entry_start T_EOL config_option_list
123 menu_end_entry();
124 printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
127 config_option_list:
128 /* empty */
129 | config_option_list config_option T_EOL
130 | config_option_list depends T_EOL
131 | config_option_list help
132 | config_option_list T_EOL
133 { };
135 config_option: T_TRISTATE prompt_stmt_opt
137 menu_set_type(S_TRISTATE);
138 printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
141 config_option: T_BOOLEAN prompt_stmt_opt
143 menu_set_type(S_BOOLEAN);
144 printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
147 config_option: T_INT prompt_stmt_opt
149 menu_set_type(S_INT);
150 printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
153 config_option: T_HEX prompt_stmt_opt
155 menu_set_type(S_HEX);
156 printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
159 config_option: T_STRING prompt_stmt_opt
161 menu_set_type(S_STRING);
162 printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
165 config_option: T_PROMPT prompt if_expr
167 menu_add_prop(P_PROMPT, $2, NULL, $3);
168 printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
171 config_option: T_DEFAULT symbol if_expr
173 menu_add_prop(P_DEFAULT, NULL, $2, $3);
174 printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
177 /* choice entry */
179 choice: T_CHOICE
181 struct symbol *sym = sym_lookup(NULL, 0);
182 sym->flags |= SYMBOL_CHOICE;
183 menu_add_entry(sym);
184 menu_add_prop(P_CHOICE, NULL, NULL, NULL);
185 printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
188 choice_entry: choice T_EOL choice_option_list
190 menu_end_entry();
191 menu_add_menu();
194 choice_end: end
196 if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
197 menu_end_menu();
198 printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
202 choice_stmt:
203 choice_entry choice_block choice_end T_EOL
204 | choice_entry choice_block
206 printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
207 zconfnerrs++;
210 choice_option_list:
211 /* empty */
212 | choice_option_list choice_option T_EOL
213 | choice_option_list depends T_EOL
214 | choice_option_list help
215 | choice_option_list T_EOL
218 choice_option: T_PROMPT prompt if_expr
220 menu_add_prop(P_PROMPT, $2, NULL, $3);
221 printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
224 choice_option: T_OPTIONAL
226 current_entry->sym->flags |= SYMBOL_OPTIONAL;
227 printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
230 choice_option: T_DEFAULT symbol
232 menu_add_prop(P_DEFAULT, NULL, $2, NULL);
233 //current_choice->prop->def = $2;
234 printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
237 choice_block:
238 /* empty */
239 | choice_block common_block
242 /* if entry */
244 if: T_IF expr
246 printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
247 menu_add_entry(NULL);
248 //current_entry->prompt = menu_add_prop(T_IF, NULL, NULL, $2);
249 menu_add_dep($2);
250 menu_end_entry();
251 menu_add_menu();
254 if_end: end
256 if (zconf_endtoken($1, T_IF, T_ENDIF)) {
257 menu_end_menu();
258 printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
262 if_stmt:
263 if T_EOL if_block if_end T_EOL
264 | if T_EOL if_block
266 printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
267 zconfnerrs++;
270 if_block:
271 /* empty */
272 | if_block common_block
273 | if_block menu_stmt
274 | if_block choice_stmt
277 /* menu entry */
279 menu: T_MENU prompt
281 menu_add_entry(NULL);
282 menu_add_prop(P_MENU, $2, NULL, NULL);
283 printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
286 menu_entry: menu T_EOL depends_list
288 menu_end_entry();
289 menu_add_menu();
292 menu_end: end
294 if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
295 menu_end_menu();
296 printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
300 menu_stmt:
301 menu_entry menu_block menu_end T_EOL
302 | menu_entry menu_block
304 printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
305 zconfnerrs++;
308 menu_block:
309 /* empty */
310 | menu_block common_block
311 | menu_block menu_stmt
312 | menu_block choice_stmt
313 | menu_block error T_EOL { zconfprint("invalid menu option"); yyerrok; }
316 source: T_SOURCE prompt
318 $$ = $2;
319 printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
322 source_stmt: source T_EOL
324 zconf_nextfile($1);
327 /* comment entry */
329 comment: T_COMMENT prompt
331 menu_add_entry(NULL);
332 menu_add_prop(P_COMMENT, $2, NULL, NULL);
333 printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
336 comment_stmt: comment T_EOL depends_list
338 menu_end_entry();
341 /* help option */
343 help_start: T_HELP T_EOL
345 printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
346 zconf_starthelp();
349 help: help_start T_HELPTEXT
351 current_entry->sym->help = $2;
354 /* depends option */
356 depends_list: /* empty */
357 | depends_list depends T_EOL
358 | depends_list T_EOL
359 { };
361 depends: T_DEPENDS T_ON expr
363 menu_add_dep($3);
364 printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
366 | T_DEPENDS expr
368 menu_add_dep($2);
369 printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
371 | T_REQUIRES expr
373 menu_add_dep($2);
374 printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
377 /* prompt statement */
379 prompt_stmt_opt:
380 /* empty */
381 | prompt
383 menu_add_prop(P_PROMPT, $1, NULL, NULL);
385 | prompt T_IF expr
387 menu_add_prop(P_PROMPT, $1, NULL, $3);
390 prompt: T_WORD
391 | T_STRING
394 end: T_ENDMENU { $$ = T_ENDMENU; }
395 | T_ENDCHOICE { $$ = T_ENDCHOICE; }
396 | T_ENDIF { $$ = T_ENDIF; }
399 nl_or_eof:
400 T_EOL | T_EOF;
402 if_expr: /* empty */ { $$ = NULL; }
403 | T_IF expr { $$ = $2; }
406 expr: symbol { $$ = expr_alloc_symbol($1); }
407 | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
408 | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
409 | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; }
410 | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); }
411 | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); }
412 | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); }
415 symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
416 | T_STRING { $$ = sym_lookup($1, 1); free($1); }
421 void conf_parse(const char *name)
423 zconf_initscan(name);
425 sym_init();
426 menu_init();
427 rootmenu.prompt = menu_add_prop(P_MENU, "Broadcom Linux Router Configuration", NULL, NULL);
429 //zconfdebug = 1;
430 zconfparse();
431 if (zconfnerrs)
432 exit(1);
433 menu_finalize(&rootmenu);
435 modules_sym = sym_lookup("MODULES", 0);
437 sym_change_count = 1;
440 const char *zconf_tokenname(int token)
442 switch (token) {
443 case T_MENU: return "menu";
444 case T_ENDMENU: return "endmenu";
445 case T_CHOICE: return "choice";
446 case T_ENDCHOICE: return "endchoice";
447 case T_IF: return "if";
448 case T_ENDIF: return "endif";
450 return "<token>";
453 static bool zconf_endtoken(int token, int starttoken, int endtoken)
455 if (token != endtoken) {
456 zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken));
457 zconfnerrs++;
458 return false;
460 if (current_menu->file != current_file) {
461 zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken));
462 zconfprint("location of the '%s'", zconf_tokenname(starttoken));
463 zconfnerrs++;
464 return false;
466 return true;
469 static void zconfprint(const char *err, ...)
471 va_list ap;
473 fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
474 va_start(ap, err);
475 vfprintf(stderr, err, ap);
476 va_end(ap);
477 fprintf(stderr, "\n");
480 static void zconferror(const char *err)
482 fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno(), err);
485 void print_quoted_string(FILE *out, const char *str)
487 const char *p;
488 int len;
490 putc('"', out);
491 while ((p = strchr(str, '"'))) {
492 len = p - str;
493 if (len)
494 fprintf(out, "%.*s", len, str);
495 fputs("\\\"", out);
496 str = p + 1;
498 fputs(str, out);
499 putc('"', out);
502 void print_symbol(FILE *out, struct menu *menu)
504 struct symbol *sym = menu->sym;
505 struct property *prop;
507 //sym->flags |= SYMBOL_PRINTED;
509 if (sym_is_choice(sym))
510 fprintf(out, "choice\n");
511 else
512 fprintf(out, "config %s\n", sym->name);
513 switch (sym->type) {
514 case S_BOOLEAN:
515 fputs(" boolean\n", out);
516 break;
517 case S_TRISTATE:
518 fputs(" tristate\n", out);
519 break;
520 case S_STRING:
521 fputs(" string\n", out);
522 break;
523 case S_INT:
524 fputs(" integer\n", out);
525 break;
526 case S_HEX:
527 fputs(" hex\n", out);
528 break;
529 default:
530 fputs(" ???\n", out);
531 break;
533 for (prop = sym->prop; prop; prop = prop->next) {
534 if (prop->menu != menu)
535 continue;
536 switch (prop->type) {
537 case P_PROMPT:
538 fputs(" prompt ", out);
539 print_quoted_string(out, prop->text);
540 if (prop->def) {
541 fputc(' ', out);
542 if (prop->def->flags & SYMBOL_CONST)
543 print_quoted_string(out, prop->def->name);
544 else
545 fputs(prop->def->name, out);
547 if (!expr_is_yes(E_EXPR(prop->visible))) {
548 fputs(" if ", out);
549 expr_fprint(E_EXPR(prop->visible), out);
551 fputc('\n', out);
552 break;
553 case P_DEFAULT:
554 fputs( " default ", out);
555 print_quoted_string(out, prop->def->name);
556 if (!expr_is_yes(E_EXPR(prop->visible))) {
557 fputs(" if ", out);
558 expr_fprint(E_EXPR(prop->visible), out);
560 fputc('\n', out);
561 break;
562 case P_CHOICE:
563 fputs(" #choice value\n", out);
564 break;
565 default:
566 fprintf(out, " unknown prop %d!\n", prop->type);
567 break;
570 if (sym->help) {
571 int len = strlen(sym->help);
572 while (sym->help[--len] == '\n')
573 sym->help[len] = 0;
574 fprintf(out, " help\n%s\n", sym->help);
576 fputc('\n', out);
579 void zconfdump(FILE *out)
581 //struct file *file;
582 struct property *prop;
583 struct symbol *sym;
584 struct menu *menu;
586 menu = rootmenu.list;
587 while (menu) {
588 if ((sym = menu->sym))
589 print_symbol(out, menu);
590 else if ((prop = menu->prompt)) {
591 switch (prop->type) {
592 //case T_MAINMENU:
593 // fputs("\nmainmenu ", out);
594 // print_quoted_string(out, prop->text);
595 // fputs("\n", out);
596 // break;
597 case P_COMMENT:
598 fputs("\ncomment ", out);
599 print_quoted_string(out, prop->text);
600 fputs("\n", out);
601 break;
602 case P_MENU:
603 fputs("\nmenu ", out);
604 print_quoted_string(out, prop->text);
605 fputs("\n", out);
606 break;
607 //case T_SOURCE:
608 // fputs("\nsource ", out);
609 // print_quoted_string(out, prop->text);
610 // fputs("\n", out);
611 // break;
612 //case T_IF:
613 // fputs("\nif\n", out);
614 default:
617 if (!expr_is_yes(E_EXPR(prop->visible))) {
618 fputs(" depends ", out);
619 expr_fprint(E_EXPR(prop->visible), out);
620 fputc('\n', out);
622 fputs("\n", out);
625 if (menu->list)
626 menu = menu->list;
627 else if (menu->next)
628 menu = menu->next;
629 else while ((menu = menu->parent)) {
630 if (menu->prompt && menu->prompt->type == P_MENU)
631 fputs("\nendmenu\n", out);
632 if (menu->next) {
633 menu = menu->next;
634 break;
640 #include "lex.zconf.c"
641 #include "confdata.c"
642 #include "expr.c"
643 #include "symbol.c"
644 #include "menu.c"