Commit cc66bca7 authored by Masahiro Yamada's avatar Masahiro Yamada
Browse files

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.

Signed-off-by: default avatarMasahiro Yamada <yamada.masahiro@socionext.com>
parent 21c5ecf6
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

#include "lkc.h"

#define YY_DECL		static int yylex1(void)

#define START_STRSIZE	16

static struct {
@@ -23,6 +25,7 @@ static struct {
	int lineno;
} current_pos;

static int prev_token = T_EOL;
static char *text;
static int text_size, text_asize;

@@ -268,6 +271,24 @@ n [A-Za-z0-9_-]
}

%%

/* second stage lexer */
int yylex(void)
{
	int token;

repeat:
	token = yylex1();

	/* Do not pass unneeded T_EOL to the parser. */
	if ((prev_token == T_EOL || prev_token == T_HELPTEXT) && token == T_EOL)
		goto repeat;

	prev_token = token;

	return token;
}

static char *expand_token(const char *in, size_t n)
{
	char *out;
+3 −15
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ struct symbol *symbol_hash[SYMBOL_HASHSIZE];
static struct menu *current_menu, *current_entry;

%}
%expect 29
%expect 21

%union
{
@@ -111,9 +111,7 @@ static struct menu *current_menu, *current_entry;
%}

%%
input: nl start | start;

start: mainmenu_stmt stmt_list | stmt_list;
input: mainmenu_stmt stmt_list | stmt_list;

/* mainmenu entry */

@@ -141,8 +139,7 @@ option_name:
;

common_stmt:
	  T_EOL
	| if_stmt
	  if_stmt
	| comment_stmt
	| config_stmt
	| menuconfig_stmt
@@ -193,7 +190,6 @@ config_option_list:
	| config_option_list depends
	| config_option_list help
	| config_option_list option_error
	| config_option_list T_EOL
;

config_option: T_TYPE prompt_stmt_opt T_EOL
@@ -293,7 +289,6 @@ choice_option_list:
	| choice_option_list choice_option
	| choice_option_list depends
	| choice_option_list help
	| choice_option_list T_EOL
	| choice_option_list option_error
;

@@ -443,7 +438,6 @@ help: help_start T_HELPTEXT
depends_list:
	  /* empty */
	| depends_list depends
	| depends_list T_EOL
	| depends_list option_error
;

@@ -458,7 +452,6 @@ depends: T_DEPENDS T_ON expr T_EOL
visibility_list:
	  /* empty */
	| visibility_list visible
	| visibility_list T_EOL
;

visible: T_VISIBLE if_expr T_EOL
@@ -484,11 +477,6 @@ end: T_ENDMENU T_EOL { $$ = $1; }
	| T_ENDIF T_EOL		{ $$ = $1; }
;

nl:
	  T_EOL
	| nl T_EOL
;

if_expr:  /* empty */			{ $$ = NULL; }
	| T_IF expr			{ $$ = $2; }
;