linux/scripts/kconfig/zconf.y
<<
>>
Prefs
   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