Path: csiph.com!xmission!news.snarked.org!news.linkpendium.com!news.linkpendium.com!panix!usenet.stanford.edu!not-for-mail From: worley@alum.mit.edu (Dale R. Worley) Newsgroups: gnu.bash.bug Subject: Removing the shift/reduce conflict in the parser Date: Sun, 26 Apr 2020 20:14:33 -0400 Lines: 68 Approved: bug-bash@gnu.org Message-ID: References: <871ro9zswm.fsf@hobgoblin.ariadne.com> NNTP-Posting-Host: lists.gnu.org X-Trace: usenet.stanford.edu 1587946484 26445 209.51.188.17 (27 Apr 2020 00:14:44 GMT) X-Complaints-To: action@cs.stanford.edu To: bug-bash@gnu.org Envelope-to: bug-bash@gnu.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=comcastmailservice.net; s=20180828_2048; t=1587946475; bh=TlTyD4bYg5HU6gtjc+e3M2BzT315YIn+/YxBNbErZ7Y=; h=Received:Received:Received:Received:From:To:Subject:Date: Message-ID; b=X5FXpQEkdNE4FGEnkjUR5I5+nyrNSbq9TnkZLs5KwY7nPzEiHrmOStPrmi0YCo1o5 TSNGBVfbwLDhbGDXSa1qbLE97F9MHqtx1CCgBaRh4KqEKESUBdb81RkAn4Kv10gTua 7V9Z/d88RHY/Z47ltD0q+rwb5V+EXShSG4Y+sFOwn5+jwHzLsf/E4yF3b84woRl7ye JVuJaaJ+E3NazvcTnkDtXGgJLmz14KEL7hLYinE8m7cvMYD1egWKwTQIygRwM/czYP vguiOlo46i2FCCsVcLxd3oIA605BO6Ox/rgb78YwIQYnQYunk1BTu7Ipt20kNMp0Ge sja9OivYoVSNg== X-Xfinity-VMeta: sc=0.00;st=legit X-Authentication-Warning: hobgoblin.ariadne.com: worley set sender to worley@alum.mit.edu using -f Received-SPF: softfail client-ip=2001:558:fe21:29:69:252:207:39; envelope-from=worley@alum.mit.edu; helo=resqmta-ch2-07v.sys.comcast.net X-detected-operating-system: by eggs.gnu.org: First seen = 2020/04/26 20:14:35 X-ACL-Warn: Detected OS = ??? X-Received-From: 2001:558:fe21:29:69:252:207:39 X-BeenThere: bug-bash@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Bug reports for the GNU Bourne Again SHell List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Mailman-Original-Message-ID: <871ro9zswm.fsf@hobgoblin.ariadne.com> Xref: csiph.com gnu.bash.bug:16245 I've been annoyed by the fact that parse.y has a shift/reduce conflict. It stems from the grammar for a function declaration: function_def: WORD '(' ')' newline_list function_body | FUNCTION WORD '(' ')' newline_list function_body | FUNCTION WORD newline_list function_body ; You can see the problem by running "bison --report=state -y -d ./parse.y" and looking at y.output. The difficulty being that when the parser is standing here: FUNCTION WORD '(' ^ it can't tell whether it is before the () of the second alternative, or it is before a function_body which is a "subshell" (a list of commands in (...)), a version of the third alternative. In the latter case, the parser has to generate an empty newline_list before it can consume the '('. It turns out that the solution is simple: Separate the third alternative into two, one of which has no newline_list (the case of the original 3rd alternative where newline_list is empty), and one in which the newline_list is not empty: function_def: WORD '(' ')' newline_list function_body | FUNCTION WORD '(' ')' newline_list function_body | FUNCTION WORD function_body | FUNCTION WORD '\n' newline_list function_body ; In the state that caused the conflict before, the parser no longer has to decide whether to generate a newline_list, it can shift the '(' and look at the following token before deciding what the situation is (whether it is now inside a function_body or still working its way through the function header). I've appended the patch to fix this. In the patch, I also remove a couple of empty lines that don't conform to the overall conventions of the file. Dale ---------------------------------------------------------------------- diff --git a/parse.y b/parse.y index 3ff87bc..75b6957 100644 --- a/parse.y +++ b/parse.y @@ -926,12 +926,12 @@ case_command: CASE WORD newline_list IN newline_list ESAC function_def: WORD '(' ')' newline_list function_body { $$ = make_function_def ($1, $5, function_dstart, function_bstart); } - | FUNCTION WORD '(' ')' newline_list function_body { $$ = make_function_def ($2, $6, function_dstart, function_bstart); } - - | FUNCTION WORD newline_list function_body - { $$ = make_function_def ($2, $4, function_dstart, function_bstart); } + | FUNCTION WORD function_body + { $$ = make_function_def ($2, $3, function_dstart, function_bstart); } + | FUNCTION WORD '\n' newline_list function_body + { $$ = make_function_def ($2, $5, function_dstart, function_bstart); } ; function_body: shell_command [END]