[PATCH] kconfig: improve error handling in the parser

Add a few error tokens to the parser to catch common errors and print more
descriptive error messages.

Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Cc: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Roman Zippel 2005-11-08 21:34:53 -08:00 коммит произвёл Linus Torvalds
Родитель 3370f9f0d9
Коммит a02f0570ae
6 изменённых файлов: 546 добавлений и 452 удалений

Просмотреть файл

@ -323,7 +323,7 @@ void zconffree (void * );
/* Begin user sect3 */ /* Begin user sect3 */
#define zconfwrap(n) 1 #define zconfwrap() 1
#define YY_SKIP_YYWRAP #define YY_SKIP_YYWRAP
typedef unsigned char YY_CHAR; typedef unsigned char YY_CHAR;
@ -686,10 +686,10 @@ struct yy_trans_info
static yyconst flex_int16_t yy_accept[61] = static yyconst flex_int16_t yy_accept[61] =
{ 0, { 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
34, 5, 4, 3, 2, 7, 8, 6, 32, 29, 34, 5, 4, 2, 3, 7, 8, 6, 32, 29,
31, 24, 28, 27, 26, 22, 17, 13, 16, 20, 31, 24, 28, 27, 26, 22, 17, 13, 16, 20,
22, 11, 12, 19, 19, 14, 22, 22, 4, 3, 22, 11, 12, 19, 19, 14, 22, 22, 4, 2,
2, 2, 1, 6, 32, 29, 31, 30, 24, 23, 3, 3, 1, 6, 32, 29, 31, 30, 24, 23,
26, 25, 15, 20, 9, 19, 19, 21, 10, 18 26, 25, 15, 20, 9, 19, 19, 21, 10, 18
} ; } ;
@ -753,6 +753,11 @@ char *zconftext;
#define START_STRSIZE 16 #define START_STRSIZE 16
static struct {
struct file *file;
int lineno;
} current_pos;
static char *text; static char *text;
static int text_size, text_asize; static int text_size, text_asize;
@ -766,7 +771,7 @@ struct buffer *current_buf;
static int last_ts, first_ts; static int last_ts, first_ts;
static void zconf_endhelp(void); static void zconf_endhelp(void);
static struct buffer *zconf_endfile(void); static void zconf_endfile(void);
void new_string(void) void new_string(void)
{ {
@ -993,17 +998,17 @@ do_action: /* This label is used only to access EOF actions. */
{ /* beginning of action switch */ { /* beginning of action switch */
case 1: case 1:
/* rule 1 can match eol */ /* rule 1 can match eol */
YY_RULE_SETUP
current_file->lineno++;
YY_BREAK
case 2: case 2:
/* rule 2 can match eol */
YY_RULE_SETUP YY_RULE_SETUP
{
current_file->lineno++;
return T_EOL;
}
YY_BREAK YY_BREAK
case 3: case 3:
/* rule 3 can match eol */
YY_RULE_SETUP YY_RULE_SETUP
current_file->lineno++; return T_EOL;
YY_BREAK YY_BREAK
case 4: case 4:
YY_RULE_SETUP YY_RULE_SETUP
@ -1023,8 +1028,10 @@ case 6:
YY_RULE_SETUP YY_RULE_SETUP
{ {
struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
BEGIN(PARAM);
current_pos.file = current_file;
current_pos.lineno = current_file->lineno;
if (id && id->flags & TF_COMMAND) { if (id && id->flags & TF_COMMAND) {
BEGIN(PARAM);
zconflval.id = id; zconflval.id = id;
return id->token; return id->token;
} }
@ -1040,7 +1047,11 @@ YY_RULE_SETUP
case 8: case 8:
/* rule 8 can match eol */ /* rule 8 can match eol */
YY_RULE_SETUP YY_RULE_SETUP
current_file->lineno++; BEGIN(INITIAL); {
BEGIN(INITIAL);
current_file->lineno++;
return T_EOL;
}
YY_BREAK YY_BREAK
case 9: case 9:
@ -1246,9 +1257,9 @@ case YY_STATE_EOF(HELP):
case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(INITIAL):
case YY_STATE_EOF(COMMAND): case YY_STATE_EOF(COMMAND):
{ {
if (current_buf) { if (current_file) {
zconf_endfile(); zconf_endfile();
return T_EOF; return T_EOL;
} }
fclose(zconfin); fclose(zconfin);
yyterminate(); yyterminate();
@ -1958,7 +1969,7 @@ YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size )
/** Setup the input buffer state to scan a string. The next call to zconflex() will /** Setup the input buffer state to scan a string. The next call to zconflex() will
* scan from a @e copy of @a str. * scan from a @e copy of @a str.
* @param str a NUL-terminated string to scan * @param yy_str a NUL-terminated string to scan
* *
* @return the newly allocated buffer state object. * @return the newly allocated buffer state object.
* @note If you want to scan bytes that may contain NUL values, then use * @note If you want to scan bytes that may contain NUL values, then use
@ -2276,7 +2287,7 @@ void zconf_nextfile(const char *name)
current_file = file; current_file = file;
} }
static struct buffer *zconf_endfile(void) static void zconf_endfile(void)
{ {
struct buffer *parent; struct buffer *parent;
@ -2292,23 +2303,15 @@ static struct buffer *zconf_endfile(void)
} }
free(current_buf); free(current_buf);
current_buf = parent; current_buf = parent;
return parent;
} }
int zconf_lineno(void) int zconf_lineno(void)
{ {
if (current_buf) return current_pos.lineno;
return current_file->lineno - 1;
else
return 0;
} }
char *zconf_curname(void) char *zconf_curname(void)
{ {
if (current_buf) return current_pos.file ? current_pos.file->name : "<none>";
return current_file->name;
else
return "<none>";
} }

Просмотреть файл

@ -70,7 +70,7 @@ void kconfig_load(void);
/* menu.c */ /* menu.c */
void menu_init(void); void menu_init(void);
void menu_add_menu(void); struct menu *menu_add_menu(void);
void menu_end_menu(void); void menu_end_menu(void);
void menu_add_entry(struct symbol *sym); void menu_add_entry(struct symbol *sym);
void menu_end_entry(void); void menu_end_entry(void);

Просмотреть файл

@ -61,10 +61,11 @@ void menu_end_entry(void)
{ {
} }
void menu_add_menu(void) struct menu *menu_add_menu(void)
{ {
current_menu = current_entry; menu_end_entry();
last_entry_ptr = &current_entry->list; last_entry_ptr = &current_entry->list;
return current_menu = current_entry;
} }
void menu_end_menu(void) void menu_end_menu(void)

Просмотреть файл

@ -18,6 +18,11 @@
#define START_STRSIZE 16 #define START_STRSIZE 16
static struct {
struct file *file;
int lineno;
} current_pos;
static char *text; static char *text;
static int text_size, text_asize; static int text_size, text_asize;
@ -31,7 +36,7 @@ struct buffer *current_buf;
static int last_ts, first_ts; static int last_ts, first_ts;
static void zconf_endhelp(void); static void zconf_endhelp(void);
static struct buffer *zconf_endfile(void); static void zconf_endfile(void);
void new_string(void) void new_string(void)
{ {
@ -70,10 +75,13 @@ n [A-Za-z0-9_]
int str = 0; int str = 0;
int ts, i; int ts, i;
[ \t]*#.*\n current_file->lineno++; [ \t]*#.*\n |
[ \t]*\n {
current_file->lineno++;
return T_EOL;
}
[ \t]*#.* [ \t]*#.*
[ \t]*\n current_file->lineno++; return T_EOL;
[ \t]+ { [ \t]+ {
BEGIN(COMMAND); BEGIN(COMMAND);
@ -88,8 +96,10 @@ n [A-Za-z0-9_]
<COMMAND>{ <COMMAND>{
{n}+ { {n}+ {
struct kconf_id *id = kconf_id_lookup(yytext, yyleng); struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
BEGIN(PARAM);
current_pos.file = current_file;
current_pos.lineno = current_file->lineno;
if (id && id->flags & TF_COMMAND) { if (id && id->flags & TF_COMMAND) {
BEGIN(PARAM);
zconflval.id = id; zconflval.id = id;
return id->token; return id->token;
} }
@ -98,7 +108,11 @@ n [A-Za-z0-9_]
return T_WORD; return T_WORD;
} }
. .
\n current_file->lineno++; BEGIN(INITIAL); \n {
BEGIN(INITIAL);
current_file->lineno++;
return T_EOL;
}
} }
<PARAM>{ <PARAM>{
@ -214,9 +228,9 @@ n [A-Za-z0-9_]
} }
<<EOF>> { <<EOF>> {
if (current_buf) { if (current_file) {
zconf_endfile(); zconf_endfile();
return T_EOF; return T_EOL;
} }
fclose(yyin); fclose(yyin);
yyterminate(); yyterminate();
@ -307,7 +321,7 @@ void zconf_nextfile(const char *name)
current_file = file; current_file = file;
} }
static struct buffer *zconf_endfile(void) static void zconf_endfile(void)
{ {
struct buffer *parent; struct buffer *parent;
@ -323,22 +337,14 @@ static struct buffer *zconf_endfile(void)
} }
free(current_buf); free(current_buf);
current_buf = parent; current_buf = parent;
return parent;
} }
int zconf_lineno(void) int zconf_lineno(void)
{ {
if (current_buf) return current_pos.lineno;
return current_file->lineno - 1;
else
return 0;
} }
char *zconf_curname(void) char *zconf_curname(void)
{ {
if (current_buf) return current_pos.file ? current_pos.file->name : "<none>";
return current_file->name;
else
return "<none>";
} }

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

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