Compare commits

...
21 Commits
Author SHA1 Message Date
Akim Demaille 71579c7219 version 3.7.1
* NEWS: Record release date.
2020-08-02 09:10:02 +02:00
Akim Demaille 2f8a874215 portability: we use termios.h and sys/ioctl.h
Reported by Maarten De Braekeleer.
https://lists.gnu.org/r/bison-patches/2020-07/msg00079.html

* bootstrap.conf (gnulib_modules): Add termios and sys_ioctl.
2020-08-02 08:36:49 +02:00
Maarten De BraekeleerandAkim Demaille ad6f600bb1 portability: rename accept to acceptsymbol because of MSVC
MSVC already defines this symbol.

* src/symtab.h, src/symtab.c (accept): Rename as...
(acceptsymbol): this.
Adjust dependencies.
2020-08-02 08:32:57 +02:00
Akim Demaille de4f41eab7 regen 2020-08-02 08:32:57 +02:00
Maarten De BraekeleerandAkim Demaille e73f086b0d portability: use CHAR_LITERAL instead of CHAR because MSVC defines CHAR
* src/parse-gram.y, src/scan-gram.l: here.
2020-08-02 08:32:57 +02:00
Maarten De BraekeleerandAkim Demaille 8cf098415e portability: use INT_LITERAL instead of INT because MSVC defines INT
It is defined as a typedef, not a macro.
https://lists.gnu.org/r/bison-patches/2020-08/msg00001.html

* src/parse-gram.y, src/scan-gram.l: here.
2020-08-02 08:32:30 +02:00
Akim Demaille 977e19840d portability: beware of max () with MSVC
Reported by Maarten De Braekeleer.
https://lists.gnu.org/r/bison-patches/2020-07/msg00080.html

We don't want to use gnulib's min and max macros, since we use
function calls in min/max arguments.

* src/location.c (max_int, min_int): Move to...
* src/system.h: here.
* src/counterexample.c, src/derivation.c: Use max_int instead of max.
2020-08-02 08:19:35 +02:00
Akim Demaille d975c2f76e libtextstyle: be sure to have ostream_printf and hyperlink support
Older versions of libtextstyle do not support them, rule them out.

Reported by Lars Wendler
https://lists.gnu.org/r/bug-bison/2020-07/msg00030.html

and by Arnold Robbins
https://lists.gnu.org/r/bug-bison/2020-07/msg00041.html and
https://lists.gnu.org/mailman/private/gawk-devel/2020-July/003988.html

and by Nelson H. F. Beebe
https://lists.gnu.org/mailman/private/gawk-devel/2020-July/003993.html

With support from Bruno Haible in gnulib
https://lists.gnu.org/r/bug-gnulib/2020-08/msg00000.html
thread starting at
https://lists.gnu.org/r/bug-gnulib/2020-07/msg00148.html

* configure.ac: Require libtextstyle 0.20.5.
* gnulib: Update.
2020-08-02 08:19:35 +02:00
Akim Demaille 0676801b8c CI: comment changes 2020-08-01 10:02:44 +02:00
Akim Demaille 82aa96e9b1 regen 2020-08-01 08:54:46 +02:00
Akim Demaille cb65553449 diagnostics: better location for type redeclarations
From

    foo.y:1.7-11: error: %type redeclaration for bar
        1 | %type <foo> bar bar
          |       ^~~~~
    foo.y:1.7-11: note: previous declaration
        1 | %type <foo> bar bar
          |       ^~~~~

to

    foo.y:1.17-19: error: %type redeclaration for bar
        1 | %type <foo> bar bar
          |                 ^~~
    foo.y:1.13-15: note: previous declaration
        1 | %type <foo> bar bar
          |             ^~~

* src/symlist.h, src/symlist.c (symbol_list_type_set): There's no need
for the tag's location, use that of the symbol.
* src/parse-gram.y: Adjust.
* tests/input.at: Adjust.
2020-08-01 08:54:46 +02:00
Akim Demaille f47a1bd622 todo: updates for D 2020-07-30 07:14:57 +02:00
Akim Demaille 205d372c68 cex: style: comment changes
* src/parse-simulation.c: here.
2020-07-29 20:00:59 +02:00
Akim Demaille 07a1243b40 cex: style: prefer "res" for the returned value
* src/derivation.c (derivation_new): here.
2020-07-29 20:00:59 +02:00
Akim Demaille ece343d2c2 cex: style: prefer FOO_print to print_FOO
* src/state-item.h, src/state-item.c (print_state_item): Rename as...
(state_item_print): this.
* src/counterexample.c (print_counterexample): Rename as...
(counterexample_print): this.
2020-07-29 20:00:27 +02:00
Akim Demaille be95a4fe29 scanner: don't crash on strings containing a NUL byte
We crash if the input contains a string containing a NUL byte.
Reported by Suhwan Song.
https://lists.gnu.org/r/bug-bison/2020-07/msg00051.html

* src/flex-scanner.h (STRING_FREE): Avoid accidental use of
last_string.
* src/scan-gram.l: Don't call STRING_FREE without calling
STRING_FINISH first.
* tests/input.at (Invalid inputs): Check that case.
2020-07-28 19:01:48 +02:00
Akim Demaille 6accee7716 doc: refer to cex from sections dealing with conflicts
The documentation about -Wcex should be put forward.

* doc/bison.texi: Refer to -Wcex from the sections about conflicts.
2020-07-28 07:45:07 +02:00
Akim Demaille e63f22703e doc: factor ifnottex/iftex examples
* doc/bison.texi: Factor the common bits out of ifnottex/iftex.
2020-07-28 07:45:07 +02:00
Akim Demaille fa390dc311 doc: fix colors
The original Texinfo macros introducing colors were made for
diagnostics, which are printed in bold.  So by copy-paste accident the
styles we introduced for counterexamples were also in bold.  They
should not.

* doc/bison.texi: Separate the styling of diagnostics from the styling
for counterexamples.
Don't use bold in the latter case.
2020-07-28 07:45:07 +02:00
Akim Demaille 17fdf5eca2 doc: fixes
* doc/bison.texi: Fix spello.
Fix missing colors, and factor.
2020-07-28 07:45:07 +02:00
Akim Demaille 72b3c1a673 maint: post-release administrivia
* NEWS: Add header line for next release.
* .prev-version: Record previous version.
* cfg.mk (old_NEWS_hash): Auto-update.
2020-07-23 20:15:38 +02:00
33 changed files with 611 additions and 244 deletions
+1 -1
View File
@@ -1 +1 @@
3.6.93
3.7
+2
View File
@@ -119,6 +119,8 @@ jobs:
- CXX='clang++-10 -fsanitize=address -stdlib=libc++'
- PART=2
# See https://github.com/simd-everywhere/simde/blob/master/.travis.yml
# and https://software.intel.com/content/www/us/en/develop/documentation/get-started-with-intel-oneapi-render-linux/top/configure-your-system.html.
- name: "ICC"
stage: check
os: linux
+17
View File
@@ -1,5 +1,22 @@
GNU Bison NEWS
* Noteworthy changes in release 3.7.1 (2020-08-02) [stable]
** Bug fixes
Crash when a token alias contains a NUL byte.
Portability issues with libtextstyle.
Portability issues of Bison itself with MSVC.
** Changes
Improvements and fixes in the documentation.
More precise location about symbol type redefinitions.
* Noteworthy changes in release 3.7 (2020-07-23) [stable]
** Deprecated features
+12 -3
View File
@@ -42,9 +42,11 @@ installing it. In that case, do not use `src/bison`: it would use the
As an experimental feature, diagnostics are now colored, controlled by the
`--color` and `--style` options.
To use them, install the libtextstyle library before configuring Bison. It
is available from https://alpha.gnu.org/gnu/gettext/, for instance
https://alpha.gnu.org/pub/gnu/gettext/libtextstyle-0.20.5.tar.gz.
To use them, install the libtextstyle library, 0.20.5 or newer, before
configuring Bison. It is available from https://alpha.gnu.org/gnu/gettext/,
for instance https://alpha.gnu.org/gnu/gettext/libtextstyle-0.20.5.tar.gz,
or as part of Gettext 0.21 or newer, for instance
https://ftp.gnu.org/gnu/gettext/gettext-0.21.tar.gz.
The option --color supports the following arguments:
- always, yes: Enable colors.
@@ -61,6 +63,13 @@ To customize the styles, create a CSS file, say `bison-bw.css`, similar to
then invoke bison with `--style=bison-bw.css`, or set the `BISON_STYLE`
environment variable to `bison-bw.css`.
In some diagnostics, bison uses libtextstyle to emit special escapes to
generate clickable hyperlinks. The environment variable
`NO_TERM_HYPERLINKS` can be used to suppress them. This may be useful for
terminal emulators which produce garbage output when they receive the escape
sequence for a hyperlink. Currently (as of 2020), this affects some versions
of emacs, guake, konsole, lxterminal, rxvt, yakuake.
## Relocatability
If you pass `--enable-relocatable` to `configure`, Bison is relocatable.
+3
View File
@@ -106,9 +106,11 @@ Keith Browne [email protected]
Ken Moffat [email protected]
Kiyoshi Kanazawa [email protected]
Lars Maier [email protected]
Lars Wendler [email protected]
László Várady [email protected]
Laurent Mascherpa [email protected]
Lie Yan [email protected]
Maarten De Braekeleer [email protected]
Magnus Fromreide [email protected]
Marc Autret [email protected]
Marc Mendiola [email protected]
@@ -185,6 +187,7 @@ Simon Sobisch [email protected]
Stefano Lattarini [email protected]
Stephen Cameron [email protected]
Steve Murphy [email protected]
Suhwan Song [email protected]
Sum Wu [email protected]
Théophile Ranquet [email protected]
Thiru Ramakrishnan [email protected]
+297 -15
View File
@@ -48,13 +48,6 @@ Unless we play it dumb (little structure).
- promote YYEOF rather than EOF.
*** D
- is there a way to attach yysymbol_name to the enum itself? As we did
in Java.
- It would be better to have TokenKind as return value. Can we use
reflection to support both output types?
** YYerror
https://git.savannah.gnu.org/gitweb/?p=gettext.git;a=blob;f=gettext-runtime/intl/plural.y;h=a712255af4f2f739c93336d4ff6556d932a426a5;hb=HEAD
@@ -67,7 +60,7 @@ Stop hard-coding "Calc". Adjust local.at (look for FIXME).
** A dev warning for b4_
Maybe we should check for m4_ and b4_ leaking out of the m4 processing, as
Autoconf does. It would have caught overquotation issues.
Autoconf does. It would have caught over-quotation issues.
** doc
I feel it's ugly to use the GNU style to declare functions in the doc. It
@@ -88,7 +81,7 @@ push parsers on top of pull parser. Which is currently not relevant, since
push parsers are measurably slower.
** %define parse.error formatted
How about pushing bistromathics' yyreport_syntax_error as another standard
How about pushing Bistromathic's yyreport_syntax_error as another standard
way to generate the error message, and leave to the user the task of
providing the message formats? Currently in bistro, it reads:
@@ -202,18 +195,282 @@ The "automaton" and "set" categories are not so useful. We should probably
introduce lr(0) and lalr, just the way we have ielr categories. The
"closure" function is too verbose, it should probably have its own category.
"set" can still be used for summariring the important sets. That would make
"set" can still be used for summarizing the important sets. That would make
tests easy to maintain.
*** complain.*
Rename these guys as "diagnostics.*" (or "diagnose.*"), since that's the
name they have in gcc, clang, etc. Likewise for the complain_* series of
name they have in GCC, clang, etc. Likewise for the complain_* series of
functions.
*** ritem
states/nstates, rules/nrules, ..., ritem/nritems
Fix the latter.
* D programming language
There's a number of features that are missing, here sorted in _suggested_
order of implementation.
When copying code from other skeletons, keep the comments exactly as they
are. Keep the same variable names. If you change the wording in one place,
do it in the others too. In other words: make sure to keep the
maintenance *simple* by avoiding any gratuitous difference.
** Rename the D example
Move the current content of examples/d into examples/d/simple.
** Create a second example
Duplicate examples/d/simple into examples/d/calc.
** Add location tracking to d/calc
Look at the examples in the other languages to see how to do that.
** yysymbol_name
The SymbolKind is an enum. For a given SymbolKind we want to get its string
representation. Currently it's a separate table in the parser that does
that:
/* Symbol kinds. */
public enum SymbolKind
{
S_YYEMPTY = -2, /* No symbol. */
S_YYEOF = 0, /* "end of file" */
S_YYerror = 1, /* error */
S_YYUNDEF = 2, /* "invalid token" */
S_EQ = 3, /* "=" */
...
S_input = 14, /* input */
S_line = 15, /* line */
S_exp = 16, /* exp */
};
...
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at \a yyntokens_, nonterminals. */
private static immutable string[] yytname_ =
[
"\"end of file\"", "error", "\"invalid token\"", "\"=\"", "\"+\"",
"\"-\"", "\"*\"", "\"/\"", "\"(\"", "\")\"", "\"end of line\"",
"\"number\"", "UNARY", "$accept", "input", "line", "exp", null
];
...
So to get a symbol kind, one runs `yytname_[yykind]`.
Is there a way to attach this conversion to string to SymbolKind? In Java
for instance, we have:
public enum SymbolKind
{
S_YYEOF(0), /* "end of file" */
S_YYerror(1), /* error */
S_YYUNDEF(2), /* "invalid token" */
...
S_input(16), /* input */
S_line(17), /* line */
S_exp(18); /* exp */
private final int yycode_;
SymbolKind (int n) {
this.yycode_ = n;
}
...
/* YYNAMES_[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at \a YYNTOKENS_, nonterminals. */
private static final String[] yynames_ = yynames_init();
private static final String[] yynames_init()
{
return new String[]
{
i18n("end of file"), i18n("error"), i18n("invalid token"), "!", "+", "-", "*",
"/", "^", "(", ")", "=", i18n("end of line"), i18n("number"), "NEG",
"$accept", "input", "line", "exp", null
};
}
/* The user-facing name of this symbol. */
public final String getName() {
return yynames_[yycode_];
}
};
which allows to write more naturally `yykind.getName()` rather than
`yytname_[yykind]`. Is there something comparable in (idiomatic) D?
** Change the return value of yylex
Historically people were allowed to return any int from the scanner (which
is convenient and allows `return '+'` from the scanner). Akim tends to see
this as an error, we should restrict the return values to TokenKind (not to
be confused with SymbolKind).
In the case of D, without the history, we have the choice to support or not
`int`. If we want to _keep_ `int`, is there a way, say via introspection,
to support both signatures of yylex? If we don't keep `int`, just move to
TokenKind.
** Documentation
Write documentation about D support in doc/bison.texi. Imitate the Java
documentation. You should be more succinct IMHO.
** Complete Symbols
The current interface from the scanner to the parser is somewhat clumsy: the
token kind is returned by yylex, but the value and location are stored in
the scanner. This reflects the fact that the implementation of the parser
uses three variables to deal with each parsed symbol: its kind, its value,
its location.
So today the scanner of examples/d/calc.d (no locations) looks like:
if (input.front.isNumber)
{
import std.conv : parse;
semanticVal_.ival = input.parse!int;
return TokenKind.NUM;
}
and the generated parser:
/* Read a lookahead token. */
if (yychar == TokenKind.YYEMPTY)
{
yychar = yylex ();
yylval = yylexer.semanticVal;
}
The parser class should feature a `Symbol` type which binds together kind,
value and location, and the scanner should be able to return an instance of
that type. Something like
if (input.front.isNumber)
{
import std.conv : parse;
return parser.Symbol (TokenKind.NUM, input.parse!int);
}
** Token Constructors
In the previous example it is possible to mix incorrectly kinds and values,
and for instance:
return parser.Symbol (TokenKind.NUM, "Hello, World!\n");
attaches a string value to NUM kind (wrong, of course). When
api.token.constructor is set, in C++, Bison generated "token constructors":
parser.make_NUM. parser.make_PLUS, parser.make_STRING, etc. The previous
example becomes
return parser.make_NUM ("Hello, World!\n");
which would easily be caught by the type checker.
** Lookahead Correction
Add support for LAC to the D skeleton. It should not be too hard: look how
this is done in lalr1.cc, and mock it.
** Push Parser
Add support for push parser. Do not start a nice skeleton, just enhance the
current one to support push parsers. This is going to be a tougher nut to
crack.
First, you need to understand well how the push parser is expected to work.
To this end:
- read the doc
- look at examples/c/pushcalc
- create an example of a Java push parser.
- have a look at the generated parser in Java, which has the advantage of
being already based on a parser object, instead of just a function.
The C case is harder to read, but it may help too. Keep in mind that
because there's no object to maintain state, the C push parser uses some
struct (yypstate) to preserve this state. We don't need this in D, the
parser object will suffice.
I think working directly on the skeleton to add push-parser support is not
the simplest path. I suggest that you (1) transform a generated parser into
a push parser by hand, and then (2) transform lalr1.d to generate such a
parser.
Use `git commit` frequently to make sure you keep track of your progress.
*** (1.a) Prepare pull parser by hand
Copy again one of the D examples into say examples/d/pushcalc. Also
check-in the generated parser to facilitate experimentation.
- find local variables of yyparse should become members of the parser object
(so that we preserve state from one call to the next).
- do it in your generated D parser. We don't need an equivalent for
yypstate, because we already have it: that the parser object itself.
- have your *pull*-parser (i.e., the good old yy::parser::parse()) work
properly this way. Write and run tests. That's one of the reasons I
suggest using examples/d/calc as a starting point: it already has tests,
you can/should add more.
At this point you have a pull-parser which you prepared to turn into a
push-parser.
*** (1.b) Turn pull parser into push parser by hand
- look again at how push parsers are implemented in Java/C to see what needs
to change in yyparse so that the control is inverted: parse() will
be *given* the tokens, instead of having to call yylex itself. When I say
"look at C", I think your best option are (i) yacc.c (look for b4_push_if)
and (ii) examples/c/pushcalc.
- rename parse() as push_parse(Symbol yyla) (or push_parse(TokenKind, Value,
Location)) that takes the symbol as argument. That's the push parser we
are looking for.
- define a new parse() function which has the same signature as the usual
pull-parser, that repeatedly calls the push_parse function. Something
like this:
int parse ()
{
int status = 0;
do {
status = this->push_parse (yylex());
} while (status == YYPUSH_MORE);
return status;
}
- show me that parser, so that we can validate the approach.
*** (2) Port that into the skeleton
- once we agree on the API of the push parser, implement it into lalr1.d.
You will probaby need help on this regard, but imitation, again, should
help.
- have example/d/pushcalc work properly and pass tests
- add tests in the "real" test suite. Do that in tests/calc.at. I can
help.
- document
** GLR Parser
This is very ambitious. That's the final boss. There are currently no
"clean" implementation to get inspiration from.
glr.c is very clean but:
- is low-level C
- is a different skeleton from yacc.c
glr.cc is (currently) an ugly hack: a C++ shell around glr.c. Valentin
Tolmer is currently rewriting glr.cc to be clean C++, but he is not
finished. There will be a lot a common code between lalr1.cc and glr.cc, so
eventually I would like them to be fused into a single skeleton, supporting
both deterministic and generalized parsing.
It would be great for D to also support this.
The basic ideas of GLR are explained here:
https://www.codeproject.com/Articles/5259825/GLR-Parsing-in-Csharp-How-to-Use-The-Most-Powerful
* Better error messages
The users are not provided with enough tools to forge their error messages.
See for instance "Is there an option to change the message produced by
@@ -231,7 +488,7 @@ and older C++ compilers. Currently the code defaults to defining it to
define it to the same type as the C ptrdiff_t type.
* Completion
Several features are not available in all the backends.
Several features are not available in all the back-ends.
- lac: D, Java (easy)
- push parsers: glr.c, glr.cc, lalr1.cc (not very difficult)
@@ -301,7 +558,7 @@ opposite side we have some use of \l, which is graphviz-specific, in what
should be generic code.
Little effort seems to have been given to factoring these files and their
rint{,-xml} counterpart. We would very much like to re-use the pretty format
print{,-xml} counterpart. We would very much like to re-use the pretty format
of states from .output for the graphs, etc.
Since graphviz dies on medium-to-big grammars, maybe consider an other tool?
@@ -579,14 +836,39 @@ to bison. If you're interested, I'll work on a patch.
Equip the parser with a means to create the (visual) parse tree.
-----
# LocalWords: Cex gnulib gl Bistromathic TokenKinds yylex enum YYEOF EOF
# LocalWords: YYerror gettext af hb YYERRCODE undef calc FIXME dev yyerror
# LocalWords: Autoconf YYUNDEFTOK lexemes parsers Bistromathic's yyreport
# LocalWords: const argc yacc yyclearin lookahead destructor Rici incluent
# LocalWords: yydestruct yydiscardin catégories d'avertissements sr activé
# LocalWords: conflits défaut rr l'alias chaîne n'est attaché un symbole
# LocalWords: obsolète règle vide midrule valeurs de intermédiaire ou avec
# LocalWords: définies inutilisées priorité associativité inutiles POSIX
# LocalWords: incompatibilités tous les autres avertissements sauf dans rp
# LocalWords: désactiver CATEGORIE traiter comme des erreurs glr Akim bool
# LocalWords: Demaille arith lalr goto struct pathlen nullable ntokens lr
# LocalWords: nterm bitsetv ielr ritem nstates nrules nritems yysymbol EQ
# LocalWords: SymbolKind YYEMPTY YYUNDEF YYTNAME NUM yyntokens yytname sed
# LocalWords: nonterminals yykind yycode YYNAMES yynames init getName conv
# LocalWords: TokenKind semanticVal ival yychar yylval yylexer Tolmer hoc
# LocalWords: Sobisch YYPTRDIFF ptrdiff Autotest YYPRINT toknum yytoknum
# LocalWords: sym Wother stderr FP fixits xgettext fdiagnostics Graphviz
# LocalWords: graphviz VCG bitset xml bw maint yytoken YYABORT deps
# LocalWords: YYACCEPT yytranslate nonnegative destructors yyerrlab repo
# LocalWords: backends stmt expr yy Mardle baz qux Vadim Maslow CPP cpp
# LocalWords: yydebug gcc UCHAR EBCDIC gung PDP NUL Pre Florian Krohm utf
# LocalWords: YYACT YYLLOC YYLSP yyval yyvsp yylen yyloc yylsp endif
# LocalWords: ispell american
Local Variables:
mode: outline
coding: utf-8
fill-column: 76
ispell-dictionary: "american"
End:
-----
Copyright (C) 2001-2004, 2006, 2008-2015, 2018-2020 Free Software
Foundation, Inc.
+2
View File
@@ -45,6 +45,8 @@ gnulib_modules='
relocatable-prog relocatable-script
rename
spawn-pipe stdbool stpcpy stpncpy strdup-posix strerror strverscmp
sys_ioctl
termios
timevar
unicodeio unistd unistd-safer unlink unlocked-io
update-copyright unsetenv verify
+3
View File
@@ -60,6 +60,9 @@ AC_PROG_CXX
# Gnulib (early checks).
gl_EARLY
# We want ostream_printf and hyperlink support.
gl_LIBTEXTSTYLE_OPTIONAL([0.20.5])
# Gnulib uses '#pragma GCC diagnostic push' to silence some
# warnings, but older gcc doesn't support this.
AC_CACHE_CHECK([whether pragma GCC diagnostic push works],
+101 -78
View File
@@ -57,44 +57,57 @@
\gdef\colorPurple{%
\setcolor{\rgbPurple}%
}
\gdef\colorOff{%
\setcolor{\maincolor}%
}
\gdef\rgbError{0.80 0 0}
\gdef\colorError{%
\gdef\diagError{%
\setcolor{\rgbError}%
}
\gdef\rgbNotice{0 0 0.80}
\gdef\colorNotice{%
\gdef\diagNotice{%
\setcolor{\rgbNotice}%
}
\gdef\colorOff{%
\gdef\rgbWarning{0.50 0 0.50}
\gdef\diagWarning{%
\setcolor{\rgbWarning}%
}
\gdef\diagOff{%
\setcolor{\maincolor}%
}
@end tex
@ifnottex
@macro colorGreen
@inlineraw{html, <b style="color:green">}
@inlineraw{html, <span style="color:green">}
@end macro
@macro colorYellow
@inlineraw{html, <b style="color:#ff8000">}
@inlineraw{html, <span style="color:#ff8000">}
@end macro
@macro colorRed
@inlineraw{html, <b style="color:red">}
@inlineraw{html, <span style="color:red">}
@end macro
@macro colorBlue
@inlineraw{html, <b style="color:blue">}
@inlineraw{html, <span style="color:blue">}
@end macro
@macro colorPurple
@inlineraw{html, <b style="color:darkviolet">}
@end macro
@macro colorError
@inlineraw{html, <b style="color:red">}
@end macro
@macro colorNotice
@inlineraw{html, <b style="color:darkcyan">}
@inlineraw{html, <span style="color:darkviolet">}
@end macro
@macro colorOff
@inlineraw{html, </span>}
@end macro
@macro diagError
@inlineraw{html, <b style="color:red">}
@end macro
@macro diagNotice
@inlineraw{html, <b style="color:darkcyan">}
@end macro
@macro diagWarning
@inlineraw{html, <b style="color:darkviolet">}
@end macro
@macro diagOff
@inlineraw{html, </b>}
@end macro
@end ifnottex
@@ -120,15 +133,15 @@
@end macro
@macro dwarning{text}
@purple{\text\}
@diagWarning{}\text\@diagOff{}
@end macro
@macro derror{text}
@colorError{}\text\@colorOff{}
@diagError{}\text\@diagOff{}
@end macro
@macro dnotice{text}
@colorNotice{}\text\@colorOff{}
@diagNotice{}\text\@diagOff{}
@end macro
@finalout
@@ -8302,7 +8315,53 @@ write an unambiguous grammar, but that is very hard to do in this case.)
This particular ambiguity was first encountered in the specifications of
Algol 60 and is called the ``dangling @code{else}'' ambiguity.
To avoid warnings from Bison about predictable, legitimate shift/reduce
To assist the grammar author in understanding the nature of each conflict,
Bison can be asked to generate ``counterexamples''. In the present case it
actually even proves that the grammar is ambiguous by exhibiting a string
with two different parses:
@macro danglingElseCex
@group
@ifnottex
Example: @yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @blue{"else" stmt}
Shift derivation
@yellow{if_stmt}
@yellow{↳ "if" expr "then"} @green{stmt}
@green{↳} @blue{if_stmt}
@blue{↳ "if" expr "then" stmt} @red{•} @blue{"else" stmt}
Example: @yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @yellow{"else" stmt}
Reduce derivation
@yellow{if_stmt}
@yellow{↳ "if" expr "then"} @green{stmt} @yellow{"else" stmt}
@green{↳} @blue{if_stmt}
@blue{↳ "if" expr "then" stmt} @red{•}
@end ifnottex
@iftex
Example: @yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @blue{"else" stmt}
Shift derivation
@yellow{if_stmt}
@yellow{@arrow{} "if" expr "then"} @green{stmt}
@green{@arrow{}} @blue{if_stmt}
@blue{@arrow{} "if" expr "then" stmt} @red{•} @blue{"else" stmt}
Example: @yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @yellow{"else" stmt}
Reduce derivation
@yellow{if_stmt}
@yellow{@arrow{} "if" expr "then"} @green{stmt} @yellow{"else" stmt}
@green{@arrow{}} @blue{if_stmt}
@blue{@arrow{} "if" expr "then" stmt} @red{•}
@end iftex
@end group
@end macro
@example
@danglingElseCex
@end example
@noindent
@xref{Counterexamples}, for more details.
@sp 1
To avoid warnings from Bison about predictable, @emph{legitimate} shift/reduce
conflicts, you can use the @code{%expect @var{n}} declaration.
There will be no warning as long as the number of shift/reduce conflicts
is exactly @var{n}, and Bison will report an error if there is a
@@ -8693,7 +8752,8 @@ maybeword:
@end example
@noindent
The error is an ambiguity: there is more than one way to parse a single
The error is an ambiguity: as counterexample generation would demonstrate
(@pxref{Counterexamples}), there is more than one way to parse a single
@code{word} into a @code{sequence}. It could be reduced to a
@code{maybeword} and then into a @code{sequence} via the second rule.
Alternatively, nothing-at-all could be reduced into a @code{sequence}
@@ -8890,12 +8950,14 @@ name_list:
It would seem that this grammar can be parsed with only a single token of
lookahead: when a @code{param_spec} is being read, an @code{"id"} is a
@code{name} if a comma or colon follows, or a @code{type} if another
@code{"id"} follows. In other words, this grammar is LR(1).
@code{"id"} follows. In other words, this grammar is LR(1). Yet Bison
finds one reduce/reduce conflict, for which counterexample generation
(@pxref{Counterexamples}) would find a @emph{nonunifying} example.
@cindex LR
@cindex LALR
However, for historical reasons, Bison cannot by default handle all
LR(1) grammars.
This is because Bison does not handle all LR(1) grammars @emph{by default},
for historical reasons.
In this grammar, two contexts, that after an @code{"id"} at the beginning
of a @code{param_spec} and likewise at the beginning of a
@code{return_spec}, are similar enough that Bison assumes they are the
@@ -9870,6 +9932,9 @@ and understand the parser run-time traces (@pxref{Tracing}).
@node Counterexamples
@section Generation of Counterexamples
@cindex cex
@cindex counterexamples
@cindex conflict counterexamples
Solving conflicts is probably the most delicate part of the design of an LR
parser, as demonstrated by the number of sections devoted to them in this
@@ -9886,8 +9951,8 @@ That task is made much easier thanks to the generation of counterexamples,
initially developed by Chinawat Isradisaikul and Andrew Myers
@pcite{Isradisaikul 2015}.
As a first example, see the example grammar of @ref{Shift/Reduce}, which
features on shift/reduce conflict:
As a first example, see the grammar of @ref{Shift/Reduce}, which features
one shift/reduce conflict:
@c see doc/if-then-else.y
@example
@@ -9901,49 +9966,14 @@ Let's rerun @command{bison} with the option
@option{-Wcex}/@option{-Wcounterexamples}@inlinefmt{info, (the following
output is actually in color)}:
@ifnottex
@example
if-then-else.y: @dwarning{warning}: 1 shift/reduce conflict [@dwarning{-Wconflicts-sr}]
if-then-else.y: @dwarning{warning}: shift/reduce conflict on token "else" [@dwarning{-Wcounterexamples}]
@group
Example: @yellow{"if" expr "then"} "if" expr "then" stmt • "else" stmt
Shift derivation
@yellow{if_stmt}
@yellow{↳ "if" expr "then"} @green{stmt}
@green{↳} @blue{if_stmt}
@blue{↳ "if" expr "then" stmt} @red{•} @blue{"else" stmt}
Example: @yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @yellow{"else" stmt}
Reduce derivation
@yellow{if_stmt}
@yellow{↳ "if" expr "then"} @green{stmt} @yellow{"else" stmt}
@green{↳} @blue{if_stmt}
@blue{↳ "if" expr "then" stmt} @red{•}
@end group
@danglingElseCex
@end example
@end ifnottex
@iftex
@example
if-then-else.y: @dwarning{warning}: 1 shift/reduce conflict [@dwarning{-Wconflicts-sr}]
if-then-else.y: @dwarning{warning}: shift/reduce conflict on token "else" [@dwarning{-Wcounterexamples}]
@group
Example: @yellow{"if" expr "then"} "if" expr "then" stmt • "else" stmt
Shift derivation
@yellow{if_stmt}
@yellow{@arrow{} "if" expr "then"} @green{stmt}
@green{@arrow{}} @blue{if_stmt}
@blue{@arrow{} "if" expr "then" stmt} @red{•} @blue{"else" stmt}
Example: @yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @yellow{"else" stmt}
Reduce derivation
@yellow{if_stmt}
@yellow{@arrow{} "if" expr "then"} @green{stmt} @yellow{"else" stmt}
@green{@arrow{}} @blue{if_stmt}
@blue{@arrow{} "if" expr "then" stmt} @red{•}
@end group
@end example
@end iftex
This shows two different derivations for one single expression. That
demonstrates that the grammar is ambiguous.
This shows two different derivations for one single expression, which proves
that the grammar is ambiguous.
@sp 1
@@ -9966,13 +9996,13 @@ maybeword:
Bison generates the following counterexamples:
@ifnottex
@example
@group
$ @kbd{bison -Wcex sequence.y}
sequence.y: @dwarning{warning}: 1 shift/reduce conflict [@dwarning{-Wconflicts-sr}]
sequence.y: @dwarning{warning}: 2 reduce/reduce conflicts [@dwarning{-Wconflicts-rr}]
@end group
@ifnottex
@group
sequence.y: @dwarning{warning}: shift/reduce conflict on token "word" [@dwarning{-Wcounterexamples}]
Example: @red{•} @green{"word"}
@@ -10017,15 +10047,8 @@ sequence.y:8.3-45: @dwarning{warning}: rule useless in parser due to conflicts [
8 | @dwarning{%empty @{ printf ("empty maybeword\n"); @}}
| @dwarning{^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
@end group
@end example
@end ifnottex
@iftex
@example
@group
$ @kbd{bison -Wcex sequence.y}
sequence.y: @dwarning{warning}: 1 shift/reduce conflict [@dwarning{-Wconflicts-sr}]
sequence.y: @dwarning{warning}: 2 reduce/reduce conflicts [@dwarning{-Wconflicts-rr}]
@end group
@group
sequence.y: @dwarning{warning}: shift/reduce conflict on token "word" [@dwarning{-Wcounterexamples}]
Example: @red{•} @green{"word"}
@@ -10070,8 +10093,8 @@ sequence.y:8.3-45: @dwarning{warning}: rule useless in parser due to conflicts [
8 | @dwarning{%empty @{ printf ("empty maybeword\n"); @}}
| @dwarning{^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
@end group
@end example
@end iftex
@end example
Each of these three conflicts, again, prove that the grammar is ambiguous.
For instance, the second conflict (the reduce/reduce one) shows that the
@@ -10096,10 +10119,10 @@ expr: %empty | expr ID ','
@command{bison} reports:
@ifnottex
@example
ids.y: @dwarning{warning}: 1 shift/reduce conflict [@dwarning{-Wconflicts-sr}]
ids.y: @dwarning{warning}: shift/reduce conflict on token ID [@dwarning{-Wcounterexamples}]
@ifnottex
@group
First example: @purple{expr} @red{•} @purple{ID ','} @green{ID} @yellow{$end}
Shift derivation
@@ -10120,12 +10143,8 @@ ids.y:4.4-7: @dwarning{warning}: rule useless in parser due to conflicts [@dwarn
4 | a: expr
| ^~~~
@end group
@end example
@end ifnottex
@iftex
@example
ids.y: @dwarning{warning}: 1 shift/reduce conflict [@dwarning{-Wconflicts-sr}]
ids.y: @dwarning{warning}: shift/reduce conflict on token ID [@dwarning{-Wcounterexamples}]
@group
First example: @purple{expr} @red{•} @purple{ID ','} @green{ID} @yellow{$end}
Shift derivation
@@ -10146,8 +10165,8 @@ ids.y:4.4-7: @dwarning{warning}: rule useless in parser due to conflicts [@dwarn
4 | a: expr
| ^~~~
@end group
@end example
@end iftex
@end example
This conflict is caused by the parser not having enough information to know
the difference between these two examples. The parser would need an
@@ -15631,6 +15650,10 @@ permitted. @xref{Language and Grammar}.
A sequence of tokens and/or nonterminals, with one dot, that demonstrates a
conflict. The dot marks the place where the conflict occurs.
@cindex unifying counterexample
@cindex counterexample, unifying
@cindex nonunifying counterexample
@cindex counterexample, nonunifying
A @emph{unifying} counterexample is a single string that has two different
parses; its existence proves that the grammar is ambiguous. When a unifying
counterexample cannot be found in reasonable time, a @emph{nonunifying}
+1 -1
Submodule gnulib updated: ac34618e85...37b6f12946
+1 -2
View File
@@ -192,8 +192,6 @@
/localcharset.h
/locale.h
/locale.in.h
/localtime-buffer.c
/localtime-buffer.h
/lstat.c
/malloc.c
/malloca.c
@@ -338,6 +336,7 @@
/sys_types.in.h
/sys_wait.in.h
/sysexits.in.h
/termios.in.h
/textstyle.h
/textstyle.in.h
/time.h
+3 -2
View File
@@ -67,7 +67,6 @@
/intlmacosx.m4
/intmax.m4
/intmax_t.m4
/inttypes-pri.m4
/inttypes.m4
/inttypes_h.m4
/isnan.m4
@@ -97,7 +96,6 @@
/locale-ja.m4
/locale-zh.m4
/locale_h.m4
/localtime-buffer.m4
/lock.m4
/longlong.m4
/lstat.m4
@@ -117,6 +115,7 @@
/msvc-inval.m4
/msvc-nothrow.m4
/multiarch.m4
/musl.m4
/nls.m4
/nocrash.m4
/non-recursive-gnulib-prefix-hack.m4
@@ -184,6 +183,7 @@
/strndup.m4
/strnlen.m4
/strverscmp.m4
/sys_ioctl_h.m4
/sys_resource_h.m4
/sys_socket_h.m4
/sys_stat_h.m4
@@ -191,6 +191,7 @@
/sys_times_h.m4
/sys_types_h.m4
/sys_wait_h.m4
/termios_h.m4
/threadlib.m4
/time_h.m4
/timespec.m4
+9 -14
View File
@@ -113,13 +113,8 @@ free_counterexample (counterexample *cex)
free (cex);
}
static int max (int a, int b)
{
return a < b ? b : a;
}
static void
print_counterexample (const counterexample *cex, FILE *out, const char *prefix)
counterexample_print (const counterexample *cex, FILE *out, const char *prefix)
{
const bool flat = getenv ("YYFLAT");
const char *example1_label
@@ -131,8 +126,8 @@ print_counterexample (const counterexample *cex, FILE *out, const char *prefix)
const char *deriv2_label
= cex->shift_reduce ? _("Reduce derivation") : _("Second reduce derivation");
const int width =
max (max (mbswidth (example1_label, 0), mbswidth (example2_label, 0)),
max (mbswidth (deriv1_label, 0), mbswidth (deriv2_label, 0)));
max_int (max_int (mbswidth (example1_label, 0), mbswidth (example2_label, 0)),
max_int (mbswidth (deriv1_label, 0), mbswidth (deriv2_label, 0)));
if (flat)
fprintf (out, " %s%s%*s ", prefix,
example1_label, width - mbswidth (example1_label, 0), "");
@@ -526,7 +521,7 @@ nonunifying_shift_path (state_item_list reduce_path, state_item *shift_conflict)
for (gl_list_iterator_t it = gl_list_iterator (result);
state_item_list_next (&it, &sip);
)
print_state_item (sip, stderr, "");
state_item_print (sip, stderr, "");
}
return result;
}
@@ -1267,7 +1262,7 @@ counterexample_report (state_item_number itm1, state_item_number itm2,
: example_from_path (shift_reduce, itm2, shortest_path, next_sym);
gl_list_free (shortest_path);
print_counterexample (cex, out, prefix);
counterexample_print (cex, out, prefix);
free_counterexample (cex);
}
@@ -1290,8 +1285,8 @@ counterexample_report_shift_reduce (state_item_number itm1, state_item_number it
// In the report, print the items.
if (out != stderr || trace_flag & trace_cex)
{
print_state_item (&state_items[itm1], out, prefix);
print_state_item (&state_items[itm2], out, prefix);
state_item_print (&state_items[itm1], out, prefix);
state_item_print (&state_items[itm2], out, prefix);
}
counterexample_report (itm1, itm2, next_sym, true, out, prefix);
}
@@ -1334,8 +1329,8 @@ counterexample_report_reduce_reduce (state_item_number itm1, state_item_number i
// In the report, print the items.
if (out != stderr || trace_flag & trace_cex)
{
print_state_item (&state_items[itm1], out, prefix);
print_state_item (&state_items[itm2], out, prefix);
state_item_print (&state_items[itm1], out, prefix);
state_item_print (&state_items[itm2], out, prefix);
}
counterexample_report (itm1, itm2, bitset_first (conflict_syms),
false, out, prefix);
+8 -14
View File
@@ -76,12 +76,12 @@ void derivation_list_free (derivation_list dl)
derivation *
derivation_new (symbol_number sym, derivation_list children)
{
derivation *deriv = xmalloc (sizeof (derivation));
deriv->sym = sym;
deriv->children = children;
deriv->reference_count = 0;
deriv->color = -1;
return deriv;
derivation *res = xmalloc (sizeof *res);
res->sym = sym;
res->children = children;
res->reference_count = 0;
res->color = -1;
return res;
}
void
@@ -135,12 +135,6 @@ derivation_size (const derivation *deriv)
}
static int
max (int a, int b)
{
return a < b ? b : a;
}
// Longest distance from root to leaf.
static int
derivation_depth (const derivation *deriv)
@@ -154,7 +148,7 @@ derivation_depth (const derivation *deriv)
for (gl_list_iterator_t it = gl_list_iterator (deriv->children);
derivation_list_next (&it, &child);
)
res = max (res, derivation_depth (child));
res = max_int (res, derivation_depth (child));
return res + 1;
}
else
@@ -237,7 +231,7 @@ derivation_width (const derivation *deriv)
// No separator at the beginning.
children_width -= derivation_separator_width;
}
return max (self_width, children_width);
return max_int (self_width, children_width);
}
else if (deriv == &d_dot)
{
+9 -1
View File
@@ -112,7 +112,15 @@ static struct obstack obstack_for_string;
# define STRING_1GROW(Char) \
obstack_1grow (&obstack_for_string, Char)
# define STRING_FREE() \
# ifdef NDEBUG
# define STRING_FREE() \
obstack_free (&obstack_for_string, last_string)
# else
# define STRING_FREE() \
do { \
obstack_free (&obstack_for_string, last_string); \
last_string = NULL; \
} while (0)
# endif
#endif
+1 -1
View File
@@ -423,7 +423,7 @@ ielr_item_has_lookahead (state *s, symbol_number lhs, size_t item,
check all predecessors' goto follows for the LHS. */
if (item_number_is_rule_number (ritem[s->items[item] - 2]))
{
aver (lhs != accept->content->number);
aver (lhs != acceptsymbol->content->number);
for (state **predecessor = predecessors[s->number];
*predecessor;
++predecessor)
-12
View File
@@ -40,18 +40,6 @@
location const empty_loc = EMPTY_LOCATION_INIT;
static int
min_int (int a, int b)
{
return a < b ? a : b;
}
static int
max_int (int a, int b)
{
return a >= b ? a : b;
}
/* The terminal width. Not less than 40. */
static int
columns (void)
+1 -1
View File
@@ -256,7 +256,7 @@ shortest_path_from_start (state_item_number target, symbol_number next_sym)
gl_list_iterator_t it = gl_list_iterator (res);
const void *sip;
while (gl_list_iterator_next (&it, &sip, NULL))
print_state_item ((state_item *) sip, stdout, "");
state_item_print ((state_item *) sip, stdout, "");
}
return res;
}
+21 -21
View File
@@ -1,4 +1,4 @@
/* A Bison parser, made by GNU Bison 3.6.90. */
/* A Bison parser, made by GNU Bison 3.7.14-eb26-dirty. */
/* Bison implementation for Yacc-like parsers in C
@@ -49,7 +49,7 @@
#define YYBISON 1
/* Bison version. */
#define YYBISON_VERSION "3.6.90"
#define YYBISON_VERSION "3.7.14-eb26-dirty"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -149,7 +149,7 @@ enum yysymbol_kind_t
YYSYMBOL_BRACED_CODE = 41, /* "{...}" */
YYSYMBOL_BRACED_PREDICATE = 42, /* "%?{...}" */
YYSYMBOL_BRACKETED_ID = 43, /* "[identifier]" */
YYSYMBOL_CHAR = 44, /* "character literal" */
YYSYMBOL_CHAR_LITERAL = 44, /* "character literal" */
YYSYMBOL_COLON = 45, /* ":" */
YYSYMBOL_EPILOGUE = 46, /* "epilogue" */
YYSYMBOL_EQUAL = 47, /* "=" */
@@ -162,7 +162,7 @@ enum yysymbol_kind_t
YYSYMBOL_TAG = 54, /* "<tag>" */
YYSYMBOL_TAG_ANY = 55, /* "<*>" */
YYSYMBOL_TAG_NONE = 56, /* "<>" */
YYSYMBOL_INT = 57, /* "integer literal" */
YYSYMBOL_INT_LITERAL = 57, /* "integer literal" */
YYSYMBOL_PERCENT_PARAM = 58, /* "%param" */
YYSYMBOL_PERCENT_UNION = 59, /* "%union" */
YYSYMBOL_PERCENT_EMPTY = 60, /* "%empty" */
@@ -1115,8 +1115,8 @@ tron (yyo);
{ fprintf (yyo, "[%s]", ((*yyvaluep).BRACKETED_ID)); }
break;
case YYSYMBOL_CHAR: /* "character literal" */
{ fputs (char_name (((*yyvaluep).CHAR)), yyo); }
case YYSYMBOL_CHAR_LITERAL: /* "character literal" */
{ fputs (char_name (((*yyvaluep).CHAR_LITERAL)), yyo); }
break;
case YYSYMBOL_EPILOGUE: /* "epilogue" */
@@ -1139,8 +1139,8 @@ tron (yyo);
{ fprintf (yyo, "<%s>", ((*yyvaluep).TAG)); }
break;
case YYSYMBOL_INT: /* "integer literal" */
{ fprintf (yyo, "%d", ((*yyvaluep).INT)); }
case YYSYMBOL_INT_LITERAL: /* "integer literal" */
{ fprintf (yyo, "%d", ((*yyvaluep).INT_LITERAL)); }
break;
case YYSYMBOL_PERCENT_PARAM: /* "%param" */
@@ -2087,11 +2087,11 @@ yyreduce:
break;
case 12: /* prologue_declaration: "%expect" "integer literal" */
{ expected_sr_conflicts = (yyvsp[0].INT); }
{ expected_sr_conflicts = (yyvsp[0].INT_LITERAL); }
break;
case 13: /* prologue_declaration: "%expect-rr" "integer literal" */
{ expected_rr_conflicts = (yyvsp[0].INT); }
{ expected_rr_conflicts = (yyvsp[0].INT_LITERAL); }
break;
case 14: /* prologue_declaration: "%file-prefix" "string" */
@@ -2339,13 +2339,13 @@ yyreduce:
case 67: /* token_decls: "<tag>" token_decl.1 */
{
(yyval.token_decls) = symbol_list_type_set ((yyvsp[0].yykind_80), (yyvsp[-1].TAG), (yylsp[-1]));
(yyval.token_decls) = symbol_list_type_set ((yyvsp[0].yykind_80), (yyvsp[-1].TAG));
}
break;
case 68: /* token_decls: token_decls "<tag>" token_decl.1 */
{
(yyval.token_decls) = symbol_list_append ((yyvsp[-2].token_decls), symbol_list_type_set ((yyvsp[0].yykind_80), (yyvsp[-1].TAG), (yylsp[-1])));
(yyval.token_decls) = symbol_list_append ((yyvsp[-2].token_decls), symbol_list_type_set ((yyvsp[0].yykind_80), (yyvsp[-1].TAG)));
}
break;
@@ -2396,13 +2396,13 @@ yyreduce:
case 78: /* token_decls_for_prec: "<tag>" token_decl_for_prec.1 */
{
(yyval.token_decls_for_prec) = symbol_list_type_set ((yyvsp[0].yykind_85), (yyvsp[-1].TAG), (yylsp[-1]));
(yyval.token_decls_for_prec) = symbol_list_type_set ((yyvsp[0].yykind_85), (yyvsp[-1].TAG));
}
break;
case 79: /* token_decls_for_prec: token_decls_for_prec "<tag>" token_decl_for_prec.1 */
{
(yyval.token_decls_for_prec) = symbol_list_append ((yyvsp[-2].token_decls_for_prec), symbol_list_type_set ((yyvsp[0].yykind_85), (yyvsp[-1].TAG), (yylsp[-1])));
(yyval.token_decls_for_prec) = symbol_list_append ((yyvsp[-2].token_decls_for_prec), symbol_list_type_set ((yyvsp[0].yykind_85), (yyvsp[-1].TAG)));
}
break;
@@ -2431,13 +2431,13 @@ yyreduce:
case 85: /* symbol_decls: "<tag>" symbol_decl.1 */
{
(yyval.symbol_decls) = symbol_list_type_set ((yyvsp[0].yykind_88), (yyvsp[-1].TAG), (yylsp[-1]));
(yyval.symbol_decls) = symbol_list_type_set ((yyvsp[0].yykind_88), (yyvsp[-1].TAG));
}
break;
case 86: /* symbol_decls: symbol_decls "<tag>" symbol_decl.1 */
{
(yyval.symbol_decls) = symbol_list_append ((yyvsp[-2].symbol_decls), symbol_list_type_set ((yyvsp[0].yykind_88), (yyvsp[-1].TAG), (yylsp[-1])));
(yyval.symbol_decls) = symbol_list_append ((yyvsp[-2].symbol_decls), symbol_list_type_set ((yyvsp[0].yykind_88), (yyvsp[-1].TAG)));
}
break;
@@ -2506,7 +2506,7 @@ yyreduce:
break;
case 105: /* rhs: rhs "%dprec" "integer literal" */
{ grammar_current_rule_dprec_set ((yyvsp[0].INT), (yylsp[0])); }
{ grammar_current_rule_dprec_set ((yyvsp[0].INT_LITERAL), (yylsp[0])); }
break;
case 106: /* rhs: rhs "%merge" "<tag>" */
@@ -2514,11 +2514,11 @@ yyreduce:
break;
case 107: /* rhs: rhs "%expect" "integer literal" */
{ grammar_current_rule_expect_sr ((yyvsp[0].INT), (yylsp[0])); }
{ grammar_current_rule_expect_sr ((yyvsp[0].INT_LITERAL), (yylsp[0])); }
break;
case 108: /* rhs: rhs "%expect-rr" "integer literal" */
{ grammar_current_rule_expect_rr ((yyvsp[0].INT), (yylsp[0])); }
{ grammar_current_rule_expect_rr ((yyvsp[0].INT_LITERAL), (yylsp[0])); }
break;
case 109: /* named_ref.opt: %empty */
@@ -2566,9 +2566,9 @@ yyreduce:
location loc = muscle_percent_define_get_loc (var);
subcomplain (&loc, complaint, _("definition of %s"), var);
}
(yyval.id) = symbol_get (char_name ((yyvsp[0].CHAR)), (yylsp[0]));
(yyval.id) = symbol_get (char_name ((yyvsp[0].CHAR_LITERAL)), (yylsp[0]));
symbol_class_set ((yyval.id), token_sym, (yylsp[0]), false);
symbol_code_set ((yyval.id), (yyvsp[0].CHAR), (yylsp[0]));
symbol_code_set ((yyval.id), (yyvsp[0].CHAR_LITERAL), (yylsp[0]));
}
break;
+5 -5
View File
@@ -1,4 +1,4 @@
/* A Bison parser, made by GNU Bison 3.6.90. */
/* A Bison parser, made by GNU Bison 3.7.14-eb26-dirty. */
/* Bison interface for Yacc-like parsers in C
@@ -123,7 +123,7 @@ extern int gram_debug;
BRACED_CODE = 41, /* "{...}" */
BRACED_PREDICATE = 42, /* "%?{...}" */
BRACKETED_ID = 43, /* "[identifier]" */
CHAR = 44, /* "character literal" */
CHAR_LITERAL = 44, /* "character literal" */
COLON = 45, /* ":" */
EPILOGUE = 46, /* "epilogue" */
EQUAL = 47, /* "=" */
@@ -136,7 +136,7 @@ extern int gram_debug;
TAG = 54, /* "<tag>" */
TAG_ANY = 55, /* "<*>" */
TAG_NONE = 56, /* "<>" */
INT = 57, /* "integer literal" */
INT_LITERAL = 57, /* "integer literal" */
PERCENT_PARAM = 58, /* "%param" */
PERCENT_UNION = 59, /* "%union" */
PERCENT_EMPTY = 60 /* "%empty" */
@@ -156,7 +156,7 @@ union GRAM_STYPE
char* EPILOGUE; /* "epilogue" */
char* PROLOGUE; /* "%{...%}" */
code_props_type code_props_type; /* code_props_type */
int INT; /* "integer literal" */
int INT_LITERAL; /* "integer literal" */
int yykind_82; /* int.opt */
named_ref* yykind_95; /* named_ref.opt */
param_type PERCENT_PARAM; /* "%param" */
@@ -188,7 +188,7 @@ union GRAM_STYPE
uniqstr yykind_74; /* tag.opt */
uniqstr tag; /* tag */
uniqstr variable; /* variable */
unsigned char CHAR; /* "character literal" */
unsigned char CHAR_LITERAL; /* "character literal" */
value_type value; /* value */
+16 -16
View File
@@ -214,7 +214,7 @@
BRACED_CODE "{...}"
BRACED_PREDICATE "%?{...}"
BRACKETED_ID _("[identifier]")
CHAR _("character literal")
CHAR_LITERAL _("character literal")
COLON ":"
EPILOGUE _("epilogue")
EQUAL "="
@@ -232,7 +232,7 @@
%code pre-printer {tron (yyo);}
%code post-printer {troff (yyo);}
%type <unsigned char> CHAR
%type <unsigned char> CHAR_LITERAL
%printer { fputs (char_name ($$), yyo); } <unsigned char>
%type <char*> "{...}" "%?{...}" "%{...%}" EPILOGUE STRING TSTRING
@@ -249,7 +249,7 @@
%printer { fprintf (yyo, "%%%s", $$); } PERCENT_FLAG
%printer { fprintf (yyo, "<%s>", $$); } TAG tag
%token <int> INT _("integer literal")
%token <int> INT_LITERAL _("integer literal")
%printer { fprintf (yyo, "%d", $$); } <int>
%type <symbol*> id id_colon string_as_id symbol token_decl token_decl_for_prec
@@ -342,8 +342,8 @@ prologue_declaration:
| "%defines" { defines_flag = true; }
| "%defines" STRING { handle_defines ($2); }
| "%error-verbose" { handle_error_verbose (&@$, $1); }
| "%expect" INT { expected_sr_conflicts = $2; }
| "%expect-rr" INT { expected_rr_conflicts = $2; }
| "%expect" INT_LITERAL { expected_sr_conflicts = $2; }
| "%expect-rr" INT_LITERAL { expected_rr_conflicts = $2; }
| "%file-prefix" STRING { handle_file_prefix (&@$, &@1, $1, $2); }
| "%glr-parser"
{
@@ -532,11 +532,11 @@ token_decls:
}
| TAG token_decl.1[syms]
{
$$ = symbol_list_type_set ($syms, $TAG, @TAG);
$$ = symbol_list_type_set ($syms, $TAG);
}
| token_decls TAG token_decl.1[syms]
{
$$ = symbol_list_append ($1, symbol_list_type_set ($syms, $TAG, @TAG));
$$ = symbol_list_append ($1, symbol_list_type_set ($syms, $TAG));
}
;
@@ -561,7 +561,7 @@ token_decl:
%type <int> int.opt;
int.opt:
%empty { $$ = -1; }
| INT
| INT_LITERAL
;
%type <symbol*> alias;
@@ -592,11 +592,11 @@ token_decls_for_prec:
}
| TAG token_decl_for_prec.1[syms]
{
$$ = symbol_list_type_set ($syms, $TAG, @TAG);
$$ = symbol_list_type_set ($syms, $TAG);
}
| token_decls_for_prec TAG token_decl_for_prec.1[syms]
{
$$ = symbol_list_append ($1, symbol_list_type_set ($syms, $TAG, @TAG));
$$ = symbol_list_append ($1, symbol_list_type_set ($syms, $TAG));
}
;
@@ -632,11 +632,11 @@ symbol_decls:
}
| TAG symbol_decl.1[syms]
{
$$ = symbol_list_type_set ($syms, $TAG, @TAG);
$$ = symbol_list_type_set ($syms, $TAG);
}
| symbol_decls TAG symbol_decl.1[syms]
{
$$ = symbol_list_append ($1, symbol_list_type_set ($syms, $TAG, @TAG));
$$ = symbol_list_append ($1, symbol_list_type_set ($syms, $TAG));
}
;
@@ -703,13 +703,13 @@ rhs:
{ grammar_current_rule_empty_set (@2); }
| rhs "%prec" symbol
{ grammar_current_rule_prec_set ($3, @3); }
| rhs "%dprec" INT
| rhs "%dprec" INT_LITERAL
{ grammar_current_rule_dprec_set ($3, @3); }
| rhs "%merge" TAG
{ grammar_current_rule_merge_set ($3, @3); }
| rhs "%expect" INT
| rhs "%expect" INT_LITERAL
{ grammar_current_rule_expect_sr ($3, @3); }
| rhs "%expect-rr" INT
| rhs "%expect-rr" INT_LITERAL
{ grammar_current_rule_expect_rr ($3, @3); }
;
@@ -765,7 +765,7 @@ value:
id:
ID
{ $$ = symbol_from_uniqstr ($1, @1); }
| CHAR
| CHAR_LITERAL
{
const char *var = "api.token.raw";
if (current_class == nterm_sym)
+13 -17
View File
@@ -30,17 +30,17 @@
typedef struct parse_state
{
// path of state-items the parser has traversed
// Path of state-items the parser has traversed.
struct si_chunk
{
// elements newly added in this chunk
// Elements newly added in this chunk.
state_item_list contents;
// properties of the linked list this chunk represents
// Properties of the linked list this chunk represents.
const state_item *head_elt;
const state_item *tail_elt;
size_t total_size;
} state_items;
// list of derivations of the symbols
// List of derivations of the symbols.
struct deriv_chunk
{
derivation_list contents;
@@ -50,16 +50,13 @@ typedef struct parse_state
} derivs;
struct parse_state *parent;
int reference_count;
// incremented during productions,
// decremented during reductions
// Incremented during productions, decremented during reductions.
int depth;
// whether the contents of the chunks should be
// prepended or appended to the list the chunks
// represent
// Whether the contents of the chunks should be prepended or
// appended to the list the chunks represent.
bool prepend;
// causes chunk contents to be freed when the
// reference count is one. Used when only the chunk metadata
// will be needed.
// Causes chunk contents to be freed when the reference count is
// one. Used when only the chunk metadata will be needed.
bool free_contents_early;
} parse_state;
@@ -438,9 +435,8 @@ simulate_transition (parse_state *ps)
// symbols into account.
parse_state_list result = parse_state_list_new ();
state_item_number si_next = si->trans;
// check for disabled transition, shouldn't happen
// as any state_items that lead to these should be
// disabled.
// Check for disabled transition, shouldn't happen as any
// state_items that lead to these should be disabled.
if (si_next < 0)
return result;
parse_state *next_ps = copy_parse_state (false, ps);
@@ -594,8 +590,8 @@ print_parse_state (parse_state *ps)
FILE *out = stderr;
fprintf (out, "(size %zu depth %d rc %d)\n",
ps->state_items.total_size, ps->depth, ps->reference_count);
print_state_item (ps->state_items.head_elt, out, "");
print_state_item (ps->state_items.tail_elt, out, "");
state_item_print (ps->state_items.head_elt, out, "");
state_item_print (ps->state_items.tail_elt, out, "");
if (ps->derivs.total_size > 0)
derivation_print (ps->derivs.head_elt, out, "");
putc ('\n', out);
+1 -1
View File
@@ -804,7 +804,7 @@ check_and_convert_grammar (void)
$accept: %start $end. */
{
symbol_list *p = symbol_list_sym_new (accept, empty_loc);
symbol_list *p = symbol_list_sym_new (acceptsymbol, empty_loc);
p->rhs_loc = grammar->rhs_loc;
p->next = symbol_list_sym_new (startsymbol, empty_loc);
p->next->next = symbol_list_sym_new (eoftoken, empty_loc);
+4 -4
View File
@@ -160,9 +160,9 @@ inaccessable_symbols (void)
bitset Pp = bitset_create (nrules, BITSET_FIXED);
/* If the start symbol isn't useful, then nothing will be useful. */
if (bitset_test (N, accept->content->number - ntokens))
if (bitset_test (N, acceptsymbol->content->number - ntokens))
{
bitset_set (V, accept->content->number);
bitset_set (V, acceptsymbol->content->number);
while (1)
{
@@ -301,7 +301,7 @@ nonterminals_reduce (void)
for (item_number *rhsp = rules[r].rhs; 0 <= *rhsp; ++rhsp)
if (ISVAR (*rhsp))
*rhsp = symbol_number_as_item_number (nterm_map[*rhsp - ntokens]);
accept->content->number = nterm_map[accept->content->number - ntokens];
acceptsymbol->content->number = nterm_map[acceptsymbol->content->number - ntokens];
}
nsyms -= nuseless_nonterminals;
@@ -381,7 +381,7 @@ reduce_grammar (void)
{
reduce_print ();
if (!bitset_test (N, accept->content->number - ntokens))
if (!bitset_test (N, acceptsymbol->content->number - ntokens))
complain (&startsymbol_loc, fatal,
_("start symbol %s does not derive any sentence"),
startsymbol->tag);
+8 -7
View File
@@ -322,8 +322,8 @@ eqopt ({sp}=)?
BEGIN SC_AFTER_IDENTIFIER;
}
{int} RETURN_VALUE (INT, scan_integer (yytext, 10, *loc));
{xint} RETURN_VALUE (INT, scan_integer (yytext, 16, *loc));
{int} RETURN_VALUE (INT_LITERAL, scan_integer (yytext, 10, *loc));
{xint} RETURN_VALUE (INT_LITERAL, scan_integer (yytext, 16, *loc));
/* Identifiers may not start with a digit. Yet, don't silently
accept "1FOO" as "1 FOO". */
@@ -403,6 +403,7 @@ eqopt ({sp}=)?
{
\0 {
complain (loc, complaint, _("invalid null character"));
STRING_FINISH ();
STRING_FREE ();
return GRAM_error;
}
@@ -599,7 +600,6 @@ eqopt ({sp}=)?
STRING_FINISH ();
BEGIN INITIAL;
loc->start = token_start;
val->CHAR = last_string[0];
if (last_string[0] == '\0')
{
@@ -615,8 +615,9 @@ eqopt ({sp}=)?
}
else
{
val->CHAR_LITERAL = last_string[0];
STRING_FREE ();
return CHAR;
return CHAR_LITERAL;
}
}
{eol} unexpected_newline (token_start, "'");
@@ -933,9 +934,9 @@ convert_ucn_to_byte (char const *ucn)
}
/*---------------------------------------------------------------------.
| Handle '#line INT( "FILE")?\n'. ARGS has already skipped '#line '. |
`---------------------------------------------------------------------*/
/*----------------------------------------------------------------------------.
| Handle '#line INT_LITERAL( "FILE")?\n'. ARGS has already skipped '#line '. |
`----------------------------------------------------------------------------*/
static void
handle_syncline (char *args, location loc)
+3 -3
View File
@@ -475,7 +475,7 @@ prune_disabled_paths (void)
}
void
print_state_item (const state_item *si, FILE *out, const char *prefix)
state_item_print (const state_item *si, FILE *out, const char *prefix)
{
fputs (prefix, out);
item_print (si->item, NULL, out);
@@ -506,7 +506,7 @@ state_items_report (void)
if (si->trans >= 0)
{
fputs (" -> ", stdout);
print_state_item (&state_items[si->trans], stdout, "");
state_item_print (&state_items[si->trans], stdout, "");
}
bitset sets[2] = { si->prods, si->revs };
@@ -521,7 +521,7 @@ state_items_report (void)
BITSET_FOR_EACH (biter, b, sin, 0)
{
fputs (txt[seti], stdout);
print_state_item (&state_items[sin], stdout, "");
state_item_print (&state_items[sin], stdout, "");
}
}
}
+2 -1
View File
@@ -90,9 +90,10 @@ state_item_index_lookup (state_number s, state_item_number off)
}
void state_items_init (void);
void print_state_item (const state_item *si, FILE *out, const char *prefix);
void state_items_free (void);
void state_item_print (const state_item *si, FILE *out, const char *prefix);
bool production_allowed (const state_item *si, const state_item *next);
// Iterating on a state_item_list.
+2 -2
View File
@@ -83,10 +83,10 @@ symbol_list_type_new (uniqstr type_name, location loc)
symbol_list *
symbol_list_type_set (symbol_list *syms, uniqstr type_name, location loc)
symbol_list_type_set (symbol_list *syms, uniqstr type_name)
{
for (symbol_list *l = syms; l; l = l->next)
symbol_type_set (l->content.sym, type_name, loc);
symbol_type_set (l->content.sym, type_name, l->sym_loc);
return syms;
}
+1 -2
View File
@@ -110,8 +110,7 @@ symbol_list *symbol_list_type_new (uniqstr type_name, location loc);
/** Assign the type \c type_name to all the members of \c syms.
** \returns \c syms */
symbol_list *symbol_list_type_set (symbol_list *syms,
uniqstr type_name, location loc);
symbol_list *symbol_list_type_set (symbol_list *syms, uniqstr type_name);
/** Print this list.
+5 -5
View File
@@ -59,7 +59,7 @@ static semantic_type **semantic_types_sorted = NULL;
symbol *errtoken = NULL;
symbol *undeftoken = NULL;
symbol *eoftoken = NULL;
symbol *accept = NULL;
symbol *acceptsymbol = NULL;
symbol *startsymbol = NULL;
location startsymbol_loc;
@@ -849,10 +849,10 @@ symbols_new (void)
hash_symbol_comparator,
symbol_free);
/* Construct the accept symbol. */
accept = symbol_get ("$accept", empty_loc);
accept->content->class = nterm_sym;
accept->content->number = nnterms++;
/* Construct the acceptsymbol symbol. */
acceptsymbol = symbol_get ("$accept", empty_loc);
acceptsymbol->content->class = nterm_sym;
acceptsymbol->content->number = nnterms++;
/* Construct the YYerror/"error" token */
errtoken = symbol_get ("YYerror", empty_loc);
+1 -1
View File
@@ -245,7 +245,7 @@ extern symbol *eoftoken;
/** The genuine start symbol.
$accept: start-symbol $end */
extern symbol *accept;
extern symbol *acceptsymbol;
/** The user start symbol. */
extern symbol *startsymbol;
+16
View File
@@ -131,6 +131,22 @@ typedef size_t uintptr_t;
# include <stdbool.h>
/*-----------.
| Integers. |
`-----------*/
static inline int
min_int (int a, int b)
{
return a < b ? a : b;
}
static inline int
max_int (int a, int b)
{
return a >= b ? a : b;
}
/*-------------.
| Assertions. |
+42 -14
View File
@@ -1,4 +1,4 @@
# Checking the Bison scanner. -*- Autotest -*-
# Checking the Bison reader. -*- Autotest -*-
# Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc.
@@ -78,10 +78,13 @@ AT_CLEANUP
## Invalid inputs. ##
## ---------------- ##
# The truly bad guys no human would write, but easily uncovered by
# fuzzers.
AT_SETUP([Invalid inputs])
AT_DATA([input.y],
[[\000\001\002\377?
"\000"
%%
?
default: 'a' }
@@ -92,16 +95,41 @@ default: 'a' }
]])
AT_PERL_REQUIRE([[-pi -e 's/\\(\d{3})/chr(oct($1))/ge' input.y]])
AT_BISON_CHECK([input.y], [1], [],
AT_BISON_CHECK([-fcaret input.y], [1], [], [stderr])
# Autotest's diffing, when there are NUL bytes, just reports "binary
# files differ". So don't leave NUL bytes.
AT_PERL_CHECK([[-p -e 's{([\0\377])}{sprintf "\\x%02x", ord($1)}ge' stderr]], [],
[[input.y:1.1-2: error: invalid characters: '\0\001\002\377?'
input.y:3.1: error: invalid character: '?'
input.y:4.14: error: invalid character: '}'
input.y:5.1: error: invalid character: '%'
input.y:5.2: error: invalid character: '&'
input.y:6.1-17: error: invalid directive: '%a-does-not-exist'
input.y:7.1: error: invalid character: '%'
input.y:7.2: error: invalid character: '-'
input.y:8.1-9.0: error: missing '%}' at end of file
1 | \x00\xff?
| ^~
input.y:2.2: error: invalid null character
2 | "\x00"
| ^
input.y:4.1: error: invalid character: '?'
4 | ?
| ^
input.y:5.14: error: invalid character: '}'
5 | default: 'a' }
| ^
input.y:6.1: error: invalid character: '%'
6 | %&
| ^
input.y:6.2: error: invalid character: '&'
6 | %&
| ^
input.y:7.1-17: error: invalid directive: '%a-does-not-exist'
7 | %a-does-not-exist
| ^~~~~~~~~~~~~~~~~
input.y:8.1: error: invalid character: '%'
8 | %-
| ^
input.y:8.2: error: invalid character: '-'
8 | %-
| ^
input.y:9.1-10.0: error: missing '%}' at end of file
9 | %{
| ^~
]])
AT_CLEANUP
@@ -1224,12 +1252,12 @@ AT_TEST([[%token foo "foo"
%%
exp: foo;
]],
[[input.y:3.7-11: error: %type redeclaration for foo
[[input.y:3.13-15: error: %type redeclaration for foo
3 | %type <baz> foo
| ^~~~~
input.y:2.7-11: note: previous declaration
| ^~~
input.y:2.13-17: note: previous declaration
2 | %type <bar> "foo"
| ^~~~~
| ^~~~~
]])
AT_TEST([[%token foo "foo"