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