1665 lines
36 KiB
Text
1665 lines
36 KiB
Text
# Exercising Bison Grammar Reduction. -*- Autotest -*-
|
|
|
|
# Copyright (C) 2001-2002, 2007-2012 Free Software Foundation, Inc.
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
AT_BANNER([[Grammar Reduction.]])
|
|
|
|
|
|
## ------------------- ##
|
|
## Useless Terminals. ##
|
|
## ------------------- ##
|
|
|
|
AT_SETUP([Useless Terminals])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%verbose
|
|
%output "input.c"
|
|
|
|
%token useless1
|
|
%token useless2
|
|
%token useless3
|
|
%token useless4
|
|
%token useless5
|
|
%token useless6
|
|
%token useless7
|
|
%token useless8
|
|
%token useless9
|
|
|
|
%token useful
|
|
%%
|
|
exp: useful;
|
|
]])
|
|
|
|
AT_BISON_CHECK([[input.y]])
|
|
|
|
AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0,
|
|
[[Terminals unused in grammar
|
|
useless1
|
|
useless2
|
|
useless3
|
|
useless4
|
|
useless5
|
|
useless6
|
|
useless7
|
|
useless8
|
|
useless9
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
## ---------------------- ##
|
|
## Useless Nonterminals. ##
|
|
## ---------------------- ##
|
|
|
|
AT_SETUP([Useless Nonterminals])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%verbose
|
|
%output "input.c"
|
|
|
|
%nterm useless1
|
|
%nterm useless2
|
|
%nterm useless3
|
|
%nterm useless4
|
|
%nterm useless5
|
|
%nterm useless6
|
|
%nterm useless7
|
|
%nterm useless8
|
|
%nterm useless9
|
|
|
|
%token useful
|
|
%%
|
|
exp: useful;
|
|
]])
|
|
|
|
AT_BISON_CHECK([[input.y]], 0, [],
|
|
[[input.y: warning: 9 nonterminals useless in grammar
|
|
input.y:4.8-15: warning: nonterminal useless in grammar: useless1
|
|
input.y:5.8-15: warning: nonterminal useless in grammar: useless2
|
|
input.y:6.8-15: warning: nonterminal useless in grammar: useless3
|
|
input.y:7.8-15: warning: nonterminal useless in grammar: useless4
|
|
input.y:8.8-15: warning: nonterminal useless in grammar: useless5
|
|
input.y:9.8-15: warning: nonterminal useless in grammar: useless6
|
|
input.y:10.8-15: warning: nonterminal useless in grammar: useless7
|
|
input.y:11.8-15: warning: nonterminal useless in grammar: useless8
|
|
input.y:12.8-15: warning: nonterminal useless in grammar: useless9
|
|
]])
|
|
|
|
AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0,
|
|
[[Nonterminals useless in grammar
|
|
useless1
|
|
useless2
|
|
useless3
|
|
useless4
|
|
useless5
|
|
useless6
|
|
useless7
|
|
useless8
|
|
useless9
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
## --------------- ##
|
|
## Useless Rules. ##
|
|
## --------------- ##
|
|
|
|
AT_SETUP([Useless Rules])
|
|
|
|
AT_KEYWORDS([report])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%verbose
|
|
%output "input.c"
|
|
%token useful
|
|
%%
|
|
exp: useful;
|
|
useless1: '1';
|
|
useless2: '2';
|
|
useless3: '3';
|
|
useless4: '4';
|
|
useless5: '5';
|
|
useless6: '6';
|
|
useless7: '7';
|
|
useless8: '8';
|
|
useless9: '9';
|
|
]])
|
|
|
|
AT_BISON_CHECK([[-fcaret input.y]], 0, [],
|
|
[[input.y: warning: 9 nonterminals useless in grammar
|
|
input.y: warning: 9 rules useless in grammar
|
|
input.y:6.1-8: warning: nonterminal useless in grammar: useless1
|
|
useless1: '1';
|
|
^^^^^^^^
|
|
input.y:7.1-8: warning: nonterminal useless in grammar: useless2
|
|
useless2: '2';
|
|
^^^^^^^^
|
|
input.y:8.1-8: warning: nonterminal useless in grammar: useless3
|
|
useless3: '3';
|
|
^^^^^^^^
|
|
input.y:9.1-8: warning: nonterminal useless in grammar: useless4
|
|
useless4: '4';
|
|
^^^^^^^^
|
|
input.y:10.1-8: warning: nonterminal useless in grammar: useless5
|
|
useless5: '5';
|
|
^^^^^^^^
|
|
input.y:11.1-8: warning: nonterminal useless in grammar: useless6
|
|
useless6: '6';
|
|
^^^^^^^^
|
|
input.y:12.1-8: warning: nonterminal useless in grammar: useless7
|
|
useless7: '7';
|
|
^^^^^^^^
|
|
input.y:13.1-8: warning: nonterminal useless in grammar: useless8
|
|
useless8: '8';
|
|
^^^^^^^^
|
|
input.y:14.1-8: warning: nonterminal useless in grammar: useless9
|
|
useless9: '9';
|
|
^^^^^^^^
|
|
input.y:6.11-13: warning: rule useless in grammar
|
|
useless1: '1';
|
|
^^^
|
|
input.y:7.11-13: warning: rule useless in grammar
|
|
useless2: '2';
|
|
^^^
|
|
input.y:8.11-13: warning: rule useless in grammar
|
|
useless3: '3';
|
|
^^^
|
|
input.y:9.11-13: warning: rule useless in grammar
|
|
useless4: '4';
|
|
^^^
|
|
input.y:10.11-13: warning: rule useless in grammar
|
|
useless5: '5';
|
|
^^^
|
|
input.y:11.11-13: warning: rule useless in grammar
|
|
useless6: '6';
|
|
^^^
|
|
input.y:12.11-13: warning: rule useless in grammar
|
|
useless7: '7';
|
|
^^^
|
|
input.y:13.11-13: warning: rule useless in grammar
|
|
useless8: '8';
|
|
^^^
|
|
input.y:14.11-13: warning: rule useless in grammar
|
|
useless9: '9';
|
|
^^^
|
|
]])
|
|
|
|
AT_BISON_CHECK([[input.y]], 0, [],
|
|
[[input.y: warning: 9 nonterminals useless in grammar
|
|
input.y: warning: 9 rules useless in grammar
|
|
input.y:6.1-8: warning: nonterminal useless in grammar: useless1
|
|
input.y:7.1-8: warning: nonterminal useless in grammar: useless2
|
|
input.y:8.1-8: warning: nonterminal useless in grammar: useless3
|
|
input.y:9.1-8: warning: nonterminal useless in grammar: useless4
|
|
input.y:10.1-8: warning: nonterminal useless in grammar: useless5
|
|
input.y:11.1-8: warning: nonterminal useless in grammar: useless6
|
|
input.y:12.1-8: warning: nonterminal useless in grammar: useless7
|
|
input.y:13.1-8: warning: nonterminal useless in grammar: useless8
|
|
input.y:14.1-8: warning: nonterminal useless in grammar: useless9
|
|
input.y:6.11-13: warning: rule useless in grammar: useless1: '1'
|
|
input.y:7.11-13: warning: rule useless in grammar: useless2: '2'
|
|
input.y:8.11-13: warning: rule useless in grammar: useless3: '3'
|
|
input.y:9.11-13: warning: rule useless in grammar: useless4: '4'
|
|
input.y:10.11-13: warning: rule useless in grammar: useless5: '5'
|
|
input.y:11.11-13: warning: rule useless in grammar: useless6: '6'
|
|
input.y:12.11-13: warning: rule useless in grammar: useless7: '7'
|
|
input.y:13.11-13: warning: rule useless in grammar: useless8: '8'
|
|
input.y:14.11-13: warning: rule useless in grammar: useless9: '9'
|
|
]])
|
|
|
|
AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0,
|
|
[[Nonterminals useless in grammar
|
|
useless1
|
|
useless2
|
|
useless3
|
|
useless4
|
|
useless5
|
|
useless6
|
|
useless7
|
|
useless8
|
|
useless9
|
|
Terminals unused in grammar
|
|
'1'
|
|
'2'
|
|
'3'
|
|
'4'
|
|
'5'
|
|
'6'
|
|
'7'
|
|
'8'
|
|
'9'
|
|
Rules useless in grammar
|
|
2 useless1: '1'
|
|
3 useless2: '2'
|
|
4 useless3: '3'
|
|
5 useless4: '4'
|
|
6 useless5: '5'
|
|
7 useless6: '6'
|
|
8 useless7: '7'
|
|
9 useless8: '8'
|
|
10 useless9: '9'
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
## ------------------- ##
|
|
## Reduced Automaton. ##
|
|
## ------------------- ##
|
|
|
|
# Check that the automaton is that as the for the grammar reduced by
|
|
# hand.
|
|
|
|
AT_SETUP([Reduced Automaton])
|
|
|
|
AT_KEYWORDS([report])
|
|
|
|
# The non reduced grammar.
|
|
# ------------------------
|
|
AT_DATA([[not-reduced.y]],
|
|
[[/* A useless token. */
|
|
%token useless_token
|
|
/* A useful one. */
|
|
%token useful
|
|
%verbose
|
|
%output "not-reduced.c"
|
|
|
|
%%
|
|
|
|
exp: useful { /* A useful action. */ }
|
|
| non_productive { /* A non productive action. */ }
|
|
;
|
|
|
|
not_reachable: useful { /* A not reachable action. */ }
|
|
;
|
|
|
|
non_productive: non_productive useless_token
|
|
{ /* Another non productive action. */ }
|
|
;
|
|
%%
|
|
]])
|
|
|
|
AT_BISON_CHECK([[-fcaret not-reduced.y]], 0, [],
|
|
[[not-reduced.y: warning: 2 nonterminals useless in grammar
|
|
not-reduced.y: warning: 3 rules useless in grammar
|
|
not-reduced.y:14.1-13: warning: nonterminal useless in grammar: not_reachable
|
|
not_reachable: useful { /* A not reachable action. */ }
|
|
^^^^^^^^^^^^^
|
|
not-reduced.y:11.6-19: warning: nonterminal useless in grammar: non_productive
|
|
| non_productive { /* A non productive action. */ }
|
|
^^^^^^^^^^^^^^
|
|
not-reduced.y:11.6-57: warning: rule useless in grammar
|
|
| non_productive { /* A non productive action. */ }
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
not-reduced.y:14.16-56: warning: rule useless in grammar
|
|
not_reachable: useful { /* A not reachable action. */ }
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
not-reduced.y:17.17-18.63: warning: rule useless in grammar
|
|
non_productive: non_productive useless_token
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
]])
|
|
|
|
AT_BISON_CHECK([[not-reduced.y]], 0, [],
|
|
[[not-reduced.y: warning: 2 nonterminals useless in grammar
|
|
not-reduced.y: warning: 3 rules useless in grammar
|
|
not-reduced.y:14.1-13: warning: nonterminal useless in grammar: not_reachable
|
|
not-reduced.y:11.6-19: warning: nonterminal useless in grammar: non_productive
|
|
not-reduced.y:11.6-57: warning: rule useless in grammar: exp: non_productive
|
|
not-reduced.y:14.16-56: warning: rule useless in grammar: not_reachable: useful
|
|
not-reduced.y:17.17-18.63: warning: rule useless in grammar: non_productive: non_productive useless_token
|
|
]])
|
|
|
|
AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' not-reduced.output]], 0,
|
|
[[Nonterminals useless in grammar
|
|
not_reachable
|
|
non_productive
|
|
Terminals unused in grammar
|
|
useless_token
|
|
Rules useless in grammar
|
|
2 exp: non_productive
|
|
3 not_reachable: useful
|
|
4 non_productive: non_productive useless_token
|
|
]])
|
|
|
|
# The reduced grammar.
|
|
# --------------------
|
|
AT_DATA([[reduced.y]],
|
|
[[/* A useless token. */
|
|
%token useless_token
|
|
/* A useful one. */
|
|
%token useful
|
|
%verbose
|
|
%output "reduced.c"
|
|
|
|
%%
|
|
|
|
exp: useful { /* A useful action. */ }
|
|
// | non_productive { /* A non productive action. */ } */
|
|
;
|
|
|
|
//not_reachable: useful { /* A not reachable action. */ }
|
|
// ;
|
|
|
|
//non_productive: non_productive useless_token
|
|
// { /* Another non productive action. */ }
|
|
// ;
|
|
%%
|
|
]])
|
|
|
|
AT_BISON_CHECK([[reduced.y]])
|
|
|
|
# Comparing the parsers.
|
|
cp reduced.c expout
|
|
AT_CHECK([sed 's/not-reduced/reduced/g' not-reduced.c], 0, [expout])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
## ------------------- ##
|
|
## Underivable Rules. ##
|
|
## ------------------- ##
|
|
|
|
AT_SETUP([Underivable Rules])
|
|
|
|
AT_KEYWORDS([report])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%verbose
|
|
%output "input.c"
|
|
%token useful
|
|
%%
|
|
exp: useful | underivable;
|
|
underivable: indirection;
|
|
indirection: underivable;
|
|
]])
|
|
|
|
AT_BISON_CHECK([[input.y]], 0, [],
|
|
[[input.y: warning: 2 nonterminals useless in grammar
|
|
input.y: warning: 3 rules useless in grammar
|
|
input.y:5.15-25: warning: nonterminal useless in grammar: underivable
|
|
input.y:6.14-24: warning: nonterminal useless in grammar: indirection
|
|
input.y:5.15-25: warning: rule useless in grammar: exp: underivable
|
|
input.y:6.14-24: warning: rule useless in grammar: underivable: indirection
|
|
input.y:7.14-24: warning: rule useless in grammar: indirection: underivable
|
|
]])
|
|
|
|
AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0,
|
|
[[Nonterminals useless in grammar
|
|
underivable
|
|
indirection
|
|
Rules useless in grammar
|
|
2 exp: underivable
|
|
3 underivable: indirection
|
|
4 indirection: underivable
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
## ---------------- ##
|
|
## Empty Language. ##
|
|
## ---------------- ##
|
|
|
|
AT_SETUP([Empty Language])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%output "input.c"
|
|
%%
|
|
exp: exp;
|
|
]])
|
|
|
|
AT_BISON_CHECK([[input.y]], 1, [],
|
|
[[input.y: warning: 2 nonterminals useless in grammar
|
|
input.y: warning: 2 rules useless in grammar
|
|
input.y:3.1-3: fatal error: start symbol exp does not derive any sentence
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
## ----------------- ##
|
|
## %define lr.type. ##
|
|
## ----------------- ##
|
|
|
|
# AT_TEST_LR_TYPE(DESCRIPTION,
|
|
# DECLS, GRAMMAR, INPUT,
|
|
# BISON-STDERR, TABLES,
|
|
# [OTHER-CHECKS],
|
|
# [PARSER-EXIT-VALUE],
|
|
# [PARSER-STDOUT], [PARSER-STDERR])
|
|
# -------------------------------------------------
|
|
m4_define([AT_TEST_LR_TYPE],
|
|
[
|
|
AT_TEST_TABLES_AND_PARSE([[no %define lr.type: ]$1],
|
|
[[LALR]], [[]],
|
|
[$2], m4_shiftn(2, $@))
|
|
AT_TEST_TABLES_AND_PARSE([[%define lr.type lalr: ]$1],
|
|
[[LALR]], [[]],
|
|
[[%define lr.type lalr
|
|
]$2],
|
|
m4_shiftn(2, $@))
|
|
AT_TEST_TABLES_AND_PARSE([[%define lr.type ielr: ]$1],
|
|
[[IELR]], [[]],
|
|
[[%define lr.type ielr
|
|
]$2],
|
|
m4_shiftn(2, $@))
|
|
AT_TEST_TABLES_AND_PARSE([[%define lr.type canonical-lr: ]$1],
|
|
[[canonical LR]], [[]],
|
|
[[%define lr.type canonical-lr
|
|
]$2],
|
|
m4_shiftn(2, $@))
|
|
])
|
|
|
|
AT_TEST_LR_TYPE([[Single State Split]],
|
|
[[%left 'a'
|
|
// Conflict resolution renders state 12 unreachable for canonical LR(1). We
|
|
// keep it so that the paser table diff is easier to code.
|
|
%define lr.keep-unreachable-states]],
|
|
[[
|
|
S: 'a' A 'a' /* rule 1 */
|
|
| 'b' A 'b' /* rule 2 */
|
|
| 'c' c /* rule 3 */
|
|
;
|
|
|
|
/* A conflict should appear after the first 'a' in rules 4 and 5 but only after
|
|
having shifted the first 'a' in rule 1. However, when LALR(1) merging is
|
|
chosen, the state containing that conflict is reused after having seen the
|
|
first 'b' in rule 2 and then the first 'a' in rules 4 and 5. In both cases,
|
|
because of the merged state, if the next token is an 'a', the %left forces a
|
|
reduction action with rule 5. In the latter case, only a shift is actually
|
|
grammatically correct. Thus, the parser would report a syntax error for the
|
|
grammatically correct sentence "baab" because it would encounter a syntax
|
|
error after that incorrect reduction.
|
|
|
|
Despite not being LALR(1), Menhir version 20070322 suffers from this problem
|
|
as well. It uses David Pager's weak compatibility test for merging states.
|
|
Bison and Menhir accept non-LR(1) grammars with conflict resolution. Pager
|
|
designed his algorithm only for LR(1) grammars. */
|
|
A: 'a' 'a' /* rule 4 */
|
|
| 'a' /* rule 5 */
|
|
;
|
|
|
|
/* Rule 3, rule 6, and rule 7 ensure that Bison does not report rule 4 as
|
|
useless after conflict resolution. This proves that, even though LALR(1)
|
|
generates incorrect parser tables sometimes, Bison will not necessarily
|
|
produce any warning to help the user realize it. */
|
|
c: 'a' 'b' /* rule 6 */
|
|
| A /* rule 7 */
|
|
;
|
|
]],
|
|
|
|
dnl INPUT
|
|
[['b', 'a', 'a', 'b']],
|
|
|
|
dnl BISON-STDERR
|
|
[],
|
|
|
|
dnl TABLES
|
|
[[State 0
|
|
|
|
0 $accept: . S $end
|
|
1 S: . 'a' A 'a'
|
|
2 | . 'b' A 'b'
|
|
3 | . 'c' c
|
|
|
|
'a' shift, and go to state 1
|
|
'b' shift, and go to state 2
|
|
'c' shift, and go to state 3
|
|
|
|
S go to state 4
|
|
|
|
|
|
State 1
|
|
|
|
1 S: 'a' . A 'a'
|
|
4 A: . 'a' 'a'
|
|
5 | . 'a'
|
|
|
|
'a' shift, and go to state 5
|
|
|
|
A go to state 6
|
|
|
|
|
|
State 2
|
|
|
|
2 S: 'b' . A 'b'
|
|
4 A: . 'a' 'a'
|
|
5 | . 'a'
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[LALR]], [[5]], [[16]])[
|
|
|
|
A go to state 7
|
|
|
|
|
|
State 3
|
|
|
|
3 S: 'c' . c
|
|
4 A: . 'a' 'a'
|
|
5 | . 'a'
|
|
6 c: . 'a' 'b'
|
|
7 | . A
|
|
|
|
'a' shift, and go to state 8
|
|
|
|
A go to state 9
|
|
c go to state 10
|
|
|
|
|
|
State 4
|
|
|
|
0 $accept: S . $end
|
|
|
|
$end shift, and go to state 11
|
|
|
|
|
|
State 5
|
|
|
|
4 A: 'a' . 'a'
|
|
5 | 'a' . ]AT_COND_CASE([[LALR]], [[['a', 'b']]], [[['a']]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['a']],
|
|
[[$default]])[ reduce using rule 5 (A)
|
|
|
|
Conflict between rule 5 and token 'a' resolved as reduce (%left 'a').
|
|
|
|
|
|
State 6
|
|
|
|
1 S: 'a' A . 'a'
|
|
|
|
'a' shift, and go to state 13
|
|
|
|
|
|
State 7
|
|
|
|
2 S: 'b' A . 'b'
|
|
|
|
'b' shift, and go to state 14
|
|
|
|
|
|
State 8
|
|
|
|
4 A: 'a' . 'a'
|
|
5 | 'a' . [$end]
|
|
6 c: 'a' . 'b'
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[17]],
|
|
[[12]])[
|
|
'b' shift, and go to state 15
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 5 (A)
|
|
|
|
|
|
State 9
|
|
|
|
7 c: A .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 7 (c)
|
|
|
|
|
|
State 10
|
|
|
|
3 S: 'c' c .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 3 (S)
|
|
|
|
|
|
State 11
|
|
|
|
0 $accept: S $end .
|
|
|
|
$default accept
|
|
|
|
|
|
State 12
|
|
|
|
4 A: 'a' 'a' .]AT_COND_CASE([[canonical LR]], [[ ['a']]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['a']],
|
|
[[$default]])[ reduce using rule 4 (A)
|
|
|
|
|
|
State 13
|
|
|
|
1 S: 'a' A 'a' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 1 (S)
|
|
|
|
|
|
State 14
|
|
|
|
2 S: 'b' A 'b' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 2 (S)
|
|
|
|
|
|
State 15
|
|
|
|
6 c: 'a' 'b' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 6 (c)]AT_COND_CASE([[LALR]],
|
|
[[]], [[
|
|
|
|
|
|
State 16
|
|
|
|
4 A: 'a' . 'a'
|
|
5 | 'a' . ['b']
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[18]],
|
|
[[12]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['b']],
|
|
[[$default]])[ reduce using rule 5 (A)]AT_COND_CASE([[canonical LR]], [[
|
|
|
|
|
|
State 17
|
|
|
|
4 A: 'a' 'a' . [$end]
|
|
|
|
$end reduce using rule 4 (A)
|
|
|
|
|
|
State 18
|
|
|
|
4 A: 'a' 'a' . ['b']
|
|
|
|
'b' reduce using rule 4 (A)]])])[
|
|
]],
|
|
|
|
dnl OTHER-CHECKS
|
|
[],
|
|
|
|
dnl PARSER-EXIT-VALUE, PARSER-STDOUT, PARSER-STDERR
|
|
[AT_COND_CASE([[LALR]], [[1]], [[0]])],
|
|
[],
|
|
[AT_COND_CASE([[LALR]],
|
|
[[syntax error
|
|
]])])
|
|
|
|
AT_TEST_LR_TYPE([[Lane Split]],
|
|
[[%left 'a'
|
|
// Conflict resolution renders state 16 unreachable for canonical LR(1). We
|
|
// keep it so that the paser table diff is easier to code.
|
|
%define lr.keep-unreachable-states]],
|
|
[[
|
|
/* Similar to the last test case set but two states must be split. */
|
|
S: 'a' A 'a' /* rule 1 */
|
|
| 'b' A 'b' /* rule 2 */
|
|
| 'c' c /* rule 3 */
|
|
;
|
|
|
|
A: 'a' 'a' 'a' /* rule 4 */
|
|
| 'a' 'a' /* rule 5 */
|
|
;
|
|
|
|
c: 'a' 'a' 'b' /* rule 6 */
|
|
| A /* rule 7 */
|
|
;
|
|
]],
|
|
|
|
dnl INPUT
|
|
[['b', 'a', 'a', 'a', 'b']],
|
|
|
|
dnl BISON-STDERR
|
|
[],
|
|
|
|
dnl TABLES
|
|
[[State 0
|
|
|
|
0 $accept: . S $end
|
|
1 S: . 'a' A 'a'
|
|
2 | . 'b' A 'b'
|
|
3 | . 'c' c
|
|
|
|
'a' shift, and go to state 1
|
|
'b' shift, and go to state 2
|
|
'c' shift, and go to state 3
|
|
|
|
S go to state 4
|
|
|
|
|
|
State 1
|
|
|
|
1 S: 'a' . A 'a'
|
|
4 A: . 'a' 'a' 'a'
|
|
5 | . 'a' 'a'
|
|
|
|
'a' shift, and go to state 5
|
|
|
|
A go to state 6
|
|
|
|
|
|
State 2
|
|
|
|
2 S: 'b' . A 'b'
|
|
4 A: . 'a' 'a' 'a'
|
|
5 | . 'a' 'a'
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[LALR]], [[5]], [[18]])[
|
|
|
|
A go to state 7
|
|
|
|
|
|
State 3
|
|
|
|
3 S: 'c' . c
|
|
4 A: . 'a' 'a' 'a'
|
|
5 | . 'a' 'a'
|
|
6 c: . 'a' 'a' 'b'
|
|
7 | . A
|
|
|
|
'a' shift, and go to state 8
|
|
|
|
A go to state 9
|
|
c go to state 10
|
|
|
|
|
|
State 4
|
|
|
|
0 $accept: S . $end
|
|
|
|
$end shift, and go to state 11
|
|
|
|
|
|
State 5
|
|
|
|
4 A: 'a' . 'a' 'a'
|
|
5 | 'a' . 'a'
|
|
|
|
'a' shift, and go to state 12
|
|
|
|
|
|
State 6
|
|
|
|
1 S: 'a' A . 'a'
|
|
|
|
'a' shift, and go to state 13
|
|
|
|
|
|
State 7
|
|
|
|
2 S: 'b' A . 'b'
|
|
|
|
'b' shift, and go to state 14
|
|
|
|
|
|
State 8
|
|
|
|
4 A: 'a' . 'a' 'a'
|
|
5 | 'a' . 'a'
|
|
6 c: 'a' . 'a' 'b'
|
|
|
|
'a' shift, and go to state 15
|
|
|
|
|
|
State 9
|
|
|
|
7 c: A .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 7 (c)
|
|
|
|
|
|
State 10
|
|
|
|
3 S: 'c' c .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 3 (S)
|
|
|
|
|
|
State 11
|
|
|
|
0 $accept: S $end .
|
|
|
|
$default accept
|
|
|
|
|
|
State 12
|
|
|
|
4 A: 'a' 'a' . 'a'
|
|
5 | 'a' 'a' . ]AT_COND_CASE([[LALR]], [[['a', 'b']]], [[['a']]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['a']],
|
|
[[$default]])[ reduce using rule 5 (A)
|
|
|
|
Conflict between rule 5 and token 'a' resolved as reduce (%left 'a').
|
|
|
|
|
|
State 13
|
|
|
|
1 S: 'a' A 'a' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 1 (S)
|
|
|
|
|
|
State 14
|
|
|
|
2 S: 'b' A 'b' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 2 (S)
|
|
|
|
|
|
State 15
|
|
|
|
4 A: 'a' 'a' . 'a'
|
|
5 | 'a' 'a' . [$end]
|
|
6 c: 'a' 'a' . 'b'
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[19]],
|
|
[[16]])[
|
|
'b' shift, and go to state 17
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 5 (A)
|
|
|
|
|
|
State 16
|
|
|
|
4 A: 'a' 'a' 'a' .]AT_COND_CASE([[canonical LR]], [[ ['a']]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['a']],
|
|
[[$default]])[ reduce using rule 4 (A)
|
|
|
|
|
|
State 17
|
|
|
|
6 c: 'a' 'a' 'b' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 6 (c)]AT_COND_CASE([[LALR]],
|
|
[[]], [[
|
|
|
|
|
|
State 18
|
|
|
|
4 A: 'a' . 'a' 'a'
|
|
5 | 'a' . 'a'
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[20]],
|
|
[[19]])[
|
|
|
|
|
|
State 19]AT_COND_CASE([[canonical LR]], [[
|
|
|
|
4 A: 'a' 'a' 'a' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 4 (A)
|
|
|
|
|
|
State 20]])[
|
|
|
|
4 A: 'a' 'a' . 'a'
|
|
5 | 'a' 'a' . ['b']
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[21]],
|
|
[[16]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['b']],
|
|
[[$default]])[ reduce using rule 5 (A)]AT_COND_CASE([[canonical LR]], [[
|
|
|
|
|
|
State 21
|
|
|
|
4 A: 'a' 'a' 'a' .]AT_COND_CASE([[canonical LR]], [[ ['b']]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['b']],
|
|
[[$default]])[ reduce using rule 4 (A)]])])[
|
|
]],
|
|
|
|
dnl OTHER-CHECKS
|
|
[],
|
|
|
|
dnl PARSER-EXIT-VALUE, PARSER-STDOUT, PARSER-STDERR
|
|
[AT_COND_CASE([[LALR]], [[1]], [[0]])],
|
|
[],
|
|
[AT_COND_CASE([[LALR]],
|
|
[[syntax error
|
|
]])])
|
|
|
|
AT_TEST_LR_TYPE([[Complex Lane Split]],
|
|
[[%left 'a'
|
|
// Conflict resolution renders state 16 unreachable for canonical LR(1). We
|
|
// keep it so that the paser table diff is easier to code.
|
|
%define lr.keep-unreachable-states]],
|
|
[[
|
|
/* Similar to the last test case set but forseeing the S/R conflict from the
|
|
first state that must be split is becoming difficult. Imagine if B were
|
|
even more complex. Imagine if A had other RHS's ending in other
|
|
nonterminals. */
|
|
S: 'a' A 'a'
|
|
| 'b' A 'b'
|
|
| 'c' c
|
|
;
|
|
A: 'a' 'a' B
|
|
;
|
|
B: 'a'
|
|
| %prec 'a'
|
|
;
|
|
c: 'a' 'a' 'b'
|
|
| A
|
|
;
|
|
]],
|
|
|
|
dnl INPUT
|
|
[['b', 'a', 'a', 'a', 'b']],
|
|
|
|
dnl BISON-STDERR
|
|
[],
|
|
|
|
dnl TABLES
|
|
[[State 0
|
|
|
|
0 $accept: . S $end
|
|
1 S: . 'a' A 'a'
|
|
2 | . 'b' A 'b'
|
|
3 | . 'c' c
|
|
|
|
'a' shift, and go to state 1
|
|
'b' shift, and go to state 2
|
|
'c' shift, and go to state 3
|
|
|
|
S go to state 4
|
|
|
|
|
|
State 1
|
|
|
|
1 S: 'a' . A 'a'
|
|
4 A: . 'a' 'a' B
|
|
|
|
'a' shift, and go to state 5
|
|
|
|
A go to state 6
|
|
|
|
|
|
State 2
|
|
|
|
2 S: 'b' . A 'b'
|
|
4 A: . 'a' 'a' B
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[LALR]], [[5]], [[19]])[
|
|
|
|
A go to state 7
|
|
|
|
|
|
State 3
|
|
|
|
3 S: 'c' . c
|
|
4 A: . 'a' 'a' B
|
|
7 c: . 'a' 'a' 'b'
|
|
8 | . A
|
|
|
|
'a' shift, and go to state 8
|
|
|
|
A go to state 9
|
|
c go to state 10
|
|
|
|
|
|
State 4
|
|
|
|
0 $accept: S . $end
|
|
|
|
$end shift, and go to state 11
|
|
|
|
|
|
State 5
|
|
|
|
4 A: 'a' . 'a' B
|
|
|
|
'a' shift, and go to state 12
|
|
|
|
|
|
State 6
|
|
|
|
1 S: 'a' A . 'a'
|
|
|
|
'a' shift, and go to state 13
|
|
|
|
|
|
State 7
|
|
|
|
2 S: 'b' A . 'b'
|
|
|
|
'b' shift, and go to state 14
|
|
|
|
|
|
State 8
|
|
|
|
4 A: 'a' . 'a' B
|
|
7 c: 'a' . 'a' 'b'
|
|
|
|
'a' shift, and go to state 15
|
|
|
|
|
|
State 9
|
|
|
|
8 c: A .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 8 (c)
|
|
|
|
|
|
State 10
|
|
|
|
3 S: 'c' c .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 3 (S)
|
|
|
|
|
|
State 11
|
|
|
|
0 $accept: S $end .
|
|
|
|
$default accept
|
|
|
|
|
|
State 12
|
|
|
|
4 A: 'a' 'a' . B
|
|
5 B: . 'a'
|
|
6 | . ]AT_COND_CASE([[LALR]], [[['a', 'b']]], [[['a']]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['a']],
|
|
[[$default]])[ reduce using rule 6 (B)
|
|
|
|
B go to state 17
|
|
|
|
Conflict between rule 6 and token 'a' resolved as reduce (%left 'a').
|
|
|
|
|
|
State 13
|
|
|
|
1 S: 'a' A 'a' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 1 (S)
|
|
|
|
|
|
State 14
|
|
|
|
2 S: 'b' A 'b' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 2 (S)
|
|
|
|
|
|
State 15
|
|
|
|
4 A: 'a' 'a' . B
|
|
5 B: . 'a'
|
|
6 | . [$end]
|
|
7 c: 'a' 'a' . 'b'
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[20]],
|
|
[[16]])[
|
|
'b' shift, and go to state 18
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 6 (B)
|
|
|
|
B go to state ]AT_COND_CASE([[canonical LR]], [[21]], [[17]])[
|
|
|
|
|
|
State 16
|
|
|
|
5 B: 'a' .]AT_COND_CASE([[canonical LR]], [[ ['a']]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['a']],
|
|
[[$default]])[ reduce using rule 5 (B)
|
|
|
|
|
|
State 17
|
|
|
|
4 A: 'a' 'a' B .]AT_COND_CASE([[canonical LR]], [[ ['a']]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['a']],
|
|
[[$default]])[ reduce using rule 4 (A)
|
|
|
|
|
|
State 18
|
|
|
|
7 c: 'a' 'a' 'b' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 7 (c)]AT_COND_CASE([[LALR]], [], [[
|
|
|
|
|
|
State 19
|
|
|
|
4 A: 'a' . 'a' B
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[22]],
|
|
[[20]])[
|
|
|
|
|
|
State 20]AT_COND_CASE([[canonical LR]], [[
|
|
|
|
5 B: 'a' . [$end]
|
|
|
|
$end reduce using rule 5 (B)
|
|
|
|
|
|
State 21
|
|
|
|
4 A: 'a' 'a' B . [$end]
|
|
|
|
$end reduce using rule 4 (A)
|
|
|
|
|
|
State 22]])[
|
|
|
|
4 A: 'a' 'a' . B
|
|
5 B: . 'a'
|
|
6 | . ['b']
|
|
|
|
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[23]],
|
|
[[16]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [['b']],
|
|
[[$default]])[ reduce using rule 6 (B)
|
|
|
|
B go to state ]AT_COND_CASE([[canonical LR]], [[24
|
|
|
|
|
|
State 23
|
|
|
|
5 B: 'a' . ['b']
|
|
|
|
'b' reduce using rule 5 (B)
|
|
|
|
|
|
State 24
|
|
|
|
4 A: 'a' 'a' B . ['b']
|
|
|
|
'b' reduce using rule 4 (A)]], [[17]])])[
|
|
]],
|
|
|
|
dnl OTHER-CHECKS
|
|
[],
|
|
|
|
dnl PARSER-EXIT-VALUE, PARSER-STDOUT, PARSER-STDERR
|
|
[AT_COND_CASE([[LALR]], [[1]], [[0]])],
|
|
[],
|
|
[AT_COND_CASE([[LALR]],
|
|
[[syntax error
|
|
]])])
|
|
|
|
AT_TEST_LR_TYPE([[Split During Added Lookahead Propagation]],
|
|
[[%define lr.keep-unreachable-states]],
|
|
[[
|
|
/* The partial state chart diagram below is for LALR(1). State 0 is the start
|
|
state. States are iterated for successor construction in numerical order.
|
|
Transitions are downwards.
|
|
|
|
State 13 has a R/R conflict that cannot be predicted by Bison's LR(1)
|
|
algorithm using annotations alone. That is, when state 11's successor on
|
|
'd' is merged with state 5 (which is originally just state 1's successor on
|
|
'd'), state 5's successor on 'e' must then be changed because the resulting
|
|
lookaheads that propagate to it now make it incompatible with state 8's
|
|
successor on 'e'. In other words, state 13 must be split to avoid the
|
|
conflict.
|
|
|
|
0
|
|
/ | \
|
|
a / c| \ b
|
|
1 3 2
|
|
| | |
|
|
d| |c | d
|
|
| 11 |
|
|
| | |
|
|
\ /d |
|
|
5 8
|
|
\ |
|
|
e \ / e
|
|
13
|
|
R/R
|
|
|
|
This grammar is designed carefully to make sure that, despite Bison's LR(1)
|
|
algorithm's bread-first iteration of transitions to reconstruct states,
|
|
state 11's successors are constructed after state 5's and state 8's.
|
|
Otherwise (for example, if you remove the first 'c' in each of rules 6 and
|
|
7), state 5's successor on 'e' would never be merged with state 8's, so the
|
|
split of the resulting state 13 would never need to be performed. */
|
|
S: 'a' A 'f'
|
|
| 'a' B
|
|
| 'b' A 'f'
|
|
| 'b' B 'g'
|
|
| 'b' 'd'
|
|
| 'c' 'c' A 'g'
|
|
| 'c' 'c' B
|
|
;
|
|
A: 'd' 'e' ;
|
|
B: 'd' 'e' ;
|
|
]],
|
|
|
|
dnl INPUT
|
|
[['b', 'd', 'e', 'g']],
|
|
|
|
dnl BISON-STDERR
|
|
[AT_COND_CASE([[LALR]],
|
|
[[input.y: conflicts: 1 reduce/reduce
|
|
]], [])],
|
|
|
|
dnl TABLES
|
|
[[State 0
|
|
|
|
0 $accept: . S $end
|
|
1 S: . 'a' A 'f'
|
|
2 | . 'a' B
|
|
3 | . 'b' A 'f'
|
|
4 | . 'b' B 'g'
|
|
5 | . 'b' 'd'
|
|
6 | . 'c' 'c' A 'g'
|
|
7 | . 'c' 'c' B
|
|
|
|
'a' shift, and go to state 1
|
|
'b' shift, and go to state 2
|
|
'c' shift, and go to state 3
|
|
|
|
S go to state 4
|
|
|
|
|
|
State 1
|
|
|
|
1 S: 'a' . A 'f'
|
|
2 | 'a' . B
|
|
8 A: . 'd' 'e'
|
|
9 B: . 'd' 'e'
|
|
|
|
'd' shift, and go to state 5
|
|
|
|
A go to state 6
|
|
B go to state 7
|
|
|
|
|
|
State 2
|
|
|
|
3 S: 'b' . A 'f'
|
|
4 | 'b' . B 'g'
|
|
5 | 'b' . 'd'
|
|
8 A: . 'd' 'e'
|
|
9 B: . 'd' 'e'
|
|
|
|
'd' shift, and go to state 8
|
|
|
|
A go to state 9
|
|
B go to state 10
|
|
|
|
|
|
State 3
|
|
|
|
6 S: 'c' . 'c' A 'g'
|
|
7 | 'c' . 'c' B
|
|
|
|
'c' shift, and go to state 11
|
|
|
|
|
|
State 4
|
|
|
|
0 $accept: S . $end
|
|
|
|
$end shift, and go to state 12
|
|
|
|
|
|
State 5
|
|
|
|
8 A: 'd' . 'e'
|
|
9 B: 'd' . 'e'
|
|
|
|
'e' shift, and go to state ]AT_COND_CASE([[LALR]], [[13]],
|
|
[[canonical LR]], [[13]],
|
|
[[20]])[
|
|
|
|
|
|
State 6
|
|
|
|
1 S: 'a' A . 'f'
|
|
|
|
'f' shift, and go to state 14
|
|
|
|
|
|
State 7
|
|
|
|
2 S: 'a' B .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 2 (S)
|
|
|
|
|
|
State 8
|
|
|
|
5 S: 'b' 'd' . [$end]
|
|
8 A: 'd' . 'e'
|
|
9 B: 'd' . 'e'
|
|
|
|
'e' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[20]],
|
|
[[13]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 5 (S)
|
|
|
|
|
|
State 9
|
|
|
|
3 S: 'b' A . 'f'
|
|
|
|
'f' shift, and go to state 15
|
|
|
|
|
|
State 10
|
|
|
|
4 S: 'b' B . 'g'
|
|
|
|
'g' shift, and go to state 16
|
|
|
|
|
|
State 11
|
|
|
|
6 S: 'c' 'c' . A 'g'
|
|
7 | 'c' 'c' . B
|
|
8 A: . 'd' 'e'
|
|
9 B: . 'd' 'e'
|
|
|
|
'd' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[21]],
|
|
[[5]])[
|
|
|
|
A go to state 17
|
|
B go to state 18
|
|
|
|
|
|
State 12
|
|
|
|
0 $accept: S $end .
|
|
|
|
$default accept]AT_COND_CASE([[LALR]], [[
|
|
|
|
|
|
State 13
|
|
|
|
8 A: 'd' 'e' . ['f', 'g']
|
|
9 B: 'd' 'e' . [$end, 'g']
|
|
|
|
$end reduce using rule 9 (B)
|
|
'g' reduce using rule 8 (A)
|
|
'g' [reduce using rule 9 (B)]
|
|
$default reduce using rule 8 (A)]], [[
|
|
|
|
|
|
State 13
|
|
|
|
8 A: 'd' 'e' . ['f']
|
|
9 B: 'd' 'e' . ]AT_COND_CASE([[canonical LR]], [[[$end]]], [[['g']]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[['g' ]])[ reduce using rule 9 (B)
|
|
]AT_COND_CASE([[canonical LR]], [['f' ]],
|
|
[[$default]])[ reduce using rule 8 (A)]])[
|
|
|
|
|
|
State 14
|
|
|
|
1 S: 'a' A 'f' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 1 (S)
|
|
|
|
|
|
State 15
|
|
|
|
3 S: 'b' A 'f' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 3 (S)
|
|
|
|
|
|
State 16
|
|
|
|
4 S: 'b' B 'g' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 4 (S)
|
|
|
|
|
|
State 17
|
|
|
|
6 S: 'c' 'c' A . 'g'
|
|
|
|
'g' shift, and go to state 19
|
|
|
|
|
|
State 18
|
|
|
|
7 S: 'c' 'c' B .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 7 (S)
|
|
|
|
|
|
State 19
|
|
|
|
6 S: 'c' 'c' A 'g' .]AT_COND_CASE([[canonical LR]], [[ [$end]]])[
|
|
|
|
]AT_COND_CASE([[canonical LR]], [[$end]],
|
|
[[$default]])[ reduce using rule 6 (S)]AT_COND_CASE([[LALR]],
|
|
[[]], [[
|
|
|
|
|
|
State 20]AT_COND_CASE([[canonical LR]], [[
|
|
|
|
8 A: 'd' 'e' . ['f']
|
|
9 B: 'd' 'e' . ['g']
|
|
|
|
'f' reduce using rule 8 (A)
|
|
'g' reduce using rule 9 (B)
|
|
|
|
|
|
State 21
|
|
|
|
8 A: 'd' . 'e'
|
|
9 B: 'd' . 'e'
|
|
|
|
'e' shift, and go to state 22
|
|
|
|
|
|
State 22
|
|
|
|
8 A: 'd' 'e' . ['g']
|
|
9 B: 'd' 'e' . [$end]
|
|
|
|
$end reduce using rule 9 (B)
|
|
'g' reduce using rule 8 (A)]], [[
|
|
|
|
8 A: 'd' 'e' . ['f', 'g']
|
|
9 B: 'd' 'e' . [$end]
|
|
|
|
$end reduce using rule 9 (B)
|
|
$default reduce using rule 8 (A)]])])[
|
|
]],
|
|
|
|
dnl OTHER-CHECKS
|
|
[],
|
|
|
|
dnl PARSER-EXIT-VALUE, PARSER-STDOUT, PARSER-STDERR
|
|
[AT_COND_CASE([[LALR]], [[1]], [[0]])],
|
|
[],
|
|
[AT_COND_CASE([[LALR]],
|
|
[[syntax error
|
|
]])])
|
|
|
|
|
|
|
|
## ------------------------------- ##
|
|
## %define lr.default-reductions. ##
|
|
## ------------------------------- ##
|
|
|
|
# AT_TEST_LR_DEFAULT_REDUCTIONS(GRAMMAR, INPUT, TABLES)
|
|
# -----------------------------------------------------
|
|
m4_define([AT_TEST_LR_DEFAULT_REDUCTIONS],
|
|
[
|
|
AT_TEST_TABLES_AND_PARSE([[no %define lr.default-reductions]],
|
|
[[most]], [[]],
|
|
[[]],
|
|
[$1], [$2], [[]], [$3])
|
|
AT_TEST_TABLES_AND_PARSE([[%define lr.default-reductions most]],
|
|
[[most]], [[]],
|
|
[[%define lr.default-reductions most]],
|
|
[$1], [$2], [[]], [$3])
|
|
AT_TEST_TABLES_AND_PARSE([[%define lr.default-reductions consistent]],
|
|
[[consistent]], [[]],
|
|
[[%define lr.default-reductions consistent]],
|
|
[$1], [$2], [[]], [$3])
|
|
AT_TEST_TABLES_AND_PARSE([[%define lr.default-reductions accepting]],
|
|
[[accepting]], [[]],
|
|
[[%define lr.default-reductions accepting]],
|
|
[$1], [$2], [[]], [$3])
|
|
])
|
|
|
|
AT_TEST_LR_DEFAULT_REDUCTIONS([[
|
|
/* The start state is consistent and has a shift on 'a' and no reductions.
|
|
After pushing the b below, enter an inconsistent state that has a shift and
|
|
one reduction with one lookahead. */
|
|
start:
|
|
a b
|
|
| a b 'a'
|
|
| a c 'b'
|
|
;
|
|
|
|
/* After shifting this 'a', enter a consistent state that has no shift and 1
|
|
reduction with multiple lookaheads. */
|
|
a: 'a' ;
|
|
|
|
/* After the previous reduction, enter an inconsistent state that has no shift
|
|
and multiple reductions. The first reduction has more lookaheads than the
|
|
second, so the first should always be preferred as the default reduction if
|
|
enabled. The second reduction has one lookahead. */
|
|
b: ;
|
|
c: ;
|
|
]],
|
|
dnl Visit each state mentioned above.
|
|
[['a', 'a']],
|
|
[[State 0
|
|
|
|
0 $accept: . start $end
|
|
1 start: . a b
|
|
2 | . a b 'a'
|
|
3 | . a c 'b'
|
|
4 a: . 'a'
|
|
|
|
'a' shift, and go to state 1
|
|
|
|
start go to state 2
|
|
a go to state 3
|
|
|
|
|
|
State 1
|
|
|
|
4 a: 'a' .]AT_COND_CASE([[accepting]], [[ [$end, 'a', 'b']
|
|
|
|
$end reduce using rule 4 (a)
|
|
'a' reduce using rule 4 (a)
|
|
'b' reduce using rule 4 (a)]], [[
|
|
|
|
$default reduce using rule 4 (a)]])[
|
|
|
|
|
|
State 2
|
|
|
|
0 $accept: start . $end
|
|
|
|
$end shift, and go to state 4
|
|
|
|
|
|
State 3
|
|
|
|
1 start: a . b
|
|
2 | a . b 'a'
|
|
3 | a . c 'b'
|
|
5 b: . [$end, 'a']
|
|
6 c: . ['b']]AT_COND_CASE([[most]], [[
|
|
|
|
'b' reduce using rule 6 (c)
|
|
$default reduce using rule 5 (b)]], [[
|
|
|
|
$end reduce using rule 5 (b)
|
|
'a' reduce using rule 5 (b)
|
|
'b' reduce using rule 6 (c)]])[
|
|
|
|
b go to state 5
|
|
c go to state 6
|
|
|
|
|
|
State 4
|
|
|
|
0 $accept: start $end .
|
|
|
|
$default accept
|
|
|
|
|
|
State 5
|
|
|
|
1 start: a b . [$end]
|
|
2 | a b . 'a'
|
|
|
|
'a' shift, and go to state 7
|
|
|
|
]AT_COND_CASE([[most]], [[$default]],
|
|
[[$end]])[ reduce using rule 1 (start)
|
|
|
|
|
|
State 6
|
|
|
|
3 start: a c . 'b'
|
|
|
|
'b' shift, and go to state 8
|
|
|
|
|
|
State 7
|
|
|
|
2 start: a b 'a' .]AT_COND_CASE([[accepting]], [[ [$end]
|
|
|
|
$end reduce using rule 2 (start)]], [[
|
|
|
|
$default reduce using rule 2 (start)]])[
|
|
|
|
|
|
State 8
|
|
|
|
3 start: a c 'b' .]AT_COND_CASE([[accepting]], [[ [$end]
|
|
|
|
$end reduce using rule 3 (start)]], [[
|
|
|
|
$default reduce using rule 3 (start)]])[
|
|
]])
|