mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-10 12:53:03 +00:00
See http://www.gnu.org/prep/maintain/maintain.html#Copyright-Notices * HACKING, Makefile.am, NEWS, PACKAGING, README, README-alpha: * TODO, bootstrap, bootstrap.conf: * build-aux/update-b4-copyright, cfg.mk, configure.ac: * data/README, data/bison.m4, data/c++-skel.m4, data/c++.m4: * data/c-skel.m4, data/c.m4, data/glr.c, data/glr.cc: * data/java-skel.m4, data/java.m4, data/lalr1.cc: * data/lalr1.java, data/location.cc: * data/xslt/bison.xsl: * data/xslt/xml2dot.xsl, data/xslt/xml2text.xsl: * data/xslt/xml2xhtml.xsl, data/yacc.c, djgpp/Makefile.maint: * djgpp/README.in, djgpp/config.bat, djgpp/config.sed: * djgpp/config.site, djgpp/config_h.sed, djgpp/djunpack.bat: * djgpp/subpipe.c, djgpp/subpipe.h: * djgpp/testsuite.sed, doc/bison.texinfo: * doc/refcard.tex, etc/README, etc/bench.pl.in: * examples/calc++/Makefile.am, examples/extexi: * lib/abitset.c, lib/abitset.h: * lib/bbitset.h, lib/bitset.c, lib/bitset.h: * lib/bitset_stats.c, lib/bitset_stats.h, lib/bitsetv-print.c: * lib/bitsetv-print.h, lib/bitsetv.c, lib/bitsetv.h: * lib/ebitset.c, lib/ebitset.h, lib/get-errno.c: * lib/get-errno.h, lib/lbitset.c, lib/lbitset.h: * lib/libiberty.h, lib/main.c, lib/timevar.c: * lib/timevar.def, lib/timevar.h, lib/vbitset.c: * lib/vbitset.h, lib/yyerror.c, m4/bison-i18n.m4: * m4/c-working.m4, m4/cxx.m4, m4/subpipe.m4, m4/timevar.m4: * src/LR0.c: * src/LR0.h, src/assoc.c: * src/assoc.h, src/closure.c, src/closure.h, src/complain.c: * src/complain.h, src/conflicts.c, src/conflicts.h: * src/derives.c, src/derives.h, src/files.c, src/files.h: * src/flex-scanner.h, src/getargs.c, src/getargs.h: * src/gram.c, src/gram.h, src/graphviz.c: * src/lalr.c, src/lalr.h: * src/location.c, src/location.h, src/main.c: * src/nullable.c, src/nullable.h: * src/output.c, src/output.h, src/parse-gram.y: * src/print-xml.c, src/print-xml.h, src/print.c, src/print.h: * src/print_graph.c, src/print_graph.h, src/reader.c: * src/reader.h, src/reduce.c, src/reduce.h, src/relation.c: * src/relation.h, src/scan-code.h, src/scan-code.l: * src/scan-gram.h, src/scan-gram.l, src/scan-skel.h: * src/scan-skel.l, src/state.c, src/state.h, src/symlist.c: * src/symlist.h, src/symtab.c, src/symtab.h, src/system.h: * src/tables.c, src/tables.h, src/uniqstr.c, src/uniqstr.h: * tests/actions.at, tests/atlocal.in, tests/c++.at: * tests/calc.at, tests/conflicts.at, tests/cxx-type.at: * tests/existing.at, tests/glr-regression.at: * tests/headers.at, tests/input.at, tests/java.at: * tests/local.at: * tests/output.at, tests/push.at, tests/reduce.at: * tests/regression.at, tests/sets.at, tests/skeletons.at: * tests/synclines.at, tests/testsuite.at, tests/torture.at: * data/Makefile.am, data/location.cc, doc/Makefile.am, src/Makefile.am: * tests/Makefile.am, lib/Makefile.am, examples/Makefile.am: * etc/Makefile.am, m4/m4.m4, src/muscle_tab.c, src/muscle_tab.h: Don't use date ranges in copyright notices. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
979 lines
19 KiB
Plaintext
979 lines
19 KiB
Plaintext
# Exercising Bison on conflicts. -*- Autotest -*-
|
|
|
|
# Copyright (C) 2002, 2003, 2004, 2005, 2007, 2009, 2010 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([[Conflicts.]])
|
|
|
|
|
|
## ---------------- ##
|
|
## S/R in initial. ##
|
|
## ---------------- ##
|
|
|
|
# I once hacked Bison in such a way that it lost its reductions on the
|
|
# initial state (because it was confusing it with the last state). It
|
|
# took me a while to strip down my failures to this simple case. So
|
|
# make sure it finds the s/r conflict below.
|
|
|
|
AT_SETUP([S/R in initial])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%expect 1
|
|
%%
|
|
exp: e 'e';
|
|
e: 'e' | /* Nothing. */;
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c input.y], 0, [],
|
|
[[input.y:4.9: warning: rule useless in parser due to conflicts: e: /* empty */
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
## ------------------- ##
|
|
## %nonassoc and eof. ##
|
|
## ------------------- ##
|
|
|
|
AT_SETUP([%nonassoc and eof])
|
|
|
|
AT_DATA_GRAMMAR([input.y],
|
|
[[
|
|
%{
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define YYERROR_VERBOSE 1
|
|
static void
|
|
yyerror (const char *msg)
|
|
{
|
|
fprintf (stderr, "%s\n", msg);
|
|
}
|
|
|
|
/* The current argument. */
|
|
static const char *input;
|
|
|
|
static int
|
|
yylex (void)
|
|
{
|
|
static size_t toknum;
|
|
if (! (toknum <= strlen (input)))
|
|
abort ();
|
|
return input[toknum++];
|
|
}
|
|
|
|
%}
|
|
|
|
%nonassoc '<' '>'
|
|
|
|
%%
|
|
expr: expr '<' expr
|
|
| expr '>' expr
|
|
| '0'
|
|
;
|
|
%%
|
|
int
|
|
main (int argc, const char *argv[])
|
|
{
|
|
input = argc <= 1 ? "" : argv[1];
|
|
return yyparse ();
|
|
}
|
|
]])
|
|
|
|
# Specify the output files to avoid problems on different file systems.
|
|
AT_BISON_CHECK([-o input.c input.y])
|
|
AT_COMPILE([input])
|
|
|
|
AT_PARSER_CHECK([./input '0<0'])
|
|
# FIXME: This is an actual bug, but a new one, in the sense that
|
|
# no one has ever spotted it! The messages are *wrong*: there should
|
|
# be nothing there, it should be expected eof.
|
|
AT_PARSER_CHECK([./input '0<0<0'], [1], [],
|
|
[syntax error, unexpected '<', expecting '<' or '>'
|
|
])
|
|
|
|
AT_PARSER_CHECK([./input '0>0'])
|
|
AT_PARSER_CHECK([./input '0>0>0'], [1], [],
|
|
[syntax error, unexpected '>', expecting '<' or '>'
|
|
])
|
|
|
|
AT_PARSER_CHECK([./input '0<0>0'], [1], [],
|
|
[syntax error, unexpected '>', expecting '<' or '>'
|
|
])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
## ------------------------- ##
|
|
## Unresolved SR Conflicts. ##
|
|
## ------------------------- ##
|
|
|
|
AT_SETUP([Unresolved SR Conflicts])
|
|
|
|
AT_KEYWORDS([report])
|
|
|
|
AT_DATA([input.y],
|
|
[[%token NUM OP
|
|
%%
|
|
exp: exp OP exp | NUM;
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c --report=all input.y], 0, [],
|
|
[input.y: conflicts: 1 shift/reduce
|
|
])
|
|
|
|
# Check the contents of the report.
|
|
AT_CHECK([cat input.output], [],
|
|
[[State 5 conflicts: 1 shift/reduce
|
|
|
|
|
|
Grammar
|
|
|
|
0 $accept: exp $end
|
|
|
|
1 exp: exp OP exp
|
|
2 | NUM
|
|
|
|
|
|
Terminals, with rules where they appear
|
|
|
|
$end (0) 0
|
|
error (256)
|
|
NUM (258) 2
|
|
OP (259) 1
|
|
|
|
|
|
Nonterminals, with rules where they appear
|
|
|
|
$accept (5)
|
|
on left: 0
|
|
exp (6)
|
|
on left: 1 2, on right: 0 1
|
|
|
|
|
|
state 0
|
|
|
|
0 $accept: . exp $end
|
|
1 exp: . exp OP exp
|
|
2 | . NUM
|
|
|
|
NUM shift, and go to state 1
|
|
|
|
exp go to state 2
|
|
|
|
|
|
state 1
|
|
|
|
2 exp: NUM .
|
|
|
|
$default reduce using rule 2 (exp)
|
|
|
|
|
|
state 2
|
|
|
|
0 $accept: exp . $end
|
|
1 exp: exp . OP exp
|
|
|
|
$end shift, and go to state 3
|
|
OP shift, and go to state 4
|
|
|
|
|
|
state 3
|
|
|
|
0 $accept: exp $end .
|
|
|
|
$default accept
|
|
|
|
|
|
state 4
|
|
|
|
1 exp: . exp OP exp
|
|
1 | exp OP . exp
|
|
2 | . NUM
|
|
|
|
NUM shift, and go to state 1
|
|
|
|
exp go to state 5
|
|
|
|
|
|
state 5
|
|
|
|
1 exp: exp . OP exp
|
|
1 | exp OP exp . [$end, OP]
|
|
|
|
OP shift, and go to state 4
|
|
|
|
OP [reduce using rule 1 (exp)]
|
|
$default reduce using rule 1 (exp)
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
## ----------------------- ##
|
|
## Resolved SR Conflicts. ##
|
|
## ----------------------- ##
|
|
|
|
AT_SETUP([Resolved SR Conflicts])
|
|
|
|
AT_KEYWORDS([report])
|
|
|
|
AT_DATA([input.y],
|
|
[[%token NUM OP
|
|
%left OP
|
|
%%
|
|
exp: exp OP exp | NUM;
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c --report=all input.y])
|
|
|
|
# Check the contents of the report.
|
|
AT_CHECK([cat input.output], [],
|
|
[[Grammar
|
|
|
|
0 $accept: exp $end
|
|
|
|
1 exp: exp OP exp
|
|
2 | NUM
|
|
|
|
|
|
Terminals, with rules where they appear
|
|
|
|
$end (0) 0
|
|
error (256)
|
|
NUM (258) 2
|
|
OP (259) 1
|
|
|
|
|
|
Nonterminals, with rules where they appear
|
|
|
|
$accept (5)
|
|
on left: 0
|
|
exp (6)
|
|
on left: 1 2, on right: 0 1
|
|
|
|
|
|
state 0
|
|
|
|
0 $accept: . exp $end
|
|
1 exp: . exp OP exp
|
|
2 | . NUM
|
|
|
|
NUM shift, and go to state 1
|
|
|
|
exp go to state 2
|
|
|
|
|
|
state 1
|
|
|
|
2 exp: NUM .
|
|
|
|
$default reduce using rule 2 (exp)
|
|
|
|
|
|
state 2
|
|
|
|
0 $accept: exp . $end
|
|
1 exp: exp . OP exp
|
|
|
|
$end shift, and go to state 3
|
|
OP shift, and go to state 4
|
|
|
|
|
|
state 3
|
|
|
|
0 $accept: exp $end .
|
|
|
|
$default accept
|
|
|
|
|
|
state 4
|
|
|
|
1 exp: . exp OP exp
|
|
1 | exp OP . exp
|
|
2 | . NUM
|
|
|
|
NUM shift, and go to state 1
|
|
|
|
exp go to state 5
|
|
|
|
|
|
state 5
|
|
|
|
1 exp: exp . OP exp
|
|
1 | exp OP exp . [$end, OP]
|
|
|
|
$default reduce using rule 1 (exp)
|
|
|
|
Conflict between rule 1 and token OP resolved as reduce (%left OP).
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
## -------------------------------- ##
|
|
## Defaulted Conflicted Reduction. ##
|
|
## -------------------------------- ##
|
|
|
|
# When there are RR conflicts, some rules are disabled. Usually it is
|
|
# simply displayed as:
|
|
#
|
|
# $end reduce using rule 3 (num)
|
|
# $end [reduce using rule 4 (id)]
|
|
#
|
|
# But when `reduce 3' is the default action, we'd produce:
|
|
#
|
|
# $end [reduce using rule 4 (id)]
|
|
# $default reduce using rule 3 (num)
|
|
#
|
|
# In this precise case (a reduction is masked by the default
|
|
# reduction), we make the `reduce 3' explicit:
|
|
#
|
|
# $end reduce using rule 3 (num)
|
|
# $end [reduce using rule 4 (id)]
|
|
# $default reduce using rule 3 (num)
|
|
#
|
|
# Maybe that's not the best display, but then, please propose something
|
|
# else.
|
|
|
|
AT_SETUP([Defaulted Conflicted Reduction])
|
|
AT_KEYWORDS([report])
|
|
|
|
AT_DATA([input.y],
|
|
[[%%
|
|
exp: num | id;
|
|
num: '0';
|
|
id : '0';
|
|
%%
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c --report=all input.y], 0, [],
|
|
[[input.y: conflicts: 1 reduce/reduce
|
|
input.y:4.6-8: warning: rule useless in parser due to conflicts: id: '0'
|
|
]])
|
|
|
|
# Check the contents of the report.
|
|
AT_CHECK([cat input.output], [],
|
|
[[Rules useless in parser due to conflicts
|
|
|
|
4 id: '0'
|
|
|
|
|
|
State 1 conflicts: 1 reduce/reduce
|
|
|
|
|
|
Grammar
|
|
|
|
0 $accept: exp $end
|
|
|
|
1 exp: num
|
|
2 | id
|
|
|
|
3 num: '0'
|
|
|
|
4 id: '0'
|
|
|
|
|
|
Terminals, with rules where they appear
|
|
|
|
$end (0) 0
|
|
'0' (48) 3 4
|
|
error (256)
|
|
|
|
|
|
Nonterminals, with rules where they appear
|
|
|
|
$accept (4)
|
|
on left: 0
|
|
exp (5)
|
|
on left: 1 2, on right: 0
|
|
num (6)
|
|
on left: 3, on right: 1
|
|
id (7)
|
|
on left: 4, on right: 2
|
|
|
|
|
|
state 0
|
|
|
|
0 $accept: . exp $end
|
|
1 exp: . num
|
|
2 | . id
|
|
3 num: . '0'
|
|
4 id: . '0'
|
|
|
|
'0' shift, and go to state 1
|
|
|
|
exp go to state 2
|
|
num go to state 3
|
|
id go to state 4
|
|
|
|
|
|
state 1
|
|
|
|
3 num: '0' . [$end]
|
|
4 id: '0' . [$end]
|
|
|
|
$end reduce using rule 3 (num)
|
|
$end [reduce using rule 4 (id)]
|
|
$default reduce using rule 3 (num)
|
|
|
|
|
|
state 2
|
|
|
|
0 $accept: exp . $end
|
|
|
|
$end shift, and go to state 5
|
|
|
|
|
|
state 3
|
|
|
|
1 exp: num .
|
|
|
|
$default reduce using rule 1 (exp)
|
|
|
|
|
|
state 4
|
|
|
|
2 exp: id .
|
|
|
|
$default reduce using rule 2 (exp)
|
|
|
|
|
|
state 5
|
|
|
|
0 $accept: exp $end .
|
|
|
|
$default accept
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
|
|
## -------------------- ##
|
|
## %expect not enough. ##
|
|
## -------------------- ##
|
|
|
|
AT_SETUP([%expect not enough])
|
|
|
|
AT_DATA([input.y],
|
|
[[%token NUM OP
|
|
%expect 0
|
|
%%
|
|
exp: exp OP exp | NUM;
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c input.y], 1, [],
|
|
[input.y: conflicts: 1 shift/reduce
|
|
input.y: expected 0 shift/reduce conflicts
|
|
])
|
|
AT_CLEANUP
|
|
|
|
|
|
## --------------- ##
|
|
## %expect right. ##
|
|
## --------------- ##
|
|
|
|
AT_SETUP([%expect right])
|
|
|
|
AT_DATA([input.y],
|
|
[[%token NUM OP
|
|
%expect 1
|
|
%%
|
|
exp: exp OP exp | NUM;
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c input.y])
|
|
AT_CLEANUP
|
|
|
|
|
|
## ------------------ ##
|
|
## %expect too much. ##
|
|
## ------------------ ##
|
|
|
|
AT_SETUP([%expect too much])
|
|
|
|
AT_DATA([input.y],
|
|
[[%token NUM OP
|
|
%expect 2
|
|
%%
|
|
exp: exp OP exp | NUM;
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c input.y], 1, [],
|
|
[input.y: conflicts: 1 shift/reduce
|
|
input.y: expected 2 shift/reduce conflicts
|
|
])
|
|
AT_CLEANUP
|
|
|
|
|
|
## ------------------------------ ##
|
|
## %expect with reduce conflicts ##
|
|
## ------------------------------ ##
|
|
|
|
AT_SETUP([%expect with reduce conflicts])
|
|
|
|
AT_DATA([input.y],
|
|
[[%expect 0
|
|
%%
|
|
program: a 'a' | a a;
|
|
a: 'a';
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c input.y], 1, [],
|
|
[input.y: conflicts: 1 reduce/reduce
|
|
input.y: expected 0 reduce/reduce conflicts
|
|
])
|
|
AT_CLEANUP
|
|
|
|
|
|
## ------------------------------- ##
|
|
## %no-default-prec without %prec ##
|
|
## ------------------------------- ##
|
|
|
|
AT_SETUP([%no-default-prec without %prec])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%left '+'
|
|
%left '*'
|
|
|
|
%%
|
|
|
|
%no-default-prec;
|
|
|
|
e: e '+' e
|
|
| e '*' e
|
|
| '0'
|
|
;
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c input.y], 0, [],
|
|
[[input.y: conflicts: 4 shift/reduce
|
|
]])
|
|
AT_CLEANUP
|
|
|
|
|
|
## ---------------------------- ##
|
|
## %no-default-prec with %prec ##
|
|
## ---------------------------- ##
|
|
|
|
AT_SETUP([%no-default-prec with %prec])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%left '+'
|
|
%left '*'
|
|
|
|
%%
|
|
|
|
%no-default-prec;
|
|
|
|
e: e '+' e %prec '+'
|
|
| e '*' e %prec '*'
|
|
| '0'
|
|
;
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c input.y])
|
|
AT_CLEANUP
|
|
|
|
|
|
## ---------------- ##
|
|
## %default-prec ##
|
|
## ---------------- ##
|
|
|
|
AT_SETUP([%default-prec])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%left '+'
|
|
%left '*'
|
|
|
|
%%
|
|
|
|
%default-prec;
|
|
|
|
e: e '+' e
|
|
| e '*' e
|
|
| '0'
|
|
;
|
|
]])
|
|
|
|
AT_BISON_CHECK([-o input.c input.y])
|
|
AT_CLEANUP
|
|
|
|
|
|
## ---------------------------------------------- ##
|
|
## Unreachable States After Conflict Resolution. ##
|
|
## ---------------------------------------------- ##
|
|
|
|
AT_SETUP([[Unreachable States After Conflict Resolution]])
|
|
|
|
# If conflict resolution makes states unreachable, remove those states, report
|
|
# rules that are then unused, and don't report conflicts in those states. Test
|
|
# what happens when a nonterminal becomes useless as a result of state removal
|
|
# since that causes lalr.o's goto map to be rewritten.
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%output "input.c"
|
|
%left 'a'
|
|
|
|
%%
|
|
|
|
start: resolved_conflict 'a' reported_conflicts 'a' ;
|
|
|
|
/* S/R conflict resolved as reduce, so the state with item
|
|
* (resolved_conflict: 'a' . unreachable1) and all it transition successors are
|
|
* unreachable, and the associated production is useless. */
|
|
resolved_conflict:
|
|
'a' unreachable1
|
|
| %prec 'a'
|
|
;
|
|
|
|
/* S/R conflict that need not be reported since it is unreachable because of
|
|
* the previous conflict resolution. Nonterminal unreachable1 and all its
|
|
* productions are useless. */
|
|
unreachable1:
|
|
'a' unreachable2
|
|
|
|
|
;
|
|
|
|
/* Likewise for a R/R conflict and nonterminal unreachable2. */
|
|
unreachable2: | ;
|
|
|
|
/* Make sure remaining S/R and R/R conflicts are still reported correctly even
|
|
* when their states are renumbered due to state removal. */
|
|
reported_conflicts:
|
|
'a'
|
|
| 'a'
|
|
|
|
|
;
|
|
|
|
]])
|
|
|
|
AT_BISON_CHECK([[--report=all input.y]], 0, [],
|
|
[[input.y: conflicts: 1 shift/reduce, 1 reduce/reduce
|
|
input.y:12.5-20: warning: rule useless in parser due to conflicts: resolved_conflict: 'a' unreachable1
|
|
input.y:20.5-20: warning: rule useless in parser due to conflicts: unreachable1: 'a' unreachable2
|
|
input.y:21.4: warning: rule useless in parser due to conflicts: unreachable1: /* empty */
|
|
input.y:25.13: warning: rule useless in parser due to conflicts: unreachable2: /* empty */
|
|
input.y:25.16: warning: rule useless in parser due to conflicts: unreachable2: /* empty */
|
|
input.y:31.5-7: warning: rule useless in parser due to conflicts: reported_conflicts: 'a'
|
|
input.y:32.4: warning: rule useless in parser due to conflicts: reported_conflicts: /* empty */
|
|
]])
|
|
|
|
AT_CHECK([[cat input.output]], 0,
|
|
[[Rules useless in parser due to conflicts
|
|
|
|
2 resolved_conflict: 'a' unreachable1
|
|
|
|
4 unreachable1: 'a' unreachable2
|
|
5 | /* empty */
|
|
|
|
6 unreachable2: /* empty */
|
|
7 | /* empty */
|
|
|
|
9 reported_conflicts: 'a'
|
|
10 | /* empty */
|
|
|
|
|
|
State 4 conflicts: 1 shift/reduce
|
|
State 5 conflicts: 1 reduce/reduce
|
|
|
|
|
|
Grammar
|
|
|
|
0 $accept: start $end
|
|
|
|
1 start: resolved_conflict 'a' reported_conflicts 'a'
|
|
|
|
2 resolved_conflict: 'a' unreachable1
|
|
3 | /* empty */
|
|
|
|
4 unreachable1: 'a' unreachable2
|
|
5 | /* empty */
|
|
|
|
6 unreachable2: /* empty */
|
|
7 | /* empty */
|
|
|
|
8 reported_conflicts: 'a'
|
|
9 | 'a'
|
|
10 | /* empty */
|
|
|
|
|
|
Terminals, with rules where they appear
|
|
|
|
$end (0) 0
|
|
'a' (97) 1 2 4 8 9
|
|
error (256)
|
|
|
|
|
|
Nonterminals, with rules where they appear
|
|
|
|
$accept (4)
|
|
on left: 0
|
|
start (5)
|
|
on left: 1, on right: 0
|
|
resolved_conflict (6)
|
|
on left: 2 3, on right: 1
|
|
unreachable1 (7)
|
|
on left: 4 5, on right: 2
|
|
unreachable2 (8)
|
|
on left: 6 7, on right: 4
|
|
reported_conflicts (9)
|
|
on left: 8 9 10, on right: 1
|
|
|
|
|
|
state 0
|
|
|
|
0 $accept: . start $end
|
|
1 start: . resolved_conflict 'a' reported_conflicts 'a'
|
|
2 resolved_conflict: . 'a' unreachable1
|
|
3 | . ['a']
|
|
|
|
$default reduce using rule 3 (resolved_conflict)
|
|
|
|
start go to state 1
|
|
resolved_conflict go to state 2
|
|
|
|
Conflict between rule 3 and token 'a' resolved as reduce (%left 'a').
|
|
|
|
|
|
state 1
|
|
|
|
0 $accept: start . $end
|
|
|
|
$end shift, and go to state 3
|
|
|
|
|
|
state 2
|
|
|
|
1 start: resolved_conflict . 'a' reported_conflicts 'a'
|
|
|
|
'a' shift, and go to state 4
|
|
|
|
|
|
state 3
|
|
|
|
0 $accept: start $end .
|
|
|
|
$default accept
|
|
|
|
|
|
state 4
|
|
|
|
1 start: resolved_conflict 'a' . reported_conflicts 'a'
|
|
8 reported_conflicts: . 'a'
|
|
9 | . 'a'
|
|
10 | . ['a']
|
|
|
|
'a' shift, and go to state 5
|
|
|
|
'a' [reduce using rule 10 (reported_conflicts)]
|
|
|
|
reported_conflicts go to state 6
|
|
|
|
|
|
state 5
|
|
|
|
8 reported_conflicts: 'a' . ['a']
|
|
9 | 'a' . ['a']
|
|
|
|
'a' reduce using rule 8 (reported_conflicts)
|
|
'a' [reduce using rule 9 (reported_conflicts)]
|
|
$default reduce using rule 8 (reported_conflicts)
|
|
|
|
|
|
state 6
|
|
|
|
1 start: resolved_conflict 'a' reported_conflicts . 'a'
|
|
|
|
'a' shift, and go to state 7
|
|
|
|
|
|
state 7
|
|
|
|
1 start: resolved_conflict 'a' reported_conflicts 'a' .
|
|
|
|
$default reduce using rule 1 (start)
|
|
]])
|
|
|
|
AT_DATA([[input-keep.y]],
|
|
[[%define lr.keep_unreachable_states
|
|
]])
|
|
AT_CHECK([[cat input.y >> input-keep.y]])
|
|
|
|
AT_BISON_CHECK([[input-keep.y]], 0, [],
|
|
[[input-keep.y: conflicts: 2 shift/reduce, 2 reduce/reduce
|
|
input-keep.y:22.4: warning: rule useless in parser due to conflicts: unreachable1: /* empty */
|
|
input-keep.y:26.16: warning: rule useless in parser due to conflicts: unreachable2: /* empty */
|
|
input-keep.y:32.5-7: warning: rule useless in parser due to conflicts: reported_conflicts: 'a'
|
|
input-keep.y:33.4: warning: rule useless in parser due to conflicts: reported_conflicts: /* empty */
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
## ------------------------------------------------------------ ##
|
|
## Solved conflicts report for multiple reductions in a state. ##
|
|
## ------------------------------------------------------------ ##
|
|
|
|
AT_SETUP([[Solved conflicts report for multiple reductions in a state]])
|
|
|
|
# Used to lose earlier solved conflict messages even within a single S/R/R.
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%left 'a'
|
|
%right 'b'
|
|
%right 'c'
|
|
%right 'd'
|
|
%%
|
|
start:
|
|
'a'
|
|
| empty_a 'a'
|
|
| 'b'
|
|
| empty_b 'b'
|
|
| 'c'
|
|
| empty_c1 'c'
|
|
| empty_c2 'c'
|
|
| empty_c3 'c'
|
|
;
|
|
empty_a: %prec 'a' ;
|
|
empty_b: %prec 'b' ;
|
|
empty_c1: %prec 'c' ;
|
|
empty_c2: %prec 'c' ;
|
|
empty_c3: %prec 'd' ;
|
|
]])
|
|
AT_BISON_CHECK([[--report=all -o input.c input.y]], 0, [], [ignore])
|
|
AT_CHECK([[cat input.output | sed -n '/^state 0$/,/^state 1$/p']], 0,
|
|
[[state 0
|
|
|
|
0 $accept: . start $end
|
|
1 start: . 'a'
|
|
2 | . empty_a 'a'
|
|
3 | . 'b'
|
|
4 | . empty_b 'b'
|
|
5 | . 'c'
|
|
6 | . empty_c1 'c'
|
|
7 | . empty_c2 'c'
|
|
8 | . empty_c3 'c'
|
|
9 empty_a: . ['a']
|
|
10 empty_b: . []
|
|
11 empty_c1: . []
|
|
12 empty_c2: . []
|
|
13 empty_c3: . ['c']
|
|
|
|
'b' shift, and go to state 1
|
|
|
|
'c' reduce using rule 13 (empty_c3)
|
|
$default reduce using rule 9 (empty_a)
|
|
|
|
start go to state 2
|
|
empty_a go to state 3
|
|
empty_b go to state 4
|
|
empty_c1 go to state 5
|
|
empty_c2 go to state 6
|
|
empty_c3 go to state 7
|
|
|
|
Conflict between rule 9 and token 'a' resolved as reduce (%left 'a').
|
|
Conflict between rule 10 and token 'b' resolved as shift (%right 'b').
|
|
Conflict between rule 11 and token 'c' resolved as shift (%right 'c').
|
|
Conflict between rule 12 and token 'c' resolved as shift (%right 'c').
|
|
Conflict between rule 13 and token 'c' resolved as reduce ('c' < 'd').
|
|
|
|
|
|
state 1
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
## ------------------------------------------------------------ ##
|
|
## %nonassoc error actions for multiple reductions in a state. ##
|
|
## ------------------------------------------------------------ ##
|
|
|
|
# Used to abort when trying to resolve conflicts as %nonassoc error actions for
|
|
# multiple reductions in a state.
|
|
|
|
# For a %nonassoc error action token, used to print the first remaining
|
|
# reduction on that token without brackets.
|
|
|
|
AT_SETUP([[%nonassoc error actions for multiple reductions in a state]])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%nonassoc 'a' 'b' 'c'
|
|
%%
|
|
start:
|
|
'a'
|
|
| empty_a 'a'
|
|
| 'b'
|
|
| empty_b 'b'
|
|
| 'c'
|
|
| empty_c1 'c'
|
|
| empty_c2 'c'
|
|
| empty_c3 'c'
|
|
;
|
|
empty_a: %prec 'a' ;
|
|
empty_b: %prec 'b' ;
|
|
empty_c1: %prec 'c' ;
|
|
empty_c2: %prec 'c' ;
|
|
empty_c3: %prec 'c' ;
|
|
]])
|
|
|
|
AT_BISON_CHECK([[--report=all -o input.c input.y]], 0, [], [ignore])
|
|
AT_CHECK([[cat input.output | sed -n '/^state 0$/,/^state 1$/p']], 0,
|
|
[[state 0
|
|
|
|
0 $accept: . start $end
|
|
1 start: . 'a'
|
|
2 | . empty_a 'a'
|
|
3 | . 'b'
|
|
4 | . empty_b 'b'
|
|
5 | . 'c'
|
|
6 | . empty_c1 'c'
|
|
7 | . empty_c2 'c'
|
|
8 | . empty_c3 'c'
|
|
9 empty_a: . []
|
|
10 empty_b: . []
|
|
11 empty_c1: . []
|
|
12 empty_c2: . ['c']
|
|
13 empty_c3: . ['c']
|
|
|
|
'a' error (nonassociative)
|
|
'b' error (nonassociative)
|
|
'c' error (nonassociative)
|
|
|
|
'c' [reduce using rule 12 (empty_c2)]
|
|
'c' [reduce using rule 13 (empty_c3)]
|
|
|
|
start go to state 1
|
|
empty_a go to state 2
|
|
empty_b go to state 3
|
|
empty_c1 go to state 4
|
|
empty_c2 go to state 5
|
|
empty_c3 go to state 6
|
|
|
|
Conflict between rule 9 and token 'a' resolved as an error (%nonassoc 'a').
|
|
Conflict between rule 10 and token 'b' resolved as an error (%nonassoc 'b').
|
|
Conflict between rule 11 and token 'c' resolved as an error (%nonassoc 'c').
|
|
|
|
|
|
state 1
|
|
]])
|
|
AT_CLEANUP
|