]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - scripts/kconfig/zconf.y
[PATCH] kconfig: improve error handling in the parser
[linux-2.6-omap-h63xx.git] / scripts / kconfig / zconf.y
index 1211781675b81ab2cfc8fc0e9be8b95e4fefbdc0..1f61fba6aa287a7699fa474a5ff999c70b6cf793 100644 (file)
@@ -25,21 +25,25 @@ int cdebug = PRINTD;
 
 extern int zconflex(void);
 static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
 static void zconferror(const char *err);
-static bool zconf_endtoken(int token, int starttoken, int endtoken);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
 
 struct symbol *symbol_hash[257];
 
 static struct menu *current_menu, *current_entry;
 
+#define YYDEBUG 0
+#if YYDEBUG
 #define YYERROR_VERBOSE
+#endif
 %}
-%expect 40
+%expect 26
 
 %union
 {
-       int token;
        char *string;
+       struct file *file;
        struct symbol *symbol;
        struct expr *expr;
        struct menu *menu;
@@ -74,7 +78,6 @@ static struct menu *current_menu, *current_entry;
 %token T_CLOSE_PAREN
 %token T_OPEN_PAREN
 %token T_EOL
-%token T_EOF
 
 %left T_OR
 %left T_AND
@@ -82,34 +85,54 @@ static struct menu *current_menu, *current_entry;
 %nonassoc T_NOT
 
 %type <string> prompt
-%type <string> source
 %type <symbol> symbol
 %type <expr> expr
 %type <expr> if_expr
-%type <token> end
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+
+%destructor {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               $$->file->name, $$->lineno);
+       if (current_menu == $$)
+               menu_end_menu();
+} if_entry menu_entry choice_entry
 
 %%
-input:   /* empty */
-       | input block
+input: stmt_list;
+
+stmt_list:
+         /* empty */
+       | stmt_list common_stmt
+       | stmt_list choice_stmt
+       | stmt_list menu_stmt
+       | stmt_list T_MAINMENU prompt nl
+       | stmt_list end                 { zconf_error("unexpected end statement"); }
+       | stmt_list T_WORD error T_EOL  { zconf_error("unknown statement \"%s\"", $2); }
+       | stmt_list option_name error T_EOL
+{
+       zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+       | stmt_list error T_EOL         { zconf_error("invalid statement"); }
 ;
 
-block:   common_block
-       | choice_stmt
-       | menu_stmt
-       | T_MAINMENU prompt nl_or_eof
-       | T_ENDMENU             { zconfprint("unexpected 'endmenu' statement"); }
-       | T_ENDIF               { zconfprint("unexpected 'endif' statement"); }
-       | T_ENDCHOICE           { zconfprint("unexpected 'endchoice' statement"); }
-       | error nl_or_eof       { zconfprint("syntax error"); yyerrok; }
+option_name:
+       T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT
 ;
 
-common_block:
-         if_stmt
+common_stmt:
+         T_EOL
+       | if_stmt
        | comment_stmt
        | config_stmt
        | menuconfig_stmt
        | source_stmt
-       | nl_or_eof
+;
+
+option_error:
+         T_WORD error T_EOL            { zconf_error("unknown option \"%s\"", $1); }
+       | error T_EOL                   { zconf_error("invalid option"); }
 ;
 
 
@@ -152,6 +175,7 @@ config_option_list:
        | config_option_list config_option
        | config_option_list depends
        | config_option_list help
+       | config_option_list option_error
        | config_option_list T_EOL
 ;
 
@@ -204,8 +228,7 @@ choice: T_CHOICE T_EOL
 
 choice_entry: choice choice_option_list
 {
-       menu_end_entry();
-       menu_add_menu();
+       $$ = menu_add_menu();
 };
 
 choice_end: end
@@ -216,13 +239,8 @@ choice_end: end
        }
 };
 
-choice_stmt:
-         choice_entry choice_block choice_end
-       | choice_entry choice_block
-{
-       printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
-       zconfnerrs++;
-};
+choice_stmt: choice_entry choice_block choice_end
+;
 
 choice_option_list:
          /* empty */
@@ -230,6 +248,7 @@ choice_option_list:
        | choice_option_list depends
        | choice_option_list help
        | choice_option_list T_EOL
+       | choice_option_list option_error
 ;
 
 choice_option: T_PROMPT prompt if_expr T_EOL
@@ -267,18 +286,17 @@ choice_option: T_DEFAULT T_WORD if_expr T_EOL
 
 choice_block:
          /* empty */
-       | choice_block common_block
+       | choice_block common_stmt
 ;
 
 /* if entry */
 
-if: T_IF expr T_EOL
+if_entry: T_IF expr nl
 {
        printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
        menu_add_entry(NULL);
        menu_add_dep($2);
-       menu_end_entry();
-       menu_add_menu();
+       $$ = menu_add_menu();
 };
 
 if_end: end
@@ -289,17 +307,12 @@ if_end: end
        }
 };
 
-if_stmt:
-         if if_block if_end
-       | if if_block
-{
-       printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
-       zconfnerrs++;
-};
+if_stmt: if_entry if_block if_end
+;
 
 if_block:
          /* empty */
-       | if_block common_block
+       | if_block common_stmt
        | if_block menu_stmt
        | if_block choice_stmt
 ;
@@ -315,8 +328,7 @@ menu: T_MENU prompt T_EOL
 
 menu_entry: menu depends_list
 {
-       menu_end_entry();
-       menu_add_menu();
+       $$ = menu_add_menu();
 };
 
 menu_end: end
@@ -327,31 +339,20 @@ menu_end: end
        }
 };
 
-menu_stmt:
-         menu_entry menu_block menu_end
-       | menu_entry menu_block
-{
-       printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
-       zconfnerrs++;
-};
+menu_stmt: menu_entry menu_block menu_end
+;
 
 menu_block:
          /* empty */
-       | menu_block common_block
+       | menu_block common_stmt
        | menu_block menu_stmt
        | menu_block choice_stmt
-       | menu_block error T_EOL                { zconfprint("invalid menu option"); yyerrok; }
 ;
 
-source: T_SOURCE prompt T_EOL
+source_stmt: T_SOURCE prompt T_EOL
 {
-       $$ = $2;
        printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
-};
-
-source_stmt: source
-{
-       zconf_nextfile($1);
+       zconf_nextfile($2);
 };
 
 /* comment entry */
@@ -383,9 +384,11 @@ help: help_start T_HELPTEXT
 
 /* depends option */
 
-depends_list:    /* empty */
-               | depends_list depends
-               | depends_list T_EOL
+depends_list:
+         /* empty */
+       | depends_list depends
+       | depends_list T_EOL
+       | depends_list option_error
 ;
 
 depends: T_DEPENDS T_ON expr T_EOL
@@ -417,13 +420,15 @@ prompt:     T_WORD
        | T_WORD_QUOTE
 ;
 
-end:     T_ENDMENU nl_or_eof   { $$ = T_ENDMENU; }
-       | T_ENDCHOICE nl_or_eof { $$ = T_ENDCHOICE; }
-       | T_ENDIF nl_or_eof     { $$ = T_ENDIF; }
+end:     T_ENDMENU T_EOL       { $$ = $1; }
+       | T_ENDCHOICE T_EOL     { $$ = $1; }
+       | T_ENDIF T_EOL         { $$ = $1; }
 ;
 
-nl_or_eof:
-       T_EOL | T_EOF;
+nl:
+         T_EOL
+       | nl T_EOL
+;
 
 if_expr:  /* empty */                  { $$ = NULL; }
        | T_IF expr                     { $$ = $2; }
@@ -456,7 +461,10 @@ void conf_parse(const char *name)
        modules_sym = sym_lookup("MODULES", 0);
        rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
-       //zconfdebug = 1;
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
        zconfparse();
        if (zconfnerrs)
                exit(1);
@@ -477,20 +485,25 @@ const char *zconf_tokenname(int token)
        case T_ENDCHOICE:       return "endchoice";
        case T_IF:              return "if";
        case T_ENDIF:           return "endif";
+       case T_DEPENDS:         return "depends";
        }
        return "<token>";
 }
 
-static bool zconf_endtoken(int token, int starttoken, int endtoken)
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
 {
-       if (token != endtoken) {
-               zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken));
+       if (id->token != endtoken) {
+               zconf_error("unexpected '%s' within %s block",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
                zconfnerrs++;
                return false;
        }
        if (current_menu->file != current_file) {
-               zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken));
-               zconfprint("location of the '%s'", zconf_tokenname(starttoken));
+               zconf_error("'%s' in different file than '%s'",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               fprintf(stderr, "%s:%d: location of the '%s'\n",
+                       current_menu->file->name, current_menu->lineno,
+                       zconf_tokenname(starttoken));
                zconfnerrs++;
                return false;
        }
@@ -501,7 +514,19 @@ static void zconfprint(const char *err, ...)
 {
        va_list ap;
 
-       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1);
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+       va_list ap;
+
+       zconfnerrs++;
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
        va_start(ap, err);
        vfprintf(stderr, err, ap);
        va_end(ap);
@@ -510,7 +535,9 @@ static void zconfprint(const char *err, ...)
 
 static void zconferror(const char *err)
 {
+#if YYDEBUG
        fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
 }
 
 void print_quoted_string(FILE *out, const char *str)