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