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 19int cdebug = PRINTD; 20 21extern int zconflex(void); 22static void zconfprint(const char *err, ...); 23static void zconferror(const char *err); 24static bool zconf_endtoken(int token, int starttoken, int endtoken); 25 26struct symbol *symbol_hash[257]; 27 28#define YYERROR_VERBOSE 29%} 30%expect 36 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_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 70 71%left T_OR 72%left T_AND 73%left T_EQUAL T_UNEQUAL 74%nonassoc T_NOT 75 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 82 83%{ 84#define LKC_DIRECT_LINK 85#include "lkc.h" 86%} 87%% 88input: /* empty */ 89 | input block 90; 91 92block: 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; } 100; 101 102common_block: 103 if_stmt 104 | comment_stmt 105 | config_stmt 106 | source_stmt 107 | nl_or_eof 108; 109 110 111/* config entry */ 112 113config_entry_start: T_CONFIG T_WORD 114{ 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); 119}; 120 121config_stmt: config_entry_start T_EOL config_option_list 122{ 123 menu_end_entry(); 124 printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); 125}; 126 127config_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{ }; 134 135config_option: T_TRISTATE prompt_stmt_opt 136{ 137 menu_set_type(S_TRISTATE); 138 printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno()); 139}; 140 141config_option: T_BOOLEAN prompt_stmt_opt 142{ 143 menu_set_type(S_BOOLEAN); 144 printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno()); 145}; 146 147config_option: T_INT prompt_stmt_opt 148{ 149 menu_set_type(S_INT); 150 printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno()); 151}; 152 153config_option: T_HEX prompt_stmt_opt 154{ 155 menu_set_type(S_HEX); 156 printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno()); 157}; 158 159config_option: T_STRING prompt_stmt_opt 160{ 161 menu_set_type(S_STRING); 162 printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno()); 163}; 164 165config_option: T_PROMPT prompt if_expr 166{ 167 menu_add_prop(P_PROMPT, $2, NULL, $3); 168 printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); 169}; 170 171config_option: T_DEFAULT symbol if_expr 172{ 173 menu_add_prop(P_DEFAULT, NULL, $2, $3); 174 printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); 175}; 176 177/* choice entry */ 178 179choice: T_CHOICE 180{ 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()); 186}; 187 188choice_entry: choice T_EOL choice_option_list 189{ 190 menu_end_entry(); 191 menu_add_menu(); 192}; 193 194choice_end: end 195{ 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()); 199 } 200}; 201 202choice_stmt: 203 choice_entry choice_block choice_end T_EOL 204 | choice_entry choice_block 205{ 206 printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno); 207 zconfnerrs++; 208}; 209 210choice_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 216; 217 218choice_option: T_PROMPT prompt if_expr 219{ 220 menu_add_prop(P_PROMPT, $2, NULL, $3); 221 printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); 222}; 223 224choice_option: T_OPTIONAL 225{ 226 current_entry->sym->flags |= SYMBOL_OPTIONAL; 227 printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); 228}; 229 230choice_option: T_DEFAULT symbol 231{ 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()); 235}; 236 237choice_block: 238 /* empty */ 239 | choice_block common_block 240; 241 242/* if entry */ 243 244if: T_IF expr 245{ 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(); 252}; 253 254if_end: end 255{ 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()); 259 } 260}; 261 262if_stmt: 263 if T_EOL if_block if_end T_EOL 264 | if T_EOL if_block 265{ 266 printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno); 267 zconfnerrs++; 268}; 269 270if_block: 271 /* empty */ 272 | if_block common_block 273 | if_block menu_stmt 274 | if_block choice_stmt 275; 276 277/* menu entry */ 278 279menu: T_MENU prompt 280{ 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()); 284}; 285 286menu_entry: menu T_EOL depends_list 287{ 288 menu_end_entry(); 289 menu_add_menu(); 290}; 291 292menu_end: end 293{ 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()); 297 } 298}; 299 300menu_stmt: 301 menu_entry menu_block menu_end T_EOL 302 | menu_entry menu_block 303{ 304 printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno); 305 zconfnerrs++; 306}; 307 308menu_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; } 314; 315 316source: T_SOURCE prompt 317{ 318 $$ = $2; 319 printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); 320}; 321 322source_stmt: source T_EOL 323{ 324 zconf_nextfile($1); 325}; 326 327/* comment entry */ 328 329comment: T_COMMENT prompt 330{ 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()); 334}; 335 336comment_stmt: comment T_EOL depends_list 337{ 338 menu_end_entry(); 339}; 340 341/* help option */ 342 343help_start: T_HELP T_EOL 344{ 345 printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); 346 zconf_starthelp(); 347}; 348 349help: help_start T_HELPTEXT 350{ 351 current_entry->sym->help = $2; 352}; 353 354/* depends option */ 355 356depends_list: /* empty */ 357 | depends_list depends T_EOL 358 | depends_list T_EOL 359{ }; 360 361depends: T_DEPENDS T_ON expr 362{ 363 menu_add_dep($3); 364 printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); 365} 366 | T_DEPENDS expr 367{ 368 menu_add_dep($2); 369 printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno()); 370} 371 | T_REQUIRES expr 372{ 373 menu_add_dep($2); 374 printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno()); 375}; 376 377/* prompt statement */ 378 379prompt_stmt_opt: 380 /* empty */ 381 | prompt 382{ 383 menu_add_prop(P_PROMPT, $1, NULL, NULL); 384} 385 | prompt T_IF expr 386{ 387 menu_add_prop(P_PROMPT, $1, NULL, $3); 388}; 389 390prompt: T_WORD 391 | T_STRING 392; 393 394end: T_ENDMENU { $$ = T_ENDMENU; } 395 | T_ENDCHOICE { $$ = T_ENDCHOICE; } 396 | T_ENDIF { $$ = T_ENDIF; } 397; 398 399nl_or_eof: 400 T_EOL | T_EOF; 401 402if_expr: /* empty */ { $$ = NULL; } 403 | T_IF expr { $$ = $2; } 404; 405 406expr: 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); } 413; 414 415symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } 416 | T_STRING { $$ = sym_lookup($1, 1); free($1); } 417; 418 419%% 420 421void conf_parse(const char *name) 422{ 423 zconf_initscan(name); 424 425 sym_init(); 426 menu_init(); 427 rootmenu.prompt = menu_add_prop(P_MENU, "Broadcom Linux Router Configuration", NULL, NULL); 428 429 //zconfdebug = 1; 430 zconfparse(); 431 if (zconfnerrs) 432 exit(1); 433 menu_finalize(&rootmenu); 434 435 modules_sym = sym_lookup("MODULES", 0); 436 437 sym_change_count = 1; 438} 439 440const char *zconf_tokenname(int token) 441{ 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"; 449 } 450 return "<token>"; 451} 452 453static bool zconf_endtoken(int token, int starttoken, int endtoken) 454{ 455 if (token != endtoken) { 456 zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken)); 457 zconfnerrs++; 458 return false; 459 } 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; 465 } 466 return true; 467} 468 469static void zconfprint(const char *err, ...) 470{ 471 va_list ap; 472 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"); 478} 479 480static void zconferror(const char *err) 481{ 482 fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno(), err); 483} 484 485void print_quoted_string(FILE *out, const char *str) 486{ 487 const char *p; 488 int len; 489 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; 497 } 498 fputs(str, out); 499 putc('"', out); 500} 501 502void print_symbol(FILE *out, struct menu *menu) 503{ 504 struct symbol *sym = menu->sym; 505 struct property *prop; 506 507 //sym->flags |= SYMBOL_PRINTED; 508 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; 532 } 533#if 0 534 if (!expr_is_yes(sym->dep)) { 535 fputs(" depends ", out); 536 expr_fprint(sym->dep, out); 537 fputc('\n', out); 538 } 539#endif 540 for (prop = sym->prop; prop; prop = prop->next) { 541 if (prop->menu != menu) 542 continue; 543 switch (prop->type) { 544 case P_PROMPT: 545 fputs(" prompt ", out); 546 print_quoted_string(out, prop->text); 547 if (prop->def) { 548 fputc(' ', out); 549 if (prop->def->flags & SYMBOL_CONST) 550 print_quoted_string(out, prop->def->name); 551 else 552 fputs(prop->def->name, out); 553 } 554 if (!expr_is_yes(E_EXPR(prop->visible))) { 555 fputs(" if ", out); 556 expr_fprint(E_EXPR(prop->visible), out); 557 } 558 fputc('\n', out); 559 break; 560 case P_DEFAULT: 561 fputs( " default ", out); 562 print_quoted_string(out, prop->def->name); 563 if (!expr_is_yes(E_EXPR(prop->visible))) { 564 fputs(" if ", out); 565 expr_fprint(E_EXPR(prop->visible), out); 566 } 567 fputc('\n', out); 568 break; 569 case P_CHOICE: 570 fputs(" #choice value\n", out); 571 break; 572 default: 573 fprintf(out, " unknown prop %d!\n", prop->type); 574 break; 575 } 576 } 577 if (sym->help) { 578 int len = strlen(sym->help); 579 while (sym->help[--len] == '\n') 580 sym->help[len] = 0; 581 fprintf(out, " help\n%s\n", sym->help); 582 } 583 fputc('\n', out); 584} 585 586void zconfdump(FILE *out) 587{ 588 //struct file *file; 589 struct property *prop; 590 struct symbol *sym; 591 struct menu *menu; 592 593 menu = rootmenu.list; 594 while (menu) { 595 if ((sym = menu->sym)) 596 print_symbol(out, menu); 597 else if ((prop = menu->prompt)) { 598 switch (prop->type) { 599 //case T_MAINMENU: 600 // fputs("\nmainmenu ", out); 601 // print_quoted_string(out, prop->text); 602 // fputs("\n", out); 603 // break; 604 case P_COMMENT: 605 fputs("\ncomment ", out); 606 print_quoted_string(out, prop->text); 607 fputs("\n", out); 608 break; 609 case P_MENU: 610 fputs("\nmenu ", out); 611 print_quoted_string(out, prop->text); 612 fputs("\n", out); 613 break; 614 //case T_SOURCE: 615 // fputs("\nsource ", out); 616 // print_quoted_string(out, prop->text); 617 // fputs("\n", out); 618 // break; 619 //case T_IF: 620 // fputs("\nif\n", out); 621 default: 622 ; 623 } 624 if (!expr_is_yes(E_EXPR(prop->visible))) { 625 fputs(" depends ", out); 626 expr_fprint(E_EXPR(prop->visible), out); 627 fputc('\n', out); 628 } 629 fputs("\n", out); 630 } 631 632 if (menu->list) 633 menu = menu->list; 634 else if (menu->next) 635 menu = menu->next; 636 else while ((menu = menu->parent)) { 637 if (menu->prompt && menu->prompt->type == P_MENU) 638 fputs("\nendmenu\n", out); 639 if (menu->next) { 640 menu = menu->next; 641 break; 642 } 643 } 644 } 645} 646 647#include "lex.zconf.c" 648#include "confdata.c" 649#include "expr.c" 650#include "symbol.c" 651#include "menu.c" 652