History

kconfig: fix ambiguous grammar in terms of new lines

This commit decreases 8 shift/reduce conflicts. A certain amount of grammatical ambiguity comes from how to reduce excessive T_EOL tokens. Let's take a look at the example code below: 1 config A 2 bool "a" 3 4 depends on B 5 6 config B 7 def_bool y The line 3 is melt into "config_option_list", but the line 5 can be either a part of "config_option_list" or "common_stmt" by itself. Currently, the lexer converts '\n' to T_EOL verbatim. In Kconfig, a new line works as a statement terminator, but new lines in empty lines are not critical since empty lines (or lines that contain only whitespaces/comments) are just no-op. If the lexer simply discards no-op lines, the parser will not be bothered by excessive T_EOL tokens. Of course, this means we are shifting the complexity from the parser to the lexer, but it is much easier than tackling on shift/reduce conflicts. I introduced the second stage lexer to tweak the behavior. Discard T_EOL if the previous token is T_EOL or T_HELPTEXT. Two T_EOL tokens in a row is meaningless. T_HELPTEXT is a special token that is reduced without T_EOL.

Masahiro Yamada committed 7 years ago

Commit cc66bca1 parent 21c5ecf2 files · +24 −15Browse files

Showing the changes to scripts (2 of 2 files). Show all

Unified · Split

2 files
  1. scripts/kconfig/zconf.l +21 −0
  2. scripts/kconfig/zconf.y +3 −15
scripts/kconfig/zconf.l+21−0
@@ -16,6 +16,8 @@ · 15 unmodified lines
1616
1717 #include "lkc.h"
1818
19+#define YY_DECL static int yylex1(void)
20+
1921 #define START_STRSIZE 16
2022
2123 static struct {
@@ -23,6 +25,7 @@ static struct { · 1 unmodified line
2325 int lineno;
2426 } current_pos;
2527
28+static int prev_token = T_EOL;
2629 static char *text;
2730 static int text_size, text_asize;
2831
@@ -268,6 +271,24 @@ n [A-Za-z0-9_-] · 239 unmodified lines
268271 }
269272
270273 %%
274+
275+/* second stage lexer */
276+int yylex(void)
277+{
278+ int token;
279+
280+repeat:
281+ token = yylex1();
282+
283+ /* Do not pass unneeded T_EOL to the parser. */
284+ if ((prev_token == T_EOL || prev_token == T_HELPTEXT) && token == T_EOL)
285+ goto repeat;
286+
287+ prev_token = token;
288+
289+ return token;
290+}
291+
271292 static char *expand_token(const char *in, size_t n)
272293 {
273294 char *out;
scripts/kconfig/zconf.y+3−15
@@ -31,7 +31,7 @@ struct symbol *symbol_hash[SYMBOL_HASHSIZE]; · 30 unmodified lines
3131 static struct menu *current_menu, *current_entry;
3232
3333 %}
34−%expect 29
34+%expect 21
3535
3636 %union
3737 {
@@ -111,9 +111,7 @@ static struct menu *current_menu, *current_entry; · 73 unmodified lines
111111 %}
112112
113113 %%
114−input: nl start | start;
115−
116−start: mainmenu_stmt stmt_list | stmt_list;
114+input: mainmenu_stmt stmt_list | stmt_list;
117115
118116 /* mainmenu entry */
119117
@@ -141,8 +139,7 @@ option_name: · 21 unmodified lines
141139 ;
142140
143141 common_stmt:
144− T_EOL
145− | if_stmt
142+ if_stmt
146143 | comment_stmt
147144 | config_stmt
148145 | menuconfig_stmt
@@ -193,7 +190,6 @@ config_option_list: · 44 unmodified lines
193190 | config_option_list depends
194191 | config_option_list help
195192 | config_option_list option_error
196− | config_option_list T_EOL
197193 ;
198194
199195 config_option: T_TYPE prompt_stmt_opt T_EOL
@@ -293,7 +289,6 @@ choice_option_list: · 93 unmodified lines
293289 | choice_option_list choice_option
294290 | choice_option_list depends
295291 | choice_option_list help
296− | choice_option_list T_EOL
297292 | choice_option_list option_error
298293 ;
299294
@@ -443,7 +438,6 @@ help: help_start T_HELPTEXT · 143 unmodified lines
443438 depends_list:
444439 /* empty */
445440 | depends_list depends
446− | depends_list T_EOL
447441 | depends_list option_error
448442 ;
449443
@@ -458,7 +452,6 @@ depends: T_DEPENDS T_ON expr T_EOL · 8 unmodified lines
458452 visibility_list:
459453 /* empty */
460454 | visibility_list visible
461− | visibility_list T_EOL
462455 ;
463456
464457 visible: T_VISIBLE if_expr T_EOL
@@ -484,11 +477,6 @@ end: T_ENDMENU T_EOL { $$ = $1; } · 19 unmodified lines
484477 | T_ENDIF T_EOL { $$ = $1; }
485478 ;
486479
487−nl:
488− T_EOL
489− | nl T_EOL
490−;
491−
492480 if_expr: /* empty */ { $$ = NULL; }
493481 | T_IF expr { $$ = $2; }
494482 ;