Commit a02f0570 authored by Roman Zippel's avatar Roman Zippel Committed by Linus Torvalds

[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: default avatarRoman Zippel <zippel@linux-m68k.org>
Cc: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3370f9f0
......@@ -323,7 +323,7 @@ void zconffree (void * );
/* Begin user sect3 */
#define zconfwrap(n) 1
#define zconfwrap() 1
#define YY_SKIP_YYWRAP
typedef unsigned char YY_CHAR;
......@@ -686,10 +686,10 @@ struct yy_trans_info
static yyconst flex_int16_t yy_accept[61] =
{ 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,
22, 11, 12, 19, 19, 14, 22, 22, 4, 3,
2, 2, 1, 6, 32, 29, 31, 30, 24, 23,
22, 11, 12, 19, 19, 14, 22, 22, 4, 2,
3, 3, 1, 6, 32, 29, 31, 30, 24, 23,
26, 25, 15, 20, 9, 19, 19, 21, 10, 18
} ;
......@@ -753,6 +753,11 @@ char *zconftext;
#define START_STRSIZE 16
static struct {
struct file *file;
int lineno;
} current_pos;
static char *text;
static int text_size, text_asize;
......@@ -766,7 +771,7 @@ struct buffer *current_buf;
static int last_ts, first_ts;
static void zconf_endhelp(void);
static struct buffer *zconf_endfile(void);
static void zconf_endfile(void);
void new_string(void)
{
......@@ -993,17 +998,17 @@ do_action: /* This label is used only to access EOF actions. */
{ /* beginning of action switch */
case 1:
/* rule 1 can match eol */
YY_RULE_SETUP
current_file->lineno++;
YY_BREAK
case 2:
/* rule 2 can match eol */
YY_RULE_SETUP
{
current_file->lineno++;
return T_EOL;
}
YY_BREAK
case 3:
/* rule 3 can match eol */
YY_RULE_SETUP
current_file->lineno++; return T_EOL;
YY_BREAK
case 4:
YY_RULE_SETUP
......@@ -1023,8 +1028,10 @@ case 6:
YY_RULE_SETUP
{
struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
if (id && id->flags & TF_COMMAND) {
BEGIN(PARAM);
current_pos.file = current_file;
current_pos.lineno = current_file->lineno;
if (id && id->flags & TF_COMMAND) {
zconflval.id = id;
return id->token;
}
......@@ -1040,7 +1047,11 @@ YY_RULE_SETUP
case 8:
/* rule 8 can match eol */
YY_RULE_SETUP
current_file->lineno++; BEGIN(INITIAL);
{
BEGIN(INITIAL);
current_file->lineno++;
return T_EOL;
}
YY_BREAK
case 9:
......@@ -1246,9 +1257,9 @@ case YY_STATE_EOF(HELP):
case YY_STATE_EOF(INITIAL):
case YY_STATE_EOF(COMMAND):
{
if (current_buf) {
if (current_file) {
zconf_endfile();
return T_EOF;
return T_EOL;
}
fclose(zconfin);
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
* 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.
* @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;
}
static struct buffer *zconf_endfile(void)
static void zconf_endfile(void)
{
struct buffer *parent;
......@@ -2292,23 +2303,15 @@ static struct buffer *zconf_endfile(void)
}
free(current_buf);
current_buf = parent;
return parent;
}
int zconf_lineno(void)
{
if (current_buf)
return current_file->lineno - 1;
else
return 0;
return current_pos.lineno;
}
char *zconf_curname(void)
{
if (current_buf)
return current_file->name;
else
return "<none>";
return current_pos.file ? current_pos.file->name : "<none>";
}
......@@ -70,7 +70,7 @@ void kconfig_load(void);
/* menu.c */
void menu_init(void);
void menu_add_menu(void);
struct menu *menu_add_menu(void);
void menu_end_menu(void);
void menu_add_entry(struct symbol *sym);
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;
return current_menu = current_entry;
}
void menu_end_menu(void)
......
......@@ -18,6 +18,11 @@
#define START_STRSIZE 16
static struct {
struct file *file;
int lineno;
} current_pos;
static char *text;
static int text_size, text_asize;
......@@ -31,7 +36,7 @@ struct buffer *current_buf;
static int last_ts, first_ts;
static void zconf_endhelp(void);
static struct buffer *zconf_endfile(void);
static void zconf_endfile(void);
void new_string(void)
{
......@@ -70,10 +75,13 @@ n [A-Za-z0-9_]
int str = 0;
int ts, i;
[ \t]*#.*\n current_file->lineno++;
[ \t]*#.*\n |
[ \t]*\n {
current_file->lineno++;
return T_EOL;
}
[ \t]*#.*
[ \t]*\n current_file->lineno++; return T_EOL;
[ \t]+ {
BEGIN(COMMAND);
......@@ -88,8 +96,10 @@ n [A-Za-z0-9_]
<COMMAND>{
{n}+ {
struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
if (id && id->flags & TF_COMMAND) {
BEGIN(PARAM);
current_pos.file = current_file;
current_pos.lineno = current_file->lineno;
if (id && id->flags & TF_COMMAND) {
zconflval.id = id;
return id->token;
}
......@@ -98,7 +108,11 @@ n [A-Za-z0-9_]
return T_WORD;
}
.
\n current_file->lineno++; BEGIN(INITIAL);
\n {
BEGIN(INITIAL);
current_file->lineno++;
return T_EOL;
}
}
<PARAM>{
......@@ -214,9 +228,9 @@ n [A-Za-z0-9_]
}
<<EOF>> {
if (current_buf) {
if (current_file) {
zconf_endfile();
return T_EOF;
return T_EOL;
}
fclose(yyin);
yyterminate();
......@@ -307,7 +321,7 @@ void zconf_nextfile(const char *name)
current_file = file;
}
static struct buffer *zconf_endfile(void)
static void zconf_endfile(void)
{
struct buffer *parent;
......@@ -323,22 +337,14 @@ static struct buffer *zconf_endfile(void)
}
free(current_buf);
current_buf = parent;
return parent;
}
int zconf_lineno(void)
{
if (current_buf)
return current_file->lineno - 1;
else
return 0;
return current_pos.lineno;
}
char *zconf_curname(void)
{
if (current_buf)
return current_file->name;
else
return "<none>";
return current_pos.file ? current_pos.file->name : "<none>";
}
This diff is collapsed.
......@@ -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:
/* 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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment