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