mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-08-08 10:15:14 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5163803a63 | ||
|
|
fee7c78a83 | ||
|
|
8fc544b03c | ||
|
|
d62d5c4b33 | ||
|
|
ab3eaff7c4 | ||
|
|
85e83ea968 | ||
|
|
0269c6fb03 | ||
|
|
23e536af49 | ||
|
|
cd56929097 | ||
|
|
7aa38561f7 | ||
|
|
22a00cfbf2 | ||
|
|
8c06cb9130 | ||
|
|
b5233ba323 | ||
|
|
013720f0e7 | ||
|
|
365b4d95a4 | ||
|
|
5bb44cca81 | ||
|
|
15f9f8c853 | ||
|
|
04676a5085 | ||
|
|
cf44351dd7 | ||
|
|
614e0bbe23 | ||
|
|
3eb7b0ee78 | ||
|
|
02a1600994 | ||
|
|
f6868c5a77 | ||
|
|
f92f2f8afe | ||
|
|
0cc04eaa2a | ||
|
|
57290d63fd | ||
|
|
33b246a624 | ||
|
|
dc5ce5989f | ||
|
|
7ea108fa67 | ||
|
|
386cf25088 | ||
|
|
a514c51e55 | ||
|
|
91b8f3f171 | ||
|
|
8f5d475079 | ||
|
|
f5a4e279bc | ||
|
|
571447afe8 | ||
|
|
9260e5ca4f | ||
|
|
971e72514f | ||
|
|
0ee5ac5367 | ||
|
|
935d119c82 | ||
|
|
01fe32ee53 | ||
|
|
19ea6b1405 | ||
|
|
a4d33cdf48 | ||
|
|
a992a3cb9e | ||
|
|
95d688957f | ||
|
|
a9b350fb3a | ||
|
|
afe7dfd3b9 | ||
|
|
6b6c3de2ae | ||
|
|
1b70f687fa | ||
|
|
520d474ec6 | ||
|
|
deec7ca65c | ||
|
|
dff7454371 | ||
|
|
e50eedf3c5 | ||
|
|
341776b03b | ||
|
|
79f7afb125 | ||
|
|
2f3d9717ee | ||
|
|
9ad7524659 | ||
|
|
4ec413da32 | ||
|
|
61d53e606d | ||
|
|
d67b7daa1d | ||
|
|
2ab70cf0c6 | ||
|
|
99664706e2 | ||
|
|
a745041b7d | ||
|
|
0dd97f7c87 | ||
|
|
69a823c72d | ||
|
|
0f193d2d21 | ||
|
|
9832fdd6ef | ||
|
|
507c679b9b | ||
|
|
0b42cf8a36 | ||
|
|
10175e4a65 | ||
|
|
18831f985c | ||
|
|
6d4e6bf118 | ||
|
|
a8558bc5a6 | ||
|
|
bbf37f2534 | ||
|
|
d332ff3c77 | ||
|
|
eb92ec3dc6 | ||
|
|
dee8fbbc1e | ||
|
|
75303c61d8 | ||
|
|
af99826ef4 | ||
|
|
af1c6f973a | ||
|
|
b5cd777ad6 | ||
|
|
ae91c3cce3 | ||
|
|
5de4e79fc8 | ||
|
|
4d34b06fb3 | ||
|
|
22a413ce9f | ||
|
|
01855ca328 | ||
|
|
225bc5836a | ||
|
|
941cdf921d | ||
|
|
58ae95670b | ||
|
|
4e19ab9fcd | ||
|
|
6cb612e7e3 | ||
|
|
35add841ee | ||
|
|
f6e38d7ac9 | ||
|
|
855fbf1c11 | ||
|
|
e5ec21215e | ||
|
|
91bbf4219d | ||
|
|
f4c1586454 | ||
|
|
9a71d9d1c6 | ||
|
|
bb0310a353 | ||
|
|
f8408562f8 | ||
|
|
8eac78f8ef | ||
|
|
d57751d2fb | ||
|
|
e062b9f70d | ||
|
|
c837141832 | ||
|
|
a415a78d71 | ||
|
|
5255b919ae | ||
|
|
b12f9c76e2 | ||
|
|
575b814119 | ||
|
|
661bbacfc7 | ||
|
|
d04962f788 | ||
|
|
ec8142391a | ||
|
|
59bec5fade | ||
|
|
5230e610fc | ||
|
|
b81419a9fd | ||
|
|
2b9ee006d8 | ||
|
|
609b40f1a1 | ||
|
|
1e76448ced | ||
|
|
967a59d2c0 | ||
|
|
fbf94ac900 | ||
|
|
a11c144609 | ||
|
|
4848092bf8 | ||
|
|
948f3decb4 | ||
|
|
7d6747cec9 | ||
|
|
420e7b03ec | ||
|
|
b31015a927 | ||
|
|
bd55d43333 | ||
|
|
98020cedf7 | ||
|
|
cbf213915c | ||
|
|
93371999ee | ||
|
|
6289d673a0 | ||
|
|
0adda755a2 | ||
|
|
0782ed3274 | ||
|
|
d7ec136ffb | ||
|
|
dbdf2878ab | ||
|
|
8654fca058 | ||
|
|
05a8097779 | ||
|
|
c06ec1f132 | ||
|
|
fb83319d9c | ||
|
|
e42a7a1862 | ||
|
|
8cbf3ce22c | ||
|
|
1997093e21 | ||
|
|
f23b879ff5 | ||
|
|
8b2d233283 | ||
|
|
40fc688765 | ||
|
|
30f61b0549 | ||
|
|
ad7d8af6d1 | ||
|
|
f293345aa8 | ||
|
|
e18ad5a96b | ||
|
|
dd232b95b7 | ||
|
|
51861998c7 | ||
|
|
e346210c03 | ||
|
|
0d44f83fcc | ||
|
|
40b5f89ee0 | ||
|
|
eed9550993 | ||
|
|
cf96d1b0af | ||
|
|
3d25b52a10 | ||
|
|
437f6250c5 | ||
|
|
334cb8f222 | ||
|
|
03878edf77 | ||
|
|
cacdfc2f6e | ||
|
|
56c00ed1ea | ||
|
|
513d2f723f | ||
|
|
48429252c1 | ||
|
|
d459a5b8e6 | ||
|
|
9566232422 | ||
|
|
dc654a925c | ||
|
|
76366e8e5c | ||
|
|
31788ed4c7 | ||
|
|
781d2b02de | ||
|
|
8b5fc2143f | ||
|
|
5670677cb6 | ||
|
|
32b9dcecc7 | ||
|
|
ac12b725ea | ||
|
|
e1783bc686 | ||
|
|
c4f143eb96 | ||
|
|
94054924a9 | ||
|
|
c639611002 | ||
|
|
69061fed82 | ||
|
|
3075d96d44 | ||
|
|
7fec997ecf | ||
|
|
7355a35e4b | ||
|
|
e585377e68 | ||
|
|
9cd7bd4d5f | ||
|
|
a108d84f88 | ||
|
|
1e83dd2229 | ||
|
|
d02ca923e2 | ||
|
|
f82f7eb1d8 | ||
|
|
0d472b29ec | ||
|
|
7a21067bb9 | ||
|
|
21a7fa8063 | ||
|
|
83463dfbee | ||
|
|
c3c50c0030 | ||
|
|
e85ab7ac9b | ||
|
|
a11463a02f |
@@ -1,3 +1,4 @@
|
||||
/ABOUT-NLS~
|
||||
*.eps
|
||||
*.log
|
||||
*.o
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3.3
|
||||
3.3.90
|
||||
|
||||
+7
-3
@@ -8,7 +8,8 @@ language: cpp
|
||||
env:
|
||||
global:
|
||||
# ICC serial number.
|
||||
secure: ED3w6rzxuE6tVu3oyxha2MoGMRzRQCtinvr9uor1gw9TGKB80esTLx4KyX0xHemUdyQVarFDDQfVS5rf7jSDY8XiWIR6O+2Af9/30gb+8eyngyvACu7E28n+1XHmYWIEHsbvB9mic6C60FBj5sPcDnFWZeyttGL0WooSjYHiw1Egafwqbeu1mD3Aet9OI9VaLQvy0KcWAdVrYWSI9UWLvLM+xPVUjPFko4oS+dTlETzVnmn6JFbZX1OKONtfcvdoDRFBzs3iHm5dQUt/Fz+y/DtKSuvF3zvePHSgF6c8URbEPPjBdh87gkovSLyy+83fVeh4WMkF8b+dGZmikQv6kRsjKJdbQrS8tiMhZlORC5Gfmn4HXNgmapL+paUweakH7UZQHm6d5SZoBgCHNazfqMrywbZsZkGvZTDQIVG1Be7Lhh2BDFbPhPZNDvI9XYiqZP0QSb0BVfeO+AUSRcUPM7TvarxB74jYdfpTBu7sqJP6dSwhcDTEUhHmuLGjzsNm3uTZe8SUw/TGGx5uPTXNsCjJq6ClIOAIYXZTXLbBmIL/NBWCy0MUpD+9zsiknU7vzzq1RfgCCExhvYgosTjBLcX1kKI+eRSU5M44e+xCg4xx0m9WfafbKbhA20FfnWxCFIkZeVpkOOsexJ9zfe0SflVLxkd7vmci5SCBixLVbN0=
|
||||
# See https://github.com/nemequ/icc-travis.
|
||||
secure: B3manbbi0anCAGDJTdAa9TlodzRHeiYD87FKmFzS877dPm8Cm0BDvtUhKBUpBvP8+nbHOWFGrgDmLugSZjTGU+mAxtuQpamUFHvinu0BIk3qtjlqouwvbtIqUu8iiZ3Uqu+xKeAANKRy0YVZGLlEb9F3N119tJ/Fxp1p9bXL1qph+CZ25OFbUgZ2s4F+/AyHMUxJlNXKFe3Qean65hC6edhU3zoaKzr/g/wtbhRmcyWbkOa1dJqzr2yKotcPvrnApGhDzgMKFtohg/t7xfMADDVv6sGS5XNpt25Z+MUCmLg4Z9eD7u109jvRV1eu/jgVafqsthWEhXbuMiFgFhKBKGCNZ0dACIfKZSkFZI6FdM7ovJ6aNhSlxZ2169Ybd22rN1UTHeCQWySPcVVOg5taLVpqe+E8Xhnv4hBO5NrzElWwCMLxIdPUSwVStYvtDr8ZytHWzfot50vSnFKIFpTOr9hP4+AJMVmmqJfaJo2MLBft/q2xkztrMv3lQSj3m4+ma9kPDwXIu9uCutjlnhc00jNx9qegi5VfpAjxcG1R+pX4T20az6ByHk/7LPQsANkT31RJq/jAeD9LEuMOy8miha83q4QuvbFaqPK3PY0el/O1LZaXqLsV2aQ0uqH8YX0l4r5NzHdhb+3lYgvpMBO5ytr/EWJiEyNYV518050IUDE=
|
||||
|
||||
matrix:
|
||||
include:
|
||||
@@ -289,7 +290,7 @@ matrix:
|
||||
env:
|
||||
# No versioned name installed, but beware that Travis installs
|
||||
# a more modern clang earlier in the default PATH.
|
||||
- MATRIX_EVAL='CC=/usr/bin/clang && CXX=/usr/bin/clang++'
|
||||
- MATRIX_EVAL='CC=/usr/bin/clang && CXX=/usr/bin/clang++ && GETTEXT_VERSION=0.18.3'
|
||||
|
||||
- name: "Clang 3.3"
|
||||
os: linux
|
||||
@@ -301,7 +302,7 @@ matrix:
|
||||
- clang-3.3
|
||||
env:
|
||||
# See comment for 3.4.
|
||||
- MATRIX_EVAL='CC=/usr/bin/clang && CXX=/usr/bin/clang++'
|
||||
- MATRIX_EVAL='CC=/usr/bin/clang && CXX=/usr/bin/clang++ && GETTEXT_VERSION=0.18.3'
|
||||
|
||||
|
||||
before_install:
|
||||
@@ -339,7 +340,10 @@ script:
|
||||
# with `Picked up _JAVA_OPTIONS: -Xmx2048m -Xms512m`, which makes
|
||||
# the test suite fail.
|
||||
- unset _JAVA_OPTIONS
|
||||
- if [[ $GETTEXT_VERSION ]]; then sed -i -re "s/(AM_GNU_GETTEXT_VERSION).*/\1([$GETTEXT_VERSION])/" configure.ac; fi
|
||||
- ./bootstrap
|
||||
# For some reason, gnulib-po/Makefile.in.in is about Gettext 0.19, so it will break here. Override it.
|
||||
- if [[ $GETTEXT_VERSION ]]; then autopoint --force; fi
|
||||
- if [[ -f ~/.bashrc ]]; then source ~/.bashrc; fi
|
||||
- ./configure --enable-gcc-warnings CC="$CC" CXX="$CXX" $CONFIGUREFLAGS || { cat config.log && false; }
|
||||
- make -j2 $MAKE_ARGS
|
||||
|
||||
+19
-5
@@ -18,7 +18,7 @@
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = po runtime-po .
|
||||
SUBDIRS = po runtime-po gnulib-po .
|
||||
|
||||
# Files installed for use by Automake.
|
||||
aclocaldir = @aclocaldir@
|
||||
@@ -29,12 +29,12 @@ EXTRA_DIST = .prev-version .version cfg.mk PACKAGING \
|
||||
|
||||
dist_doc_DATA = AUTHORS COPYING NEWS README THANKS TODO
|
||||
|
||||
# Let generated files (e.g., from exampkles/) depend on this variable,
|
||||
# Let generated files (e.g., from examples/) depend on this variable,
|
||||
# to make sure they are regenerated when there are changes in Bison.
|
||||
#
|
||||
# Don't depend on $(BISON) otherwise we would rebuild these files
|
||||
# in srcdir, including during distcheck, which is forbidden.
|
||||
dependencies = $(BISON_IN) $(dist_skeletons_DATA)
|
||||
dependencies = $(BISON_IN) $(src_bison_SOURCES) $(dist_skeletons_DATA)
|
||||
|
||||
## Running the bison from this tarball. To generate our own parser,
|
||||
## but also to run the tests. Of course, you ought to keep a sane
|
||||
@@ -42,7 +42,8 @@ dependencies = $(BISON_IN) $(dist_skeletons_DATA)
|
||||
BISON = $(top_builddir)/tests/bison
|
||||
BISON_IN = $(top_srcdir)/tests/bison.in
|
||||
YACC = $(BISON) -o y.tab.c
|
||||
AM_YFLAGS = -d -v -Werror -Wall -Wno-yacc --report=all
|
||||
AM_YFLAGS_WITH_LINES = --defines -Werror -Wall --report=all
|
||||
AM_YFLAGS = $(AM_YFLAGS_WITH_LINES) --no-lines
|
||||
|
||||
# Initialization before completion by local.mk's.
|
||||
AM_CFLAGS = $(WARN_CFLAGS)
|
||||
@@ -87,9 +88,22 @@ clean-local:
|
||||
BUILT_SOURCES += $(top_srcdir)/.version
|
||||
$(top_srcdir)/.version: configure
|
||||
echo $(VERSION) > $@-t && mv $@-t $@
|
||||
dist-hook: gen-ChangeLog
|
||||
dist-hook: gen-ChangeLog gen-synclines
|
||||
echo $(VERSION) > $(distdir)/.tarball-version
|
||||
|
||||
# When generating a release, include the #lines in Bison's parser. Do it
|
||||
# only if needed. In particular, distcheck runs dist with read-only
|
||||
# sources, so don't try to update src/parse-gram.c: we don't have the
|
||||
# permissions.
|
||||
.PHONY: gen-synclines
|
||||
gen-synclines:
|
||||
cd $(distdir) && \
|
||||
if ! grep '#line' src/parse-gram.c >/dev/null 2>&1; then \
|
||||
$(abs_top_builddir)/tests/bison \
|
||||
$(AM_YFLAGS_WITH_LINES) src/parse-gram.y \
|
||||
-o src/parse-gram.c; \
|
||||
fi
|
||||
|
||||
.PHONY: update-b4-copyright update-package-copyright-year
|
||||
update-b4-copyright:
|
||||
$(AM_V_GEN)find $(srcdir)/data -type f \
|
||||
|
||||
@@ -1,5 +1,150 @@
|
||||
GNU Bison NEWS
|
||||
|
||||
* Noteworthy changes in release 3.3.91 (2019-05-12) [beta]
|
||||
|
||||
** Bug fixes
|
||||
|
||||
Portability issues were fixed.
|
||||
|
||||
* Noteworthy changes in release 3.3.90 (2019-04-28) [beta]
|
||||
|
||||
** New features
|
||||
|
||||
*** Colored diagnostics
|
||||
|
||||
As an experimental feature, Bison now generates colored diagnostics,
|
||||
controlled by the new options --color and --style.
|
||||
|
||||
Install the libtextstyle library before configuring Bison to use them.
|
||||
It is available from
|
||||
|
||||
https://alpha.gnu.org/gnu/gettext/
|
||||
|
||||
for instance
|
||||
|
||||
https://alpha.gnu.org/gnu/gettext/libtextstyle-0.8.tar.gz
|
||||
|
||||
The option --color supports the following arguments:
|
||||
- always, yes: Enable colors.
|
||||
- never, no: Disable colors.
|
||||
- auto, tty (default): Enable colors if the output device is a tty.
|
||||
|
||||
To customize the styles, create a CSS file similar to
|
||||
|
||||
/* black-and-white.css */
|
||||
.warning { }
|
||||
.error { font-weight: 800; text-decoration: underline; }
|
||||
.note { }
|
||||
|
||||
then invoke bison with --style=black-and-white.css.
|
||||
|
||||
*** Disabling output
|
||||
|
||||
When given -fsyntax-only, the diagnostics are reported, but no output is
|
||||
generated.
|
||||
|
||||
The name of this option is somewhat misleading as bison does more than
|
||||
just checking the syntax: every stage is run (including checking for
|
||||
conflicts for instance), except the generation of the output files.
|
||||
|
||||
*** Include the generated header (yacc.c)
|
||||
|
||||
Before, when --defines is used, bison generated a header, and pasted an
|
||||
exact copy of it into the generated parser implementation file. If the
|
||||
header name is not "y.tab.h", it is now #included instead of being
|
||||
duplicated.
|
||||
|
||||
To use an '#include' even if the header name is "y.tab.h" (which is what
|
||||
happens with --yacc, or when using the Autotools' ylwrap), define
|
||||
api.header.include to the exact argument to pass to #include. For
|
||||
instance:
|
||||
|
||||
%define api.header.include {"parse.h"}
|
||||
|
||||
or
|
||||
|
||||
%define api.header.include {<parser/parse.h>}
|
||||
|
||||
*** api.location.type is now supported in C (yacc.c, glr.c)
|
||||
|
||||
The %define variable api.location.type defines the name of the type to use
|
||||
for locations. When defined, Bison no longer defines YYLTYPE.
|
||||
|
||||
This can be used in programs with several parsers to factor their
|
||||
definition of locations: let one of them generate them, and the others
|
||||
just use them.
|
||||
|
||||
** Changes
|
||||
|
||||
*** Graphviz output
|
||||
|
||||
In conformance with the recommendations of the Graphviz team, if %require
|
||||
"3.4" (or better) is specified, the option --graph generates a *.gv file
|
||||
by default, instead of *.dot.
|
||||
|
||||
*** Diagnostics overhaul
|
||||
|
||||
Column numbers were wrong with multibyte characters, which would also
|
||||
result in skewed diagnostics with carets. Beside, because we were
|
||||
indenting the quoted source with a single space, lines with tab characters
|
||||
were incorrectly underlined.
|
||||
|
||||
To address these issues, and to be clearer, Bison now issues diagnostics
|
||||
as GCC9 does. For instance it used to display (there's a tab before the
|
||||
opening brace):
|
||||
|
||||
foo.y:3.37-38: error: $2 of ‘expr’ has no declared type
|
||||
expr: expr '+' "number" { $$ = $1 + $2; }
|
||||
^~
|
||||
It now reports
|
||||
|
||||
foo.y:3.37-38: error: $2 of ‘expr’ has no declared type
|
||||
3 | expr: expr '+' "number" { $$ = $1 + $2; }
|
||||
| ^~
|
||||
|
||||
Other constructs now also have better locations, resulting in more precise
|
||||
diagnostics.
|
||||
|
||||
*** Fix-it hints for %empty
|
||||
|
||||
Running Bison with -Wempty-rules and --update will remove incorrect %empty
|
||||
annotations, and add the missing ones.
|
||||
|
||||
*** Generated reports
|
||||
|
||||
The format of the reports (parse.output) was improved for readability.
|
||||
|
||||
*** Better support for --no-line.
|
||||
|
||||
When --no-line is used, the generated files are now cleaner: no lines are
|
||||
generated instead of empty lines. Together with using api.header.include,
|
||||
that should help people saving the generated files into version control
|
||||
systems get smaller diffs.
|
||||
|
||||
** Documentation
|
||||
|
||||
A new example in C shows an simple infix calculator with a hand-written
|
||||
scanner (examples/c/calc).
|
||||
|
||||
A new example in C shows a reentrant parser (capable of recursive calls)
|
||||
built with Flex and Bison (examples/c/reccalc).
|
||||
|
||||
There is a new section about the history of Yaccs and Bison.
|
||||
|
||||
** Bug fixes
|
||||
|
||||
A few obscure bugs were fixed, including the second oldest (known) bug in
|
||||
Bison: it was there when Bison was entered in the RCS version control
|
||||
system, in December 1987. See the NEWS of Bison 3.3 for the previous
|
||||
oldest bug.
|
||||
|
||||
* Noteworthy changes in release 3.3.2 (2019-02-03) [stable]
|
||||
|
||||
** Bug fixes
|
||||
|
||||
Bison 3.3 failed to generate parsers for grammars with unused nonterminal
|
||||
symbols.
|
||||
|
||||
* Noteworthy changes in release 3.3.1 (2019-01-27) [stable]
|
||||
|
||||
** Changes
|
||||
@@ -216,17 +361,18 @@ GNU Bison NEWS
|
||||
symbol_type (int token, const int&);
|
||||
symbol_type (int token);
|
||||
|
||||
which should be used in a Flex-scanner as follows.
|
||||
|
||||
%%
|
||||
[a-z]+ return yy::parser::symbol_type (ID, yytext);
|
||||
[0-9]+ return yy::parser::symbol_type (INT, text_to_int (yytext);
|
||||
":" return yy::parser::symbol_type (’:’);
|
||||
<<EOF>> return yy::parser::symbol_type (0);
|
||||
|
||||
Correct matching between token types and value types is checked via
|
||||
'assert'. For instance, 'symbol_type (ID, 42)' would abort (while
|
||||
'make_ID (42)' would not even compile).
|
||||
'assert'; for instance, 'symbol_type (ID, 42)' would abort. Named
|
||||
constructors are preferable, as they offer better type safety (for
|
||||
instance 'make_ID (42)' would not even compile), but symbol_type
|
||||
constructors may help when token types are discovered at run-time, e.g.,
|
||||
|
||||
[a-z]+ {
|
||||
if (auto i = lookup_keyword (yytext))
|
||||
return yy::parser::symbol_type (i);
|
||||
else
|
||||
return yy::parser::make_ID (yytext);
|
||||
}
|
||||
|
||||
*** C++: Variadic emplace
|
||||
|
||||
@@ -3479,7 +3625,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
LocalWords: Heimbigner AST src ast Makefile srcdir MinGW xxlex XXSTYPE
|
||||
LocalWords: XXLTYPE strictfp IDEs ffixit fdiagnostics parseable fixits
|
||||
LocalWords: Wdeprecated yytext Variadic variadic yyrhs yyphrs RCS README
|
||||
LocalWords: noexcept constexpr ispell american
|
||||
LocalWords: noexcept constexpr ispell american deprecations
|
||||
|
||||
Local Variables:
|
||||
ispell-dictionary: "american"
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
This package contains the GNU Bison parser generator.
|
||||
|
||||
* Installation
|
||||
** Build
|
||||
** Build from git
|
||||
Here are basic installation instructions for a repository checkout:
|
||||
|
||||
$ git submodules update --init
|
||||
$ ./bootstrap
|
||||
|
||||
then proceed with the usual 'configure && make' steps.
|
||||
|
||||
README-hacking contains more information about building and modifying the
|
||||
software.
|
||||
|
||||
** Build for tarball
|
||||
See the file INSTALL for generic compilation and installation instructions.
|
||||
|
||||
Bison requires GNU m4 1.4.6 or later. See:
|
||||
|
||||
+32
-3
@@ -133,9 +133,15 @@ Enjoy!
|
||||
|
||||
** Updating
|
||||
|
||||
The use of submodules make things somewhat different because git does not
|
||||
support recursive operations: submodules must be taken care of explicitly by
|
||||
the user.
|
||||
If you have git at version 1.8.2 or later, the command
|
||||
|
||||
$ git submodule update --recursive --remote
|
||||
|
||||
will be useful for updating to the latest version of all submodules.
|
||||
|
||||
Under earlier versions, use of submodules make things somewhat different
|
||||
because git does not yet support recursive operations: submodules must be
|
||||
taken care of explicitly.
|
||||
|
||||
*** Updating Bison
|
||||
|
||||
@@ -189,6 +195,11 @@ update.
|
||||
** make check
|
||||
Use liberally.
|
||||
|
||||
** Updating the expectations
|
||||
Sometimes some changes have a large impact on the test suite (e.g., when we
|
||||
added the "[-Wother]" part to all the warnings). Part of the update can be
|
||||
done with a crude tool: tests/update-test. Read it for more information.
|
||||
|
||||
** TESTSUITEFLAGS
|
||||
|
||||
To run just the testsuite (not the tests related to the examples), run `make
|
||||
@@ -282,6 +293,24 @@ release:
|
||||
- Test with a very recent version of GCC for both C and C++. Testing with
|
||||
older versions that are still in use is nice too.
|
||||
|
||||
** gnulib
|
||||
To run tests on gnulib components (e.g., on bitset):
|
||||
|
||||
cd gnulib
|
||||
./gnulib-tool --test bitset-tests
|
||||
|
||||
possibly within a specified environment:
|
||||
|
||||
CC='gcc-mp-8 -fsanitize=undefined' ./gnulib-tool --test bitset-tests
|
||||
|
||||
To be able to run the tests several times, and to use symlinks instead of
|
||||
copies so that one can update the origin gnulib directory and immediately
|
||||
re-run the tests, run:
|
||||
|
||||
./gnulib-tool --symlink --create-test --dir=/tmp/gnutest bitset-tests
|
||||
cd /tmp/gnutest
|
||||
./configure CC='gcc-mp-8 -fsanitize=undefined'
|
||||
make check
|
||||
|
||||
* Release Procedure
|
||||
This section needs to be updated to take into account features from gnulib.
|
||||
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
From phr Tue Jul 8 10:36:19 1986
|
||||
Date: Tue, 8 Jul 86 00:52:24 EDT
|
||||
From: phr (Paul Rubin)
|
||||
To: riferguson%[email protected], tower
|
||||
Subject: Re: Bison documentation?
|
||||
|
||||
The main difference between Bison and Yacc that I know of is that
|
||||
Bison supports the @N construction, which gives you access to
|
||||
the starting and ending line number and character number associated
|
||||
with any of the symbols in the current rule.
|
||||
|
||||
Also, Bison supports the command '%expect N' which says not to mention
|
||||
the conflicts if there are N shift/reduce conflicts and no reduce/reduce
|
||||
conflicts.
|
||||
|
||||
The differences in the algorithms stem mainly from the horrible
|
||||
kludges that Johnson had to perpetrate to make Yacc fit in a PDP-11.
|
||||
|
||||
Also, Bison uses a faster but less space-efficient encoding for the
|
||||
parse tables (see Corbett's PhD thesis from Berkeley, "Static
|
||||
Semantics in Compiler Error Recovery", June 1985, Report No. UCB/CSD
|
||||
85/251), and more modern technique for generating the lookahead sets.
|
||||
(See Frank DeRemer and Thomas Pennello, "Efficient Computation of
|
||||
LALR(1) Look-Ahead Sets", ACM Transactions on Programming Languages
|
||||
and Systems (TOPLAS) 4, 4 (October 1982), 615-649. Their
|
||||
technique is the standard one now.)
|
||||
|
||||
paul rubin
|
||||
free software foundation
|
||||
|
||||
|
||||
[DeRemer-Pennello reference corrected by Paul Eggert <[email protected]>,
|
||||
2004-06-21.]
|
||||
@@ -18,6 +18,7 @@ Antonio Silva Correia [email protected]
|
||||
Arnold Robbins [email protected]
|
||||
Art Haas [email protected]
|
||||
Askar Safin [email protected]
|
||||
Balázs Scheidler [email protected]
|
||||
Baron Schwartz [email protected]
|
||||
Ben Pfaff [email protected]
|
||||
Benoit Perrot [email protected]
|
||||
@@ -55,6 +56,7 @@ Didier Godefroy [email protected]
|
||||
Efi Fogel [email protected]
|
||||
Enrico Scholz [email protected]
|
||||
Eric Blake [email protected]
|
||||
Eric S. Raymond [email protected]
|
||||
Étienne Renault [email protected]
|
||||
Evgeny Stambulchik [email protected]
|
||||
Fabrice Bauzac [email protected]
|
||||
@@ -64,6 +66,7 @@ Frank Heckenbach [email protected]
|
||||
Frans Englich [email protected]
|
||||
Gabriel Rassoul [email protected]
|
||||
Gary L Peskin [email protected]
|
||||
Gavin Smith [email protected]
|
||||
Georg Sauthoff [email protected]
|
||||
George Neuner [email protected]
|
||||
Gilles Espinasse [email protected]
|
||||
@@ -126,6 +129,7 @@ Oliver Mangold [email protected]
|
||||
Paolo Bonzini [email protected]
|
||||
Paolo Simone Gasparello [email protected]
|
||||
Pascal Bart [email protected]
|
||||
Patrice Dumas [email protected]
|
||||
Paul Eggert [email protected]
|
||||
Paul Hilfinger [email protected]
|
||||
Per Allansson [email protected]
|
||||
@@ -168,12 +172,14 @@ Tim Josling [email protected]
|
||||
Tim Landscheidt [email protected]
|
||||
Tim Van Holder [email protected]
|
||||
Tobias Frost [email protected]
|
||||
Todd Freed [email protected]
|
||||
Tom Lane [email protected]
|
||||
Tom Tromey [email protected]
|
||||
Tommy Nordgren [email protected]
|
||||
Troy A. Johnson [email protected]
|
||||
Tys Lefering [email protected]
|
||||
Valentin Tolmer [email protected]
|
||||
wcventure [email protected]
|
||||
Victor Khomenko [email protected]
|
||||
Victor Zverovich [email protected]
|
||||
Vin Shelton [email protected]
|
||||
|
||||
@@ -1,7 +1,37 @@
|
||||
* Bison 3.4
|
||||
** injection rules
|
||||
** bad diagnostics
|
||||
%token <val> NUM
|
||||
%type <val> expr term fact
|
||||
|
||||
%%
|
||||
|
||||
res: expr { printf ("%d\n", $1); };
|
||||
expr: expr '+' term { $$ = $1 + $3; } | term;
|
||||
term: NUM | { $$ = 0; };
|
||||
|
||||
The second warning about fact is... useless.
|
||||
|
||||
$ bison /tmp/bar.y
|
||||
/tmp/bar.y:2.24-27: warning: symbol fact is used, but is not defined as a token and has no rules [-Wother]
|
||||
%type <val> expr term fact
|
||||
^~~~
|
||||
/tmp/bar.y: warning: 1 nonterminal useless in grammar [-Wother]
|
||||
/tmp/bar.y:2.24-27: warning: nonterminal useless in grammar: fact [-Wother]
|
||||
%type <val> expr term fact
|
||||
^~~~
|
||||
|
||||
* Bison 3.5
|
||||
** doc
|
||||
I feel its ugly to use the GNU style to declare functions in the doc. It
|
||||
generates tons of white space in the page, and may contribute to bad page
|
||||
breaks.
|
||||
|
||||
Also, we seem to teach YYPRINT very early on, although it should be
|
||||
considered deprecated: %printer is superior.
|
||||
|
||||
** glr.cc
|
||||
move glr.c into the yy namespace
|
||||
|
||||
** improve syntax errors (UTF-8, internationalization)
|
||||
Bison depends on the current locale. For instance:
|
||||
|
||||
@@ -45,15 +75,50 @@ syntax error, unexpected $end, expecting ↦ or 🎅🐃 or '\n'
|
||||
While at it, we should stop using "$end" by default, in favor of "end of
|
||||
file", or "end of input", whatever.
|
||||
|
||||
** use gettext-h in gnulib instead of gettext
|
||||
** use gnulib-po
|
||||
For some reason, according to syntax-check, we have to keep getopt.c in
|
||||
POTIFILES.in, but not bitset/stats.c, although both come from gnulib. But
|
||||
bitset/stats.c is a symlink, not getopt.c. This is fishy and should be
|
||||
fixed.
|
||||
* Bison 3.6
|
||||
** Unit rules
|
||||
Maybe we could expand unit rules (or "injections", see
|
||||
https://homepages.cwi.nl/~daybuild/daily-books/syntax/2-sdf/sdf.html), i.e.,
|
||||
transform
|
||||
|
||||
exp: arith | bool;
|
||||
arith: exp '+' exp;
|
||||
bool: exp '&' exp;
|
||||
|
||||
into
|
||||
|
||||
exp: exp '+' exp | exp '&' exp;
|
||||
|
||||
when there are no actions. This can significantly speed up some grammars.
|
||||
I can't find the papers. In particular the book 'LR parsing: Theory and
|
||||
Practice' is impossible to find, but according to 'Parsing Techniques: a
|
||||
Practical Guide', it includes information about this issue. Does anybody
|
||||
have it?
|
||||
|
||||
** Injection rules
|
||||
See above.
|
||||
|
||||
** clean up
|
||||
*** lalr.c
|
||||
Introduce a goto struct, and use it in place of from_state/to_state.
|
||||
Rename states1 as path, length as pathlen.
|
||||
Introduce inline functions for things such as nullable[*rp - ntokens]
|
||||
where we need to map from symbol number to nterm number.
|
||||
|
||||
There are probably a significant part of the relations management that
|
||||
should be migrated on top of a bitsetv.
|
||||
|
||||
*** closure
|
||||
It should probably take a "state*" instead of two arguments.
|
||||
|
||||
*** traces
|
||||
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
|
||||
tests easy to maintain.
|
||||
|
||||
Meanwhile, bitset/stats.c is removed from the set of translations, which is
|
||||
not too much of a problem as users are not expected to see this.
|
||||
|
||||
|
||||
* Completion
|
||||
@@ -77,10 +142,6 @@ $ ./tests/testsuite -l | grep errors | sed q
|
||||
** consistency
|
||||
token vs terminal
|
||||
|
||||
** yacc.c
|
||||
Now that ylwrap is fixed, we should include foo.tab.h from foo.tab.c rather
|
||||
than duplicating it.
|
||||
|
||||
** C++
|
||||
Move to int everywhere instead of unsigned? stack_size, etc. The parser
|
||||
itself uses int (for yylen for instance), yet stack is based on size_t.
|
||||
@@ -171,9 +232,6 @@ class in the printers/destructors, which is not good for an operator<<
|
||||
since it is no longer bound to a particular parser, it's just a
|
||||
(standalone symbol).
|
||||
|
||||
** Rename LR0.cc
|
||||
as lr0.cc, why upper case?
|
||||
|
||||
* Various
|
||||
** Rewrite glr.cc in C++
|
||||
As a matter of fact, it would be very interesting to see how much we can
|
||||
@@ -263,7 +321,7 @@ grammars she is working on. We should probably also include some
|
||||
information about the variables (I'm not sure for instance we even
|
||||
specify what LR variant was used).
|
||||
|
||||
** GLR
|
||||
** GLR
|
||||
How would Paul like to display the conflicted actions? In particular,
|
||||
what when two reductions are possible on a given lookahead token, but one is
|
||||
part of $default. Should we make the two reductions explicit, or just
|
||||
@@ -355,33 +413,6 @@ XML output for GNU Bison
|
||||
https://lists.gnu.org/archive/html/bug-bison/2016-06/msg00000.html
|
||||
http://www.cs.cornell.edu/andru/papers/cupex/
|
||||
|
||||
* Unit rules
|
||||
Maybe we could expand unit rules (or "injections", see
|
||||
https://homepages.cwi.nl/~daybuild/daily-books/syntax/2-sdf/sdf.html), i.e.,
|
||||
transform
|
||||
|
||||
exp: arith | bool;
|
||||
arith: exp '+' exp;
|
||||
bool: exp '&' exp;
|
||||
|
||||
into
|
||||
|
||||
exp: exp '+' exp | exp '&' exp;
|
||||
|
||||
when there are no actions. This can significantly speed up some grammars.
|
||||
I can't find the papers. In particular the book 'LR parsing: Theory and
|
||||
Practice' is impossible to find, but according to 'Parsing Techniques: a
|
||||
Practical Guide', it includes information about this issue. Does anybody
|
||||
have it?
|
||||
|
||||
|
||||
|
||||
* Documentation
|
||||
|
||||
** History/Bibliography
|
||||
Some history of Bison and some bibliography would be most welcome.
|
||||
Are there any Texinfo standards for bibliography?
|
||||
|
||||
* Coding system independence
|
||||
Paul notes:
|
||||
|
||||
|
||||
+4
-20
@@ -17,17 +17,18 @@
|
||||
|
||||
# gnulib modules used by this package.
|
||||
gnulib_modules='
|
||||
argmatch array-list assert
|
||||
argmatch array-list assert assure
|
||||
bitsetv
|
||||
calloc-posix close closeout config-h c-strcase
|
||||
configmake
|
||||
dirname
|
||||
error extensions fdl fopen-safer
|
||||
getopt-gnu
|
||||
gettext git-version-gen gitlog-to-changelog
|
||||
gettext-h git-version-gen gitlog-to-changelog
|
||||
gpl-3.0 hash inttypes isnan javacomp-script
|
||||
javaexec-script
|
||||
ldexpl
|
||||
libtextstyle-optional
|
||||
malloc-gnu
|
||||
mbswidth
|
||||
non-recursive-gnulib-prefix-hack
|
||||
@@ -67,24 +68,7 @@ XGETTEXT_OPTIONS_RUNTIME=$XGETTEXT_OPTIONS'\\\
|
||||
--keyword=YY_ \\\
|
||||
'
|
||||
|
||||
# Gettext supplies these files, but we don't need them since
|
||||
# we don't have an intl subdirectory.
|
||||
excluded_files='
|
||||
m4/glibc2.m4
|
||||
m4/intdiv0.m4
|
||||
m4/intl.m4
|
||||
m4/intldir.m4
|
||||
m4/intmax.m4
|
||||
m4/lcmessage.m4
|
||||
m4/lock.m4
|
||||
m4/longdouble.m4
|
||||
m4/signed.m4
|
||||
m4/uintmax_t.m4
|
||||
m4/ulonglong.m4
|
||||
m4/visibility.m4
|
||||
'
|
||||
|
||||
gnulib_tool_option_extras='--symlink --conditional-dependencies --makefile-name=gnulib.mk'
|
||||
gnulib_tool_option_extras='--symlink --conditional-dependencies --makefile-name=gnulib.mk --po-base=gnulib-po --po-domain=bison'
|
||||
|
||||
bootstrap_post_import_hook()
|
||||
{
|
||||
|
||||
@@ -27,3 +27,4 @@
|
||||
/install-reloc
|
||||
/reloc-ldflags
|
||||
/relocatable.sh.in
|
||||
/libtool-reloc
|
||||
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# usage:
|
||||
# update-test _build/8d/tests/testsuite.dir/*.testsuite.log
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
def getargs():
|
||||
p = argparse.ArgumentParser(description='Update test cases.')
|
||||
opt = p.add_argument
|
||||
opt('tests', metavar='test', nargs='+', type=str, default=None,
|
||||
help='test files to update')
|
||||
opt('-v', '--verbose', action='store_true',
|
||||
help='Be verbose')
|
||||
return p.parse_args()
|
||||
|
||||
args = getargs()
|
||||
subst = dict()
|
||||
|
||||
|
||||
def log(*args_):
|
||||
if args.verbose:
|
||||
print(*args_)
|
||||
|
||||
|
||||
def contents(file):
|
||||
'''The contents of a file.'''
|
||||
log(file)
|
||||
f = open(file)
|
||||
return f.read()
|
||||
|
||||
|
||||
def diff_to_re(match):
|
||||
'''Convert a portion of patch into a regex substitution to perform.
|
||||
No longer used, we now use the expected/effective parts.
|
||||
'''
|
||||
frm = []
|
||||
to = []
|
||||
is_diff = False
|
||||
for l in match.group(1).splitlines():
|
||||
print(l)
|
||||
# t in [-+ ]
|
||||
t = l[0]
|
||||
l = l[1:]
|
||||
if t in ['-', ' ']:
|
||||
is_diff = True
|
||||
frm.append(l)
|
||||
if t in ['+', ' ']:
|
||||
is_diff = True
|
||||
to.append(l)
|
||||
if is_diff:
|
||||
frm = "\n".join(frm)
|
||||
to = "\n".join(to)
|
||||
subst[frm] = to
|
||||
|
||||
|
||||
def update(at_file, logfile):
|
||||
test = contents(at_file)
|
||||
if os.path.isfile(logfile):
|
||||
log("LOG: ", logfile)
|
||||
l = contents(logfile)
|
||||
log("LOG: ", l)
|
||||
global subst
|
||||
subst = {}
|
||||
re.sub(r'(?:^@@.*\n)((?:^[-+ ].*\n)+)',
|
||||
diff_to_re, l, flags = re.MULTILINE)
|
||||
print(subst)
|
||||
if subst:
|
||||
# Turn "subst{frm} -> to" into a large RE.
|
||||
frm = '|'.join([re.escape(x) for x in subst])
|
||||
log("FROM:", frm)
|
||||
test = re.sub("(" + frm + ")",
|
||||
lambda m: subst[m.group(1)],
|
||||
test, flags=re.MULTILINE)
|
||||
open(at_file, 'w').write(test)
|
||||
|
||||
|
||||
def process(logfile):
|
||||
log = contents(logfile)
|
||||
# Look for the file to update.
|
||||
m = re.search(r'^\d+\. (\w+\.at):\d+: ', log, re.MULTILINE)
|
||||
if not m:
|
||||
return
|
||||
at_file = 'tests/' + m.group(1)
|
||||
print(at_file)
|
||||
update(at_file, logfile)
|
||||
|
||||
for t in args.tests:
|
||||
log("FILE:", t)
|
||||
process(t)
|
||||
@@ -60,18 +60,6 @@ update-copyright-env = \
|
||||
## More syntax-checks. ##
|
||||
## -------------------- ##
|
||||
|
||||
# At least for Mac OS X's grep, the order between . and [ in "[^.[]"
|
||||
# matters:
|
||||
# $ LC_ALL=fr_FR grep -nE '[^[.]' /dev/null
|
||||
# $ LC_ALL=C grep -nE '[^[.]' /dev/null
|
||||
# grep: invalid collating element or class
|
||||
# $ LC_ALL=fr_FR grep -nE '[^.[]' /dev/null
|
||||
# $ LC_ALL=C grep -nE '[^.[]' /dev/null
|
||||
sc_at_parser_check:
|
||||
@prohibit='AT_PARSER_CHECK\(\[+[^.[]|AT_CHECK\(\[+\./' \
|
||||
halt='use AT_PARSER_CHECK for and only for generated parsers' \
|
||||
$(_sc_search_regexp)
|
||||
|
||||
# Indent only with spaces.
|
||||
# Taken from Coreutils.
|
||||
sc_prohibit_tab_based_indentation:
|
||||
@@ -156,11 +144,16 @@ sc_space_before_open_paren:
|
||||
## syntax-checks exceptions. ##
|
||||
## -------------------------- ##
|
||||
|
||||
# po-check: we use gnulib-po, so we don't need/want them in our POTFILE.
|
||||
generated_files =
|
||||
|
||||
exclude = \
|
||||
$(foreach a,$(1),$(eval $(subst $$,$$$$,exclude_file_name_regexp--sc_$(a))))
|
||||
|
||||
$(call exclude, \
|
||||
bindtextdomain=^lib/main.c$$ \
|
||||
cast_of_argument_to_free=^src/muscle-tab.c$$ \
|
||||
po_check=^po/POTFILES.in$$ \
|
||||
preprocessor_indentation=^data/|^lib/|^src/parse-gram.[ch]$$ \
|
||||
program_name=^lib/main.c$$ \
|
||||
prohibit_always-defined_macros=^data/skeletons/yacc.c$$ \
|
||||
@@ -169,8 +162,8 @@ $(call exclude,
|
||||
prohibit_doubled_word=^tests/named-refs.at$$ \
|
||||
prohibit_magic_number_exit=^doc/bison.texi$$ \
|
||||
prohibit_magic_number_exit+=?|^tests/(conflicts|regression).at$$ \
|
||||
prohibit_strcmp=^doc/bison\.texi|tests/local\.at$$ \
|
||||
prohibit_tab_based_indentation=install-icc.sh|\.(am|mk)$$|^\.git|Makefile$$ \
|
||||
prohibit_strcmp=^doc/bison\.texi|examples|tests/local\.at$$ \
|
||||
prohibit_tab_based_indentation=install-icc.sh|\.(am|mk)$$|^\.git|tests/input.at|Makefile$$ \
|
||||
require_config_h=^(lib/yyerror|data/skeletons/(glr|yacc))\.c$$ \
|
||||
require_config_h_first=^(lib/yyerror|data/skeletons/(glr|yacc))\.c$$ \
|
||||
space_before_open_paren=^data/skeletons/ \
|
||||
|
||||
+3
-1
@@ -192,6 +192,7 @@ BISON_CXX_COMPILER_POSIXLY_CORRECT
|
||||
|
||||
# D.
|
||||
AC_CHECK_PROGS([DC], [dmd])
|
||||
AC_CHECK_PROGS([DCFLAGS], [])
|
||||
AM_CONDITIONAL([ENABLE_D], [test x"$DC" != x])
|
||||
|
||||
# Java.
|
||||
@@ -248,8 +249,9 @@ AM_WITH_DMALLOC
|
||||
# We use gnulib, which is only guaranteed to work properly with the
|
||||
# latest Gettext.
|
||||
AM_GNU_GETTEXT([external], [need-ngettext])
|
||||
AM_GNU_GETTEXT_VERSION([0.18])
|
||||
AM_GNU_GETTEXT_VERSION([0.19])
|
||||
BISON_I18N
|
||||
AC_CONFIG_FILES([gnulib-po/Makefile.in])
|
||||
|
||||
# Internationalized parsers.
|
||||
AC_CONFIG_FILES([runtime-po/Makefile.in])
|
||||
|
||||
@@ -75,48 +75,76 @@ skeletons.
|
||||
|
||||
## Symbols
|
||||
|
||||
### `b4_symbol(NUM, FIELD)`
|
||||
In order to unify the handling of the various aspects of symbols (tag, type
|
||||
name, whether terminal, etc.), bison.exe defines one macro per (token,
|
||||
field), where field can `has_id`, `id`, etc.: see
|
||||
src/output.c:prepare_symbols_definitions().
|
||||
`prepare_symbols_definitions()` in `src/output.c`.
|
||||
|
||||
The various FIELDS are:
|
||||
The macro `b4_symbol(NUM, FIELD)` gives access to the following FIELDS:
|
||||
|
||||
- `has_id`: 0 or 1.
|
||||
|
||||
- has_id: 0 or 1.
|
||||
Whether the symbol has an id.
|
||||
- id: string
|
||||
If has_id, the id. Guaranteed to be usable as a C identifier.
|
||||
Prefixed by api.token.prefix if defined.
|
||||
- tag: string.
|
||||
|
||||
- `id`: string
|
||||
If has_id, the id (prefixed by api.token.prefix if defined), otherwise
|
||||
defined as empty. Guaranteed to be usable as a C identifier.
|
||||
|
||||
- `tag`: string.
|
||||
A representation of the symbol. Can be 'foo', 'foo.id', '"foo"' etc.
|
||||
- user_number: integer
|
||||
|
||||
- `user_number`: integer
|
||||
The external number as used by yylex. Can be ASCII code when a character,
|
||||
some number chosen by bison, or some user number in the case of
|
||||
%token FOO <NUM>. Corresponds to yychar in yacc.c.
|
||||
- is_token: 0 or 1
|
||||
|
||||
- `is_token`: 0 or 1
|
||||
Whether this is a terminal symbol.
|
||||
- number: integer
|
||||
|
||||
- `number`: integer
|
||||
The internal number (computed from the external number by yytranslate).
|
||||
Corresponds to yytoken in yacc.c. This is the same number that serves as
|
||||
key in b4_symbol(NUM, FIELD).
|
||||
- has_type: 0, 1
|
||||
|
||||
In bison, symbols are first assigned increasing numbers in order of
|
||||
appearance (but tokens first, then nterms). After grammar reduction,
|
||||
unused nterms are then renumbered to appear last (i.e., first tokens, then
|
||||
used nterms and finally unused nterms). This final number NUM is the one
|
||||
contained in this field, and it is the one used as key in `b4_symbol(NUM,
|
||||
FIELD)`.
|
||||
|
||||
The code of the rule actions, however, is emitted before we know what
|
||||
symbols are unused, so they use the original numbers. To avoid confusion,
|
||||
they actually use "orig NUM" instead of just "NUM". bison also emits
|
||||
definitions for `b4_symbol(orig NUM, number)` that map from original
|
||||
numbers to the new ones. `b4_symbol` actually resolves `orig NUM` in the
|
||||
other case, i.e., `b4_symbol(orig 42, tag)` would return the tag of the
|
||||
symbols whose original number was 42.
|
||||
|
||||
- `has_type`: 0, 1
|
||||
Whether has a semantic value.
|
||||
- type_tag: string
|
||||
|
||||
- `type_tag`: string
|
||||
When api.value.type=union, the generated name for the union member.
|
||||
yytype_INT etc. for symbols that has_id, otherwise yytype_1 etc.
|
||||
- type
|
||||
|
||||
- `type`
|
||||
If it has a semantic value, its type tag, or, if variant are used,
|
||||
its type.
|
||||
In the case of api.value.type=union, type is the real type (e.g. int).
|
||||
- has_printer: 0, 1
|
||||
- printer: string
|
||||
- printer_file: string
|
||||
- printer_line: integer
|
||||
|
||||
- `has_printer`: 0, 1
|
||||
- `printer`: string
|
||||
- `printer_file`: string
|
||||
- `printer_line`: integer
|
||||
- `printer_loc`: location
|
||||
If the symbol has a printer, everything about it.
|
||||
- has_destructor, destructor, destructor_file, destructor_line
|
||||
|
||||
- `has_destructor`, `destructor`, `destructor_file`, `destructor_line`, `destructor_loc`
|
||||
Likewise.
|
||||
|
||||
### b4_symbol_value(VAL, [SYMBOL-NUM], [TYPE-TAG])
|
||||
### `b4_symbol_value(VAL, [SYMBOL-NUM], [TYPE-TAG])`
|
||||
Expansion of $$, $1, $<TYPE-TAG>3, etc.
|
||||
|
||||
The semantic value from a given VAL.
|
||||
@@ -127,14 +155,14 @@ The semantic value from a given VAL.
|
||||
The result can be used safely, it is put in parens to avoid nasty precedence
|
||||
issues.
|
||||
|
||||
### b4_lhs_value(SYMBOL-NUM, [TYPE])
|
||||
### `b4_lhs_value(SYMBOL-NUM, [TYPE])`
|
||||
Expansion of `$$` or `$<TYPE>$`, for symbol `SYMBOL-NUM`.
|
||||
|
||||
### b4_rhs_data(RULE-LENGTH, POS)
|
||||
### `b4_rhs_data(RULE-LENGTH, POS)`
|
||||
The data corresponding to the symbol `#POS`, where the current rule has
|
||||
`RULE-LENGTH` symbols on RHS.
|
||||
|
||||
### b4_rhs_value(RULE-LENGTH, POS, SYMBOL-NUM, [TYPE])
|
||||
### `b4_rhs_value(RULE-LENGTH, POS, SYMBOL-NUM, [TYPE])`
|
||||
Expansion of `$<TYPE>POS`, where the current rule has `RULE-LENGTH` symbols
|
||||
on RHS.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/* CSS style for Bison's diagnostics.
|
||||
|
||||
This is an experimental feature. The class names may change in the
|
||||
future. */
|
||||
|
||||
.warning { color: purple; }
|
||||
.error { color: red; }
|
||||
.note { color: cyan; }
|
||||
/* Semantic values in Bison's parser traces. */
|
||||
.value { color: green; }
|
||||
+2
-1
@@ -15,7 +15,8 @@
|
||||
## along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
dist_pkgdata_DATA = \
|
||||
data/README
|
||||
data/README.md \
|
||||
data/diagnostics.css
|
||||
|
||||
skeletonsdir = $(pkgdatadir)/skeletons
|
||||
dist_skeletons_DATA = \
|
||||
|
||||
+42
-24
@@ -389,17 +389,28 @@ m4_define([b4_glr_cc_if],
|
||||
#
|
||||
# The following macros provide access to symbol related values.
|
||||
|
||||
# _b4_symbol(NUM, FIELD)
|
||||
# ----------------------
|
||||
# __b4_symbol(NUM, FIELD)
|
||||
# -----------------------
|
||||
# Recover a FIELD about symbol #NUM. Thanks to m4_indir, fails if
|
||||
# undefined.
|
||||
m4_define([_b4_symbol],
|
||||
m4_define([__b4_symbol],
|
||||
[m4_indir([b4_symbol($1, $2)])])
|
||||
|
||||
|
||||
# _b4_symbol(NUM, FIELD)
|
||||
# ----------------------
|
||||
# Recover a FIELD about symbol #NUM (or "orig NUM"). Fails if
|
||||
# undefined.
|
||||
m4_define([_b4_symbol],
|
||||
[m4_ifdef([b4_symbol($1, number)],
|
||||
[__b4_symbol(m4_indir([b4_symbol($1, number)]), $2)],
|
||||
[__b4_symbol([$1], [$2])])])
|
||||
|
||||
|
||||
|
||||
# b4_symbol(NUM, FIELD)
|
||||
# ---------------------
|
||||
# Recover a FIELD about symbol #NUM. Thanks to m4_indir, fails if
|
||||
# Recover a FIELD about symbol #NUM (or "orig NUM"). Fails if
|
||||
# undefined. If FIELD = id, prepend the token prefix.
|
||||
m4_define([b4_symbol],
|
||||
[m4_case([$2],
|
||||
@@ -427,13 +438,6 @@ m4_define([b4_symbol_tag_comment],
|
||||
])
|
||||
|
||||
|
||||
# b4_symbol_action_location(SYMBOL-NUM, KIND)
|
||||
# -------------------------------------------
|
||||
# Report the location of the KIND action as FILE:LINE.
|
||||
m4_define([b4_symbol_action_location],
|
||||
[b4_symbol([$1], [$2_file]):b4_syncline([b4_symbol([$1], [$2_line])])])
|
||||
|
||||
|
||||
# b4_symbol_action(SYMBOL-NUM, KIND)
|
||||
# ----------------------------------
|
||||
# Run the action KIND (destructor or printer) for SYMBOL-NUM.
|
||||
@@ -444,9 +448,9 @@ m4_define([b4_symbol_action],
|
||||
[],
|
||||
[(*yylocationp)])dnl
|
||||
_b4_symbol_case([$1])[]dnl
|
||||
b4_syncline([b4_symbol([$1], [$2_line])], [b4_symbol([$1], [$2_file])])
|
||||
b4_syncline([b4_symbol([$1], [$2_line])], [b4_symbol([$1], [$2_file])])dnl
|
||||
b4_symbol([$1], [$2])
|
||||
b4_syncline([@oline@], [@ofile@])
|
||||
b4_syncline([@oline@], [@ofile@])dnl
|
||||
break;
|
||||
|
||||
b4_dollar_popdef[]dnl
|
||||
@@ -575,12 +579,15 @@ m4_define([b4_basename],
|
||||
[m4_bpatsubst([$1], [^.*/\([^/]+\)/*$], [\1])])
|
||||
|
||||
|
||||
# b4_syncline(LINE, FILE)
|
||||
# -----------------------
|
||||
# b4_syncline(LINE, FILE)dnl
|
||||
# --------------------------
|
||||
# Should always be following by a dnl.
|
||||
#
|
||||
# Emit "#line LINE FILE /* __LINE__ __FILE__ */".
|
||||
m4_define([b4_syncline],
|
||||
[b4_flag_if([synclines],
|
||||
[b4_sync_start([$1], [$2]) b4_sync_end([__line__],
|
||||
[b4_basename(m4_quote(__file__))])[]dnl
|
||||
[b4_sync_start([$1], [$2])[]dnl
|
||||
b4_sync_end([__line__], [b4_basename(m4_quote(__file__))])
|
||||
])])
|
||||
|
||||
# b4_sync_start(LINE, FILE)
|
||||
@@ -592,7 +599,17 @@ m4_define([b4_sync_start], [b4_comment([$2:$1])])
|
||||
# -----------------------
|
||||
# Syncline for the current place, which ends. Typically a comment
|
||||
# left for the reader.
|
||||
m4_define([b4_sync_end], [b4_comment([$2:$1])])
|
||||
m4_define([b4_sync_end], [ b4_comment([$2:$1])]
|
||||
)
|
||||
# This generates dependencies on the Bison skeletons hence lots of
|
||||
# useless 'git diff'. This location is useless for the regular
|
||||
# user (who does not care about the skeletons) and is actually not
|
||||
# useful for Bison developpers too (I, Akim, never used this to locate
|
||||
# the code in skeletons that generated output). So disable it
|
||||
# completely. If someone thinks this was actually useful, a %define
|
||||
# variable should be provided to control the level of verbosity of
|
||||
# '#line', in replacement of --no-lines.
|
||||
m4_define([b4_sync_end])
|
||||
|
||||
|
||||
# b4_user_code(USER-CODE)
|
||||
@@ -742,8 +759,10 @@ m4_define([b4_percent_define_get_kind],
|
||||
[m4_indir([b4_percent_define_kind(]$1[)])],
|
||||
[b4_fatal([[$0: undefined %%define variable '%s']], [$1])])])
|
||||
|
||||
# b4_percent_define_get_syncline(VARIABLE)
|
||||
# ----------------------------------------
|
||||
# b4_percent_define_get_syncline(VARIABLE)dnl
|
||||
# -------------------------------------------
|
||||
# Should always be following by a dnl.
|
||||
#
|
||||
# Mimic muscle_percent_define_get_syncline in ../src/muscle-tab.h exactly.
|
||||
# That is, if the %define variable VARIABLE is undefined, complain fatally
|
||||
# since that's a Bison or skeleton error. Otherwise, return its definition
|
||||
@@ -959,8 +978,7 @@ m4_ifval([$1], [m4_define([b4_percent_code_bison_qualifiers(]$1[)])])dnl
|
||||
m4_ifdef(b4_macro_name,
|
||||
[b4_comment([m4_if([$#], [0], [[Unqualified %code]],
|
||||
[["%code ]$1["]])[ blocks.]])
|
||||
b4_user_code([m4_indir(b4_macro_name)])
|
||||
])dnl
|
||||
b4_user_code([m4_indir(b4_macro_name)])])dnl
|
||||
m4_popdef([b4_macro_name])])
|
||||
|
||||
# b4_percent_code_ifdef(QUALIFIER, IF-TRUE, [IF-FALSE])
|
||||
@@ -1060,10 +1078,10 @@ m4_define_default([b4_location_initial_line], [1])
|
||||
## Sanity checks. ##
|
||||
## --------------- ##
|
||||
|
||||
# api.location.prefix={...} (Java and C++).
|
||||
# api.location.type={...} (C, C++ and Java).
|
||||
b4_percent_define_check_kind([api.location.type], [code], [deprecated])
|
||||
|
||||
# api.position.prefix={...} (Java).
|
||||
# api.position.type={...} (Java).
|
||||
b4_percent_define_check_kind([api.position.type], [code], [deprecated])
|
||||
|
||||
# api.prefix >< %name-prefix.
|
||||
|
||||
@@ -147,13 +147,13 @@ m4_if(m4_bregexp(b4_namespace_ref, [::[ ]*$]), [-1], [],
|
||||
[[namespace reference has a trailing "::"]])])
|
||||
|
||||
m4_define([b4_namespace_open],
|
||||
[b4_user_code([b4_percent_define_get_syncline([[api.namespace]])
|
||||
[b4_user_code([b4_percent_define_get_syncline([[api.namespace]])dnl
|
||||
[namespace ]m4_bpatsubst(m4_dquote(m4_bpatsubst(m4_dquote(b4_namespace_ref),
|
||||
[^\(.\)[ ]*::], [\1])),
|
||||
[::], [ { namespace ])[ {]])])
|
||||
|
||||
m4_define([b4_namespace_close],
|
||||
[b4_user_code([b4_percent_define_get_syncline([[api.namespace]])
|
||||
[b4_user_code([b4_percent_define_get_syncline([[api.namespace]])dnl
|
||||
m4_bpatsubst(m4_dquote(m4_bpatsubst(m4_dquote(b4_namespace_ref[ ]),
|
||||
[^\(.\)[ ]*\(::\)?\([^][:]\|:[^:]\)*],
|
||||
[\1])),
|
||||
@@ -194,7 +194,7 @@ m4_define([b4_value_type_declare],
|
||||
[union\|union-directive],
|
||||
[[ union semantic_type
|
||||
{
|
||||
]b4_user_union_members[
|
||||
]b4_user_union_members[
|
||||
};]])])dnl
|
||||
])
|
||||
|
||||
|
||||
+30
-21
@@ -229,18 +229,22 @@ m4_define([b4_attribute_define],
|
||||
#endif
|
||||
|
||||
]m4_bmatch([$1], [\bnoreturn\b], [[/* The _Noreturn keyword of C11. */
|
||||
#if ! defined _Noreturn
|
||||
# if defined __cplusplus && 201103L <= __cplusplus
|
||||
]dnl This is an exact copy of lib/_Noreturn.h.
|
||||
[#ifndef _Noreturn
|
||||
# if (defined __cplusplus \
|
||||
&& ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \
|
||||
|| (defined _MSC_VER && 1900 <= _MSC_VER)))
|
||||
# define _Noreturn [[noreturn]]
|
||||
# elif !(defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__)
|
||||
# if (3 <= __GNUC__ || (__GNUC__ == 2 && 8 <= __GNUC_MINOR__) \
|
||||
|| 0x5110 <= __SUNPRO_C)
|
||||
# define _Noreturn __attribute__ ((__noreturn__))
|
||||
# elif defined _MSC_VER && 1200 <= _MSC_VER
|
||||
# define _Noreturn __declspec (noreturn)
|
||||
# else
|
||||
# define _Noreturn
|
||||
# endif
|
||||
# elif ((!defined __cplusplus || defined __clang__) \
|
||||
&& (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \
|
||||
|| 4 < __GNUC__ + (7 <= __GNUC_MINOR__)))
|
||||
/* _Noreturn works as-is. */
|
||||
# elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__) || 0x5110 <= __SUNPRO_C
|
||||
# define _Noreturn __attribute__ ((__noreturn__))
|
||||
# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0)
|
||||
# define _Noreturn __declspec (noreturn)
|
||||
# else
|
||||
# define _Noreturn
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -470,7 +474,7 @@ m4_define([b4_sync_start], [[#]line $1 $2])
|
||||
m4_define([b4_case],
|
||||
[ case $1:
|
||||
$2
|
||||
b4_syncline([@oline@], [@ofile@])
|
||||
b4_syncline([@oline@], [@ofile@])dnl
|
||||
break;])
|
||||
|
||||
|
||||
@@ -480,7 +484,7 @@ m4_define([b4_predicate_case],
|
||||
[ case $1:
|
||||
if (! (
|
||||
$2)) YYERROR;
|
||||
b4_syncline([@oline@], [@ofile@])
|
||||
b4_syncline([@oline@], [@ofile@])dnl
|
||||
break;])
|
||||
|
||||
|
||||
@@ -540,8 +544,10 @@ m4_if(b4_skeleton, ["yacc.c"],
|
||||
YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
|
||||
# endif
|
||||
]])dnl
|
||||
b4_symbol_actions([printer])[
|
||||
}
|
||||
b4_percent_code_get([[pre-printer]])dnl
|
||||
b4_symbol_actions([printer])
|
||||
b4_percent_code_get([[post-printer]])dnl
|
||||
[}
|
||||
|
||||
|
||||
/*---------------------------.
|
||||
@@ -709,13 +715,13 @@ typedef ]b4_percent_define_get([[api.value.type]])[ ]b4_api_PREFIX[STYPE;
|
||||
[m4_bmatch(b4_percent_define_get([[api.value.type]]),
|
||||
[union\|union-directive],
|
||||
[[#if ! defined ]b4_api_PREFIX[STYPE && ! defined ]b4_api_PREFIX[STYPE_IS_DECLARED
|
||||
]b4_percent_define_get_syncline([[api.value.union.name]])[
|
||||
union ]b4_percent_define_get([[api.value.union.name]])[
|
||||
]b4_percent_define_get_syncline([[api.value.union.name]])dnl
|
||||
[union ]b4_percent_define_get([[api.value.union.name]])[
|
||||
{
|
||||
]b4_user_union_members[
|
||||
};
|
||||
]b4_percent_define_get_syncline([[api.value.union.name]])[
|
||||
typedef union ]b4_percent_define_get([[api.value.union.name]])[ ]b4_api_PREFIX[STYPE;
|
||||
]b4_percent_define_get_syncline([[api.value.union.name]])dnl
|
||||
[typedef union ]b4_percent_define_get([[api.value.union.name]])[ ]b4_api_PREFIX[STYPE;
|
||||
# define ]b4_api_PREFIX[STYPE_IS_TRIVIAL 1
|
||||
# define ]b4_api_PREFIX[STYPE_IS_DECLARED 1
|
||||
#endif
|
||||
@@ -726,7 +732,10 @@ typedef union ]b4_percent_define_get([[api.value.union.name]])[ ]b4_api_PREFIX[S
|
||||
# -----------------------
|
||||
m4_define([b4_location_type_define],
|
||||
[[/* Location type. */
|
||||
#if ! defined ]b4_api_PREFIX[LTYPE && ! defined ]b4_api_PREFIX[LTYPE_IS_DECLARED
|
||||
]b4_percent_define_ifdef([[api.location.type]],
|
||||
[[typedef ]b4_percent_define_get([[api.location.type]])[ ]b4_api_PREFIX[LTYPE;
|
||||
]],
|
||||
[[#if ! defined ]b4_api_PREFIX[LTYPE && ! defined ]b4_api_PREFIX[LTYPE_IS_DECLARED
|
||||
typedef struct ]b4_api_PREFIX[LTYPE ]b4_api_PREFIX[LTYPE;
|
||||
struct ]b4_api_PREFIX[LTYPE
|
||||
{
|
||||
@@ -738,7 +747,7 @@ struct ]b4_api_PREFIX[LTYPE
|
||||
# define ]b4_api_PREFIX[LTYPE_IS_DECLARED 1
|
||||
# define ]b4_api_PREFIX[LTYPE_IS_TRIVIAL 1
|
||||
#endif
|
||||
]])
|
||||
]])])
|
||||
|
||||
|
||||
# b4_declare_yylstype
|
||||
|
||||
+19
-6
@@ -18,11 +18,24 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# b4_comment(TEXT)
|
||||
# ----------------
|
||||
m4_define([b4_comment], [/* m4_bpatsubst([$1], [
|
||||
], [
|
||||
]) */])
|
||||
# _b4_comment(TEXT, OPEN, CONTINUE, END)
|
||||
# --------------------------------------
|
||||
# Put TEXT in comment. Avoid trailing spaces: don't indent empty lines.
|
||||
# Avoid adding indentation to the first line, as the indentation comes
|
||||
# from OPEN. That's why we don't patsubst([$1], [^\(.\)], [ \1]).
|
||||
#
|
||||
# Prefix all the output lines with PREFIX.
|
||||
m4_define([_b4_comment],
|
||||
[$2[]m4_bpatsubst(m4_expand([[$1]]), [
|
||||
\(.\)], [
|
||||
$3\1])$4])
|
||||
|
||||
|
||||
# b4_comment(TEXT, [PREFIX])
|
||||
# --------------------------
|
||||
# Put TEXT in comment. Prefix all the output lines with PREFIX.
|
||||
m4_define([b4_comment],
|
||||
[_b4_comment([$1], [$2/* ], [$2 ], [ */])])
|
||||
|
||||
|
||||
# b4_list2(LIST1, LIST2)
|
||||
@@ -177,7 +190,7 @@ b4_percent_define_default([[stype]], [[YYSemanticType]])])
|
||||
# %name-prefix
|
||||
m4_define_default([b4_prefix], [[YY]])
|
||||
|
||||
b4_percent_define_default([[api.parser.class]], [b4_prefix[]YYParser])])
|
||||
b4_percent_define_default([[api.parser.class]], [b4_prefix[]Parser])])
|
||||
m4_define([b4_parser_class], [b4_percent_define_get([[api.parser.class]])])
|
||||
|
||||
#b4_percent_define_default([[location_type]], [Location])])
|
||||
|
||||
@@ -196,14 +196,14 @@ m4_if(b4_skeleton, ["glr.c"],
|
||||
# glr.cc produces its own header.
|
||||
b4_glr_cc_if([],
|
||||
[b4_defines_if(
|
||||
[b4_output_begin([b4_spec_defines_file])
|
||||
[b4_output_begin([b4_spec_header_file])
|
||||
b4_copyright([Skeleton interface for Bison GLR parsers in C],
|
||||
[2002-2015, 2018-2019])[
|
||||
]b4_cpp_guard_open([b4_spec_defines_file])[
|
||||
]b4_cpp_guard_open([b4_spec_header_file])[
|
||||
]b4_shared_declarations[
|
||||
]b4_cpp_guard_close([b4_spec_defines_file])[
|
||||
]b4_output_end
|
||||
])])
|
||||
]b4_cpp_guard_close([b4_spec_header_file])[
|
||||
]b4_output_end[
|
||||
]])])
|
||||
|
||||
|
||||
# ------------------------- #
|
||||
@@ -238,7 +238,7 @@ b4_copyright([Skeleton implementation for Bison GLR parsers in C],
|
||||
|
||||
]b4_null_define[
|
||||
|
||||
]b4_defines_if([[#include "@basename(]b4_spec_defines_file[@)"]],
|
||||
]b4_defines_if([[#include "@basename(]b4_spec_header_file[@)"]],
|
||||
[b4_shared_declarations])[
|
||||
|
||||
/* Enabling verbose error messages. */
|
||||
|
||||
@@ -100,8 +100,8 @@ m4_defn([b4_initial_action])]))])[
|
||||
|
||||
# Hijack the post prologue to declare yyerror.
|
||||
]m4_append([b4_post_prologue],
|
||||
[b4_syncline([@oline@], [@ofile@])[
|
||||
]b4_function_declare([yyerror],
|
||||
[b4_syncline([@oline@], [@ofile@])dnl
|
||||
b4_function_declare([yyerror],
|
||||
[static void],b4_locations_if([
|
||||
[[const ]b4_namespace_ref::b4_parser_class[::location_type *yylocationp],
|
||||
[yylocationp]],])
|
||||
@@ -128,8 +128,8 @@ m4_if(b4_prefix, [yy], [],
|
||||
# Hijack the epilogue to define implementations (yyerror, parser member
|
||||
# functions etc.).
|
||||
m4_append([b4_epilogue],
|
||||
[b4_syncline([@oline@], [@ofile@])[
|
||||
|
||||
[b4_syncline([@oline@], [@ofile@])dnl
|
||||
[
|
||||
/*------------------.
|
||||
| Report an error. |
|
||||
`------------------*/
|
||||
@@ -234,7 +234,7 @@ m4_pushdef([b4_parse_param], m4_defn([b4_parse_param_orig]))dnl
|
||||
|
||||
#endif
|
||||
]m4_popdef([b4_parse_param])dnl
|
||||
b4_namespace_close
|
||||
b4_namespace_close[]dnl
|
||||
])
|
||||
|
||||
|
||||
@@ -351,15 +351,15 @@ b4_percent_define_flag_if([[global_tokens_and_yystype]],
|
||||
])
|
||||
|
||||
b4_defines_if(
|
||||
[b4_output_begin([b4_spec_defines_file])
|
||||
[b4_output_begin([b4_spec_header_file])
|
||||
b4_copyright([Skeleton interface for Bison GLR parsers in C++],
|
||||
[2002-2015, 2018-2019])[
|
||||
// C++ GLR parser skeleton written by Akim Demaille.
|
||||
|
||||
]b4_disclaimer[
|
||||
]b4_cpp_guard_open([b4_spec_defines_file])[
|
||||
]b4_cpp_guard_open([b4_spec_header_file])[
|
||||
]b4_shared_declarations[
|
||||
]b4_cpp_guard_close([b4_spec_defines_file])[
|
||||
]b4_cpp_guard_close([b4_spec_header_file])[
|
||||
]b4_output_end])
|
||||
|
||||
# Let glr.c (and b4_shared_declarations) believe that the user
|
||||
|
||||
@@ -111,9 +111,9 @@ b4_dollar_pushdef([yysym.value],
|
||||
[],
|
||||
[yysym.location])dnl
|
||||
_b4_symbol_case([$1])[]dnl
|
||||
b4_syncline([b4_symbol([$1], [$2_line])], [b4_symbol([$1], [$2_file])])
|
||||
b4_syncline([b4_symbol([$1], [$2_line])], [b4_symbol([$1], [$2_file])])dnl
|
||||
b4_symbol([$1], [$2])
|
||||
b4_syncline([@oline@], [@ofile@])
|
||||
b4_syncline([@oline@], [@ofile@])dnl
|
||||
break;
|
||||
|
||||
m4_popdef([b4_symbol_value])[]dnl
|
||||
@@ -399,22 +399,22 @@ m4_define([b4_shared_declarations],
|
||||
## -------------- ##
|
||||
|
||||
b4_defines_if(
|
||||
[b4_output_begin([b4_spec_defines_file])
|
||||
[b4_output_begin([b4_spec_header_file])
|
||||
b4_copyright([Skeleton interface for Bison LALR(1) parsers in C++])
|
||||
[
|
||||
/**
|
||||
** \file ]b4_spec_defines_file[
|
||||
** \file ]b4_spec_header_file[
|
||||
** Define the ]b4_namespace_ref[::parser class.
|
||||
*/
|
||||
|
||||
// C++ LALR(1) parser skeleton written by Akim Demaille.
|
||||
|
||||
]b4_disclaimer[
|
||||
]b4_cpp_guard_open([b4_spec_defines_file])[
|
||||
]b4_cpp_guard_open([b4_spec_header_file])[
|
||||
]b4_shared_declarations(hh)[
|
||||
]b4_cpp_guard_close([b4_spec_defines_file])
|
||||
b4_output_end
|
||||
])
|
||||
]b4_cpp_guard_close([b4_spec_header_file])[
|
||||
]b4_output_end[
|
||||
]])
|
||||
|
||||
|
||||
b4_output_begin([b4_parser_file_name])[
|
||||
@@ -428,7 +428,7 @@ m4_if(b4_prefix, [yy], [],
|
||||
|
||||
]b4_user_pre_prologue[
|
||||
|
||||
]b4_defines_if([[#include "@basename(]b4_spec_defines_file[@)"]],
|
||||
]b4_defines_if([[#include "@basename(]b4_spec_header_file[@)"]],
|
||||
[b4_shared_declarations([cc])])[
|
||||
|
||||
]b4_user_post_prologue[
|
||||
|
||||
+36
-37
@@ -47,8 +47,8 @@ import std.format;
|
||||
* parser <tt>]b4_parser_class[</tt>.
|
||||
*/
|
||||
public interface Lexer
|
||||
{
|
||||
]b4_locations_if([[/**
|
||||
{]b4_locations_if([[
|
||||
/**
|
||||
* Method to retrieve the beginning position of the last scanned token.
|
||||
* @@return the position at which the last scanned token starts. */
|
||||
@@property ]b4_position_type[ startPos ();
|
||||
@@ -56,8 +56,9 @@ public interface Lexer
|
||||
/**
|
||||
* Method to retrieve the ending position of the last scanned token.
|
||||
* @@return the first position beyond the last scanned token. */
|
||||
@@property ]b4_position_type[ endPos ();]])[
|
||||
@@property ]b4_position_type[ endPos ();
|
||||
|
||||
]])[
|
||||
/**
|
||||
* Method to retrieve the semantic value of the last scanned token.
|
||||
* @@return the semantic value of the last scanned token. */
|
||||
@@ -68,13 +69,13 @@ public interface Lexer
|
||||
* to the next token and prepares to return the semantic value
|
||||
* ]b4_locations_if([and beginning/ending positions ])[of the token.
|
||||
* @@return the token identifier corresponding to the next token. */
|
||||
YYTokenType yylex ();
|
||||
int yylex ();
|
||||
|
||||
/**
|
||||
* Entry point for error reporting. Emits an error
|
||||
* ]b4_locations_if([referring to the given location ])[in a user-defined way.
|
||||
*
|
||||
* ]b4_locations_if([[@@param loc The location of the element to which the
|
||||
*]b4_locations_if([[
|
||||
* @@param loc The location of the element to which the
|
||||
* error message is related]])[
|
||||
* @@param s The string for the error message. */
|
||||
void yyerror (]b4_locations_if([b4_location_type[ loc, ]])[string s);
|
||||
@@ -82,8 +83,8 @@ public interface Lexer
|
||||
|
||||
private final struct YYStackElement{
|
||||
int state;
|
||||
]b4_yystype[ value;
|
||||
]b4_locations_if(b4_location_type[[] location;])[
|
||||
]b4_yystype[ value;]b4_locations_if(
|
||||
b4_location_type[[] location;])[
|
||||
}
|
||||
|
||||
private final struct YYStack {
|
||||
@@ -231,9 +232,9 @@ b4_user_union_members
|
||||
]b4_identification[
|
||||
|
||||
/** True if verbose error messages are enabled. */
|
||||
public bool errorVerbose = ]b4_flag_value([error_verbose]);
|
||||
public bool errorVerbose = ]b4_flag_value([error_verbose])[;
|
||||
|
||||
b4_locations_if([[
|
||||
]b4_locations_if([[
|
||||
private final ]b4_location_type[ yylloc_from_stack (ref YYStack rhs, int n)
|
||||
{
|
||||
static if (yy_location_is_class) {
|
||||
@@ -249,34 +250,34 @@ b4_user_union_members
|
||||
}
|
||||
}]])[
|
||||
|
||||
]b4_lexer_if([[private class YYLexer implements Lexer {
|
||||
]b4_lexer_if([[ private class YYLexer implements Lexer {
|
||||
]b4_percent_code_get([[lexer]])[
|
||||
}
|
||||
|
||||
]])[/** The object doing lexical analysis for us. */
|
||||
]])[
|
||||
/** The object doing lexical analysis for us. */
|
||||
private Lexer yylexer;
|
||||
]
|
||||
b4_parse_param_vars
|
||||
|
||||
b4_lexer_if([[
|
||||
]b4_parse_param_vars[
|
||||
|
||||
]b4_lexer_if([[
|
||||
/**
|
||||
* Instantiates the Bison-generated parser.
|
||||
*/
|
||||
public this] (b4_parse_param_decl([b4_lex_param_decl])[) {
|
||||
this.yylexer = new YYLexer(]b4_lex_param_call[);
|
||||
this.yyDebugStream = stderr;
|
||||
]b4_parse_param_cons[
|
||||
]b4_parse_param_cons[
|
||||
}
|
||||
]])
|
||||
]])[
|
||||
|
||||
/**
|
||||
* Instantiates the Bison-generated parser.
|
||||
* @@param yylexer The scanner that will supply tokens to the parser.
|
||||
*/
|
||||
b4_lexer_if([[protected]], [[public]]) [this (]b4_parse_param_decl([[Lexer yylexer]])[) {
|
||||
]b4_lexer_if([[protected]], [[public]]) [this (]b4_parse_param_decl([[Lexer yylexer]])[) {
|
||||
this.yylexer = yylexer;
|
||||
this.yyDebugStream = stderr;
|
||||
]b4_parse_param_cons[
|
||||
]b4_parse_param_cons[
|
||||
}
|
||||
|
||||
private File yyDebugStream;
|
||||
@@ -358,8 +359,8 @@ b4_lexer_if([[
|
||||
|
||||
private int yyaction (int yyn, ref YYStack yystack, int yylen)
|
||||
{
|
||||
]b4_yystype[ yyval;
|
||||
]b4_locations_if([b4_location_type[ yyloc = yylloc_from_stack (yystack, yylen);]])[
|
||||
]b4_yystype[ yyval;]b4_locations_if([[
|
||||
]b4_location_type[ yyloc = yylloc_from_stack (yystack, yylen);]])[
|
||||
|
||||
/* If YYLEN is nonzero, implement the default value of the action:
|
||||
`$$ = $1'. Otherwise, use the top of the stack.
|
||||
@@ -408,7 +409,8 @@ b4_lexer_if([[
|
||||
if (yystr[0] == '"')
|
||||
{
|
||||
string yyr;
|
||||
strip_quotes: for (int i = 1; i < yystr.length; i++)
|
||||
strip_quotes:
|
||||
for (int i = 1; i < yystr.length; i++)
|
||||
switch (yystr[i])
|
||||
{
|
||||
case '\'':
|
||||
@@ -475,15 +477,15 @@ b4_locations_if([, ref ]b4_location_type[ yylocationp])[)
|
||||
YYStack yystack;
|
||||
|
||||
/* Error handling. */
|
||||
int yynerrs_ = 0;
|
||||
]b4_locations_if([/// The location where the error started.
|
||||
int yynerrs_ = 0;]b4_locations_if([[
|
||||
/// The location where the error started.
|
||||
]b4_location_type[ yyerrloc = null;
|
||||
|
||||
/// ]b4_location_type[ of the lookahead.
|
||||
]b4_location_type[ yylloc;
|
||||
|
||||
/// @@$.
|
||||
]b4_location_type[ yyloc;])[
|
||||
]b4_location_type[ yyloc;]])[
|
||||
|
||||
/// Semantic value of the lookahead.
|
||||
]b4_yystype[ yylval;
|
||||
@@ -531,8 +533,7 @@ m4_popdef([b4_at_dollar])])dnl
|
||||
if (yychar == yyempty_)
|
||||
{
|
||||
yycdebug ("Reading a token: ");
|
||||
yychar = yylex ();]
|
||||
b4_locations_if([[
|
||||
yychar = yylex ();]b4_locations_if([[
|
||||
static if (yy_location_is_class) {
|
||||
yylloc = new ]b4_location_type[(yylexer.startPos, yylexer.endPos);
|
||||
} else {
|
||||
@@ -624,7 +625,7 @@ m4_popdef([b4_at_dollar])])dnl
|
||||
yyerror (]b4_locations_if([yylloc, ])[yysyntax_error (yystate, yytoken));
|
||||
}
|
||||
|
||||
]b4_locations_if([yyerrloc = yylloc;])[
|
||||
]b4_locations_if([ yyerrloc = yylloc;])[
|
||||
if (yyerrstatus_ == 3)
|
||||
{
|
||||
/* If just tried and failed to reuse lookahead token after an
|
||||
@@ -648,9 +649,8 @@ m4_popdef([b4_at_dollar])])dnl
|
||||
/*-------------------------------------------------.
|
||||
| errorlab -- error raised explicitly by YYERROR. |
|
||||
`-------------------------------------------------*/
|
||||
case YYERROR:
|
||||
|
||||
]b4_locations_if([yyerrloc = yystack.locationAt (yylen - 1);])[
|
||||
case YYERROR:]b4_locations_if([
|
||||
yyerrloc = yystack.locationAt (yylen - 1);])[
|
||||
/* Do not reclaim the symbols of the rule which action triggered
|
||||
this YYERROR. */
|
||||
yystack.pop (yylen);
|
||||
@@ -663,7 +663,7 @@ m4_popdef([b4_at_dollar])])dnl
|
||||
| yyerrlab1 -- common code for both syntax error and YYERROR. |
|
||||
`-------------------------------------------------------------*/
|
||||
case YYERRLAB1:
|
||||
yyerrstatus_ = 3; /* Each real token shifted decrements this.xb */
|
||||
yyerrstatus_ = 3; /* Each real token shifted decrements this. */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -683,14 +683,14 @@ m4_popdef([b4_at_dollar])])dnl
|
||||
if (yystack.height == 1)
|
||||
return false;
|
||||
|
||||
]b4_locations_if([yyerrloc = yystack.locationAt (0);])[
|
||||
]b4_locations_if([ yyerrloc = yystack.locationAt (0);])[
|
||||
yystack.pop ();
|
||||
yystate = yystack.stateAt (0);
|
||||
if (yydebug > 0)
|
||||
yystack.print (yyDebugStream);
|
||||
}
|
||||
|
||||
]b4_locations_if([
|
||||
]b4_locations_if([
|
||||
/* Muck with the stack to setup for yylloc. */
|
||||
yystack.push (0, yy_semantic_null, yylloc);
|
||||
yystack.push (0, yy_semantic_null, yyerrloc);
|
||||
@@ -892,6 +892,5 @@ m4_popdef([b4_at_dollar])])dnl
|
||||
b4_percent_code_get[]dnl
|
||||
|
||||
}
|
||||
|
||||
b4_epilogue
|
||||
b4_epilogue[]dnl
|
||||
m4_divert_pop(0)dnl
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
|
||||
m4_include(b4_skeletonsdir/[java.m4])
|
||||
|
||||
b4_defines_if([b4_fatal([%s: %%defines does not make sense in Java],
|
||||
[b4_skeleton])])
|
||||
b4_defines_if([b4_complain([%defines does not make sense in Java])])
|
||||
|
||||
# We do not depend on %debug in Java, but pacify warnings about
|
||||
# non-used flags.
|
||||
@@ -26,9 +25,8 @@ b4_parse_trace_if([0], [0])
|
||||
|
||||
m4_define([b4_symbol_no_destructor_assert],
|
||||
[b4_symbol_if([$1], [has_destructor],
|
||||
[b4_fatal([%s: %s: %%destructor does not make sense in Java],
|
||||
[b4_skeleton],
|
||||
[b4_symbol_action_location([$1], [destructor])])])])
|
||||
[b4_complain_at(m4_unquote(b4_symbol([$1], [destructor_loc])),
|
||||
[%destructor does not make sense in Java])])])
|
||||
b4_symbol_foreach([b4_symbol_no_destructor_assert])
|
||||
|
||||
# Setup some macros for api.push-pull.
|
||||
@@ -89,8 +87,8 @@ b4_output_begin([b4_parser_file_name])[
|
||||
]])[
|
||||
]b4_user_pre_prologue[
|
||||
]b4_user_post_prologue[
|
||||
]b4_percent_code_get([[imports]])
|
||||
[/**
|
||||
]b4_percent_code_get([[imports]])[
|
||||
/**
|
||||
* A Bison parser, automatically generated from <tt>]m4_bpatsubst(b4_file_name, [^"\(.*\)"$], [\1])[</tt>.
|
||||
*
|
||||
* @@author LALR (1) parser skeleton written by Paolo Bonzini.
|
||||
|
||||
+49
-20
@@ -284,20 +284,48 @@ m4_define([b4_declare_yyparse],
|
||||
# Declaration that might either go into the header (if --defines)
|
||||
# or open coded in the parser body.
|
||||
m4_define([b4_shared_declarations],
|
||||
[b4_cpp_guard_open([b4_spec_defines_file])[
|
||||
[b4_cpp_guard_open([b4_spec_header_file])[
|
||||
]b4_declare_yydebug[
|
||||
]b4_percent_code_get([[requires]])[
|
||||
]b4_token_enums_defines[
|
||||
]b4_declare_yylstype[
|
||||
]b4_declare_yyparse[
|
||||
]b4_percent_code_get([[provides]])[
|
||||
]b4_cpp_guard_close([b4_spec_defines_file])[]dnl
|
||||
]b4_cpp_guard_close([b4_spec_header_file])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# b4_header_include_if(IF-TRUE, IF-FALSE)
|
||||
# ---------------------------------------
|
||||
# Run IF-TRUE if we generate an output file and api.header.include
|
||||
# is defined.
|
||||
m4_define([b4_header_include_if],
|
||||
[m4_ifval(m4_quote(b4_spec_header_file),
|
||||
[b4_percent_define_ifdef([[api.header.include]],
|
||||
[$1],
|
||||
[$2])],
|
||||
[$2])])
|
||||
|
||||
m4_if(b4_spec_header_file, [[y.tab.h]],
|
||||
[b4_percent_define_default([[api.header.include]],
|
||||
[["@basename(]b4_spec_header_file[@)"]])])
|
||||
|
||||
|
||||
|
||||
|
||||
## -------------- ##
|
||||
## Output files. ##
|
||||
## -------------- ##
|
||||
|
||||
|
||||
b4_defines_if([[
|
||||
]b4_output_begin([b4_spec_header_file])[
|
||||
]b4_copyright([Bison interface for Yacc-like parsers in C])[
|
||||
]b4_disclaimer[
|
||||
]b4_shared_declarations[
|
||||
]b4_output_end[
|
||||
]])# b4_defines_if
|
||||
|
||||
b4_output_begin([b4_parser_file_name])[
|
||||
]b4_copyright([Bison implementation for Yacc-like parsers in C])[
|
||||
/* C LALR(1) parser skeleton written by Richard Stallman, by
|
||||
@@ -345,11 +373,11 @@ m4_if(b4_api_prefix, [yy], [],
|
||||
# define YYERROR_VERBOSE ]b4_error_verbose_if([1], [0])[
|
||||
#endif
|
||||
|
||||
]m4_ifval(m4_quote(b4_spec_defines_file),
|
||||
[[/* In a future release of Bison, this section will be replaced
|
||||
by #include "@basename(]b4_spec_defines_file[@)". */
|
||||
]])dnl
|
||||
b4_shared_declarations[
|
||||
]b4_header_include_if([[#include ]b4_percent_define_get([[api.header.include]])],
|
||||
[m4_ifval(m4_quote(b4_spec_header_file),
|
||||
[/* Use api.header.include to #include this header
|
||||
instead of duplicating it here. */
|
||||
])b4_shared_declarations])[
|
||||
|
||||
]b4_user_post_prologue[
|
||||
]b4_percent_code_get[]dnl
|
||||
@@ -411,6 +439,15 @@ typedef short yytype_int16;
|
||||
|
||||
]b4_attribute_define[
|
||||
|
||||
]b4_parse_assert_if([[#ifdef NDEBUG
|
||||
# define YY_ASSERT(E) ((void) (0 && (E)))
|
||||
#else
|
||||
# include <assert.h> /* INFRINGES ON USER NAME SPACE */
|
||||
# define YY_ASSERT(E) assert (E)
|
||||
#endif
|
||||
]],
|
||||
[[#define YY_ASSERT(E) ((void) (0 && (E)))]])[
|
||||
|
||||
#if ]b4_lac_if([[1]], [[! defined yyoverflow || YYERROR_VERBOSE]])[
|
||||
|
||||
/* The parser invokes alloca or malloc; define the necessary symbols. */]dnl
|
||||
@@ -1453,6 +1490,8 @@ yynewstate:
|
||||
| yynewstate -- set current state (the top of the stack) to yystate. |
|
||||
`--------------------------------------------------------------------*/
|
||||
yysetstate:
|
||||
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
|
||||
YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
|
||||
*yyssp = (yytype_int16) yystate;
|
||||
|
||||
if (yyss + yystacksize - 1 <= yyssp)
|
||||
@@ -1520,8 +1559,6 @@ yysetstate:
|
||||
}
|
||||
#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
|
||||
|
||||
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
|
||||
|
||||
if (yystate == YYFINAL)
|
||||
YYACCEPT;
|
||||
|
||||
@@ -1613,8 +1650,8 @@ yyread_pushed_token:]])[
|
||||
yystate = yyn;
|
||||
YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
|
||||
*++yyvsp = yylval;
|
||||
YY_IGNORE_MAYBE_UNINITIALIZED_END
|
||||
]b4_locations_if([ *++yylsp = yylloc;])[
|
||||
YY_IGNORE_MAYBE_UNINITIALIZED_END]b4_locations_if([
|
||||
*++yylsp = yylloc;])[
|
||||
goto yynewstate;
|
||||
|
||||
|
||||
@@ -1662,7 +1699,7 @@ yyreduce:
|
||||
}]], [[
|
||||
switch (yyn)
|
||||
{
|
||||
]b4_user_actions[
|
||||
]b4_user_actions[
|
||||
default: break;
|
||||
}]])[
|
||||
/* User semantic actions sometimes alter yychar, and that requires
|
||||
@@ -1917,11 +1954,3 @@ yypushreturn:]])[
|
||||
}
|
||||
]b4_epilogue[]dnl
|
||||
b4_output_end
|
||||
|
||||
b4_defines_if([[
|
||||
]b4_output_begin([b4_spec_defines_file])[
|
||||
]b4_copyright([Bison interface for Yacc-like parsers in C])[
|
||||
]b4_disclaimer[
|
||||
]b4_shared_declarations[
|
||||
]b4_output_end[
|
||||
]])# b4_defines_if
|
||||
|
||||
+512
-285
File diff suppressed because it is too large
Load Diff
+18
-11
@@ -14,7 +14,12 @@
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AM_MAKEINFOFLAGS = --no-split
|
||||
AM_MAKEINFOFLAGS = \
|
||||
--no-split \
|
||||
--set-customization-variable=SECTION_NAME_IN_TITLE=true \
|
||||
--set-customization-variable=AVOID_MENU_REDUNDANCY=true \
|
||||
--set-customization-variable=ICONS=true
|
||||
|
||||
info_TEXINFOS = doc/bison.texi
|
||||
doc_bison_TEXINFOS = \
|
||||
$(CROSS_OPTIONS_TEXI) \
|
||||
@@ -28,7 +33,7 @@ doc_bison = doc/bison
|
||||
$(doc_bison).dvi: $(FIGS_GV:.gv=.eps)
|
||||
$(doc_bison).info: $(FIGS_GV:.gv=.txt)
|
||||
$(doc_bison).pdf: $(FIGS_GV:.gv=.pdf)
|
||||
$(doc_bison).html: $(FIGS_GV:.gv=.png)
|
||||
$(doc_bison).html: $(FIGS_GV:.gv=.svg)
|
||||
|
||||
TEXI2DVI = texi2dvi --build-dir=doc/bison.t2d -I doc
|
||||
CLEANDIRS += doc/bison.t2d
|
||||
@@ -88,11 +93,13 @@ EXTRA_DIST += $(top_srcdir)/doc/bison.help
|
||||
if ! CROSS_COMPILING
|
||||
MAINTAINERCLEANFILES += $(top_srcdir)/doc/bison.help
|
||||
$(top_srcdir)/doc/bison.help: src/bison$(EXEEXT)
|
||||
$(AM_V_GEN)LC_ALL=C src/bison$(EXEEXT) --version >doc/bison.help.tmp
|
||||
$(AM_V_at) LC_ALL=C src/bison$(EXEEXT) --help | \
|
||||
$(AM_V_GEN)LC_ALL=C tests/bison --version >doc/bison.help.tmp
|
||||
$(AM_V_at) LC_ALL=C tests/bison --help | \
|
||||
## Avoid depending on the path to Bison.
|
||||
sed -e 's,^Usage: .*/bison \[OPTION\],Usage: bison [OPTION],g' \
|
||||
## Avoid variations in the output depending on whether we are
|
||||
## on a glibc system.
|
||||
sed '/translation bugs/d' >>doc/bison.help.tmp
|
||||
-e '/translation bugs/d' >>doc/bison.help.tmp
|
||||
$(AM_V_at)$(top_srcdir)/build-aux/move-if-change doc/bison.help.tmp $@
|
||||
endif ! CROSS_COMPILING
|
||||
|
||||
@@ -118,7 +125,7 @@ endif
|
||||
$(top_srcdir)/doc/bison.1: $(MAN_DEPS)
|
||||
$(AM_V_GEN)$(HELP2MAN) \
|
||||
--include=$(top_srcdir)/doc/bison.x \
|
||||
--output=$@.tmp src/bison$(EXEEXT)
|
||||
--output=$@.tmp tests/bison
|
||||
$(AM_V_at)if $(remove_time_stamp) $@ >$@a.tmp 2>/dev/null && \
|
||||
$(remove_time_stamp) $@.tmp | cmp $@a.tmp - >/dev/null 2>&1; then \
|
||||
touch $@; \
|
||||
@@ -135,14 +142,14 @@ endif
|
||||
## Graphviz examples generation. ##
|
||||
## ----------------------------- ##
|
||||
|
||||
CLEANFILES += $(FIGS_GV:.gv=.eps) $(FIGS_GV:.gv=.pdf) $(FIGS_GV:.gv=.png)
|
||||
CLEANFILES += $(FIGS_GV:.gv=.eps) $(FIGS_GV:.gv=.pdf) $(FIGS_GV:.gv=.svg)
|
||||
FIGS_GV = \
|
||||
doc/figs/example.gv \
|
||||
doc/figs/example-reduce.gv doc/figs/example-shift.gv
|
||||
EXTRA_DIST += \
|
||||
$(FIGS_GV) $(FIGS_GV:.gv=.txt) \
|
||||
$(FIGS_GV:.gv=.eps) $(FIGS_GV:.gv=.pdf) $(FIGS_GV:.gv=.png)
|
||||
SUFFIXES += .gv .eps .pdf .png
|
||||
$(FIGS_GV:.gv=.eps) $(FIGS_GV:.gv=.pdf) $(FIGS_GV:.gv=.svg)
|
||||
SUFFIXES += .gv .eps .pdf .svg
|
||||
|
||||
.gv.eps:
|
||||
$(AM_V_GEN) $(MKDIR_P) `echo "./$@" | sed -e 's,/[^/]*$$,,'`
|
||||
@@ -154,9 +161,9 @@ SUFFIXES += .gv .eps .pdf .png
|
||||
$(AM_V_at) $(DOT) -Gmargin=0 -Tpdf $< >$@.tmp
|
||||
$(AM_V_at) mv $@.tmp $@
|
||||
|
||||
.gv.png:
|
||||
.gv.svg:
|
||||
$(AM_V_GEN) $(MKDIR_P) `echo "./$@" | sed -e 's,/[^/]*$$,,'`
|
||||
$(AM_V_at) $(DOT) -Gmargin=0 -Tpng $< >$@.tmp
|
||||
$(AM_V_at) $(DOT) -Gmargin=0 -Tsvg $< >$@.tmp
|
||||
$(AM_V_at) mv $@.tmp $@
|
||||
|
||||
## -------------- ##
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
## Parser generation. ##
|
||||
## ------------------- ##
|
||||
|
||||
# Don't depend on $(BISON) otherwise we would rebuild these files
|
||||
# in srcdir, including during distcheck, which is forbidden.
|
||||
%D%/parser.stamp: $(dependencies)
|
||||
SUFFIXES += .yy .stamp
|
||||
.yy.stamp:
|
||||
@@ -33,6 +31,7 @@ $(calcxx_sources_generated): %D%/parser.stamp
|
||||
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) %D%/parser.stamp
|
||||
CLEANFILES += \
|
||||
$(calcxx_sources_generated) \
|
||||
%D%/parser.dot \
|
||||
%D%/parser.output \
|
||||
%D%/parser.stamp \
|
||||
%D%/scanner.cc
|
||||
|
||||
@@ -68,4 +68,6 @@ endif
|
||||
EXTRA_DIST += %D%/variant-11.test
|
||||
|
||||
dist_cxx_DATA = %D%/README.md %D%/Makefile %D%/variant.yy %D%/variant-11.yy
|
||||
CLEANFILES += %D%/simple.output %D%/variant.output %D%/variant-11.output
|
||||
CLEANFILES += \
|
||||
%D%/simple.output %D%/variant.output %D%/variant-11.output \
|
||||
%D%/simple.hh %D%/variant.hh %D%/variant-11.hh
|
||||
|
||||
+27
-6
@@ -1,9 +1,11 @@
|
||||
This directory contains examples of Bison grammar files.
|
||||
# Examples in C
|
||||
|
||||
Most of them come from the documentation, which should be installed together
|
||||
This directory contains simple examples of Bison grammar files in C.
|
||||
|
||||
Some of them come from the documentation, which should be installed together
|
||||
with Bison. The URLs are provided for convenience.
|
||||
|
||||
# rpcalc - Reverse Polish Notation Calculator
|
||||
## rpcalc - Reverse Polish Notation Calculator
|
||||
The first example is that of a simple double-precision Reverse Polish
|
||||
Notation calculator (a calculator using postfix operators). This example
|
||||
provides a good starting point, since operator precedence is not an issue.
|
||||
@@ -11,12 +13,30 @@ provides a good starting point, since operator precedence is not an issue.
|
||||
Extracted from the documentation: "Reverse Polish Notation Calculator"
|
||||
https://www.gnu.org/software/bison/manual/html_node/RPN-Calc.html
|
||||
|
||||
# mfcalc - Multi-Function Calculator
|
||||
A more complete C example: a multi-function calculator.
|
||||
## calc - Simple Calculator
|
||||
This example is slightly more complex than rpcalc: it features infix
|
||||
operators (`1 + 2`, instead of `1 2 +` in rpcalc), but it does so using a
|
||||
unambiguous grammar of the arithmetic instead of using precedence
|
||||
directives (%left, etc.).
|
||||
|
||||
## mfcalc - Multi-Function Calculator
|
||||
A more complete C example: a multi-function calculator. More complex than
|
||||
the previous example. Using precedence directives to support infix
|
||||
operators.
|
||||
|
||||
Extracted from the documentation: "Multi-Function Calculator: mfcalc".
|
||||
https://www.gnu.org/software/bison/manual/html_node/Multi_002dfunction-Calc.html
|
||||
|
||||
## lexcalc - calculator with Flex and Bison
|
||||
The calculator, redux. This time using a scanner generated by Flex.
|
||||
|
||||
## reccalc - recursive calculator with Flex and Bison
|
||||
The example builds on top of the previous one to provide a reentrant parser.
|
||||
Such parsers can be called concurrently in different threads, or even
|
||||
recursively. To demonstrate this feature, expressions in parentheses are
|
||||
tokenized as strings, and then recursively parsed from the parser. So
|
||||
`(((1)+(2))*((3)+(4)))` uses eight parsers, with a depth of four.
|
||||
|
||||
|
||||
<!---
|
||||
|
||||
@@ -34,5 +54,6 @@ Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
|
||||
Texts. A copy of the license is included in the "GNU Free
|
||||
Documentation License" file as part of this distribution.
|
||||
|
||||
# LocalWords: mfcalc calc parsers yy
|
||||
# LocalWords: mfcalc calc parsers yy rpcalc lexcalc redux reccalc ispell
|
||||
# LocalWords: reentrant tokenized american postfix
|
||||
--->
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# This Makefile is designed to be simple and readable. It does not
|
||||
# aim at portability. It requires GNU Make.
|
||||
|
||||
BASE = calc
|
||||
BISON = bison
|
||||
XSLTPROC = xsltproc
|
||||
|
||||
all: $(BASE)
|
||||
|
||||
%.c %.h %.xml %.gv: %.y
|
||||
$(BISON) $(BISONFLAGS) --defines --xml --graph=$*.gv -o $*.c $<
|
||||
|
||||
$(BASE): $(BASE).o
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
run: $(BASE)
|
||||
@echo "Type arithmetic expressions. Quit with ctrl-d."
|
||||
./$<
|
||||
|
||||
html: $(BASE).html
|
||||
%.html: %.xml
|
||||
$(XSLTPROC) $(XSLTPROCFLAGS) -o $@ $$($(BISON) --print-datadir)/xslt/xml2xhtml.xsl $<
|
||||
|
||||
CLEANFILES = \
|
||||
$(BASE) *.o $(BASE).[ch] $(BASE).output $(BASE).xml $(BASE).html $(BASE).gv
|
||||
|
||||
clean:
|
||||
rm -f $(CLEANFILES)
|
||||
@@ -0,0 +1,28 @@
|
||||
# calc - calculator with Bison
|
||||
|
||||
This directory contains calc, the traditional example of using Bison to
|
||||
build a simple calculator.
|
||||
|
||||
<!---
|
||||
Local Variables:
|
||||
fill-column: 76
|
||||
ispell-dictionary: "american"
|
||||
End:
|
||||
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of Bison, the GNU Compiler Compiler.
|
||||
|
||||
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/>.
|
||||
--->
|
||||
@@ -0,0 +1,37 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2019 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/>.
|
||||
|
||||
cat >input <<EOF
|
||||
1+2*3
|
||||
EOF
|
||||
run 0 7
|
||||
|
||||
cat >input <<EOF
|
||||
1 - 2 - 3
|
||||
EOF
|
||||
run 0 -4
|
||||
|
||||
cat >input <<EOF
|
||||
8 / 2 / 2
|
||||
EOF
|
||||
run 0 2
|
||||
|
||||
cat >input <<EOF
|
||||
(1+2) * 3
|
||||
EOF
|
||||
run 0 9
|
||||
run -noerr 0 9 -p
|
||||
@@ -0,0 +1,93 @@
|
||||
%code top {
|
||||
#include <ctype.h> /* isdigit. */
|
||||
#include <stdio.h> /* For printf, etc. */
|
||||
#include <string.h> /* strcmp. */
|
||||
|
||||
int yylex (void);
|
||||
void yyerror (char const *);
|
||||
}
|
||||
|
||||
%define api.header.include {"calc.h"}
|
||||
%define api.value.type union /* Generate YYSTYPE from these types: */
|
||||
%token <double> NUM "number"
|
||||
%type <double> expr term fact
|
||||
|
||||
/* Generate the parser description file. */
|
||||
%verbose
|
||||
/* Enable run-time traces (yydebug). */
|
||||
%define parse.trace
|
||||
|
||||
/* Formatting semantic values. */
|
||||
%printer { fprintf (yyo, "%g", $$); } <double>;
|
||||
|
||||
%% /* The grammar follows. */
|
||||
input:
|
||||
%empty
|
||||
| input line
|
||||
;
|
||||
|
||||
line:
|
||||
'\n'
|
||||
| expr '\n' { printf ("%.10g\n", $1); }
|
||||
| error '\n' { yyerrok; }
|
||||
;
|
||||
|
||||
expr:
|
||||
expr '+' term { $$ = $1 + $3; }
|
||||
| expr '-' term { $$ = $1 - $3; }
|
||||
| term
|
||||
;
|
||||
|
||||
term:
|
||||
term '*' fact { $$ = $1 * $3; }
|
||||
| term '/' fact { $$ = $1 / $3; }
|
||||
| fact
|
||||
;
|
||||
|
||||
fact:
|
||||
"number"
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
int
|
||||
yylex (void)
|
||||
{
|
||||
int c;
|
||||
|
||||
/* Ignore white space, get first nonwhite character. */
|
||||
while ((c = getchar ()) == ' ' || c == '\t')
|
||||
continue;
|
||||
|
||||
if (c == EOF)
|
||||
return 0;
|
||||
|
||||
/* Char starts a number => parse the number. */
|
||||
if (c == '.' || isdigit (c))
|
||||
{
|
||||
ungetc (c, stdin);
|
||||
scanf ("%lf", &yylval.NUM);
|
||||
return NUM;
|
||||
}
|
||||
|
||||
/* Any other character is a token by itself. */
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Called by yyparse on error. */
|
||||
void
|
||||
yyerror (char const *s)
|
||||
{
|
||||
fprintf (stderr, "%s\n", s);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char const* argv[])
|
||||
{
|
||||
/* Enable parse traces on option -p. */
|
||||
for (int i = 1; i < argc; ++i)
|
||||
if (!strcmp (argv[i], "-p"))
|
||||
yydebug = 1;
|
||||
return yyparse ();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
## Copyright (C) 2019 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/>.
|
||||
|
||||
calcdir = $(docdir)/%D%
|
||||
|
||||
## ------ ##
|
||||
## Calc. ##
|
||||
## ------ ##
|
||||
|
||||
check_PROGRAMS += %D%/calc
|
||||
TESTS += %D%/calc.test
|
||||
EXTRA_DIST += %D%/calc.test
|
||||
nodist_%C%_calc_SOURCES = %D%/calc.y
|
||||
%D%/calc.c: $(dependencies)
|
||||
|
||||
# Don't use gnulib's system headers.
|
||||
%C%_calc_CPPFLAGS = -I$(top_srcdir)/%D% -I$(top_builddir)/%D%
|
||||
|
||||
dist_calc_DATA = %D%/calc.y %D%/Makefile %D%/README.md
|
||||
CLEANFILES += %D%/calc.[ch] %D%/calc.output %D%/scan.c
|
||||
CLEANDIRS += %D%/*.dSYM
|
||||
@@ -15,7 +15,7 @@ all: $(BASE)
|
||||
$(FLEX) $(FLEXFLAGS) -o$@ $<
|
||||
|
||||
scan.o: parse.h
|
||||
lexcalc: parse.o scan.o
|
||||
$(BASE): parse.o scan.o
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
run: $(BASE)
|
||||
|
||||
@@ -25,3 +25,8 @@ cat >input <<EOF
|
||||
EOF
|
||||
run 0 9
|
||||
run -noerr 0 9 -p
|
||||
|
||||
cat >input <<EOF
|
||||
(1+2) *
|
||||
EOF
|
||||
run 1 'err: syntax error, unexpected end-of-line, expecting ( or number'
|
||||
|
||||
@@ -22,11 +22,12 @@ lexcalcdir = $(docdir)/%D%
|
||||
check_PROGRAMS += %D%/lexcalc
|
||||
TESTS += %D%/lexcalc.test
|
||||
EXTRA_DIST += %D%/lexcalc.test
|
||||
%C%_lexcalc_SOURCES = %D%/parse.y %D%/parse.h %D%/scan.l
|
||||
nodist_%C%_lexcalc_SOURCES = %D%/parse.y %D%/parse.h %D%/scan.l
|
||||
%D%/parse.c: $(dependencies)
|
||||
|
||||
# Don't use gnulib's system headers.
|
||||
%C%_lexcalc_CPPFLAGS = -I$(top_srcdir)/%D% -I$(top_builddir)/%D%
|
||||
|
||||
dist_lexcalc_DATA = %D%/parse.y %D%/scan.l %D%/Makefile %D%/README.md
|
||||
CLEANFILES += %D%/lexcalc %D%/*.o %D%/parse.c %D%/scan.c
|
||||
CLEANFILES += %D%/parse.[ch] %D%/scan.c %D%/parse.output
|
||||
CLEANDIRS += %D%/*.dSYM
|
||||
|
||||
+11
-11
@@ -15,8 +15,8 @@
|
||||
// Emitted on top of the implementation file.
|
||||
%code top
|
||||
{
|
||||
#include <stdio.h> /* printf. */
|
||||
#include <stdlib.h> /* getenv. */
|
||||
#include <stdio.h> // printf.
|
||||
#include <stdlib.h> // getenv.
|
||||
}
|
||||
|
||||
%define api.pure full
|
||||
@@ -39,7 +39,7 @@
|
||||
;
|
||||
|
||||
%token <int> NUM "number"
|
||||
%type <int> exp line
|
||||
%type <int> exp
|
||||
%printer { fprintf (yyo, "%d", $$); } <int>
|
||||
|
||||
// Precedence (from lowest to highest) and associativity.
|
||||
@@ -50,18 +50,18 @@
|
||||
// Rules.
|
||||
input:
|
||||
%empty
|
||||
| input line { printf ("%d\n", $line); }
|
||||
| input line
|
||||
;
|
||||
|
||||
line:
|
||||
exp EOL { $$ = $1; }
|
||||
exp EOL { printf ("%d\n", $exp); }
|
||||
| error EOL { yyerrok; }
|
||||
;
|
||||
|
||||
exp:
|
||||
exp "+" exp { $$ = $1 + $3; }
|
||||
| exp "-" exp { $$ = $1 - $3; }
|
||||
| exp "*" exp { $$ = $1 * $3; }
|
||||
exp "+" exp { $$ = $1 + $3; }
|
||||
| exp "-" exp { $$ = $1 - $3; }
|
||||
| exp "*" exp { $$ = $1 * $3; }
|
||||
| exp "/" exp
|
||||
{
|
||||
if ($3 == 0)
|
||||
@@ -72,15 +72,15 @@ exp:
|
||||
else
|
||||
$$ = $1 / $3;
|
||||
}
|
||||
| "(" exp ")" { $$ = $2; }
|
||||
| "(" exp ")" { $$ = $2; }
|
||||
| NUM { $$ = $1; }
|
||||
;
|
||||
%%
|
||||
// Epilogue (C code).
|
||||
void yyerror(int *nerrs, const char *msg)
|
||||
void yyerror (int *nerrs, const char *msg)
|
||||
{
|
||||
fprintf (stderr, "%s\n", msg);
|
||||
++nerrs;
|
||||
++*nerrs;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
cdir = $(docdir)/%D%
|
||||
dist_c_DATA = %D%/README.md
|
||||
|
||||
include %D%/calc/local.mk
|
||||
include %D%/lexcalc/local.mk
|
||||
include %D%/mfcalc/local.mk
|
||||
include %D%/reccalc/local.mk
|
||||
include %D%/rpcalc/local.mk
|
||||
|
||||
@@ -28,6 +28,7 @@ extracted += $(mfcalc_extracted)
|
||||
|
||||
check_PROGRAMS += %D%/mfcalc
|
||||
nodist_%C%_mfcalc_SOURCES = $(mfcalc_sources)
|
||||
%D%/mfcalc.c: $(dependencies)
|
||||
# Don't use gnulib's system headers.
|
||||
%C%_mfcalc_CPPFLAGS = -I$(top_srcdir)/%D% -I$(top_builddir)/%D%
|
||||
%C%_mfcalc_LDADD = -lm
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# This Makefile is designed to be simple and readable. It does not
|
||||
# aim at portability. It requires GNU Make.
|
||||
|
||||
BASE = reccalc
|
||||
BISON = bison
|
||||
FLEX = flex
|
||||
XSLTPROC = xsltproc
|
||||
|
||||
all: $(BASE)
|
||||
|
||||
%.c %.h %.xml %.gv: %.y
|
||||
$(BISON) $(BISONFLAGS) --defines --xml --graph=$*.gv -o $*.c $<
|
||||
|
||||
%.c %.h: %.l
|
||||
$(FLEX) $(FLEXFLAGS) -o$*.c --header-file=$*.h $<
|
||||
|
||||
scan.o: parse.h
|
||||
parse.o: scan.h
|
||||
$(BASE): parse.o scan.o
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
run: $(BASE)
|
||||
@echo "Type arithmetic expressions. Quit with ctrl-d."
|
||||
./$<
|
||||
|
||||
html: parse.html
|
||||
%.html: %.xml
|
||||
$(XSLTPROC) $(XSLTPROCFLAGS) -o $@ $$($(BISON) --print-datadir)/xslt/xml2xhtml.xsl $<
|
||||
|
||||
CLEANFILES = \
|
||||
$(BASE) *.o \
|
||||
parse.[ch] parse.output parse.xml parse.html parse.gv \
|
||||
scan.[ch]
|
||||
clean:
|
||||
rm -f $(CLEANFILES)
|
||||
@@ -0,0 +1,45 @@
|
||||
# reccalc - recursive calculator with Flex and Bison
|
||||
|
||||
In this example the generated parser is pure and reentrant: it can be used
|
||||
concurrently in different threads, or recursively. As a proof of this
|
||||
reentrancy, expressions in parenthesis are tokenized as strings, and then
|
||||
recursively parsed from the parser:
|
||||
|
||||
```
|
||||
exp: STR
|
||||
{
|
||||
result r = parse_string ($1);
|
||||
free ($1);
|
||||
if (r.nerrs)
|
||||
{
|
||||
res->nerrs += r.nerrs;
|
||||
YYERROR;
|
||||
}
|
||||
else
|
||||
$$ = r.value;
|
||||
}
|
||||
```
|
||||
|
||||
<!---
|
||||
Local Variables:
|
||||
fill-column: 76
|
||||
ispell-dictionary: "american"
|
||||
End:
|
||||
|
||||
Copyright (C) 2018-2019 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of Bison, the GNU Compiler Compiler.
|
||||
|
||||
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/>.
|
||||
--->
|
||||
@@ -0,0 +1,52 @@
|
||||
## Copyright (C) 2019 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/>.
|
||||
|
||||
reccalcdir = $(docdir)/%D%
|
||||
|
||||
## ------ ##
|
||||
## Calc. ##
|
||||
## ------ ##
|
||||
|
||||
check_PROGRAMS += %D%/reccalc
|
||||
TESTS += %D%/reccalc.test
|
||||
EXTRA_DIST += %D%/reccalc.test %D%/scan.l
|
||||
nodist_%C%_reccalc_SOURCES = %D%/parse.y %D%/scan.h %D%/scan.c
|
||||
BUILT_SOURCES += $(nodist_%C%_reccalc_SOURCES)
|
||||
%D%/parse.c: $(dependencies)
|
||||
|
||||
# Tell Make that parse.o depends on scan.h, so that scan.h is built
|
||||
# before parse.o. Obfuscate the name of the target, otherwise
|
||||
# Automake removes its recipe for parse.o and leaves only our
|
||||
# additional dependency.
|
||||
DASH = -
|
||||
%D%/reccalc$(DASH)parse.o: %D%/scan.h
|
||||
|
||||
%D%/scan.c %D%/scan.h: %D%/scan.stamp
|
||||
@test -f $@ || rm -f %D%/scan.stamp
|
||||
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) %D%/scan.stamp
|
||||
|
||||
%D%/scan.stamp: %D%/scan.l
|
||||
$(AM_V_LEX)rm -f $@ $@.tmp
|
||||
$(AM_V_at)$(MKDIR_P) %D%
|
||||
$(AM_V_at)touch $@.tmp
|
||||
$(AM_V_at) $(LEX) -o %D%/scan.c --header-file=%D%/scan.h $<
|
||||
$(AM_V_at)mv $@.tmp $@
|
||||
|
||||
# Don't use gnulib's system headers.
|
||||
%C%_reccalc_CPPFLAGS = -I$(top_srcdir)/%D% -I$(top_builddir)/%D%
|
||||
|
||||
dist_reccalc_DATA = %D%/parse.y %D%/scan.l %D%/Makefile %D%/README.md
|
||||
CLEANFILES += %D%/parse.[ch] %D%/parse.output %D%/scan.[ch] %D%/*.stamp
|
||||
CLEANDIRS += %D%/*.dSYM
|
||||
@@ -0,0 +1,183 @@
|
||||
// Prologue (directives).
|
||||
%expect 0
|
||||
|
||||
// Emitted in the header file, before the definition of YYSTYPE.
|
||||
%code requires
|
||||
{
|
||||
typedef void* yyscan_t;
|
||||
typedef struct
|
||||
{
|
||||
// Whether to print the intermediate results.
|
||||
int verbose;
|
||||
// Value of the last computation.
|
||||
int value;
|
||||
// Number of errors.
|
||||
int nerrs;
|
||||
} result;
|
||||
}
|
||||
|
||||
// Emitted in the header file, after the definition of YYSTYPE.
|
||||
%code provides
|
||||
{
|
||||
// Tell Flex the expected prototype of yylex.
|
||||
// The scanner argument must be named yyscanner.
|
||||
#define YY_DECL \
|
||||
enum yytokentype yylex (YYSTYPE* yylval, yyscan_t yyscanner, result *res)
|
||||
YY_DECL;
|
||||
|
||||
void yyerror (yyscan_t scanner, result *res, const char *msg, ...);
|
||||
}
|
||||
|
||||
// Emitted on top of the implementation file.
|
||||
%code top
|
||||
{
|
||||
#include <stdarg.h> // va_list.
|
||||
#include <stdio.h> // printf.
|
||||
#include <stdlib.h> // getenv.
|
||||
}
|
||||
|
||||
%code
|
||||
{
|
||||
result parse_string (const char* cp);
|
||||
result parse (void);
|
||||
}
|
||||
|
||||
%define api.pure full
|
||||
%define api.token.prefix {TOK_}
|
||||
%define api.value.type union
|
||||
%define parse.error verbose
|
||||
%define parse.trace
|
||||
%verbose
|
||||
|
||||
// Scanner and error count are exchanged between main, yyparse and yylex.
|
||||
%param {yyscan_t scanner}{result *res}
|
||||
|
||||
%token
|
||||
PLUS "+"
|
||||
MINUS "-"
|
||||
STAR "*"
|
||||
SLASH "/"
|
||||
EOL "end-of-line"
|
||||
EOF 0 "end-of-file"
|
||||
;
|
||||
|
||||
%token <int> NUM "number"
|
||||
%type <int> exp
|
||||
%printer { fprintf (yyo, "%d", $$); } <int>
|
||||
|
||||
%token <char*> STR "string"
|
||||
%printer { fprintf (yyo, "\"%s\"", $$); } <char*>
|
||||
%destructor { free ($$); } <char*>
|
||||
|
||||
// Precedence (from lowest to highest) and associativity.
|
||||
%left "+" "-"
|
||||
%left "*" "/"
|
||||
%precedence UNARY
|
||||
|
||||
%%
|
||||
// Rules.
|
||||
input:
|
||||
line
|
||||
| input line
|
||||
;
|
||||
|
||||
line:
|
||||
exp eol
|
||||
{
|
||||
res->value = $exp;
|
||||
if (res->verbose)
|
||||
printf ("%d\n", $exp);
|
||||
}
|
||||
| error eol
|
||||
{
|
||||
yyerrok;
|
||||
}
|
||||
;
|
||||
|
||||
eol:
|
||||
EOF
|
||||
| EOL
|
||||
;
|
||||
|
||||
exp:
|
||||
NUM { $$ = $1; }
|
||||
| exp "+" exp { $$ = $1 + $3; }
|
||||
| exp "-" exp { $$ = $1 - $3; }
|
||||
| exp "*" exp { $$ = $1 * $3; }
|
||||
| exp "/" exp
|
||||
{
|
||||
if ($3 == 0)
|
||||
{
|
||||
yyerror (scanner, res, "invalid division by zero");
|
||||
YYERROR;
|
||||
}
|
||||
else
|
||||
$$ = $1 / $3;
|
||||
}
|
||||
| "+" exp %prec UNARY { $$ = + $2; }
|
||||
| "-" exp %prec UNARY { $$ = - $2; }
|
||||
| STR
|
||||
{
|
||||
result r = parse_string ($1);
|
||||
free ($1);
|
||||
if (r.nerrs)
|
||||
{
|
||||
res->nerrs += r.nerrs;
|
||||
YYERROR;
|
||||
}
|
||||
else
|
||||
$$ = r.value;
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
// Epilogue (C code).
|
||||
|
||||
#include "scan.h"
|
||||
|
||||
result
|
||||
parse (void)
|
||||
{
|
||||
yyscan_t scanner;
|
||||
yylex_init (&scanner);
|
||||
result res = {1, 0, 0};
|
||||
yyparse (scanner, &res);
|
||||
yylex_destroy (scanner);
|
||||
return res;
|
||||
}
|
||||
|
||||
result
|
||||
parse_string (const char *str)
|
||||
{
|
||||
yyscan_t scanner;
|
||||
yylex_init (&scanner);
|
||||
YY_BUFFER_STATE buf = yy_scan_string (str ? str : "", scanner);
|
||||
result res = {0, 0, 0};
|
||||
yyparse (scanner, &res);
|
||||
yy_delete_buffer (buf, scanner);
|
||||
yylex_destroy (scanner);
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
yyerror (yyscan_t scanner, result *res,
|
||||
const char *msg, ...)
|
||||
{
|
||||
(void) scanner;
|
||||
va_list args;
|
||||
va_start (args, msg);
|
||||
vfprintf (stderr, msg, args);
|
||||
va_end (args);
|
||||
fputc ('\n', stderr);
|
||||
res->nerrs += 1;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
// Possibly enable parser runtime debugging.
|
||||
yydebug = !!getenv ("YYDEBUG");
|
||||
result res = parse ();
|
||||
// Exit on failure if there were errors.
|
||||
return !!res.nerrs;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2018-2019 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/>.
|
||||
|
||||
cat >input <<EOF
|
||||
1+2*3
|
||||
EOF
|
||||
run 0 '7'
|
||||
|
||||
cat >input <<EOF
|
||||
(1+2) * 3
|
||||
EOF
|
||||
run 0 '9'
|
||||
run -noerr 0 '9' -p
|
||||
|
||||
cat >input <<EOF
|
||||
(((1)+(2))*((3)+(4)))
|
||||
EOF
|
||||
run 0 '21'
|
||||
|
||||
# Some really deep computation.
|
||||
# for 4, gives 4 + (3 + (2 + (1 + (- (4 * (4 + 1)) / 2)))).
|
||||
n=100
|
||||
for i in $(seq 0 $n)
|
||||
do
|
||||
if [ "$i" -eq 0 ]; then
|
||||
input="- ($n * ($n + 1)) / 2"
|
||||
else
|
||||
input="$i + ($input)"
|
||||
fi
|
||||
done
|
||||
echo "$input" > input
|
||||
run 0 '0'
|
||||
|
||||
cat >input <<EOF
|
||||
() + ()
|
||||
EOF
|
||||
run 1 'err: syntax error, unexpected end-of-file, expecting + or - or number or string'
|
||||
|
||||
cat >input <<EOF
|
||||
1 + $
|
||||
EOF
|
||||
run 1 'err: syntax error, invalid character: $
|
||||
err: syntax error, unexpected end-of-line, expecting + or - or number or string'
|
||||
@@ -0,0 +1,85 @@
|
||||
/* Prologue (directives). -*- C++ -*- */
|
||||
|
||||
/* Disable Flex features we don't need, to avoid warnings. */
|
||||
%option nodefault noinput nounput noyywrap
|
||||
|
||||
%option reentrant
|
||||
|
||||
%{
|
||||
#include <assert.h>
|
||||
#include <limits.h> /* INT_MIN */
|
||||
#include <stdlib.h> /* strtol */
|
||||
|
||||
#include "parse.h"
|
||||
%}
|
||||
|
||||
%x SC_STRING
|
||||
|
||||
%%
|
||||
%{
|
||||
int nesting = 0;
|
||||
char *str = NULL;
|
||||
int size = 0;
|
||||
int capacity = 0;
|
||||
#define STR_APPEND() \
|
||||
do { \
|
||||
if (capacity < size + yyleng + 1) \
|
||||
{ \
|
||||
do \
|
||||
capacity = capacity ? 2 * capacity : 128; \
|
||||
while (capacity < size + yyleng + 1); \
|
||||
str = realloc (str, capacity); \
|
||||
} \
|
||||
memcpy (str + size, yytext, yyleng); \
|
||||
size += yyleng; \
|
||||
assert (size < capacity); \
|
||||
} while (0)
|
||||
%}
|
||||
|
||||
// Rules.
|
||||
|
||||
"+" return TOK_PLUS;
|
||||
"-" return TOK_MINUS;
|
||||
"*" return TOK_STAR;
|
||||
"/" return TOK_SLASH;
|
||||
|
||||
"(" nesting += 1; BEGIN SC_STRING;
|
||||
|
||||
/* Scan an integer. */
|
||||
[0-9]+ {
|
||||
errno = 0;
|
||||
long n = strtol (yytext, NULL, 10);
|
||||
if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
|
||||
yyerror (yyscanner, res, "integer is out of range");
|
||||
yylval->TOK_NUM = (int) n;
|
||||
return TOK_NUM;
|
||||
}
|
||||
|
||||
/* Ignore white spaces. */
|
||||
[ \t]+ continue;
|
||||
|
||||
"\n" return TOK_EOL;
|
||||
|
||||
. yyerror (yyscanner, res, "syntax error, invalid character: %c", yytext[0]);
|
||||
|
||||
<SC_STRING>
|
||||
{
|
||||
"("+ nesting += yyleng; STR_APPEND ();
|
||||
")" {
|
||||
if (!--nesting)
|
||||
{
|
||||
BEGIN INITIAL;
|
||||
if (str)
|
||||
str[size] = 0;
|
||||
yylval->TOK_STR = str;
|
||||
return TOK_STR;
|
||||
}
|
||||
else
|
||||
STR_APPEND ();
|
||||
}
|
||||
[^()]+ STR_APPEND ();
|
||||
}
|
||||
|
||||
<<EOF>> return TOK_EOF;
|
||||
%%
|
||||
/* Epilogue (C code). */
|
||||
@@ -28,6 +28,7 @@ extracted += $(rpcalc_extracted)
|
||||
|
||||
check_PROGRAMS += %D%/rpcalc
|
||||
nodist_%C%_rpcalc_SOURCES = $(rpcalc_sources)
|
||||
%D%/rpcalc.c: $(dependencies)
|
||||
# Don't use gnulib's system headers.
|
||||
%C%_rpcalc_CPPFLAGS = -I$(top_builddir)/%D%
|
||||
%C%_rpcalc_LDADD = -lm
|
||||
|
||||
@@ -23,4 +23,4 @@ run 0 7
|
||||
cat >input <<EOF
|
||||
1 + 2 * * 3
|
||||
EOF
|
||||
run 0 "err: syntax error, unexpected *, expecting - or ! or ( or number"
|
||||
run 1 "err: syntax error, unexpected *, expecting + or - or ( or number"
|
||||
|
||||
+61
-73
@@ -18,17 +18,15 @@
|
||||
MINUS "-"
|
||||
STAR "*"
|
||||
SLASH "/"
|
||||
BANG "!"
|
||||
LPAR "("
|
||||
RPAR ")"
|
||||
EOL "end of line"
|
||||
%token <ival> NUM "number"
|
||||
%type <ival> exp
|
||||
|
||||
%nonassoc "=" /* comparison */
|
||||
%left "-" "+"
|
||||
%left "*" "/"
|
||||
%precedence NEG /* negation--unary minus */
|
||||
%precedence UNARY /* unary operators */
|
||||
|
||||
/* Grammar follows */
|
||||
%%
|
||||
@@ -44,96 +42,86 @@ line:
|
||||
;
|
||||
|
||||
exp:
|
||||
NUM { $$ = $1; }
|
||||
| exp "=" exp
|
||||
{
|
||||
if ($1 != $3)
|
||||
yyerror (format ("calc: error: %d != %d", $1, $3));
|
||||
}
|
||||
| exp "+" exp { $$ = $1 + $3; }
|
||||
| exp "-" exp { $$ = $1 - $3; }
|
||||
| exp "*" exp { $$ = $1 * $3; }
|
||||
| exp "/" exp { $$ = $1 / $3; }
|
||||
| "-" exp %prec NEG { $$ = -$2; }
|
||||
| "(" exp ")" { $$ = $2; }
|
||||
| "(" error ")" { $$ = 1111; }
|
||||
| "!" { $$ = 0; return YYERROR; }
|
||||
| "-" error { $$ = 0; return YYERROR; }
|
||||
NUM { $$ = $1; }
|
||||
| exp "+" exp { $$ = $1 + $3; }
|
||||
| exp "-" exp { $$ = $1 - $3; }
|
||||
| exp "*" exp { $$ = $1 * $3; }
|
||||
| exp "/" exp { $$ = $1 / $3; }
|
||||
| "+" exp %prec UNARY { $$ = -$2; }
|
||||
| "-" exp %prec UNARY { $$ = -$2; }
|
||||
| "(" exp ")" { $$ = $2; }
|
||||
;
|
||||
|
||||
|
||||
%%
|
||||
class CalcLexer : Lexer {
|
||||
import std.range.primitives;
|
||||
import std.stdio;
|
||||
|
||||
this ()
|
||||
{}
|
||||
auto calcLexer(R)(R range)
|
||||
if (isInputRange!R && is (ElementType!R : dchar))
|
||||
{
|
||||
return new CalcLexer!R(range);
|
||||
}
|
||||
|
||||
int
|
||||
get_char ()
|
||||
{
|
||||
import stdc = core.stdc.stdio;
|
||||
return stdc.getc (stdc.stdin);
|
||||
}
|
||||
auto calcLexer (File f)
|
||||
{
|
||||
import std.algorithm : map, joiner;
|
||||
import std.utf : byDchar;
|
||||
|
||||
void
|
||||
unget_char (int c)
|
||||
{
|
||||
import stdc = core.stdc.stdio;
|
||||
stdc.ungetc (c, stdc.stdin);
|
||||
}
|
||||
return f.byChunk(1024) // avoid making a syscall roundtrip per char
|
||||
.map!(chunk => cast(char[]) chunk) // because byChunk returns ubyte[]
|
||||
.joiner // combine chunks into a single virtual range of char
|
||||
.calcLexer; // forward to other overload
|
||||
}
|
||||
|
||||
class CalcLexer(R) : Lexer
|
||||
if (isInputRange!R && is (ElementType!R : dchar))
|
||||
{
|
||||
R input;
|
||||
|
||||
this(R r) { input = r; }
|
||||
|
||||
// Should be a local in main, shared with %parse-param.
|
||||
int exit_status = 0;
|
||||
|
||||
public void yyerror (string s)
|
||||
{
|
||||
exit_status = 1;
|
||||
stderr.writeln (s);
|
||||
}
|
||||
|
||||
int
|
||||
read_signed_integer ()
|
||||
{
|
||||
int c = get_char ();
|
||||
int sign = 1;
|
||||
int n = 0;
|
||||
|
||||
if (c == '-')
|
||||
{
|
||||
c = get_char ();
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
while (isDigit (c))
|
||||
{
|
||||
n = 10 * n + (c - '0');
|
||||
c = get_char ();
|
||||
}
|
||||
|
||||
unget_char (c);
|
||||
return sign * n;
|
||||
}
|
||||
|
||||
YYSemanticType semanticVal_;
|
||||
|
||||
public final @property YYSemanticType semanticVal()
|
||||
public final @property YYSemanticType semanticVal ()
|
||||
{
|
||||
return semanticVal_;
|
||||
}
|
||||
|
||||
YYTokenType yylex ()
|
||||
int yylex ()
|
||||
{
|
||||
int c;
|
||||
/* Skip white spaces. */
|
||||
do
|
||||
{}
|
||||
while ((c = get_char ()) == ' ' || c == '\t');
|
||||
import std.uni : isWhite, isNumber;
|
||||
|
||||
/* process numbers */
|
||||
if (c == '.' || isDigit (c))
|
||||
// Skip initial spaces
|
||||
while (!input.empty && input.front != '\n' && isWhite (input.front))
|
||||
{
|
||||
input.popFront;
|
||||
}
|
||||
|
||||
// Handle EOF.
|
||||
if (input.empty)
|
||||
return YYTokenType.EOF;
|
||||
|
||||
// Numbers.
|
||||
if (input.front == '.' || input.front.isNumber)
|
||||
{
|
||||
unget_char (c);
|
||||
semanticVal_.ival = read_signed_integer ();
|
||||
import std.conv : parse;
|
||||
semanticVal_.ival = input.parse!int;
|
||||
return YYTokenType.NUM;
|
||||
}
|
||||
|
||||
switch (c)
|
||||
// Individual characters
|
||||
auto ch = input.front;
|
||||
input.popFront;
|
||||
switch (ch)
|
||||
{
|
||||
case EOF: return YYTokenType.EOF;
|
||||
case '=': return YYTokenType.EQ;
|
||||
@@ -141,7 +129,6 @@ class CalcLexer : Lexer {
|
||||
case '-': return YYTokenType.MINUS;
|
||||
case '*': return YYTokenType.STAR;
|
||||
case '/': return YYTokenType.SLASH;
|
||||
case '!': return YYTokenType.BANG;
|
||||
case '(': return YYTokenType.LPAR;
|
||||
case ')': return YYTokenType.RPAR;
|
||||
case '\n': return YYTokenType.EOL;
|
||||
@@ -150,9 +137,10 @@ class CalcLexer : Lexer {
|
||||
}
|
||||
}
|
||||
|
||||
void main ()
|
||||
int main ()
|
||||
{
|
||||
CalcLexer l = new CalcLexer ();
|
||||
Calc p = new Calc (l);
|
||||
auto l = calcLexer (stdin);
|
||||
auto p = new Calc (l);
|
||||
p.parse ();
|
||||
return l.exit_status;
|
||||
}
|
||||
|
||||
+5
-1
@@ -60,7 +60,11 @@ sub normalize($)
|
||||
{
|
||||
local ($_) = @_;
|
||||
|
||||
s/^\@(c |comment|dots|end (ignore|group)|ignore|group).*\n//mg;
|
||||
# If we just remove this lines, then the compiler's tracking of
|
||||
# #lines is broken. Leave lines that that accepted by all our tools
|
||||
# (including flex, hence the leading space), and that will be easy
|
||||
# to remove (see the Make examples-unline recipe).
|
||||
s{^\@(c |comment|dots|end (ignore|group)|ignore|group).*}{ /**/}mg;
|
||||
s/\@value\{VERSION\}/$ENV{VERSION}/g;
|
||||
s/^\@(error|result)\{\}//mg;
|
||||
s/\@([{}@])/$1/g;
|
||||
|
||||
+20
-6
@@ -14,6 +14,24 @@
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
## Because some of our examples use
|
||||
##
|
||||
## %C%_reccalc_SOURCES = %D%/parse.y
|
||||
##
|
||||
## Automake ships parse.y and parse.c, and possibly parse.h when it
|
||||
## "understands" that there is one. This is not what we want: ship only
|
||||
## parser.y. Yet we still want to use Automake to compile the sources
|
||||
## from parser.y. The easiest seems to use
|
||||
##
|
||||
## nodist_%C%_reccalc_SOURCES = %D%/parse.y
|
||||
##
|
||||
## together with
|
||||
##
|
||||
## dist_reccalc_DATA = %D%/parse.y %D%/scan.l %D%/Makefile %D%/README.md
|
||||
##
|
||||
## which guarantees that parse.y is indeed shipped.
|
||||
|
||||
dist_noinst_SCRIPTS = %D%/extexi %D%/test
|
||||
TEST_LOG_COMPILER = $(top_srcdir)/%D%/test
|
||||
|
||||
@@ -59,12 +77,8 @@ EXTRA_DIST += %D%/extracted.stamp
|
||||
dist-hook: examples-unline
|
||||
.PHONY: examples-unline
|
||||
examples-unline:
|
||||
for e in $(extracted); \
|
||||
do \
|
||||
e=$(distdir)/$$e; \
|
||||
sed -e '/#line/d' $$e >$$e.tmp; \
|
||||
mv -f $$e.tmp $$e; \
|
||||
done
|
||||
cd $(distdir) && \
|
||||
perl -pi -0777 -e 's/#line.*\n//g;s{^ /\*\*/\n}{}mg' $(extracted)
|
||||
|
||||
|
||||
## ---------- ##
|
||||
|
||||
+1
-1
Submodule gnulib updated: 34881aff40...03752516b2
@@ -0,0 +1,15 @@
|
||||
/*.gmo
|
||||
/*.po
|
||||
/LINGUAS
|
||||
/Makefile.in.in
|
||||
/Makevars
|
||||
/Makevars.template
|
||||
/POTFILES.in
|
||||
/Rules-quot
|
||||
/bison-gnulib.pot
|
||||
/boldquot.sed
|
||||
/[email protected]
|
||||
/[email protected]
|
||||
/insert-header.sin
|
||||
/quot.sed
|
||||
/remove-potcdate.sin
|
||||
@@ -318,3 +318,6 @@
|
||||
/rename.c
|
||||
/rmdir.c
|
||||
/same-inode.h
|
||||
/assure.h
|
||||
/fsync.c
|
||||
/textstyle.in.h
|
||||
|
||||
+23
-18
@@ -5,6 +5,8 @@
|
||||
/asm-underscore.m4
|
||||
/assert.m4
|
||||
/calloc.m4
|
||||
/canonicalize.m4
|
||||
/clock_time.m4
|
||||
/close-stream.m4
|
||||
/close.m4
|
||||
/closeout.m4
|
||||
@@ -36,16 +38,22 @@
|
||||
/frexpl.m4
|
||||
/fseterr.m4
|
||||
/fstat.m4
|
||||
/fsync.m4
|
||||
/getdtablesize.m4
|
||||
/gethrxtime.m4
|
||||
/getopt.m4
|
||||
/getprogname.m4
|
||||
/getrusage.m4
|
||||
/gettext.m4
|
||||
/gettime.m4
|
||||
/gettimeofday.m4
|
||||
/glibc2.m4
|
||||
/glibc21.m4
|
||||
/gnulib-cache.m4
|
||||
/gnulib-common.m4
|
||||
/gnulib-comp.m4
|
||||
/gnulib-tool.m4
|
||||
/host-cpu-c-abi.m4
|
||||
/iconv.m4
|
||||
/include_next.m4
|
||||
/intdiv0.m4
|
||||
@@ -70,12 +78,15 @@
|
||||
/lib-ld.m4
|
||||
/lib-link.m4
|
||||
/lib-prefix.m4
|
||||
/libtextstyle-optional.m4
|
||||
/libtextstyle.m4
|
||||
/libunistring-base.m4
|
||||
/limits-h.m4
|
||||
/localcharset.m4
|
||||
/locale-fr.m4
|
||||
/locale-ja.m4
|
||||
/locale-zh.m4
|
||||
/localtime-buffer.m4
|
||||
/lock.m4
|
||||
/longlong.m4
|
||||
/lstat.m4
|
||||
@@ -117,9 +128,15 @@
|
||||
/quotearg.m4
|
||||
/raise.m4
|
||||
/rawmemchr.m4
|
||||
/readlink.m4
|
||||
/realloc.m4
|
||||
/relocatable-lib.m4
|
||||
/relocatable.m4
|
||||
/rename.m4
|
||||
/rmdir.m4
|
||||
/sched_h.m4
|
||||
/setenv.m4
|
||||
/sh-filename.m4
|
||||
/sig_atomic_t.m4
|
||||
/sigaction.m4
|
||||
/signal_h.m4
|
||||
@@ -132,7 +149,9 @@
|
||||
/spawn_h.m4
|
||||
/sprintf-posix.m4
|
||||
/ssize_t.m4
|
||||
/stat-time.m4
|
||||
/stat.m4
|
||||
/std-gnu11.m4
|
||||
/stdbool.m4
|
||||
/stddef_h.m4
|
||||
/stdint.m4
|
||||
@@ -148,12 +167,16 @@
|
||||
/strndup.m4
|
||||
/strnlen.m4
|
||||
/strverscmp.m4
|
||||
/sys_resource_h.m4
|
||||
/sys_socket_h.m4
|
||||
/sys_stat_h.m4
|
||||
/sys_time_h.m4
|
||||
/sys_times_h.m4
|
||||
/sys_types_h.m4
|
||||
/sys_wait_h.m4
|
||||
/threadlib.m4
|
||||
/time_h.m4
|
||||
/timespec.m4
|
||||
/uintmax_t.m4
|
||||
/unistd-safer.m4
|
||||
/unistd_h.m4
|
||||
@@ -177,21 +200,3 @@
|
||||
/xalloc.m4
|
||||
/xsize.m4
|
||||
/xstrndup.m4
|
||||
/host-cpu-c-abi.m4
|
||||
/stat-time.m4
|
||||
/sys_time_h.m4
|
||||
/sys_times_h.m4
|
||||
/sh-filename.m4
|
||||
/clock_time.m4
|
||||
/gethrxtime.m4
|
||||
/getrusage.m4
|
||||
/gettime.m4
|
||||
/gettimeofday.m4
|
||||
/localtime-buffer.m4
|
||||
/sys_resource_h.m4
|
||||
/timespec.m4
|
||||
/intl-thread-locale.m4
|
||||
/canonicalize.m4
|
||||
/readlink.m4
|
||||
/relocatable-lib.m4
|
||||
/relocatable.m4
|
||||
|
||||
+1
-13
@@ -9,23 +9,11 @@ src/location.c
|
||||
src/main.c
|
||||
src/muscle-tab.c
|
||||
src/parse-gram.y
|
||||
src/print-graph.c
|
||||
src/print.c
|
||||
src/print_graph.c
|
||||
src/reader.c
|
||||
src/reduce.c
|
||||
src/scan-code.l
|
||||
src/scan-gram.l
|
||||
src/scan-skel.l
|
||||
src/symtab.c
|
||||
|
||||
lib/argmatch.c
|
||||
lib/closeout.c
|
||||
lib/error.c
|
||||
lib/getopt.c
|
||||
lib/obstack.c
|
||||
lib/spawn-pipe.c
|
||||
lib/quotearg.c
|
||||
lib/timevar.c
|
||||
lib/w32spawn.h
|
||||
lib/wait-process.c
|
||||
lib/xalloc-die.c
|
||||
|
||||
+1
-3
@@ -29,9 +29,6 @@ assoc_to_string (assoc a)
|
||||
{
|
||||
switch (a)
|
||||
{
|
||||
default:
|
||||
abort ();
|
||||
|
||||
case undef_assoc:
|
||||
return "undefined associativity";
|
||||
|
||||
@@ -47,4 +44,5 @@ assoc_to_string (assoc a)
|
||||
case precedence_assoc:
|
||||
return "%precedence";
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
|
||||
+13
-10
@@ -35,6 +35,9 @@
|
||||
item_number *itemset;
|
||||
size_t nitemset;
|
||||
|
||||
/* RULESET contains a bit for each rule. CLOSURE sets the bits for
|
||||
all rules which could potentially describe the next input to be
|
||||
read. */
|
||||
static bitset ruleset;
|
||||
|
||||
/* internal data. See comments before set_fderives and set_firsts. */
|
||||
@@ -51,7 +54,7 @@ static bitsetv firsts = NULL;
|
||||
`-----------------*/
|
||||
|
||||
static void
|
||||
print_closure (char const *title, item_number const *array, size_t size)
|
||||
closure_print (char const *title, item_number const *array, size_t size)
|
||||
{
|
||||
fprintf (stderr, "Closure: %s\n", title);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
@@ -167,7 +170,7 @@ set_fderives (void)
|
||||
|
||||
|
||||
void
|
||||
new_closure (unsigned n)
|
||||
closure_new (unsigned n)
|
||||
{
|
||||
itemset = xnmalloc (n, sizeof *itemset);
|
||||
|
||||
@@ -181,8 +184,8 @@ new_closure (unsigned n)
|
||||
void
|
||||
closure (item_number const *core, size_t n)
|
||||
{
|
||||
if (trace_flag & trace_sets)
|
||||
print_closure ("input", core, n);
|
||||
if (trace_flag & trace_closure)
|
||||
closure_print ("input", core, n);
|
||||
|
||||
bitset_zero (ruleset);
|
||||
|
||||
@@ -192,12 +195,12 @@ closure (item_number const *core, size_t n)
|
||||
|
||||
/* core is sorted on item index in ritem, which is sorted on rule number.
|
||||
Compute itemset with the same sort. */
|
||||
nitemset = 0;
|
||||
size_t c = 0;
|
||||
|
||||
/* A bit index over RULESET. */
|
||||
rule_number ruleno;
|
||||
bitset_iterator iter;
|
||||
|
||||
nitemset = 0;
|
||||
size_t c = 0;
|
||||
BITSET_FOR_EACH (iter, ruleset, ruleno, 0)
|
||||
{
|
||||
item_number itemno = rules[ruleno].rhs - ritem;
|
||||
@@ -218,13 +221,13 @@ closure (item_number const *core, size_t n)
|
||||
c++;
|
||||
}
|
||||
|
||||
if (trace_flag & trace_sets)
|
||||
print_closure ("output", itemset, nitemset);
|
||||
if (trace_flag & trace_closure)
|
||||
closure_print ("output", itemset, nitemset);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
free_closure (void)
|
||||
closure_free (void)
|
||||
{
|
||||
free (itemset);
|
||||
bitset_free (ruleset);
|
||||
|
||||
+10
-13
@@ -27,29 +27,26 @@
|
||||
data so that closure can be called. n is the number of elements to
|
||||
allocate for itemset. */
|
||||
|
||||
void new_closure (unsigned n);
|
||||
void closure_new (unsigned n);
|
||||
|
||||
|
||||
/* Given the kernel (aka core) of a state (a sorted vector of item numbers
|
||||
ITEMS, of length N), set up RULESET and ITEMSET to indicate what
|
||||
rules could be run and which items could be accepted when those
|
||||
items are the active ones.
|
||||
|
||||
RULESET contains a bit for each rule. CLOSURE sets the bits for
|
||||
all rules which could potentially describe the next input to be
|
||||
read.
|
||||
|
||||
ITEMSET is a sorted vector of item numbers; NITEMSET is its size
|
||||
(actually, points to just beyond the end of the part of it that is
|
||||
significant). CLOSURE places there the indices of all items which
|
||||
represent units of input that could arrive next. */
|
||||
items are the active ones. */
|
||||
|
||||
void closure (item_number const *items, size_t n);
|
||||
|
||||
|
||||
/* Frees ITEMSET, RULESET and internal data. */
|
||||
/* Free ITEMSET, RULESET and internal data. */
|
||||
|
||||
void free_closure (void);
|
||||
void closure_free (void);
|
||||
|
||||
|
||||
/* ITEMSET is a sorted vector of item numbers; NITEMSET is its size
|
||||
(actually, points to just beyond the end of the part of it that is
|
||||
significant). CLOSURE places there the indices of all items which
|
||||
represent units of input that could arrive next. */
|
||||
|
||||
extern item_number *itemset;
|
||||
extern size_t nitemset;
|
||||
|
||||
+163
-23
@@ -23,8 +23,10 @@
|
||||
#include "system.h"
|
||||
|
||||
#include <argmatch.h>
|
||||
#include <stdarg.h>
|
||||
#include <progname.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <textstyle.h>
|
||||
|
||||
#include "complain.h"
|
||||
#include "files.h"
|
||||
@@ -61,7 +63,47 @@ typedef enum
|
||||
/** For each warning type, its severity. */
|
||||
static severity warnings_flag[warnings_size];
|
||||
|
||||
static unsigned *indent_ptr = 0;
|
||||
static unsigned *indent_ptr = NULL;
|
||||
|
||||
styled_ostream_t errstream = NULL;
|
||||
|
||||
void
|
||||
begin_use_class (const char *s, FILE *out)
|
||||
{
|
||||
if (out == stderr)
|
||||
{
|
||||
if (color_debug)
|
||||
fprintf (out, "<%s>", s);
|
||||
else
|
||||
{
|
||||
styled_ostream_begin_use_class (errstream, s);
|
||||
styled_ostream_flush_to_current_style (errstream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
end_use_class (const char *s, FILE *out)
|
||||
{
|
||||
if (out == stderr)
|
||||
{
|
||||
if (color_debug)
|
||||
fprintf (out, "</%s>", s);
|
||||
else
|
||||
{
|
||||
styled_ostream_end_use_class (errstream, s);
|
||||
styled_ostream_flush_to_current_style (errstream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
flush (FILE *out)
|
||||
{
|
||||
if (out == stderr)
|
||||
ostream_flush (errstream, FLUSH_THIS_STREAM);
|
||||
fflush (out);
|
||||
}
|
||||
|
||||
/*------------------------.
|
||||
| --warnings's handling. |
|
||||
@@ -165,11 +207,89 @@ warnings_argmatch (char *args)
|
||||
warning_argmatch ("all", 0, 0);
|
||||
}
|
||||
|
||||
static const char*
|
||||
severity_style (severity s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case severity_disabled:
|
||||
case severity_unset:
|
||||
return "note";
|
||||
case severity_warning:
|
||||
return "warning";
|
||||
case severity_error:
|
||||
case severity_fatal:
|
||||
return "error";
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
|
||||
static const char*
|
||||
severity_prefix (severity s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case severity_disabled:
|
||||
case severity_unset:
|
||||
return "";
|
||||
case severity_warning:
|
||||
return _("warning");
|
||||
case severity_error:
|
||||
return _("error");
|
||||
case severity_fatal:
|
||||
return _("fatal error");
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
|
||||
|
||||
/*-----------.
|
||||
| complain. |
|
||||
`-----------*/
|
||||
|
||||
void
|
||||
complain_init_color (void)
|
||||
{
|
||||
#if HAVE_LIBTEXTSTYLE
|
||||
if (color_mode == color_yes
|
||||
|| color_mode == color_html
|
||||
|| (color_mode == color_tty && isatty (STDERR_FILENO)))
|
||||
{
|
||||
style_file_prepare ("BISON_DIAGNOSTICS_STYLE", NULL,
|
||||
pkgdatadir (),
|
||||
"diagnostics.css");
|
||||
/* As a fallback, use the default in the current directory. */
|
||||
struct stat statbuf;
|
||||
if ((style_file_name == NULL || stat (style_file_name, &statbuf) < 0)
|
||||
&& stat ("diagnostics.css", &statbuf) == 0)
|
||||
style_file_name = "diagnostics.css";
|
||||
}
|
||||
else
|
||||
/* No styling. */
|
||||
style_file_name = NULL;
|
||||
#endif
|
||||
|
||||
/* Workaround clang's warning (starting at Clang 3.5) about the stub
|
||||
code of html_styled_ostream_create:
|
||||
|
||||
| src/complain.c:274:7: error: code will never be executed [-Werror,-Wunreachable-code]
|
||||
| ? html_styled_ostream_create (file_ostream_create (stderr),
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
#if defined __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wunreachable-code"
|
||||
#endif
|
||||
errstream =
|
||||
color_mode == color_html
|
||||
? html_styled_ostream_create (file_ostream_create (stderr),
|
||||
style_file_name)
|
||||
: styled_ostream_create (STDERR_FILENO, "(stderr)", TTYCTL_AUTO,
|
||||
style_file_name);
|
||||
#if defined __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
complain_init (void)
|
||||
{
|
||||
@@ -185,6 +305,12 @@ complain_init (void)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
complain_free (void)
|
||||
{
|
||||
caret_free ();
|
||||
styled_ostream_free (errstream);
|
||||
}
|
||||
|
||||
/* A diagnostic with FLAGS is about to be issued. With what severity?
|
||||
(severity_fatal, severity_error, severity_disabled, or
|
||||
@@ -229,19 +355,30 @@ warning_is_unset (warnings flags)
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Display a "[-Wyacc]" like message on \a f. */
|
||||
bool
|
||||
warning_is_enabled (warnings flags)
|
||||
{
|
||||
return severity_warning <= warning_severity (flags);
|
||||
}
|
||||
|
||||
/** Display a "[-Wyacc]" like message on \a out. */
|
||||
|
||||
static void
|
||||
warnings_print_categories (warnings warn_flags, FILE *f)
|
||||
warnings_print_categories (warnings warn_flags, FILE *out)
|
||||
{
|
||||
/* Display only the first match, the second is "-Wall". */
|
||||
for (size_t i = 0; warnings_args[i]; ++i)
|
||||
if (warn_flags & warnings_types[i])
|
||||
{
|
||||
severity s = warning_severity (warnings_types[i]);
|
||||
fprintf (f, " [-W%s%s]",
|
||||
const char* style = severity_style (s);
|
||||
fputs (" [", out);
|
||||
begin_use_class (style, out);
|
||||
fprintf (out, "-W%s%s",
|
||||
s == severity_error ? "error=" : "",
|
||||
warnings_args[i]);
|
||||
end_use_class (style, out);
|
||||
fputc (']', out);
|
||||
/* Display only the first match, the second is "-Wall". */
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -251,7 +388,8 @@ warnings_print_categories (warnings warn_flags, FILE *f)
|
||||
* \param loc the location, defaulting to the current file,
|
||||
* or the program name.
|
||||
* \param flags the category for this message.
|
||||
* \param prefix put before the message (e.g., "warning").
|
||||
* \param sever to decide the prefix to put before the message
|
||||
* (e.g., "warning").
|
||||
* \param message the error message, a printf format string. Iff it
|
||||
* ends with ": ", then no trailing newline is printed,
|
||||
* and the caller should print the remaining
|
||||
@@ -260,7 +398,7 @@ warnings_print_categories (warnings warn_flags, FILE *f)
|
||||
*/
|
||||
static
|
||||
void
|
||||
error_message (const location *loc, warnings flags, const char *prefix,
|
||||
error_message (const location *loc, warnings flags, severity sever,
|
||||
const char *message, va_list args)
|
||||
{
|
||||
unsigned pos = 0;
|
||||
@@ -274,7 +412,7 @@ error_message (const location *loc, warnings flags, const char *prefix,
|
||||
if (indent_ptr)
|
||||
{
|
||||
if (*indent_ptr)
|
||||
prefix = NULL;
|
||||
sever = severity_disabled;
|
||||
if (!*indent_ptr)
|
||||
*indent_ptr = pos;
|
||||
else if (*indent_ptr > pos)
|
||||
@@ -282,13 +420,20 @@ error_message (const location *loc, warnings flags, const char *prefix,
|
||||
indent_ptr = NULL;
|
||||
}
|
||||
|
||||
if (prefix)
|
||||
fprintf (stderr, "%s: ", prefix);
|
||||
const char* style = severity_style (sever);
|
||||
|
||||
if (sever != severity_disabled)
|
||||
{
|
||||
begin_use_class (style, stderr);
|
||||
fprintf (stderr, "%s:", severity_prefix (sever));
|
||||
end_use_class (style, stderr);
|
||||
fputc (' ', stderr);
|
||||
}
|
||||
|
||||
vfprintf (stderr, message, args);
|
||||
/* Print the type of warning, only if this is not a sub message
|
||||
(in which case the prefix is null). */
|
||||
if (! (flags & silent) && prefix)
|
||||
if (! (flags & silent) && sever != severity_disabled)
|
||||
warnings_print_categories (flags, stderr);
|
||||
|
||||
{
|
||||
@@ -296,16 +441,15 @@ error_message (const location *loc, warnings flags, const char *prefix,
|
||||
if (l < 2 || message[l - 2] != ':' || message[l - 1] != ' ')
|
||||
{
|
||||
putc ('\n', stderr);
|
||||
fflush (stderr);
|
||||
flush (stderr);
|
||||
if (loc && feature_flag & feature_caret && !(flags & no_caret))
|
||||
location_caret (*loc, stderr);
|
||||
location_caret (*loc, style, stderr);
|
||||
}
|
||||
}
|
||||
fflush (stderr);
|
||||
flush (stderr);
|
||||
}
|
||||
|
||||
/** Raise a complaint. That can be a fatal error, an error or just a
|
||||
warning. */
|
||||
/** Raise a complaint (fatal error, error or just warning). */
|
||||
|
||||
static void
|
||||
complains (const location *loc, warnings flags, const char *message,
|
||||
@@ -317,13 +461,9 @@ complains (const location *loc, warnings flags, const char *message,
|
||||
|
||||
if (severity_warning <= s)
|
||||
{
|
||||
const char* prefix =
|
||||
s == severity_fatal ? _("fatal error")
|
||||
: s == severity_error ? _("error")
|
||||
: _("warning");
|
||||
if (severity_error <= s && ! complaint_status)
|
||||
complaint_status = status_warning_as_error;
|
||||
error_message (loc, flags, prefix, message, args);
|
||||
error_message (loc, flags, s, message, args);
|
||||
}
|
||||
|
||||
if (flags & fatal)
|
||||
@@ -398,7 +538,7 @@ deprecated_directive (location const *loc, char const *old, char const *upd)
|
||||
_("deprecated directive: %s, use %s"),
|
||||
quote (old), quote_n (1, upd));
|
||||
/* Register updates only if -Wdeprecated is enabled. */
|
||||
if (warnings_flag[warning_deprecated] != severity_disabled)
|
||||
if (warning_is_enabled (Wdeprecated))
|
||||
fixits_register (loc, upd);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,20 @@
|
||||
/* Sub-messages indent. */
|
||||
# define SUB_INDENT (4)
|
||||
|
||||
/*---------------.
|
||||
| Error stream. |
|
||||
`---------------*/
|
||||
|
||||
/** Enable a style on \a out provided it's stderr. */
|
||||
void begin_use_class (const char *style, FILE *out);
|
||||
|
||||
/** Disable a style on \a out provided it's stderr. */
|
||||
void end_use_class (const char *style, FILE *out);
|
||||
|
||||
/** Flush \a out. */
|
||||
void flush (FILE *out);
|
||||
|
||||
|
||||
/*-------------.
|
||||
| --warnings. |
|
||||
`-------------*/
|
||||
@@ -76,6 +90,12 @@ void warnings_argmatch (char *args);
|
||||
/** Initialize this module. */
|
||||
void complain_init (void);
|
||||
|
||||
/** Reclaim resources. */
|
||||
void complain_free (void);
|
||||
|
||||
/** Initialize support for colored messages. */
|
||||
void complain_init_color (void);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
Wnone = 0, /**< Issue no warnings. */
|
||||
@@ -105,6 +125,9 @@ typedef enum
|
||||
(Never enabled, never disabled). */
|
||||
bool warning_is_unset (warnings flags);
|
||||
|
||||
/** Whether warnings of \a flags should be reported. */
|
||||
bool warning_is_enabled (warnings flags);
|
||||
|
||||
/** Make a complaint, with maybe a location. */
|
||||
void complain (location const *loc, warnings flags, char const *message, ...)
|
||||
__attribute__ ((__format__ (__printf__, 3, 4)));
|
||||
|
||||
+11
-8
@@ -23,13 +23,13 @@
|
||||
|
||||
#include <bitset.h>
|
||||
|
||||
#include "LR0.h"
|
||||
#include "complain.h"
|
||||
#include "conflicts.h"
|
||||
#include "files.h"
|
||||
#include "getargs.h"
|
||||
#include "gram.h"
|
||||
#include "lalr.h"
|
||||
#include "lr0.h"
|
||||
#include "print-xml.h"
|
||||
#include "reader.h"
|
||||
#include "state.h"
|
||||
@@ -369,13 +369,16 @@ set_conflicts (state *s, symbol **errors)
|
||||
s->solved_conflicts_xml = obstack_finish0 (&solved_conflicts_xml_obstack);
|
||||
|
||||
/* Loop over all rules which require lookahead in this state. Check
|
||||
for conflicts not resolved above. */
|
||||
for (int i = 0; i < reds->num; ++i)
|
||||
{
|
||||
if (!bitset_disjoint_p (reds->lookahead_tokens[i], lookahead_set))
|
||||
conflicts[s->number] = 1;
|
||||
bitset_or (lookahead_set, lookahead_set, reds->lookahead_tokens[i]);
|
||||
}
|
||||
for conflicts not resolved above.
|
||||
|
||||
reds->lookahead_tokens can be NULL if the LR type is LR(0). */
|
||||
if (reds->lookahead_tokens)
|
||||
for (int i = 0; i < reds->num; ++i)
|
||||
{
|
||||
if (!bitset_disjoint_p (reds->lookahead_tokens[i], lookahead_set))
|
||||
conflicts[s->number] = 1;
|
||||
bitset_or (lookahead_set, lookahead_set, reds->lookahead_tokens[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+5
-9
@@ -46,9 +46,8 @@ print_derives (void)
|
||||
|
||||
for (i = ntokens; i < nsyms; i++)
|
||||
{
|
||||
rule **rp;
|
||||
fprintf (stderr, " %s derives\n", symbols[i]->tag);
|
||||
for (rp = derives[i - ntokens]; *rp; ++rp)
|
||||
for (rule **rp = derives[i - ntokens]; *rp; ++rp)
|
||||
{
|
||||
fprintf (stderr, " %3d ", (*rp)->user_number);
|
||||
rule_rhs_print (*rp, stderr);
|
||||
@@ -63,10 +62,6 @@ print_derives (void)
|
||||
void
|
||||
derives_compute (void)
|
||||
{
|
||||
symbol_number i;
|
||||
rule_number r;
|
||||
rule **q;
|
||||
|
||||
/* DSET[NTERM - NTOKENS] -- A linked list of the numbers of the rules
|
||||
whose LHS is NTERM. */
|
||||
rule_list **dset = xcalloc (nvars, sizeof *dset);
|
||||
@@ -76,7 +71,7 @@ derives_compute (void)
|
||||
indexed by rule numbers. */
|
||||
rule_list *delts = xnmalloc (nrules, sizeof *delts);
|
||||
|
||||
for (r = nrules - 1; r >= 0; --r)
|
||||
for (rule_number r = nrules - 1; r >= 0; --r)
|
||||
{
|
||||
symbol_number lhs = rules[r].lhs->number;
|
||||
rule_list *p = &delts[r];
|
||||
@@ -90,9 +85,10 @@ derives_compute (void)
|
||||
it a single array. */
|
||||
|
||||
derives = xnmalloc (nvars, sizeof *derives);
|
||||
q = xnmalloc (nvars + nrules, sizeof *q);
|
||||
/* Q is the storage for DERIVES[...] (DERIVES[0] = q). */
|
||||
rule **q = xnmalloc (nvars + nrules, sizeof *q);
|
||||
|
||||
for (i = ntokens; i < nsyms; i++)
|
||||
for (symbol_number i = ntokens; i < nsyms; i++)
|
||||
{
|
||||
rule_list *p = dset[i - ntokens];
|
||||
derives[i - ntokens] = q;
|
||||
|
||||
+24
-5
@@ -21,11 +21,13 @@
|
||||
#include <config.h>
|
||||
#include "system.h"
|
||||
|
||||
#include <configmake.h> /* PKGDATADIR */
|
||||
#include <error.h>
|
||||
#include <dirname.h>
|
||||
#include <get-errno.h>
|
||||
#include <quote.h>
|
||||
#include <quotearg.h>
|
||||
#include <relocatable.h> /* relocate2 */
|
||||
#include <stdio-safer.h>
|
||||
#include <xstrndup.h>
|
||||
|
||||
@@ -49,7 +51,7 @@ location spec_name_prefix_loc = EMPTY_LOCATION_INIT;
|
||||
char *spec_verbose_file = NULL; /* for --verbose. */
|
||||
char *spec_graph_file = NULL; /* for -g. */
|
||||
char *spec_xml_file = NULL; /* for -x. */
|
||||
char *spec_defines_file = NULL; /* for --defines. */
|
||||
char *spec_header_file = NULL; /* for --defines. */
|
||||
char *parser_file_name;
|
||||
|
||||
/* All computed output file names. */
|
||||
@@ -333,14 +335,15 @@ compute_output_file_names (void)
|
||||
|
||||
if (defines_flag)
|
||||
{
|
||||
if (! spec_defines_file)
|
||||
spec_defines_file = concat2 (all_but_ext, header_extension);
|
||||
if (! spec_header_file)
|
||||
spec_header_file = concat2 (all_but_ext, header_extension);
|
||||
}
|
||||
|
||||
if (graph_flag)
|
||||
{
|
||||
if (! spec_graph_file)
|
||||
spec_graph_file = concat2 (all_but_tab_ext, ".dot");
|
||||
spec_graph_file = concat2 (all_but_tab_ext,
|
||||
304 <= required_version ? ".gv" : ".dot");
|
||||
output_file_name_check (&spec_graph_file, false);
|
||||
}
|
||||
|
||||
@@ -404,6 +407,21 @@ unlink_generated_sources (void)
|
||||
unlink (generated_files[i].name);
|
||||
}
|
||||
|
||||
/* Memory allocated by relocate2, to free. */
|
||||
static char *relocate_buffer = NULL;
|
||||
|
||||
char const *
|
||||
pkgdatadir (void)
|
||||
{
|
||||
if (relocate_buffer)
|
||||
return relocate_buffer;
|
||||
else
|
||||
{
|
||||
char const *cp = getenv ("BISON_PKGDATADIR");
|
||||
return cp ? cp : relocate2 (PKGDATADIR, &relocate_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
output_file_names_free (void)
|
||||
{
|
||||
@@ -411,10 +429,11 @@ output_file_names_free (void)
|
||||
free (spec_verbose_file);
|
||||
free (spec_graph_file);
|
||||
free (spec_xml_file);
|
||||
free (spec_defines_file);
|
||||
free (spec_header_file);
|
||||
free (parser_file_name);
|
||||
free (dir_prefix);
|
||||
for (int i = 0; i < generated_files_size; i++)
|
||||
free (generated_files[i].name);
|
||||
free (generated_files);
|
||||
free (relocate_buffer);
|
||||
}
|
||||
|
||||
+4
-1
@@ -48,7 +48,7 @@ extern char *spec_graph_file;
|
||||
extern char *spec_xml_file;
|
||||
|
||||
/* File name specified with --defines. */
|
||||
extern char *spec_defines_file;
|
||||
extern char *spec_header_file;
|
||||
|
||||
/* Directory prefix of output file names. */
|
||||
extern char *dir_prefix;
|
||||
@@ -64,6 +64,9 @@ extern uniqstr current_file;
|
||||
/* The computed base for output file names. */
|
||||
extern char *all_but_ext;
|
||||
|
||||
/* Where our data files are installed. */
|
||||
char const *pkgdatadir (void);
|
||||
|
||||
void compute_output_file_names (void);
|
||||
void output_file_names_free (void);
|
||||
|
||||
|
||||
+23
-7
@@ -52,6 +52,11 @@ fixit_new (location const *loc, char const* fix)
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
fixit_cmp (const fixit *a, const fixit *b)
|
||||
{
|
||||
return location_cmp (a->location, b->location);
|
||||
}
|
||||
|
||||
static void
|
||||
fixit_free (fixit *f)
|
||||
@@ -69,8 +74,8 @@ fixit_print (fixit const *f, FILE *out)
|
||||
{
|
||||
fprintf (out, "fix-it:%s:{%d:%d-%d:%d}:%s\n",
|
||||
quotearg_n_style (1, c_quoting_style, f->location.start.file),
|
||||
f->location.start.line, f->location.start.column,
|
||||
f->location.end.line, f->location.end.column,
|
||||
f->location.start.line, f->location.start.byte,
|
||||
f->location.end.line, f->location.end.byte,
|
||||
quotearg_n_style (2, c_quoting_style, f->fix));
|
||||
}
|
||||
|
||||
@@ -85,7 +90,7 @@ fixits_register (location const *loc, char const* fix)
|
||||
(gl_listelement_dispose_fn) fixit_free,
|
||||
true);
|
||||
fixit *f = fixit_new (loc, fix);
|
||||
gl_list_add_last (fixits, f);
|
||||
gl_sortedlist_add (fixits, (gl_listelement_compar_fn) fixit_cmp, f);
|
||||
if (feature_flag & feature_fixit_parsable)
|
||||
fixit_print (f, stderr);
|
||||
}
|
||||
@@ -136,19 +141,29 @@ fixits_run (void)
|
||||
}
|
||||
putc (c, out);
|
||||
}
|
||||
|
||||
/* Look for the right offset. */
|
||||
while (offset < f->location.start.column)
|
||||
bool need_eol = false;
|
||||
while (offset < f->location.start.byte)
|
||||
{
|
||||
int c = getc (in);
|
||||
if (c == EOF)
|
||||
break;
|
||||
++offset;
|
||||
putc (c, out);
|
||||
if (c == '\n')
|
||||
/* The position we are asked for is beyond the actual
|
||||
line: pad with spaces, and remember we need a \n. */
|
||||
need_eol = true;
|
||||
putc (need_eol ? ' ' : c, out);
|
||||
}
|
||||
|
||||
/* Paste the fix instead. */
|
||||
fputs (f->fix, out);
|
||||
|
||||
/* Maybe install the eol afterwards. */
|
||||
if (need_eol)
|
||||
putc ('\n', out);
|
||||
|
||||
/* Skip the bad input. */
|
||||
while (line < f->location.end.line)
|
||||
{
|
||||
@@ -161,16 +176,17 @@ fixits_run (void)
|
||||
offset = 1;
|
||||
}
|
||||
}
|
||||
while (offset < f->location.end.column)
|
||||
while (offset < f->location.end.byte)
|
||||
{
|
||||
int c = getc (in);
|
||||
if (c == EOF)
|
||||
break;
|
||||
++offset;
|
||||
}
|
||||
|
||||
/* If erasing the content of a full line, also remove the
|
||||
end-of-line. */
|
||||
if (f->fix[0] == 0 && f->location.start.column == 1)
|
||||
if (f->fix[0] == 0 && f->location.start.byte == 1)
|
||||
{
|
||||
int c = getc (in);
|
||||
if (c == EOF)
|
||||
|
||||
+76
-18
@@ -19,8 +19,9 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
#include "getargs.h"
|
||||
|
||||
#include "system.h"
|
||||
#include "output.h"
|
||||
|
||||
#include <argmatch.h>
|
||||
#include <c-strcase.h>
|
||||
@@ -28,12 +29,13 @@
|
||||
#include <error.h>
|
||||
#include <getopt.h>
|
||||
#include <progname.h>
|
||||
#include <quote.h>
|
||||
#include <textstyle.h>
|
||||
|
||||
#include "complain.h"
|
||||
#include "files.h"
|
||||
#include "getargs.h"
|
||||
#include "muscle-tab.h"
|
||||
#include "quote.h"
|
||||
#include "output.h"
|
||||
#include "uniqstr.h"
|
||||
|
||||
bool defines_flag = false;
|
||||
@@ -43,6 +45,7 @@ bool no_lines_flag = false;
|
||||
bool token_table_flag = false;
|
||||
location yacc_loc = EMPTY_LOCATION_INIT;
|
||||
bool update_flag = false; /* for -u */
|
||||
bool color_debug = false;
|
||||
|
||||
bool nondeterministic_parser = false;
|
||||
bool glr_parser = false;
|
||||
@@ -182,10 +185,12 @@ ARGMATCH_VERIFY (report_args, report_types);
|
||||
static const char * const trace_args[] =
|
||||
{
|
||||
"none - no traces",
|
||||
"locations - full display of the locations",
|
||||
"scan - grammar scanner traces",
|
||||
"parse - grammar parser traces",
|
||||
"automaton - construction of the automaton",
|
||||
"bitsets - use of bitsets",
|
||||
"closure - input/output of closure",
|
||||
"grammar - reading, reducing the grammar",
|
||||
"resource - memory consumption (where available)",
|
||||
"sets - grammar sets: firsts, nullable etc.",
|
||||
@@ -202,10 +207,12 @@ static const char * const trace_args[] =
|
||||
static const int trace_types[] =
|
||||
{
|
||||
trace_none,
|
||||
trace_locations,
|
||||
trace_scan,
|
||||
trace_parse,
|
||||
trace_automaton,
|
||||
trace_bitsets,
|
||||
trace_closure,
|
||||
trace_grammar,
|
||||
trace_resource,
|
||||
trace_sets,
|
||||
@@ -230,6 +237,7 @@ static const char * const feature_args[] =
|
||||
"none",
|
||||
"caret", "diagnostics-show-caret",
|
||||
"fixit", "diagnostics-parseable-fixits",
|
||||
"syntax-only",
|
||||
"all",
|
||||
0
|
||||
};
|
||||
@@ -239,6 +247,7 @@ static const int feature_types[] =
|
||||
feature_none,
|
||||
feature_caret, feature_caret,
|
||||
feature_fixit_parsable, feature_fixit_parsable,
|
||||
feature_syntax_only,
|
||||
feature_all
|
||||
};
|
||||
|
||||
@@ -290,7 +299,7 @@ Operation modes:\n\
|
||||
-u, --update apply fixes to the source grammar file and exit\n\
|
||||
-y, --yacc emulate POSIX Yacc\n\
|
||||
-W, --warnings[=CATEGORY] report the warnings falling in CATEGORY\n\
|
||||
-f, --feature[=FEATURE] activate miscellaneous features\n\
|
||||
-f, --feature[=FEATURES] activate miscellaneous features\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
|
||||
@@ -329,13 +338,13 @@ Output:\n\
|
||||
|
||||
fputs (_("\
|
||||
Warning categories include:\n\
|
||||
'midrule-values' unset or unused midrule values\n\
|
||||
'yacc' incompatibilities with POSIX Yacc\n\
|
||||
'conflicts-sr' S/R conflicts (enabled by default)\n\
|
||||
'conflicts-rr' R/R conflicts (enabled by default)\n\
|
||||
'deprecated' obsolete constructs\n\
|
||||
'empty-rule' empty rules without %empty\n\
|
||||
'midrule-values' unset or unused midrule values\n\
|
||||
'precedence' useless precedence and associativity\n\
|
||||
'yacc' incompatibilities with POSIX Yacc\n\
|
||||
'other' all other warnings (enabled by default)\n\
|
||||
'all' all the warnings except 'yacc'\n\
|
||||
'no-CATEGORY' turn off warnings in CATEGORY\n\
|
||||
@@ -356,10 +365,17 @@ THINGS is a list of comma separated words that can include:\n\
|
||||
putc ('\n', stdout);
|
||||
|
||||
fputs (_("\
|
||||
FEATURE is a list of comma separated words that can include:\n\
|
||||
'caret' show errors with carets\n\
|
||||
'all' all of the above\n\
|
||||
'none' disable all of the above\n\
|
||||
FEATURES is a list of comma separated words that can include:\n\
|
||||
'caret', 'diagnostics-show-caret'\n\
|
||||
show errors with carets\n\
|
||||
'fixit', 'diagnostics-parseable-fixits'\n\
|
||||
show machine-readable fixes\n\
|
||||
'syntax-only'\n\
|
||||
do not generate any file\n\
|
||||
'all'\n\
|
||||
all of the above\n\
|
||||
'none'\n\
|
||||
disable all of the above\n\
|
||||
"), stdout);
|
||||
|
||||
putc ('\n', stdout);
|
||||
@@ -491,10 +507,12 @@ static char const short_options[] =
|
||||
/* Values for long options that do not have single-letter equivalents. */
|
||||
enum
|
||||
{
|
||||
LOCATIONS_OPTION = CHAR_MAX + 1,
|
||||
PRINT_LOCALEDIR_OPTION,
|
||||
COLOR_OPTION = CHAR_MAX + 1,
|
||||
LOCATIONS_OPTION,
|
||||
PRINT_DATADIR_OPTION,
|
||||
REPORT_FILE_OPTION
|
||||
PRINT_LOCALEDIR_OPTION,
|
||||
REPORT_FILE_OPTION,
|
||||
STYLE_OPTION
|
||||
};
|
||||
|
||||
static struct option const long_options[] =
|
||||
@@ -521,7 +539,9 @@ static struct option const long_options[] =
|
||||
{ "verbose", no_argument, 0, 'v' },
|
||||
|
||||
/* Hidden. */
|
||||
{ "trace", optional_argument, 0, 'T' },
|
||||
{ "trace", optional_argument, 0, 'T' },
|
||||
{ "color", optional_argument, 0, COLOR_OPTION },
|
||||
{ "style", optional_argument, 0, STYLE_OPTION },
|
||||
|
||||
/* Output. */
|
||||
{ "defines", optional_argument, 0, 'd' },
|
||||
@@ -559,17 +579,46 @@ command_line_location (void)
|
||||
{
|
||||
location res;
|
||||
/* "<command line>" is used in GCC's messages about -D. */
|
||||
boundary_set (&res.start, uniqstr_new ("<command line>"), optind - 1, -1);
|
||||
boundary_set (&res.start, uniqstr_new ("<command line>"), optind - 1, -1, -1);
|
||||
res.end = res.start;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the command line options for color support. Do it early, so
|
||||
that error messages from getargs be also colored as per the user's
|
||||
request. This is consistent with the way GCC and Clang behave. */
|
||||
|
||||
static void
|
||||
getargs_colors (int argc, char *argv[])
|
||||
{
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
const char *arg = argv[i];
|
||||
if (STRPREFIX_LIT ("--color=", arg))
|
||||
{
|
||||
const char *color = arg + strlen ("--color=");
|
||||
if (STREQ (color, "debug"))
|
||||
color_debug = true;
|
||||
else
|
||||
handle_color_option (color);
|
||||
}
|
||||
else if (STRPREFIX_LIT ("--style=", arg))
|
||||
{
|
||||
const char *style = arg + strlen ("--style=");
|
||||
handle_style_option (style);
|
||||
}
|
||||
}
|
||||
complain_init_color ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
getargs (int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
getargs_colors (argc, argv);
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long (argc, argv, short_options, long_options, NULL))
|
||||
!= -1)
|
||||
switch (c)
|
||||
@@ -646,8 +695,8 @@ getargs (int argc, char *argv[])
|
||||
defines_flag = true;
|
||||
if (optarg)
|
||||
{
|
||||
free (spec_defines_file);
|
||||
spec_defines_file = xstrdup (AS_FILE_NAME (optarg));
|
||||
free (spec_header_file);
|
||||
spec_header_file = xstrdup (AS_FILE_NAME (optarg));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -692,6 +741,7 @@ getargs (int argc, char *argv[])
|
||||
|
||||
case 'u':
|
||||
update_flag = true;
|
||||
feature_flag |= feature_syntax_only;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
@@ -712,6 +762,10 @@ getargs (int argc, char *argv[])
|
||||
yacc_loc = command_line_location ();
|
||||
break;
|
||||
|
||||
case COLOR_OPTION:
|
||||
/* Handled in getargs_colors. */
|
||||
break;
|
||||
|
||||
case LOCATIONS_OPTION:
|
||||
muscle_percent_define_ensure ("locations",
|
||||
command_line_location (), true);
|
||||
@@ -730,6 +784,10 @@ getargs (int argc, char *argv[])
|
||||
spec_verbose_file = xstrdup (AS_FILE_NAME (optarg));
|
||||
break;
|
||||
|
||||
case STYLE_OPTION:
|
||||
/* Handled in getargs_colors. */
|
||||
break;
|
||||
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+8
-5
@@ -41,7 +41,7 @@ extern bool no_lines_flag; /* for -l */
|
||||
extern bool token_table_flag; /* for -k */
|
||||
extern location yacc_loc; /* for -y */
|
||||
extern bool update_flag; /* for -u */
|
||||
|
||||
extern bool color_debug; /* --color=debug. */
|
||||
/* GLR_PARSER is true if the input file says to use the GLR
|
||||
(Generalized LR) parser, and to output some additional information
|
||||
used by the GLR algorithm. */
|
||||
@@ -103,6 +103,8 @@ enum trace
|
||||
trace_m4 = 1 << 10, /**< M4 traces. */
|
||||
trace_muscles = 1 << 11, /**< M4 definitions of the muscles. */
|
||||
trace_ielr = 1 << 12, /**< IELR conversion. */
|
||||
trace_closure = 1 << 13, /**< Input/output of closure(). */
|
||||
trace_locations = 1 << 14, /**< Full display of locations. */
|
||||
trace_all = ~0 /**< All of the above. */
|
||||
};
|
||||
/** What debug items bison displays during its run. */
|
||||
@@ -114,10 +116,11 @@ extern int trace_flag;
|
||||
|
||||
enum feature
|
||||
{
|
||||
feature_none = 0, /**< No additional feature. */
|
||||
feature_caret = 1 << 0, /**< Output errors with carets. */
|
||||
feature_fixit_parsable = 1 << 1, /**< Issue instructions to fix the sources. */
|
||||
feature_all = ~0 /**< All above features. */
|
||||
feature_none = 0, /**< No additional feature. */
|
||||
feature_caret = 1 << 0, /**< Output errors with carets. */
|
||||
feature_fixit_parsable = 1 << 1, /**< Issue instructions to fix the sources. */
|
||||
feature_syntax_only = 1 << 2, /**< Don't generate output. */
|
||||
feature_all = ~0 /**< All above features. */
|
||||
};
|
||||
/** What additional features to use. */
|
||||
extern int feature_flag;
|
||||
|
||||
+72
-38
@@ -48,6 +48,34 @@ int max_user_token_number = 256;
|
||||
|
||||
int required_version = 0;
|
||||
|
||||
rule const *
|
||||
item_rule (item_number const *item)
|
||||
{
|
||||
item_number const *sp = item;
|
||||
while (0 <= *sp)
|
||||
++sp;
|
||||
rule_number r = item_number_as_rule_number (*sp);
|
||||
return &rules[r];
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
item_print (item_number *item, rule const *previous_rule, FILE *out)
|
||||
{
|
||||
rule const *r = item_rule (item);
|
||||
rule_lhs_print (r, previous_rule ? previous_rule->lhs : NULL, out);
|
||||
|
||||
for (item_number *sp = r->rhs; sp < item; sp++)
|
||||
fprintf (out, " %s", symbols[*sp]->tag);
|
||||
fputs (" .", out);
|
||||
if (0 <= *r->rhs)
|
||||
for (item_number *sp = item; 0 <= *sp; ++sp)
|
||||
fprintf (out, " %s", symbols[*sp]->tag);
|
||||
else
|
||||
fprintf (out, " %%empty");
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
rule_useful_in_grammar_p (rule const *r)
|
||||
{
|
||||
@@ -66,6 +94,12 @@ rule_useless_in_parser_p (rule const *r)
|
||||
return !r->useful && rule_useful_in_grammar_p (r);
|
||||
}
|
||||
|
||||
bool
|
||||
rule_useless_chain_p (rule const *r)
|
||||
{
|
||||
return rule_rhs_length (r) == 1 && !r->action;
|
||||
}
|
||||
|
||||
void
|
||||
rule_lhs_print (rule const *r, sym_content const *previous_lhs, FILE *out)
|
||||
{
|
||||
@@ -86,7 +120,7 @@ size_t
|
||||
rule_rhs_length (rule const *r)
|
||||
{
|
||||
size_t res = 0;
|
||||
for (item_number *rhsp = r->rhs; *rhsp >= 0; ++rhsp)
|
||||
for (item_number *rhsp = r->rhs; 0 <= *rhsp; ++rhsp)
|
||||
++res;
|
||||
return res;
|
||||
}
|
||||
@@ -95,8 +129,8 @@ void
|
||||
rule_rhs_print (rule const *r, FILE *out)
|
||||
{
|
||||
if (0 <= *r->rhs)
|
||||
for (item_number *rp = r->rhs; *rp >= 0; rp++)
|
||||
fprintf (out, " %s", symbols[*rp]->tag);
|
||||
for (item_number *rhsp = r->rhs; 0 <= *rhsp; ++rhsp)
|
||||
fprintf (out, " %s", symbols[*rhsp]->tag);
|
||||
else
|
||||
fputs (" %empty", out);
|
||||
}
|
||||
@@ -107,9 +141,9 @@ rule_rhs_print_xml (rule const *r, FILE *out, int level)
|
||||
if (*r->rhs >= 0)
|
||||
{
|
||||
xml_puts (out, level, "<rhs>");
|
||||
for (item_number *rp = r->rhs; *rp >= 0; rp++)
|
||||
for (item_number *rhsp = r->rhs; 0 <= *rhsp; ++rhsp)
|
||||
xml_printf (out, level + 1, "<symbol>%s</symbol>",
|
||||
xml_escape (symbols[*rp]->tag));
|
||||
xml_escape (symbols[*rhsp]->tag));
|
||||
xml_puts (out, level, "</rhs>");
|
||||
}
|
||||
else
|
||||
@@ -120,6 +154,13 @@ rule_rhs_print_xml (rule const *r, FILE *out, int level)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rule_print (rule const *r, rule const *prev_rule, FILE *out)
|
||||
{
|
||||
rule_lhs_print (r, prev_rule ? prev_rule->lhs : NULL, out);
|
||||
rule_rhs_print (r, out);
|
||||
}
|
||||
|
||||
void
|
||||
ritem_print (FILE *out)
|
||||
{
|
||||
@@ -138,7 +179,7 @@ ritem_longest_rhs (void)
|
||||
int max = 0;
|
||||
for (rule_number r = 0; r < nrules; ++r)
|
||||
{
|
||||
int length = rule_rhs_length (&rules[r]);
|
||||
size_t length = rule_rhs_length (&rules[r]);
|
||||
if (length > max)
|
||||
max = length;
|
||||
}
|
||||
@@ -151,7 +192,7 @@ grammar_rules_partial_print (FILE *out, const char *title,
|
||||
rule_filter filter)
|
||||
{
|
||||
bool first = true;
|
||||
sym_content *previous_lhs = NULL;
|
||||
rule *previous_rule = NULL;
|
||||
|
||||
/* rule # : LHS -> RHS */
|
||||
for (rule_number r = 0; r < nrules + nuseless_productions; r++)
|
||||
@@ -160,13 +201,12 @@ grammar_rules_partial_print (FILE *out, const char *title,
|
||||
continue;
|
||||
if (first)
|
||||
fprintf (out, "%s\n\n", title);
|
||||
else if (previous_lhs && previous_lhs != rules[r].lhs)
|
||||
else if (previous_rule && previous_rule->lhs != rules[r].lhs)
|
||||
fputc ('\n', out);
|
||||
first = false;
|
||||
rule_lhs_print (&rules[r], previous_lhs, out);
|
||||
rule_rhs_print (&rules[r], out);
|
||||
fprintf (out, "\n");
|
||||
previous_lhs = rules[r].lhs;
|
||||
rule_print (&rules[r], previous_rule, out);
|
||||
fputc ('\n', out);
|
||||
previous_rule = &rules[r];
|
||||
}
|
||||
if (!first)
|
||||
fputs ("\n\n", out);
|
||||
@@ -189,13 +229,10 @@ grammar_rules_print_xml (FILE *out, int level)
|
||||
xml_puts (out, level + 1, "<rules>");
|
||||
first = false;
|
||||
{
|
||||
char const *usefulness;
|
||||
if (rule_useless_in_grammar_p (&rules[r]))
|
||||
usefulness = "useless-in-grammar";
|
||||
else if (rule_useless_in_parser_p (&rules[r]))
|
||||
usefulness = "useless-in-parser";
|
||||
else
|
||||
usefulness = "useful";
|
||||
char const *usefulness
|
||||
= rule_useless_in_grammar_p (&rules[r]) ? "useless-in-grammar"
|
||||
: rule_useless_in_parser_p (&rules[r]) ? "useless-in-parser"
|
||||
: "useful";
|
||||
xml_indent (out, level + 2);
|
||||
fprintf (out, "<rule number=\"%d\" usefulness=\"%s\"",
|
||||
rules[r].number, usefulness);
|
||||
@@ -238,39 +275,36 @@ grammar_dump (FILE *out, const char *title)
|
||||
fprintf (out, "Rules\n-----\n\n");
|
||||
{
|
||||
fprintf (out,
|
||||
"Num (Prec, Assoc, Useful, Ritem Range) Lhs"
|
||||
" -> Rhs (Ritem range) [Num]\n");
|
||||
for (rule_number i = 0; i < nrules + nuseless_productions; i++)
|
||||
"Num (Prec, Assoc, Useful, UselessChain) Lhs"
|
||||
" -> (Ritem Range) Rhs\n");
|
||||
for (rule_number i = 0; i < nrules + nuseless_productions; ++i)
|
||||
{
|
||||
rule const *rule_i = &rules[i];
|
||||
unsigned const rhs_itemno = rule_i->rhs - ritem;
|
||||
/* Find the last RHS index in ritems. */
|
||||
unsigned rhs_count = 0;
|
||||
for (item_number *rp = rule_i->rhs; *rp >= 0; ++rp)
|
||||
++rhs_count;
|
||||
fprintf (out, "%3d (%2d, %2d, %2d, %2u-%2u) %2d ->",
|
||||
unsigned length = rule_rhs_length (rule_i);
|
||||
aver (item_number_as_rule_number (rule_i->rhs[length] == i));
|
||||
fprintf (out, "%3d (%2d, %2d, %2s, %2s) %2d -> (%2u-%2u)",
|
||||
i,
|
||||
rule_i->prec ? rule_i->prec->prec : 0,
|
||||
rule_i->prec ? rule_i->prec->assoc : 0,
|
||||
rule_i->useful,
|
||||
rhs_itemno,
|
||||
rhs_itemno + rhs_count - 1,
|
||||
rule_i->lhs->number);
|
||||
rule_i->useful ? "t" : "f",
|
||||
rule_useless_chain_p (rule_i) ? "t" : "f",
|
||||
rule_i->lhs->number,
|
||||
rhs_itemno, rhs_itemno + length - 1);
|
||||
/* Dumped the RHS. */
|
||||
for (item_number *rp = rule_i->rhs; *rp >= 0; ++rp)
|
||||
fprintf (out, " %3d", *rp);
|
||||
fprintf (out, " [%d]\n",
|
||||
item_number_as_rule_number (rule_i->rhs[rhs_count+1]));
|
||||
for (item_number *rhsp = rule_i->rhs; 0 <= *rhsp; ++rhsp)
|
||||
fprintf (out, " %3d", *rhsp);
|
||||
fputc ('\n', out);
|
||||
}
|
||||
}
|
||||
fprintf (out, "\n\n");
|
||||
|
||||
fprintf (out, "Rules interpreted\n-----------------\n\n");
|
||||
for (rule_number r = 0; r < nrules + nuseless_productions; r++)
|
||||
for (rule_number r = 0; r < nrules + nuseless_productions; ++r)
|
||||
{
|
||||
fprintf (out, "%-5d %s:", r, rules[r].lhs->symbol->tag);
|
||||
rule_rhs_print (&rules[r], out);
|
||||
fprintf (out, "\n");
|
||||
fputc ('\n', out);
|
||||
}
|
||||
fprintf (out, "\n\n");
|
||||
}
|
||||
@@ -278,7 +312,7 @@ grammar_dump (FILE *out, const char *title)
|
||||
void
|
||||
grammar_rules_useless_report (const char *message)
|
||||
{
|
||||
for (rule_number r = 0; r < nrules ; ++r)
|
||||
for (rule_number r = 0; r < nrules; ++r)
|
||||
/* Don't complain about rules whose LHS is useless, we already
|
||||
complained about it. */
|
||||
if (!reduce_nonterminal_useless_in_grammar (rules[r].lhs)
|
||||
|
||||
+27
-9
@@ -75,7 +75,7 @@
|
||||
|
||||
RULES[R].line -- the line where R was defined.
|
||||
|
||||
RULES[R].useful -- true iff the rule is used (i.e., false if thrown
|
||||
RULES[R].useful -- whether the rule is used (i.e., false if thrown
|
||||
away by reduce).
|
||||
|
||||
The right hand side is stored as symbol numbers in a portion of
|
||||
@@ -146,7 +146,6 @@ item_number_is_symbol_number (item_number i)
|
||||
/* Rule numbers. */
|
||||
typedef int rule_number;
|
||||
# define RULE_NUMBER_MAX INT_MAX
|
||||
extern rule_number nrules;
|
||||
|
||||
static inline item_number
|
||||
rule_number_as_item_number (rule_number r)
|
||||
@@ -166,6 +165,7 @@ item_number_is_rule_number (item_number i)
|
||||
return i < 0;
|
||||
}
|
||||
|
||||
|
||||
/*--------.
|
||||
| Rules. |
|
||||
`--------*/
|
||||
@@ -192,6 +192,7 @@ typedef struct
|
||||
/* This symbol was attached to the rule via %prec. */
|
||||
sym_content *precsym;
|
||||
|
||||
/* Location of the rhs. */
|
||||
location location;
|
||||
bool useful;
|
||||
bool is_predicate;
|
||||
@@ -202,26 +203,40 @@ typedef struct
|
||||
int expected_rr_conflicts;
|
||||
|
||||
const char *action;
|
||||
location action_location;
|
||||
location action_loc;
|
||||
} rule;
|
||||
|
||||
/* The used rules (size NRULES). */
|
||||
extern rule *rules;
|
||||
extern rule_number nrules;
|
||||
|
||||
/* Get the rule associated to this item. ITEM points inside RITEM. */
|
||||
rule const *item_rule (item_number const *item);
|
||||
|
||||
/* Pretty-print this ITEM (as in the report). ITEM points inside
|
||||
RITEM. PREVIOUS_RULE is used to see if the lhs is common, in which
|
||||
case LHS is factored. Passing NULL is fine. */
|
||||
void item_print (item_number *item, rule const *previous_rule,
|
||||
FILE *out);
|
||||
|
||||
/* A function that selects a rule. */
|
||||
typedef bool (*rule_filter) (rule const *);
|
||||
|
||||
/* Return true IFF the rule has a 'number' smaller than NRULES. That is, it is
|
||||
useful in the grammar. */
|
||||
/* Whether the rule has a 'number' smaller than NRULES. That is, it
|
||||
is useful in the grammar. */
|
||||
bool rule_useful_in_grammar_p (rule const *r);
|
||||
|
||||
/* Return true IFF the rule has a 'number' higher than NRULES. That is, it is
|
||||
/* Whether the rule has a 'number' higher than NRULES. That is, it is
|
||||
useless in the grammar. */
|
||||
bool rule_useless_in_grammar_p (rule const *r);
|
||||
|
||||
/* Return true IFF the rule is not flagged as useful but is useful in the
|
||||
/* Whether the rule is not flagged as useful but is useful in the
|
||||
grammar. In other words, it was discarded because of conflicts. */
|
||||
bool rule_useless_in_parser_p (rule const *r);
|
||||
|
||||
/* Whether the rule has a single RHS, and no user action. */
|
||||
bool rule_useless_chain_p (rule const *r);
|
||||
|
||||
/* Print this rule's number and lhs on OUT. If a PREVIOUS_LHS was
|
||||
already displayed (by a previous call for another rule), avoid
|
||||
useless repetitions. */
|
||||
@@ -229,12 +244,15 @@ void rule_lhs_print (rule const *r, sym_content const *previous_lhs,
|
||||
FILE *out);
|
||||
void rule_lhs_print_xml (rule const *r, FILE *out, int level);
|
||||
|
||||
/* Return the length of the RHS. */
|
||||
/* The length of the RHS. */
|
||||
size_t rule_rhs_length (rule const *r);
|
||||
|
||||
/* Print this rule's RHS on OUT. */
|
||||
void rule_rhs_print (rule const *r, FILE *out);
|
||||
|
||||
/* Print this rule on OUT. If a PREVIOUS_RULE was already displayed,
|
||||
avoid useless repetitions of their LHS. */
|
||||
void rule_print (rule const *r, rule const *prev_rule, FILE *out);
|
||||
|
||||
|
||||
|
||||
@@ -252,7 +270,7 @@ extern int max_user_token_number;
|
||||
/* Dump RITEM for traces. */
|
||||
void ritem_print (FILE *out);
|
||||
|
||||
/* Return the size of the longest rule RHS. */
|
||||
/* The size of the longest rule RHS. */
|
||||
size_t ritem_longest_rhs (void);
|
||||
|
||||
/* Print the grammar's rules that match FILTER on OUT under TITLE. */
|
||||
|
||||
+3
-5
@@ -159,6 +159,9 @@ output_red (state const *s, reductions const *reds, FILE *fout)
|
||||
bitset no_reduce_set;
|
||||
no_reduce_bitset_init (s, &no_reduce_set);
|
||||
|
||||
rule *default_reduction
|
||||
= yydefact[s->number] ? &rules[yydefact[s->number] - 1] : NULL;
|
||||
|
||||
/* Two obstacks are needed: one for the enabled reductions, and one
|
||||
for the disabled reductions, because in the end we want two
|
||||
separate edges, even though in most cases only one will actually
|
||||
@@ -171,11 +174,6 @@ output_red (state const *s, reductions const *reds, FILE *fout)
|
||||
const int source = s->number;
|
||||
for (int j = 0; j < reds->num; ++j)
|
||||
{
|
||||
rule *default_reduction =
|
||||
yydefact[s->number]
|
||||
? &rules[yydefact[s->number] - 1]
|
||||
: NULL;
|
||||
|
||||
bool defaulted = default_reduction && default_reduction == reds->rules[j];
|
||||
|
||||
/* Build the lookahead tokens lists, one for enabled transitions
|
||||
|
||||
+59
-35
@@ -36,7 +36,36 @@
|
||||
#include "symtab.h"
|
||||
|
||||
/** Records the value of the \%define variable lr.type. */
|
||||
typedef enum { LR_TYPE__LALR, LR_TYPE__IELR, LR_TYPE__CANONICAL_LR } LrType;
|
||||
typedef enum
|
||||
{
|
||||
LR_TYPE__LR0,
|
||||
LR_TYPE__LALR,
|
||||
LR_TYPE__IELR,
|
||||
LR_TYPE__CANONICAL_LR
|
||||
} LrType;
|
||||
|
||||
/* The user's requested LR type. */
|
||||
static LrType
|
||||
lr_type_get (void)
|
||||
{
|
||||
char *type = muscle_percent_define_get ("lr.type");
|
||||
LrType res;
|
||||
if (STREQ (type, "lr""(0)"))
|
||||
res = LR_TYPE__LR0;
|
||||
else if (STREQ (type, "lalr"))
|
||||
res = LR_TYPE__LALR;
|
||||
else if (STREQ (type, "ielr"))
|
||||
res = LR_TYPE__IELR;
|
||||
else if (STREQ (type, "canonical-lr"))
|
||||
res = LR_TYPE__CANONICAL_LR;
|
||||
else
|
||||
{
|
||||
aver (false);
|
||||
abort ();
|
||||
}
|
||||
free (type);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* \post:
|
||||
@@ -167,10 +196,7 @@ ielr_compute_internal_follow_edges (bitset ritem_sees_lookahead_set,
|
||||
relation_transpose (edgesp, ngotos);
|
||||
|
||||
if (trace_flag & trace_ielr)
|
||||
{
|
||||
fprintf (stderr, "internal_follow_edges:\n");
|
||||
relation_print (*edgesp, ngotos, stderr);
|
||||
}
|
||||
relation_print ("internal_follow_edges", *edgesp, ngotos, NULL, stderr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,7 +241,7 @@ ielr_compute_follow_kernel_items (bitset ritem_sees_lookahead_set,
|
||||
&& bitset_test (ritem_sees_lookahead_set, items[j]))
|
||||
bitset_set ((*follow_kernel_itemsp)[i], j);
|
||||
}
|
||||
relation_digraph (internal_follow_edges, ngotos, follow_kernel_itemsp);
|
||||
relation_digraph (internal_follow_edges, ngotos, *follow_kernel_itemsp);
|
||||
|
||||
if (trace_flag & trace_ielr)
|
||||
{
|
||||
@@ -271,12 +297,11 @@ ielr_compute_always_follows (goto_number ***edgesp,
|
||||
}
|
||||
free (edge_array);
|
||||
}
|
||||
relation_digraph (*edgesp, ngotos, always_followsp);
|
||||
relation_digraph (*edgesp, ngotos, *always_followsp);
|
||||
|
||||
if (trace_flag & trace_ielr)
|
||||
{
|
||||
fprintf (stderr, "always follow edges:\n");
|
||||
relation_print (*edgesp, ngotos, stderr);
|
||||
relation_print ("always follow edges", *edgesp, ngotos, NULL, stderr);
|
||||
fprintf (stderr, "always_follows:\n");
|
||||
debug_bitsetv (*always_followsp);
|
||||
}
|
||||
@@ -540,7 +565,7 @@ typedef struct state_list
|
||||
/**
|
||||
* nextIsocore is the next state in a circularly linked-list of all states
|
||||
* with the same core. The one originally computed by generate_states in
|
||||
* LR0.c is lr0Isocore.
|
||||
* lr0.c is lr0Isocore.
|
||||
*/
|
||||
struct state_list *lr0Isocore;
|
||||
struct state_list *nextIsocore;
|
||||
@@ -1051,41 +1076,40 @@ ielr_split_states (bitsetv follow_kernel_items, bitsetv always_follows,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ielr (void)
|
||||
{
|
||||
LrType lr_type;
|
||||
|
||||
/* Examine user options. */
|
||||
{
|
||||
char *type = muscle_percent_define_get ("lr.type");
|
||||
if (STREQ (type, "lalr"))
|
||||
lr_type = LR_TYPE__LALR;
|
||||
else if (STREQ (type, "ielr"))
|
||||
lr_type = LR_TYPE__IELR;
|
||||
else if (STREQ (type, "canonical-lr"))
|
||||
lr_type = LR_TYPE__CANONICAL_LR;
|
||||
else
|
||||
{
|
||||
aver (false);
|
||||
abort ();
|
||||
}
|
||||
free (type);
|
||||
}
|
||||
LrType lr_type = lr_type_get ();
|
||||
|
||||
/* Phase 0: LALR(1). */
|
||||
timevar_push (tv_lalr);
|
||||
if (lr_type == LR_TYPE__CANONICAL_LR)
|
||||
set_goto_map ();
|
||||
else
|
||||
lalr ();
|
||||
if (lr_type == LR_TYPE__LALR)
|
||||
switch (lr_type)
|
||||
{
|
||||
case LR_TYPE__LR0:
|
||||
timevar_push (tv_lalr);
|
||||
set_goto_map ();
|
||||
timevar_pop (tv_lalr);
|
||||
return;
|
||||
|
||||
case LR_TYPE__CANONICAL_LR:
|
||||
timevar_push (tv_lalr);
|
||||
set_goto_map ();
|
||||
timevar_pop (tv_lalr);
|
||||
break;
|
||||
|
||||
case LR_TYPE__LALR:
|
||||
timevar_push (tv_lalr);
|
||||
lalr ();
|
||||
bitsetv_free (goto_follows);
|
||||
timevar_pop (tv_lalr);
|
||||
return;
|
||||
|
||||
case LR_TYPE__IELR:
|
||||
timevar_push (tv_lalr);
|
||||
lalr ();
|
||||
timevar_pop (tv_lalr);
|
||||
break;
|
||||
}
|
||||
timevar_pop (tv_lalr);
|
||||
|
||||
{
|
||||
bitsetv follow_kernel_items;
|
||||
|
||||
+244
-110
@@ -28,18 +28,19 @@
|
||||
#include <bitset.h>
|
||||
#include <bitsetv.h>
|
||||
|
||||
#include "LR0.h"
|
||||
#include "complain.h"
|
||||
#include "derives.h"
|
||||
#include "getargs.h"
|
||||
#include "gram.h"
|
||||
#include "lalr.h"
|
||||
#include "lr0.h"
|
||||
#include "muscle-tab.h"
|
||||
#include "nullable.h"
|
||||
#include "reader.h"
|
||||
#include "relation.h"
|
||||
#include "symtab.h"
|
||||
|
||||
/* goto_map[nterm - NTOKENS] -> number of gotos. */
|
||||
goto_number *goto_map = NULL;
|
||||
goto_number ngotos = 0;
|
||||
state_number *from_state = NULL;
|
||||
@@ -53,8 +54,16 @@ typedef struct goto_list
|
||||
goto_number value;
|
||||
} goto_list;
|
||||
|
||||
static goto_list *
|
||||
goto_list_new (goto_number value, struct goto_list *next)
|
||||
{
|
||||
goto_list *res = xmalloc (sizeof *res);
|
||||
res->next = next;
|
||||
res->value = value;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* LA is an NLA by NTOKENS matrix of bits. LA[l, i] is 1 if the rule
|
||||
/* LA is an nLA by NTOKENS matrix of bits. LA[l, i] is 1 if the rule
|
||||
LArule[l] is applicable in the appropriate state when the next
|
||||
token is symbol i. If LA[l, i] and LA[l, j] are both 1 for i != j,
|
||||
it is a conflict. */
|
||||
@@ -63,31 +72,48 @@ static bitsetv LA = NULL;
|
||||
size_t nLA;
|
||||
|
||||
|
||||
/* "(p, A) includes (p', B)" iff
|
||||
B → βAγ, γ nullable, and p'-- β --> p (i.e., state p' reaches p on label β).
|
||||
|
||||
Definition p.621 [DeRemer 1982].
|
||||
|
||||
INCLUDES[(p, A)] = [(p', B),...] */
|
||||
static goto_number **includes;
|
||||
|
||||
/* "(q, A → ω) lookback (p, A)" iff state p reaches state q on label ω.
|
||||
|
||||
Definition p.621 [DeRemer 1982]. */
|
||||
static goto_list **lookback;
|
||||
|
||||
static void
|
||||
goto_print (goto_number i, FILE *out)
|
||||
{
|
||||
const state_number src = from_state[i];
|
||||
const state_number dst = to_state[i];
|
||||
symbol_number var = states[dst]->accessing_symbol;
|
||||
fprintf (out,
|
||||
"goto[%ld] = (%d, %s, %d)", i, src, symbols[var]->tag, dst);
|
||||
}
|
||||
|
||||
void
|
||||
set_goto_map (void)
|
||||
{
|
||||
goto_number *temp_map = xnmalloc (nvars + 1, sizeof *temp_map);
|
||||
|
||||
/* Count the number of gotos (ngotos) per nterm (goto_map). */
|
||||
goto_map = xcalloc (nvars + 1, sizeof *goto_map);
|
||||
ngotos = 0;
|
||||
for (state_number s = 0; s < nstates; ++s)
|
||||
{
|
||||
transitions *sp = states[s]->transitions;
|
||||
for (int i = sp->num - 1; i >= 0 && TRANSITION_IS_GOTO (sp, i); --i)
|
||||
transitions *trans = states[s]->transitions;
|
||||
for (int i = trans->num - 1; 0 <= i && TRANSITION_IS_GOTO (trans, i); --i)
|
||||
{
|
||||
ngotos++;
|
||||
|
||||
/* Abort if (ngotos + 1) would overflow. */
|
||||
aver (ngotos != GOTO_NUMBER_MAXIMUM);
|
||||
|
||||
goto_map[TRANSITION_SYMBOL (sp, i) - ntokens]++;
|
||||
goto_map[TRANSITION_SYMBOL (trans, i) - ntokens]++;
|
||||
}
|
||||
}
|
||||
|
||||
goto_number *temp_map = xnmalloc (nvars + 1, sizeof *temp_map);
|
||||
{
|
||||
goto_number k = 0;
|
||||
for (symbol_number i = ntokens; i < nsyms; ++i)
|
||||
@@ -108,21 +134,28 @@ set_goto_map (void)
|
||||
|
||||
for (state_number s = 0; s < nstates; ++s)
|
||||
{
|
||||
const transitions *sp = states[s]->transitions;
|
||||
for (int i = sp->num - 1; i >= 0 && TRANSITION_IS_GOTO (sp, i); --i)
|
||||
const transitions *trans = states[s]->transitions;
|
||||
for (int i = trans->num - 1; 0 <= i && TRANSITION_IS_GOTO (trans, i); --i)
|
||||
{
|
||||
goto_number k = temp_map[TRANSITION_SYMBOL (sp, i) - ntokens]++;
|
||||
goto_number k = temp_map[TRANSITION_SYMBOL (trans, i) - ntokens]++;
|
||||
from_state[k] = s;
|
||||
to_state[k] = sp->states[i]->number;
|
||||
to_state[k] = trans->states[i]->number;
|
||||
}
|
||||
}
|
||||
|
||||
free (temp_map);
|
||||
|
||||
if (trace_flag & trace_automaton)
|
||||
for (int i = 0; i < ngotos; ++i)
|
||||
{
|
||||
goto_print (i, stderr);
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
goto_number
|
||||
map_goto (state_number s0, symbol_number sym)
|
||||
map_goto (state_number src, symbol_number sym)
|
||||
{
|
||||
goto_number low = goto_map[sym - ntokens];
|
||||
goto_number high = goto_map[sym - ntokens + 1] - 1;
|
||||
@@ -132,39 +165,62 @@ map_goto (state_number s0, symbol_number sym)
|
||||
aver (low <= high);
|
||||
goto_number middle = (low + high) / 2;
|
||||
state_number s = from_state[middle];
|
||||
if (s == s0)
|
||||
if (s == src)
|
||||
return middle;
|
||||
else if (s < s0)
|
||||
else if (s < src)
|
||||
low = middle + 1;
|
||||
else
|
||||
high = middle - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Print FOLLOWS for debugging. */
|
||||
static void
|
||||
initialize_F (void)
|
||||
follows_print (const char* title, FILE *out)
|
||||
{
|
||||
fprintf (out, "%s:\n", title);
|
||||
for (goto_number i = 0; i < ngotos; ++i)
|
||||
{
|
||||
fputs (" FOLLOWS[", out);
|
||||
goto_print (i, out);
|
||||
fputs ("] =", out);
|
||||
bitset_iterator iter;
|
||||
symbol_number sym;
|
||||
BITSET_FOR_EACH (iter, goto_follows[i], sym, 0)
|
||||
fprintf (out, " %s", symbols[sym]->tag);
|
||||
fputc ('\n', out);
|
||||
}
|
||||
fputc ('\n', out);
|
||||
}
|
||||
|
||||
/* Build goto_follows. */
|
||||
static void
|
||||
initialize_goto_follows (void)
|
||||
{
|
||||
goto_number **reads = xnmalloc (ngotos, sizeof *reads);
|
||||
goto_number *edge = xnmalloc (ngotos + 1, sizeof *edge);
|
||||
goto_number nedges = 0;
|
||||
goto_number *edge = xnmalloc (ngotos, sizeof *edge);
|
||||
|
||||
goto_follows = bitsetv_create (ngotos, ntokens, BITSET_FIXED);
|
||||
|
||||
for (goto_number i = 0; i < ngotos; ++i)
|
||||
{
|
||||
state_number stateno = to_state[i];
|
||||
const transitions *sp = states[stateno]->transitions;
|
||||
state_number dst = to_state[i];
|
||||
const transitions *trans = states[dst]->transitions;
|
||||
|
||||
int j;
|
||||
FOR_EACH_SHIFT (sp, j)
|
||||
bitset_set (goto_follows[i], TRANSITION_SYMBOL (sp, j));
|
||||
FOR_EACH_SHIFT (trans, j)
|
||||
bitset_set (goto_follows[i], TRANSITION_SYMBOL (trans, j));
|
||||
|
||||
for (; j < sp->num; ++j)
|
||||
/* Gotos outgoing from DST. */
|
||||
goto_number nedges = 0;
|
||||
for (; j < trans->num; ++j)
|
||||
{
|
||||
symbol_number sym = TRANSITION_SYMBOL (sp, j);
|
||||
symbol_number sym = TRANSITION_SYMBOL (trans, j);
|
||||
if (nullable[sym - ntokens])
|
||||
edge[nedges++] = map_goto (stateno, sym);
|
||||
{
|
||||
assert (nedges < ngotos);
|
||||
edge[nedges++] = map_goto (dst, sym);
|
||||
}
|
||||
}
|
||||
|
||||
if (nedges == 0)
|
||||
@@ -174,82 +230,164 @@ initialize_F (void)
|
||||
reads[i] = xnmalloc (nedges + 1, sizeof reads[i][0]);
|
||||
memcpy (reads[i], edge, nedges * sizeof edge[0]);
|
||||
reads[i][nedges] = END_NODE;
|
||||
nedges = 0;
|
||||
}
|
||||
}
|
||||
if (trace_flag & trace_automaton)
|
||||
{
|
||||
follows_print ("follows after shifts", stderr);
|
||||
relation_print ("reads", reads, ngotos, goto_print, stderr);
|
||||
}
|
||||
|
||||
relation_digraph (reads, ngotos, &goto_follows);
|
||||
relation_digraph (reads, ngotos, goto_follows);
|
||||
if (trace_flag & trace_automaton)
|
||||
follows_print ("follows after read", stderr);
|
||||
|
||||
for (goto_number i = 0; i < ngotos; ++i)
|
||||
free (reads[i]);
|
||||
|
||||
free (reads);
|
||||
free (edge);
|
||||
}
|
||||
|
||||
|
||||
/* Find the state which LOOKBACK[LOOKBACK_INDEX] is about. */
|
||||
static const state *
|
||||
lookback_find_state (int lookback_index)
|
||||
{
|
||||
state *res = NULL;
|
||||
for (int j = 0; j < nstates; ++j)
|
||||
if (states[j]->reductions
|
||||
&& states[j]->reductions->lookahead_tokens)
|
||||
{
|
||||
if (states[j]->reductions->lookahead_tokens - LA > lookback_index)
|
||||
/* Went too far. */
|
||||
break;
|
||||
else
|
||||
res = states[j];
|
||||
}
|
||||
/* Pacify "potential null pointer dereference" warning. */
|
||||
if (!res)
|
||||
abort ();
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Print LOOKBACK for debugging. */
|
||||
static void
|
||||
add_lookback_edge (state *s, rule *r, goto_number gotono)
|
||||
lookback_print (FILE *out)
|
||||
{
|
||||
fputs ("lookback:\n", out);
|
||||
for (int i = 0; i < nLA; ++i)
|
||||
if (lookback[i])
|
||||
{
|
||||
fprintf (out, " %3d = ", i);
|
||||
const state *s = lookback_find_state (i);
|
||||
int rnum = i - (s->reductions->lookahead_tokens - LA);
|
||||
const rule *r = s->reductions->rules[rnum];
|
||||
fprintf (out, "(%3d, ", s->number);
|
||||
rule_print (r, NULL, out);
|
||||
fputs (") ->", out);
|
||||
for (goto_list *sp = lookback[i]; sp; sp = sp->next)
|
||||
{
|
||||
fputc (' ', out);
|
||||
goto_print (sp->value, out);
|
||||
}
|
||||
fputc ('\n', out);
|
||||
}
|
||||
fputc ('\n', out);
|
||||
}
|
||||
|
||||
/* Add (S, R) -> GOTONO to LOOKBACK.
|
||||
|
||||
"(q, A → ω) lookback (p, A)" iff state p reaches state q on label ω.
|
||||
|
||||
The goto number GOTONO, whose source is S (which is
|
||||
inconsistent), */
|
||||
static void
|
||||
add_lookback_edge (state *s, rule const *r, goto_number gotono)
|
||||
{
|
||||
int ri = state_reduction_find (s, r);
|
||||
goto_list *sp = xmalloc (sizeof *sp);
|
||||
sp->next = lookback[(s->reductions->lookahead_tokens - LA) + ri];
|
||||
sp->value = gotono;
|
||||
lookback[(s->reductions->lookahead_tokens - LA) + ri] = sp;
|
||||
int idx = (s->reductions->lookahead_tokens - LA) + ri;
|
||||
lookback[idx] = goto_list_new (gotono, lookback[idx]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Compute INCLUDES and LOOKBACK. Corresponds to step E in Sec. 6 of
|
||||
[DeRemer 1982]. */
|
||||
static void
|
||||
build_relations (void)
|
||||
{
|
||||
goto_number *edge = xnmalloc (ngotos + 1, sizeof *edge);
|
||||
state_number *states1 = xnmalloc (ritem_longest_rhs () + 1, sizeof *states1);
|
||||
goto_number *edge = xnmalloc (ngotos, sizeof *edge);
|
||||
state_number *path = xnmalloc (ritem_longest_rhs () + 1, sizeof *path);
|
||||
|
||||
includes = xnmalloc (ngotos, sizeof *includes);
|
||||
|
||||
/* For each goto (from SRC to DST labeled by nterm VAR), iterate
|
||||
over each rule with VAR as LHS, and find the path PATH from SRC
|
||||
labeled with the RHS of the rule. */
|
||||
for (goto_number i = 0; i < ngotos; ++i)
|
||||
{
|
||||
const state_number src = from_state[i];
|
||||
const state_number dst = to_state[i];
|
||||
symbol_number var = states[dst]->accessing_symbol;
|
||||
|
||||
/* Size of EDGE. */
|
||||
int nedges = 0;
|
||||
symbol_number symbol1 = states[to_state[i]]->accessing_symbol;
|
||||
|
||||
for (rule **rulep = derives[symbol1 - ntokens]; *rulep; rulep++)
|
||||
for (rule **rulep = derives[var - ntokens]; *rulep; ++rulep)
|
||||
{
|
||||
rule const *r = *rulep;
|
||||
state *s = states[src];
|
||||
path[0] = s->number;
|
||||
|
||||
/* Length of PATH. */
|
||||
int length = 1;
|
||||
item_number const *rp;
|
||||
state *s = states[from_state[i]];
|
||||
states1[0] = s->number;
|
||||
|
||||
for (rp = (*rulep)->rhs; ! item_number_is_rule_number (*rp); rp++)
|
||||
for (item_number const *rp = r->rhs; 0 <= *rp; rp++)
|
||||
{
|
||||
s = transitions_to (s->transitions,
|
||||
item_number_as_symbol_number (*rp));
|
||||
states1[length++] = s->number;
|
||||
symbol_number sym = item_number_as_symbol_number (*rp);
|
||||
s = transitions_to (s, sym);
|
||||
path[length++] = s->number;
|
||||
}
|
||||
|
||||
/* S is the end of PATH. */
|
||||
if (!s->consistent)
|
||||
add_lookback_edge (s, *rulep, i);
|
||||
add_lookback_edge (s, r, i);
|
||||
|
||||
length--;
|
||||
bool done = false;
|
||||
while (!done)
|
||||
/* Walk back PATH from penultimate to beginning.
|
||||
|
||||
The "0 <= p" part is actually useless: each rhs ends in a
|
||||
rule number (for which ISVAR(...) is false), and there is
|
||||
a sentinel (ritem[-1]=0) before the first rhs. */
|
||||
for (int p = length - 2; 0 <= p && ISVAR (r->rhs[p]); --p)
|
||||
{
|
||||
done = true;
|
||||
/* Each rhs ends in a rule number, and there is a
|
||||
sentinel (ritem[-1]=0) before the first rhs, so it is safe to
|
||||
decrement RP here. */
|
||||
rp--;
|
||||
if (ISVAR (*rp))
|
||||
{
|
||||
/* Downcasting from item_number to symbol_number. */
|
||||
edge[nedges++] = map_goto (states1[--length],
|
||||
item_number_as_symbol_number (*rp));
|
||||
if (nullable[*rp - ntokens])
|
||||
done = false;
|
||||
}
|
||||
symbol_number sym = item_number_as_symbol_number (r->rhs[p]);
|
||||
goto_number g = map_goto (path[p], sym);
|
||||
/* Insert G if not already in EDGE.
|
||||
FIXME: linear search. A bitset instead? */
|
||||
{
|
||||
bool found = false;
|
||||
for (int j = 0; !found && j < nedges; ++j)
|
||||
found = edge[j] == g;
|
||||
if (!found)
|
||||
{
|
||||
assert (nedges < ngotos);
|
||||
edge[nedges++] = g;
|
||||
}
|
||||
}
|
||||
if (!nullable[sym - ntokens])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (trace_flag & trace_automaton)
|
||||
{
|
||||
goto_print (i, stderr);
|
||||
fputs (" edges = ", stderr);
|
||||
for (int j = 0; j < nedges; ++j)
|
||||
{
|
||||
fputc (' ', stderr);
|
||||
goto_print (edge[j], stderr);
|
||||
}
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
|
||||
if (nedges == 0)
|
||||
includes[i] = NULL;
|
||||
else
|
||||
@@ -262,21 +400,22 @@ build_relations (void)
|
||||
}
|
||||
|
||||
free (edge);
|
||||
free (states1);
|
||||
free (path);
|
||||
|
||||
relation_transpose (&includes, ngotos);
|
||||
if (trace_flag & trace_automaton)
|
||||
relation_print ("includes", includes, ngotos, goto_print, stderr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Compute FOLLOWS from INCLUDES, and free INCLUDES. */
|
||||
static void
|
||||
compute_FOLLOWS (void)
|
||||
compute_follows (void)
|
||||
{
|
||||
relation_digraph (includes, ngotos, &goto_follows);
|
||||
|
||||
relation_digraph (includes, ngotos, goto_follows);
|
||||
if (trace_flag & trace_sets)
|
||||
follows_print ("follows after includes", stderr);
|
||||
for (goto_number i = 0; i < ngotos; ++i)
|
||||
free (includes[i]);
|
||||
|
||||
free (includes);
|
||||
}
|
||||
|
||||
@@ -284,6 +423,9 @@ compute_FOLLOWS (void)
|
||||
static void
|
||||
compute_lookahead_tokens (void)
|
||||
{
|
||||
if (trace_flag & trace_automaton)
|
||||
lookback_print (stderr);
|
||||
|
||||
for (size_t i = 0; i < nLA; ++i)
|
||||
for (goto_list *sp = lookback[i]; sp; sp = sp->next)
|
||||
bitset_or (LA[i], LA[i], goto_follows[sp->value]);
|
||||
@@ -291,7 +433,6 @@ compute_lookahead_tokens (void)
|
||||
/* Free LOOKBACK. */
|
||||
for (size_t i = 0; i < nLA; ++i)
|
||||
LIST_FREE (goto_list, lookback[i]);
|
||||
|
||||
free (lookback);
|
||||
}
|
||||
|
||||
@@ -304,16 +445,15 @@ compute_lookahead_tokens (void)
|
||||
static int
|
||||
state_lookahead_tokens_count (state *s, bool default_reduction_only_for_accept)
|
||||
{
|
||||
int n_lookahead_tokens = 0;
|
||||
reductions *rp = s->reductions;
|
||||
transitions *sp = s->transitions;
|
||||
const reductions *reds = s->reductions;
|
||||
const transitions *trans = s->transitions;
|
||||
|
||||
/* Transitions are only disabled during conflict resolution, and that
|
||||
hasn't happened yet, so there should be no need to check that
|
||||
transition 0 hasn't been disabled before checking if it is a shift.
|
||||
However, this check was performed at one time, so we leave it as an
|
||||
aver. */
|
||||
aver (sp->num == 0 || !TRANSITION_IS_DISABLED (sp, 0));
|
||||
aver (trans->num == 0 || !TRANSITION_IS_DISABLED (trans, 0));
|
||||
|
||||
/* We need a lookahead either to distinguish different reductions
|
||||
(i.e., there are two or more), or to distinguish a reduction from a
|
||||
@@ -323,15 +463,13 @@ state_lookahead_tokens_count (state *s, bool default_reduction_only_for_accept)
|
||||
a lookahead token that makes sense there, and so no lookahead token
|
||||
should be read) if the user has otherwise disabled default
|
||||
reductions. */
|
||||
if (rp->num > 1
|
||||
|| (rp->num == 1 && sp->num && TRANSITION_IS_SHIFT (sp, 0))
|
||||
|| (rp->num == 1 && rp->rules[0]->number != 0
|
||||
&& default_reduction_only_for_accept))
|
||||
n_lookahead_tokens += rp->num;
|
||||
else
|
||||
s->consistent = true;
|
||||
s->consistent =
|
||||
!(reds->num > 1
|
||||
|| (reds->num == 1 && trans->num && TRANSITION_IS_SHIFT (trans, 0))
|
||||
|| (reds->num == 1 && reds->rules[0]->number != 0
|
||||
&& default_reduction_only_for_accept));
|
||||
|
||||
return n_lookahead_tokens;
|
||||
return s->consistent ? 0 : reds->num;
|
||||
}
|
||||
|
||||
|
||||
@@ -385,32 +523,28 @@ initialize_LA (void)
|
||||
static void
|
||||
lookahead_tokens_print (FILE *out)
|
||||
{
|
||||
fprintf (out, "Lookahead tokens: BEGIN\n");
|
||||
fputs ("Lookaheads:\n", out);
|
||||
for (state_number i = 0; i < nstates; ++i)
|
||||
{
|
||||
const reductions *reds = states[i]->reductions;
|
||||
int n_lookahead_tokens = 0;
|
||||
|
||||
if (reds->lookahead_tokens)
|
||||
for (int j = 0; j < reds->num; ++j)
|
||||
if (reds->lookahead_tokens[j])
|
||||
++n_lookahead_tokens;
|
||||
|
||||
fprintf (out, "State %d: %d lookahead tokens\n",
|
||||
i, n_lookahead_tokens);
|
||||
|
||||
if (reds->lookahead_tokens)
|
||||
for (int j = 0; j < reds->num; ++j)
|
||||
{
|
||||
bitset_iterator iter;
|
||||
int k;
|
||||
BITSET_FOR_EACH (iter, reds->lookahead_tokens[j], k, 0)
|
||||
fprintf (out, " on %d (%s) -> rule %d\n",
|
||||
k, symbols[k]->tag,
|
||||
reds->rules[j]->number);
|
||||
}
|
||||
if (reds->num)
|
||||
{
|
||||
fprintf (out, " State %d:\n", i);
|
||||
for (int j = 0; j < reds->num; ++j)
|
||||
{
|
||||
fprintf (out, " rule %d:", reds->rules[j]->number);
|
||||
if (reds->lookahead_tokens)
|
||||
{
|
||||
bitset_iterator iter;
|
||||
int k;
|
||||
BITSET_FOR_EACH (iter, reds->lookahead_tokens[j], k, 0)
|
||||
fprintf (out, " %s", symbols[k]->tag);
|
||||
}
|
||||
fputc ('\n', out);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf (out, "Lookahead tokens: END\n");
|
||||
fputc ('\n', out);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -418,10 +552,10 @@ lalr (void)
|
||||
{
|
||||
initialize_LA ();
|
||||
set_goto_map ();
|
||||
initialize_F ();
|
||||
initialize_goto_follows ();
|
||||
lookback = xcalloc (nLA, sizeof *lookback);
|
||||
build_relations ();
|
||||
compute_FOLLOWS ();
|
||||
compute_follows ();
|
||||
compute_lookahead_tokens ();
|
||||
|
||||
if (trace_flag & trace_sets)
|
||||
|
||||
+4
-5
@@ -83,8 +83,8 @@ typedef size_t goto_number;
|
||||
/** Index into #from_state and #to_state.
|
||||
|
||||
All the transitions that accept a particular variable are grouped
|
||||
together and GOTO_MAP[I - NTOKENS] is the index in FROM_STATE and
|
||||
TO_STATE of the first of them. */
|
||||
together in FROM_STATE and TO_STATE, with indexes from GOTO_MAP[I -
|
||||
NTOKENS] to GOTO_MAP[I - NTOKENS + 1] - 1 (including both). */
|
||||
extern goto_number *goto_map;
|
||||
|
||||
/** The size of #from_state and #to_state. */
|
||||
@@ -96,11 +96,10 @@ extern state_number *from_state;
|
||||
/** State number it leads to. */
|
||||
extern state_number *to_state;
|
||||
|
||||
/** Map a state/symbol pair into its numeric representation. */
|
||||
goto_number map_goto (state_number s0, symbol_number sym);
|
||||
/** The number of the goto from state SRC labeled with nterm SYM. */
|
||||
goto_number map_goto (state_number src, symbol_number sym);
|
||||
|
||||
/* goto_follows[i] is the set of tokens following goto i. */
|
||||
extern bitsetv goto_follows;
|
||||
|
||||
|
||||
#endif /* !LALR_H_ */
|
||||
|
||||
+7
-6
@@ -30,8 +30,6 @@ src_bison_SOURCES = \
|
||||
src/AnnotationList.h \
|
||||
src/InadequacyList.c \
|
||||
src/InadequacyList.h \
|
||||
src/LR0.c \
|
||||
src/LR0.h \
|
||||
src/Sbitset.c \
|
||||
src/Sbitset.h \
|
||||
src/assoc.c \
|
||||
@@ -55,12 +53,14 @@ src_bison_SOURCES = \
|
||||
src/gram.h \
|
||||
src/graphviz.c \
|
||||
src/graphviz.h \
|
||||
src/lalr.c \
|
||||
src/lalr.h \
|
||||
src/ielr.c \
|
||||
src/ielr.h \
|
||||
src/lalr.c \
|
||||
src/lalr.h \
|
||||
src/location.c \
|
||||
src/location.h \
|
||||
src/lr0.c \
|
||||
src/lr0.h \
|
||||
src/main.c \
|
||||
src/muscle-tab.c \
|
||||
src/muscle-tab.h \
|
||||
@@ -71,12 +71,12 @@ src_bison_SOURCES = \
|
||||
src/output.c \
|
||||
src/output.h \
|
||||
src/parse-gram.y \
|
||||
src/print-graph.c \
|
||||
src/print-graph.h \
|
||||
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 \
|
||||
@@ -126,6 +126,7 @@ src_bison_LDADD = \
|
||||
$(LIBTHREAD) \
|
||||
$(LIB_CLOCK_GETTIME) \
|
||||
$(LIB_GETHRXTIME) \
|
||||
$(LIBTEXTSTYLE) \
|
||||
lib/libbison.a
|
||||
|
||||
|
||||
|
||||
+161
-84
@@ -23,33 +23,27 @@
|
||||
|
||||
#include <mbswidth.h>
|
||||
#include <quotearg.h>
|
||||
#include <stdio.h> /* fileno */
|
||||
#include <sys/stat.h> /* fstat */
|
||||
|
||||
#include "complain.h"
|
||||
#include "getargs.h"
|
||||
#include "location.h"
|
||||
|
||||
location const empty_location = EMPTY_LOCATION_INIT;
|
||||
location const empty_loc = EMPTY_LOCATION_INIT;
|
||||
|
||||
/* If BUF is null, add BUFSIZE (which in this case must be less than
|
||||
INT_MAX) to COLUMN; otherwise, add mbsnwidth (BUF, BUFSIZE, 0) to
|
||||
COLUMN. If an overflow occurs, or might occur but is undetectable,
|
||||
return INT_MAX. Assume COLUMN is nonnegative. */
|
||||
COLUMN. If an overflow occurs, return INT_MAX. */
|
||||
|
||||
static inline int
|
||||
add_column_width (int column, char const *buf, size_t bufsize)
|
||||
{
|
||||
size_t width;
|
||||
unsigned remaining_columns = INT_MAX - column;
|
||||
|
||||
if (buf)
|
||||
{
|
||||
if (INT_MAX / 2 <= bufsize)
|
||||
return INT_MAX;
|
||||
width = mbsnwidth (buf, bufsize, 0);
|
||||
}
|
||||
else
|
||||
width = bufsize;
|
||||
|
||||
return width <= remaining_columns ? column + width : INT_MAX;
|
||||
int width
|
||||
= buf ? mbsnwidth (buf, bufsize, 0)
|
||||
: INT_MAX <= bufsize ? INT_MAX
|
||||
: bufsize;
|
||||
return column <= INT_MAX - width ? column + width : INT_MAX;
|
||||
}
|
||||
|
||||
/* Set *LOC and adjust scanner cursor to account for token TOKEN of
|
||||
@@ -60,18 +54,20 @@ location_compute (location *loc, boundary *cur, char const *token, size_t size)
|
||||
{
|
||||
int line = cur->line;
|
||||
int column = cur->column;
|
||||
int byte = cur->byte;
|
||||
char const *p0 = token;
|
||||
char const *p = token;
|
||||
char const *lim = token + size;
|
||||
|
||||
loc->start = *cur;
|
||||
|
||||
for (p = token; p < lim; p++)
|
||||
for (p = token; p < lim; ++p)
|
||||
switch (*p)
|
||||
{
|
||||
case '\n':
|
||||
line += line < INT_MAX;
|
||||
column = 1;
|
||||
byte = 1;
|
||||
p0 = p + 1;
|
||||
break;
|
||||
|
||||
@@ -79,14 +75,17 @@ location_compute (location *loc, boundary *cur, char const *token, size_t size)
|
||||
column = add_column_width (column, p0, p - p0);
|
||||
column = add_column_width (column, NULL, 8 - ((column - 1) & 7));
|
||||
p0 = p + 1;
|
||||
byte += byte < INT_MAX;
|
||||
break;
|
||||
|
||||
default:
|
||||
byte += byte < INT_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
cur->line = line;
|
||||
cur->column = column = add_column_width (column, p0, p - p0);
|
||||
cur->byte = byte;
|
||||
|
||||
loc->end = *cur;
|
||||
|
||||
@@ -94,44 +93,62 @@ location_compute (location *loc, boundary *cur, char const *token, size_t size)
|
||||
complain (loc, Wother, _("line number overflow"));
|
||||
if (column == INT_MAX && loc->start.column != INT_MAX)
|
||||
complain (loc, Wother, _("column number overflow"));
|
||||
if (byte == INT_MAX && loc->start.byte != INT_MAX)
|
||||
complain (loc, Wother, _("byte number overflow"));
|
||||
}
|
||||
|
||||
static unsigned
|
||||
boundary_print (boundary const *b, FILE *out)
|
||||
{
|
||||
return fprintf (out, "%s:%d.%d@%d",
|
||||
quotearg_n_style (3, escape_quoting_style, b->file),
|
||||
b->line, b->column, b->byte);
|
||||
}
|
||||
|
||||
unsigned
|
||||
location_print (location loc, FILE *out)
|
||||
{
|
||||
unsigned res = 0;
|
||||
int end_col = 0 != loc.end.column ? loc.end.column - 1 : 0;
|
||||
res += fprintf (out, "%s",
|
||||
quotearg_n_style (3, escape_quoting_style, loc.start.file));
|
||||
if (0 <= loc.start.line)
|
||||
if (trace_flag & trace_locations)
|
||||
{
|
||||
res += fprintf (out, ":%d", loc.start.line);
|
||||
if (0 <= loc.start.column)
|
||||
res += fprintf (out, ".%d", loc.start.column);
|
||||
res += boundary_print (&loc.start, out);
|
||||
res += fprintf (out, "-");
|
||||
res += boundary_print (&loc.end, out);
|
||||
}
|
||||
if (loc.start.file != loc.end.file)
|
||||
else
|
||||
{
|
||||
res += fprintf (out, "-%s",
|
||||
quotearg_n_style (3, escape_quoting_style,
|
||||
loc.end.file));
|
||||
if (0 <= loc.end.line)
|
||||
int end_col = 0 != loc.end.column ? loc.end.column - 1 : 0;
|
||||
res += fprintf (out, "%s",
|
||||
quotearg_n_style (3, escape_quoting_style, loc.start.file));
|
||||
if (0 <= loc.start.line)
|
||||
{
|
||||
res += fprintf (out, ":%d", loc.end.line);
|
||||
if (0 <= end_col)
|
||||
res += fprintf (out, ".%d", end_col);
|
||||
res += fprintf (out, ":%d", loc.start.line);
|
||||
if (0 <= loc.start.column)
|
||||
res += fprintf (out, ".%d", loc.start.column);
|
||||
}
|
||||
}
|
||||
else if (0 <= loc.end.line)
|
||||
{
|
||||
if (loc.start.line < loc.end.line)
|
||||
if (loc.start.file != loc.end.file)
|
||||
{
|
||||
res += fprintf (out, "-%d", loc.end.line);
|
||||
if (0 <= end_col)
|
||||
res += fprintf (out, ".%d", end_col);
|
||||
res += fprintf (out, "-%s",
|
||||
quotearg_n_style (3, escape_quoting_style,
|
||||
loc.end.file));
|
||||
if (0 <= loc.end.line)
|
||||
{
|
||||
res += fprintf (out, ":%d", loc.end.line);
|
||||
if (0 <= end_col)
|
||||
res += fprintf (out, ".%d", end_col);
|
||||
}
|
||||
}
|
||||
else if (0 <= loc.end.line)
|
||||
{
|
||||
if (loc.start.line < loc.end.line)
|
||||
{
|
||||
res += fprintf (out, "-%d", loc.end.line);
|
||||
if (0 <= end_col)
|
||||
res += fprintf (out, ".%d", end_col);
|
||||
}
|
||||
else if (0 <= end_col && loc.start.column < end_col)
|
||||
res += fprintf (out, "-%d", end_col);
|
||||
}
|
||||
else if (0 <= end_col && loc.start.column < end_col)
|
||||
res += fprintf (out, "-%d", end_col);
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -140,34 +157,63 @@ location_print (location loc, FILE *out)
|
||||
|
||||
/* Persistent data used by location_caret to avoid reopening and rereading the
|
||||
same file all over for each error. */
|
||||
struct caret_info
|
||||
static struct
|
||||
{
|
||||
FILE *source;
|
||||
/* The last file we tried to open. If non NULL, but SOURCE is NULL,
|
||||
it means this file is special and should not be quoted. */
|
||||
uniqstr file;
|
||||
size_t line;
|
||||
/* Offset in SOURCE where line LINE starts. */
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
static struct caret_info caret_info = { NULL, 1, 0 };
|
||||
} caret_info;
|
||||
|
||||
void
|
||||
cleanup_caret ()
|
||||
caret_free ()
|
||||
{
|
||||
if (caret_info.source)
|
||||
fclose (caret_info.source);
|
||||
caret_info.source = NULL;
|
||||
caret_info.line = 1;
|
||||
caret_info.offset = 0;
|
||||
{
|
||||
fclose (caret_info.source);
|
||||
caret_info.source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
location_caret (location loc, FILE *out)
|
||||
location_caret (location loc, const char *style, FILE *out)
|
||||
{
|
||||
/* FIXME: find a way to support multifile locations, and only open once each
|
||||
file. That would make the procedure future-proof. */
|
||||
if (! (caret_info.source
|
||||
|| (caret_info.source = fopen (loc.start.file, "r")))
|
||||
|| loc.start.column == -1 || loc.start.line == -1)
|
||||
if (loc.start.column == -1 || loc.start.line == -1)
|
||||
return;
|
||||
/* If a different source than before, close and let the rest open
|
||||
the new one. */
|
||||
if (caret_info.file && caret_info.file != loc.start.file)
|
||||
{
|
||||
caret_free ();
|
||||
caret_info.file = NULL;
|
||||
}
|
||||
if (!caret_info.file)
|
||||
{
|
||||
caret_info.file = loc.start.file;
|
||||
if ((caret_info.source = fopen (caret_info.file, "r")))
|
||||
{
|
||||
/* If the file is not regular (imagine #line 1 "/dev/stdin"
|
||||
in the input file for instance), don't try to quote the
|
||||
source. Keep caret_info.file set so that we don't try to
|
||||
open it again, but leave caret_info.source NULL so that
|
||||
we don't try to quote it. */
|
||||
struct stat buf;
|
||||
if (fstat (fileno (caret_info.source), &buf) == 0
|
||||
&& buf.st_mode & S_IFREG)
|
||||
{
|
||||
caret_info.line = 1;
|
||||
caret_info.offset = 0;
|
||||
}
|
||||
else
|
||||
caret_free ();
|
||||
}
|
||||
}
|
||||
if (!caret_info.source)
|
||||
return;
|
||||
|
||||
|
||||
/* If the line we want to quote is seekable (the same line as the previous
|
||||
location), just seek it. If it was a previous line, we lost track of it,
|
||||
@@ -192,25 +238,44 @@ location_caret (location loc, FILE *out)
|
||||
int c = getc (caret_info.source);
|
||||
if (c != EOF)
|
||||
{
|
||||
/* Quote the file, indent by a single column. */
|
||||
putc (' ', out);
|
||||
do
|
||||
putc (c, out);
|
||||
while ((c = getc (caret_info.source)) != EOF && c != '\n');
|
||||
/* Quote the file (at most the first line in the case of
|
||||
multiline locations). */
|
||||
fprintf (out, "%5d | ", loc.start.line);
|
||||
bool single_line = loc.start.line == loc.end.line;
|
||||
/* Consider that single point location (with equal boundaries)
|
||||
actually denote the character that they follow. */
|
||||
int byte_end = loc.end.byte +
|
||||
(single_line && loc.start.byte == loc.end.byte);
|
||||
/* Byte number. */
|
||||
int byte = 1;
|
||||
while (c != EOF && c != '\n')
|
||||
{
|
||||
if (byte == loc.start.byte)
|
||||
begin_use_class (style, out);
|
||||
fputc (c, out);
|
||||
c = getc (caret_info.source);
|
||||
++byte;
|
||||
if (single_line
|
||||
? byte == byte_end
|
||||
: c == '\n' || c == EOF)
|
||||
end_use_class (style, out);
|
||||
}
|
||||
putc ('\n', out);
|
||||
|
||||
{
|
||||
/* The caret of a multiline location ends with the first line. */
|
||||
size_t len = loc.start.line != loc.end.line
|
||||
? ftell (caret_info.source) - caret_info.offset
|
||||
: loc.end.column;
|
||||
int i;
|
||||
|
||||
/* Print the carets (at least one), with the same indent as above.*/
|
||||
fprintf (out, " %*s", loc.start.column - 1, "");
|
||||
for (i = loc.start.column; i == loc.start.column || i < len; ++i)
|
||||
putc (i == loc.start.column ? '^' : '~', out);
|
||||
}
|
||||
/* Print the carets with the same indentation as above. */
|
||||
fprintf (out, " | %*s", loc.start.column - 1, "");
|
||||
begin_use_class (style, out);
|
||||
putc ('^', out);
|
||||
/* Underlining a multiline location ends with the first
|
||||
line. */
|
||||
int len = single_line
|
||||
? loc.end.column
|
||||
: ftell (caret_info.source) - caret_info.offset;
|
||||
for (int i = loc.start.column + 1; i < len; ++i)
|
||||
putc ('~', out);
|
||||
end_use_class (style, out);
|
||||
}
|
||||
putc ('\n', out);
|
||||
}
|
||||
}
|
||||
@@ -224,17 +289,29 @@ location_empty (location loc)
|
||||
}
|
||||
|
||||
void
|
||||
boundary_set_from_string (boundary *bound, char *loc_str)
|
||||
boundary_set_from_string (boundary *bound, char *str)
|
||||
{
|
||||
/* Must search in reverse since the file name field may
|
||||
* contain '.' or ':'. */
|
||||
char *delim = strrchr (loc_str, '.');
|
||||
aver (delim);
|
||||
*delim = '\0';
|
||||
bound->column = atoi (delim+1);
|
||||
delim = strrchr (loc_str, ':');
|
||||
aver (delim);
|
||||
*delim = '\0';
|
||||
bound->line = atoi (delim+1);
|
||||
bound->file = uniqstr_new (loc_str);
|
||||
/* Must search in reverse since the file name field may contain '.'
|
||||
or ':'. */
|
||||
char *at = strrchr (str, '@');
|
||||
if (at)
|
||||
{
|
||||
*at = '\0';
|
||||
bound->byte = atoi (at+1);
|
||||
}
|
||||
{
|
||||
char *dot = strrchr (str, '.');
|
||||
aver (dot);
|
||||
*dot = '\0';
|
||||
bound->column = atoi (dot+1);
|
||||
if (!at)
|
||||
bound->byte = bound->column;
|
||||
}
|
||||
{
|
||||
char *colon = strrchr (str, ':');
|
||||
aver (colon);
|
||||
*colon = '\0';
|
||||
bound->line = atoi (colon+1);
|
||||
}
|
||||
bound->file = uniqstr_new (str);
|
||||
}
|
||||
|
||||
+18
-11
@@ -49,15 +49,21 @@ typedef struct
|
||||
*/
|
||||
int column;
|
||||
|
||||
/* If nonnegative, (origin-0) bytes number in the current line.
|
||||
Never displayed, used when printing error messages with colors to
|
||||
know where colors start and ends. */
|
||||
int byte;
|
||||
|
||||
} boundary;
|
||||
|
||||
/* Set the position of \a a. */
|
||||
/* Set the position of \a p. */
|
||||
static inline void
|
||||
boundary_set (boundary *b, const char *f, int l, int c)
|
||||
boundary_set (boundary *p, const char *f, int l, int c, int b)
|
||||
{
|
||||
b->file = f;
|
||||
b->line = l;
|
||||
b->column = c;
|
||||
p->file = f;
|
||||
p->line = l;
|
||||
p->column = c;
|
||||
p->byte = b;
|
||||
}
|
||||
|
||||
/* Return -1, 0, 1, depending whether a is before, equal, or
|
||||
@@ -95,8 +101,8 @@ typedef struct
|
||||
|
||||
# define GRAM_LTYPE location
|
||||
|
||||
# define EMPTY_LOCATION_INIT {{NULL, 0, 0}, {NULL, 0, 0}}
|
||||
extern location const empty_location;
|
||||
# define EMPTY_LOCATION_INIT {{NULL, 0, 0, 0}, {NULL, 0, 0, 0}}
|
||||
extern location const empty_loc;
|
||||
|
||||
/* Set *LOC and adjust scanner cursor to account for token TOKEN of
|
||||
size SIZE. */
|
||||
@@ -110,10 +116,10 @@ unsigned location_print (location loc, FILE *out);
|
||||
|
||||
/* Free any allocated resources and close any open file handles that are
|
||||
left-over by the usage of location_caret. */
|
||||
void cleanup_caret (void);
|
||||
void caret_free (void);
|
||||
|
||||
/* Output to OUT the line and caret corresponding to location LOC. */
|
||||
void location_caret (location loc, FILE *out);
|
||||
void location_caret (location loc, const char* style, FILE *out);
|
||||
|
||||
/* Return -1, 0, 1, depending whether a is before, equal, or
|
||||
after b. */
|
||||
@@ -129,7 +135,8 @@ location_cmp (location a, location b)
|
||||
/* Whether this is the empty location. */
|
||||
bool location_empty (location loc);
|
||||
|
||||
/* LOC_STR must be formatted as 'file:line.column', it will be modified. */
|
||||
void boundary_set_from_string (boundary *bound, char *loc_str);
|
||||
/* STR must be formatted as 'file:line.column@byte' or 'file:line.column',
|
||||
it will be modified. */
|
||||
void boundary_set_from_string (boundary *bound, char *str);
|
||||
|
||||
#endif /* ! defined LOCATION_H_ */
|
||||
|
||||
+84
-53
@@ -27,12 +27,12 @@
|
||||
|
||||
#include <bitset.h>
|
||||
|
||||
#include "LR0.h"
|
||||
#include "closure.h"
|
||||
#include "complain.h"
|
||||
#include "getargs.h"
|
||||
#include "gram.h"
|
||||
#include "lalr.h"
|
||||
#include "lr0.h"
|
||||
#include "reader.h"
|
||||
#include "reduce.h"
|
||||
#include "state.h"
|
||||
@@ -47,6 +47,16 @@ typedef struct state_list
|
||||
static state_list *first_state = NULL;
|
||||
static state_list *last_state = NULL;
|
||||
|
||||
/* Print CORE for debugging. */
|
||||
static void
|
||||
core_print (size_t core_size, item_number *core, FILE *out)
|
||||
{
|
||||
for (int i = 0; i < core_size; ++i)
|
||||
{
|
||||
item_print (ritem + core[i], NULL, out);
|
||||
fputc ('\n', out);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------.
|
||||
| A state was just discovered from another state. Queue it for |
|
||||
@@ -57,14 +67,14 @@ static state *
|
||||
state_list_append (symbol_number sym, size_t core_size, item_number *core)
|
||||
{
|
||||
state_list *node = xmalloc (sizeof *node);
|
||||
state *s = state_new (sym, core_size, core);
|
||||
state *res = state_new (sym, core_size, core);
|
||||
|
||||
if (trace_flag & trace_automaton)
|
||||
fprintf (stderr, "state_list_append (state = %d, symbol = %d (%s))\n",
|
||||
nstates, sym, symbols[sym]->tag);
|
||||
|
||||
node->next = NULL;
|
||||
node->state = s;
|
||||
node->state = res;
|
||||
|
||||
if (!first_state)
|
||||
first_state = node;
|
||||
@@ -72,17 +82,28 @@ state_list_append (symbol_number sym, size_t core_size, item_number *core)
|
||||
last_state->next = node;
|
||||
last_state = node;
|
||||
|
||||
return s;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int nshifts;
|
||||
static symbol_number *shift_symbol;
|
||||
/* Symbols that can be "shifted" (including non terminals) from the
|
||||
current state. */
|
||||
bitset shift_symbol;
|
||||
|
||||
static rule **redset;
|
||||
/* For the current state, the list of pointers to states that can be
|
||||
reached via a shift/goto. Could be indexed by the reaching symbol,
|
||||
but labels of incoming transitions can be recovered by the state
|
||||
itself. */
|
||||
static state **shiftset;
|
||||
|
||||
|
||||
/* KERNEL_BASE[symbol-number] -> list of item numbers (offsets inside
|
||||
RITEM) of lenngth KERNEL_SIZE[symbol-number]. */
|
||||
static item_number **kernel_base;
|
||||
static int *kernel_size;
|
||||
|
||||
/* A single dimension array that serves as storage for
|
||||
KERNEL_BASE. */
|
||||
static item_number *kernel_items;
|
||||
|
||||
|
||||
@@ -98,10 +119,11 @@ allocate_itemsets (void)
|
||||
sizeof *symbol_count);
|
||||
|
||||
for (rule_number r = 0; r < nrules; ++r)
|
||||
for (item_number *rhsp = rules[r].rhs; *rhsp >= 0; ++rhsp)
|
||||
for (item_number *rhsp = rules[r].rhs; 0 <= *rhsp; ++rhsp)
|
||||
{
|
||||
count++;
|
||||
symbol_count[*rhsp]++;
|
||||
symbol_number sym = item_number_as_symbol_number (*rhsp);
|
||||
count += 1;
|
||||
symbol_count[sym] += 1;
|
||||
}
|
||||
|
||||
/* See comments before new_itemsets. All the vectors of items
|
||||
@@ -124,6 +146,17 @@ allocate_itemsets (void)
|
||||
kernel_size = xnmalloc (nsyms, sizeof *kernel_size);
|
||||
}
|
||||
|
||||
/* Print the current kernel (in KERNEL_BASE). */
|
||||
static void
|
||||
kernel_print (FILE *out)
|
||||
{
|
||||
for (symbol_number i = 0; i < nsyms; ++i)
|
||||
if (kernel_size[i])
|
||||
{
|
||||
fprintf (out, "kernel[%s] =\n", symbols[i]->tag);
|
||||
core_print (kernel_size[i], kernel_base[i], out);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
allocate_storage (void)
|
||||
@@ -133,14 +166,14 @@ allocate_storage (void)
|
||||
shiftset = xnmalloc (nsyms, sizeof *shiftset);
|
||||
redset = xnmalloc (nrules, sizeof *redset);
|
||||
state_hash_new ();
|
||||
shift_symbol = xnmalloc (nsyms, sizeof *shift_symbol);
|
||||
shift_symbol = bitset_create (nsyms, BITSET_FIXED);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_storage (void)
|
||||
{
|
||||
free (shift_symbol);
|
||||
bitset_free (shift_symbol);
|
||||
free (redset);
|
||||
free (shiftset);
|
||||
free (kernel_base);
|
||||
@@ -152,44 +185,44 @@ free_storage (void)
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------.
|
||||
| Find which symbols can be shifted in S, and for each one |
|
||||
| record which items would be active after that shift. Uses the |
|
||||
| contents of itemset. |
|
||||
| |
|
||||
| shift_symbol is set to a vector of the symbols that can be |
|
||||
| shifted. For each symbol in the grammar, kernel_base[symbol] |
|
||||
| points to a vector of item numbers activated if that symbol is |
|
||||
| shifted, and kernel_size[symbol] is their numbers. |
|
||||
| |
|
||||
| itemset is sorted on item index in ritem, which is sorted on |
|
||||
| rule number. Compute each kernel_base[symbol] with the same |
|
||||
| sort. |
|
||||
`---------------------------------------------------------------*/
|
||||
/*------------------------------------------------------------------.
|
||||
| Find which term/nterm symbols can be "shifted" in S, and for each |
|
||||
| one record which items would be active after that transition. |
|
||||
| Uses the contents of itemset. |
|
||||
| |
|
||||
| shift_symbol is a bitset of the term/nterm symbols that can be |
|
||||
| shifted. For each symbol in the grammar, kernel_base[symbol] |
|
||||
| points to a vector of item numbers activated if that symbol is |
|
||||
| shifted, and kernel_size[symbol] is their numbers. |
|
||||
| |
|
||||
| itemset is sorted on item index in ritem, which is sorted on rule |
|
||||
| number. Compute each kernel_base[symbol] with the same sort. |
|
||||
`------------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
new_itemsets (state *s)
|
||||
{
|
||||
if (trace_flag & trace_automaton)
|
||||
fprintf (stderr, "Entering new_itemsets, state = %d\n", s->number);
|
||||
fprintf (stderr, "new_itemsets: begin: state = %d\n", s->number);
|
||||
|
||||
memset (kernel_size, 0, nsyms * sizeof *kernel_size);
|
||||
|
||||
nshifts = 0;
|
||||
bitset_zero (shift_symbol);
|
||||
|
||||
for (size_t i = 0; i < nitemset; ++i)
|
||||
if (item_number_is_symbol_number (ritem[itemset[i]]))
|
||||
{
|
||||
symbol_number sym = item_number_as_symbol_number (ritem[itemset[i]]);
|
||||
if (!kernel_size[sym])
|
||||
{
|
||||
shift_symbol[nshifts] = sym;
|
||||
nshifts++;
|
||||
}
|
||||
|
||||
bitset_set (shift_symbol, sym);
|
||||
kernel_base[sym][kernel_size[sym]] = itemset[i] + 1;
|
||||
kernel_size[sym]++;
|
||||
}
|
||||
|
||||
if (trace_flag & trace_automaton)
|
||||
{
|
||||
kernel_print (stderr);
|
||||
fprintf (stderr, "new_itemsets: end: state = %d\n\n", s->number);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -204,8 +237,12 @@ static state *
|
||||
get_state (symbol_number sym, size_t core_size, item_number *core)
|
||||
{
|
||||
if (trace_flag & trace_automaton)
|
||||
fprintf (stderr, "Entering get_state, symbol = %d (%s)\n",
|
||||
sym, symbols[sym]->tag);
|
||||
{
|
||||
fprintf (stderr, "Entering get_state, symbol = %d (%s), core:\n",
|
||||
sym, symbols[sym]->tag);
|
||||
core_print (core_size, core, stderr);
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
|
||||
state *s = state_hash_lookup (core_size, core);
|
||||
if (!s)
|
||||
@@ -228,24 +265,19 @@ static void
|
||||
append_states (state *s)
|
||||
{
|
||||
if (trace_flag & trace_automaton)
|
||||
fprintf (stderr, "Entering append_states, state = %d\n", s->number);
|
||||
fprintf (stderr, "append_states: begin: state = %d\n", s->number);
|
||||
|
||||
/* First sort shift_symbol into increasing order. */
|
||||
|
||||
for (int i = 1; i < nshifts; i++)
|
||||
bitset_iterator iter;
|
||||
symbol_number sym;
|
||||
int i = 0;
|
||||
BITSET_FOR_EACH (iter, shift_symbol, sym, 0)
|
||||
{
|
||||
const symbol_number sym = shift_symbol[i];
|
||||
int j = i;
|
||||
for (; 0 < j && sym < shift_symbol[j - 1]; j--)
|
||||
shift_symbol[j] = shift_symbol[j - 1];
|
||||
shift_symbol[j] = sym;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nshifts; i++)
|
||||
{
|
||||
const symbol_number sym = shift_symbol[i];
|
||||
shiftset[i] = get_state (sym, kernel_size[sym], kernel_base[sym]);
|
||||
++i;
|
||||
}
|
||||
|
||||
if (trace_flag & trace_automaton)
|
||||
fprintf (stderr, "append_states: end: state = %d\n", s->number);
|
||||
}
|
||||
|
||||
|
||||
@@ -324,7 +356,7 @@ void
|
||||
generate_states (void)
|
||||
{
|
||||
allocate_storage ();
|
||||
new_closure (nritems);
|
||||
closure_new (nritems);
|
||||
|
||||
/* Create the initial state. The 0 at the lhs is the index of the
|
||||
item of this initial rule. */
|
||||
@@ -344,18 +376,17 @@ generate_states (void)
|
||||
closure (s->items, s->nitems);
|
||||
/* Record the reductions allowed out of this state. */
|
||||
save_reductions (s);
|
||||
/* Find the itemsets of the states that shifts can reach. */
|
||||
/* Find the itemsets of the states that shifts/gotos can reach. */
|
||||
new_itemsets (s);
|
||||
/* Find or create the core structures for those states. */
|
||||
append_states (s);
|
||||
|
||||
/* Create the shifts structures for the shifts to those states,
|
||||
now that the state numbers transitioning to are known. */
|
||||
state_transitions_set (s, nshifts, shiftset);
|
||||
state_transitions_set (s, bitset_count (shift_symbol), shiftset);
|
||||
}
|
||||
|
||||
/* discard various storage */
|
||||
free_closure ();
|
||||
free_storage ();
|
||||
|
||||
/* Set up STATES. */
|
||||
+17
-13
@@ -23,14 +23,14 @@
|
||||
|
||||
#include <bitset.h>
|
||||
#include <bitset/stats.h>
|
||||
#include <closeout.h>
|
||||
#include <configmake.h>
|
||||
#include <progname.h>
|
||||
#include <quote.h>
|
||||
#include <quotearg.h>
|
||||
#include <relocatable.h> /* relocate2 */
|
||||
#include <timevar.h>
|
||||
|
||||
#include "LR0.h"
|
||||
#include "closeout.h"
|
||||
#include "complain.h"
|
||||
#include "conflicts.h"
|
||||
#include "derives.h"
|
||||
@@ -38,15 +38,15 @@
|
||||
#include "fixits.h"
|
||||
#include "getargs.h"
|
||||
#include "gram.h"
|
||||
#include "lalr.h"
|
||||
#include "ielr.h"
|
||||
#include "lalr.h"
|
||||
#include "lr0.h"
|
||||
#include "muscle-tab.h"
|
||||
#include "nullable.h"
|
||||
#include "output.h"
|
||||
#include "print.h"
|
||||
#include "print_graph.h"
|
||||
#include "print-graph.h"
|
||||
#include "print-xml.h"
|
||||
#include <quote.h>
|
||||
#include "print.h"
|
||||
#include "reader.h"
|
||||
#include "reduce.h"
|
||||
#include "scan-code.h"
|
||||
@@ -66,11 +66,12 @@ main (int argc, char *argv[])
|
||||
{
|
||||
char *cp = NULL;
|
||||
char const *localedir = relocate2 (LOCALEDIR, &cp);
|
||||
(void) bindtextdomain (PACKAGE, localedir);
|
||||
(void) bindtextdomain ("bison-runtime", localedir);
|
||||
bindtextdomain ("bison", localedir);
|
||||
bindtextdomain ("bison-gnulib", localedir);
|
||||
bindtextdomain ("bison-runtime", localedir);
|
||||
free (cp);
|
||||
}
|
||||
(void) textdomain (PACKAGE);
|
||||
textdomain ("bison");
|
||||
|
||||
{
|
||||
char const *cp = getenv ("LC_CTYPE");
|
||||
@@ -155,7 +156,10 @@ main (int argc, char *argv[])
|
||||
|
||||
print_precedence_warnings ();
|
||||
|
||||
if (!update_flag)
|
||||
/* Whether to generate output files. */
|
||||
bool generate = !(feature_flag & feature_syntax_only);
|
||||
|
||||
if (generate)
|
||||
{
|
||||
/* Output file names. */
|
||||
compute_output_file_names ();
|
||||
@@ -196,7 +200,7 @@ main (int argc, char *argv[])
|
||||
timevar_pop (tv_free);
|
||||
|
||||
/* Output the tables and the parser to ftable. In file output. */
|
||||
if (!update_flag)
|
||||
if (generate)
|
||||
{
|
||||
timevar_push (tv_parser);
|
||||
output ();
|
||||
@@ -231,8 +235,6 @@ main (int argc, char *argv[])
|
||||
timevar_stop (tv_total);
|
||||
timevar_print (stderr);
|
||||
|
||||
cleanup_caret ();
|
||||
|
||||
/* Fix input file now, even if there are errors: that's less
|
||||
warnings in the following runs. */
|
||||
if (!fixits_empty ())
|
||||
@@ -246,5 +248,7 @@ main (int argc, char *argv[])
|
||||
}
|
||||
uniqstrs_free ();
|
||||
|
||||
complain_free ();
|
||||
|
||||
return complaint_status ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
+9
-11
@@ -211,7 +211,7 @@ muscle_syncline_grow (char const *key, location loc)
|
||||
obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
|
||||
obstack_quote (&muscle_obstack,
|
||||
quotearg_style (c_quoting_style, loc.start.file));
|
||||
obstack_sgrow (&muscle_obstack, ")[");
|
||||
obstack_sgrow (&muscle_obstack, ")dnl\n[");
|
||||
char const *extension = obstack_finish0 (&muscle_obstack);
|
||||
muscle_grow (key, extension, "", "");
|
||||
obstack_free (&muscle_obstack, extension);
|
||||
@@ -227,7 +227,7 @@ void
|
||||
muscle_code_grow (const char *key, const char *val, location loc)
|
||||
{
|
||||
muscle_syncline_grow (key, loc);
|
||||
muscle_grow (key, val, "\n", "\n");
|
||||
muscle_grow (key, val, "", "\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -275,18 +275,14 @@ muscle_boundary_grow (char const *key, boundary bound)
|
||||
{
|
||||
obstack_sgrow (&muscle_obstack, "[[");
|
||||
obstack_escape (&muscle_obstack, bound.file);
|
||||
obstack_printf (&muscle_obstack, ":%d.%d]]", bound.line, bound.column);
|
||||
obstack_printf (&muscle_obstack, ":%d.%d@@%d]]", bound.line, bound.column, bound.byte);
|
||||
char const *extension = obstack_finish0 (&muscle_obstack);
|
||||
muscle_grow (key, extension, "", "");
|
||||
obstack_free (&muscle_obstack, extension);
|
||||
}
|
||||
|
||||
|
||||
/* In the format '[[file_name:line.column]], [[file_name:line.column]]',
|
||||
append LOC to MUSCLE. Use digraphs for special characters in each
|
||||
file name. */
|
||||
|
||||
static void
|
||||
void
|
||||
muscle_location_grow (char const *key, location loc)
|
||||
{
|
||||
muscle_boundary_grow (key, loc.start);
|
||||
@@ -714,9 +710,11 @@ muscle_percent_define_default (char const *variable, char const *value)
|
||||
{
|
||||
uniqstr loc_name = muscle_name (variable, "loc");
|
||||
location loc;
|
||||
loc.start.file = loc.end.file = "<default value>";
|
||||
loc.start.line = loc.end.line = -1;
|
||||
loc.start.column = loc.end.column = -1;
|
||||
loc.start.file = "<default value>";
|
||||
loc.start.line = -1;
|
||||
loc.start.column = -1;
|
||||
loc.start.byte = -1;
|
||||
loc.end = loc.start;
|
||||
muscle_insert (loc_name, "");
|
||||
muscle_location_grow (loc_name, loc);
|
||||
}
|
||||
|
||||
@@ -119,6 +119,11 @@ void muscle_pair_list_grow (const char *muscle,
|
||||
void muscle_user_name_list_grow (char const *key, char const *user_name,
|
||||
location loc);
|
||||
|
||||
/* In the format '[[file_name:line.column]], [[file_name:line.column]]',
|
||||
append LOC to MUSCLE. Use digraphs for special characters in each
|
||||
file name. */
|
||||
void muscle_location_grow (char const *key, location loc);
|
||||
|
||||
/* Indicates whether a variable's value was specified with -D/--define, with
|
||||
-F/--force-define, or in the grammar file. */
|
||||
typedef enum {
|
||||
|
||||
+21
-28
@@ -21,12 +21,10 @@
|
||||
#include <config.h>
|
||||
#include "system.h"
|
||||
|
||||
#include <configmake.h>
|
||||
#include <filename.h> /* IS_PATH_WITH_DIR */
|
||||
#include <get-errno.h>
|
||||
#include <path-join.h>
|
||||
#include <quotearg.h>
|
||||
#include <relocatable.h> /* relocate2 */
|
||||
#include <spawn-pipe.h>
|
||||
#include <timevar.h>
|
||||
#include <wait-process.h>
|
||||
@@ -38,6 +36,7 @@
|
||||
#include "muscle-tab.h"
|
||||
#include "output.h"
|
||||
#include "reader.h"
|
||||
#include "reduce.h"
|
||||
#include "scan-code.h" /* max_left_semantic_context */
|
||||
#include "scan-skel.h"
|
||||
#include "symtab.h"
|
||||
@@ -45,9 +44,6 @@
|
||||
|
||||
static struct obstack format_obstack;
|
||||
|
||||
/* Memory allocated by relocate2, to free. */
|
||||
static char *relocate_buffer = NULL;
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------.
|
||||
| Create a function NAME which associates to the muscle NAME the |
|
||||
@@ -137,9 +133,8 @@ string_output (FILE *out, char const *string)
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------.
|
||||
| Prepare the symbols names. |
|
||||
`----------------------------*/
|
||||
/* Generate the b4_<MUSCLE_NAME> (e.g., b4_tname) table with the
|
||||
symbol names (aka tags). */
|
||||
|
||||
static void
|
||||
prepare_symbol_names (char const *muscle_name)
|
||||
@@ -377,9 +372,9 @@ user_actions_output (FILE *out)
|
||||
{
|
||||
fprintf (out, "%s(%d, [b4_syncline(%d, ",
|
||||
rules[r].is_predicate ? "b4_predicate_case" : "b4_case",
|
||||
r + 1, rules[r].action_location.start.line);
|
||||
string_output (out, rules[r].action_location.start.file);
|
||||
fprintf (out, ")\n[ %s]])\n\n", rules[r].action);
|
||||
r + 1, rules[r].action_loc.start.line);
|
||||
string_output (out, rules[r].action_loc.start.file);
|
||||
fprintf (out, ")dnl\n[ %s]])\n\n", rules[r].action);
|
||||
}
|
||||
fputs ("])\n\n", out);
|
||||
}
|
||||
@@ -414,6 +409,14 @@ merger_output (FILE *out)
|
||||
static void
|
||||
prepare_symbol_definitions (void)
|
||||
{
|
||||
/* Map "orig NUM" to new numbers. See data/README. */
|
||||
for (symbol_number i = ntokens; i < nsyms + nuseless_nonterminals; ++i)
|
||||
{
|
||||
obstack_printf (&format_obstack, "symbol(orig %d, number)", i);
|
||||
const char *key = obstack_finish0 (&format_obstack);
|
||||
MUSCLE_INSERT_INT (key, nterm_map ? nterm_map[i - ntokens] : i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nsyms; ++i)
|
||||
{
|
||||
symbol *sym = symbols[i];
|
||||
@@ -430,13 +433,13 @@ prepare_symbol_definitions (void)
|
||||
key = obstack_finish0 (&format_obstack);
|
||||
|
||||
/* Whether the symbol has an identifier. */
|
||||
const char *value = symbol_id_get (sym);
|
||||
const char *id = symbol_id_get (sym);
|
||||
SET_KEY ("has_id");
|
||||
MUSCLE_INSERT_INT (key, !!value);
|
||||
MUSCLE_INSERT_INT (key, !!id);
|
||||
|
||||
/* Its identifier. */
|
||||
SET_KEY ("id");
|
||||
MUSCLE_INSERT_STRING (key, value ? value : "");
|
||||
MUSCLE_INSERT_STRING (key, id ? id : "");
|
||||
|
||||
/* Its tag. Typically for documentation purpose. */
|
||||
SET_KEY ("tag");
|
||||
@@ -475,6 +478,9 @@ prepare_symbol_definitions (void)
|
||||
SET_KEY2 (pname, "line");
|
||||
MUSCLE_INSERT_INT (key, p->location.start.line);
|
||||
|
||||
SET_KEY2 (pname, "loc");
|
||||
muscle_location_grow (key, p->location);
|
||||
|
||||
SET_KEY (pname);
|
||||
MUSCLE_INSERT_STRING_RAW (key, p->code);
|
||||
}
|
||||
@@ -676,7 +682,7 @@ prepare (void)
|
||||
#define DEFINE(Name) MUSCLE_INSERT_STRING (#Name, Name ? Name : "")
|
||||
DEFINE (dir_prefix);
|
||||
DEFINE (parser_file_name);
|
||||
DEFINE (spec_defines_file);
|
||||
DEFINE (spec_header_file);
|
||||
DEFINE (spec_file_prefix);
|
||||
DEFINE (spec_graph_file);
|
||||
DEFINE (spec_name_prefix);
|
||||
@@ -728,17 +734,4 @@ output (void)
|
||||
unlink_generated_sources ();
|
||||
|
||||
obstack_free (&format_obstack, NULL);
|
||||
free (relocate_buffer);
|
||||
}
|
||||
|
||||
char const *
|
||||
pkgdatadir (void)
|
||||
{
|
||||
if (relocate_buffer)
|
||||
return relocate_buffer;
|
||||
else
|
||||
{
|
||||
char const *cp = getenv ("BISON_PKGDATADIR");
|
||||
return cp ? cp : relocate2 (PKGDATADIR, &relocate_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,4 @@
|
||||
/* Output the parsing tables and the parser code to FTABLE. */
|
||||
void output (void);
|
||||
|
||||
/* Where our data files are installed. */
|
||||
char const *pkgdatadir (void);
|
||||
|
||||
#endif /* !OUTPUT_H_ */
|
||||
|
||||
+252
-752
File diff suppressed because it is too large
Load Diff
+25
-30
@@ -1,4 +1,4 @@
|
||||
/* A Bison parser, made by GNU Bison 3.2.90.23-0bbcb-dirty. */
|
||||
/* A Bison parser, made by GNU Bison 3.3.2.153-f5a4-dirty. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
@@ -52,11 +52,9 @@
|
||||
extern int gram_debug;
|
||||
#endif
|
||||
/* "%code requires" blocks. */
|
||||
#line 21 "src/parse-gram.y" /* yacc.c:1921 */
|
||||
|
||||
#include "symlist.h"
|
||||
#include "symtab.h"
|
||||
#line 239 "src/parse-gram.y" /* yacc.c:1921 */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -65,7 +63,6 @@ extern int gram_debug;
|
||||
param_parse = 1 << 1,
|
||||
param_both = param_lex | param_parse
|
||||
} param_type;
|
||||
#line 682 "src/parse-gram.y" /* yacc.c:1921 */
|
||||
|
||||
#include "muscle-tab.h"
|
||||
typedef struct
|
||||
@@ -74,7 +71,6 @@ extern int gram_debug;
|
||||
muscle_kind kind;
|
||||
} value_type;
|
||||
|
||||
#line 78 "src/parse-gram.h" /* yacc.c:1921 */
|
||||
|
||||
/* Token type. */
|
||||
#ifndef GRAM_TOKENTYPE
|
||||
@@ -122,27 +118,27 @@ extern int gram_debug;
|
||||
BRACED_PREDICATE = 295,
|
||||
BRACKETED_ID = 296,
|
||||
CHAR = 297,
|
||||
EPILOGUE = 298,
|
||||
EQUAL = 299,
|
||||
ID = 300,
|
||||
ID_COLON = 301,
|
||||
PERCENT_PERCENT = 302,
|
||||
PIPE = 303,
|
||||
PROLOGUE = 304,
|
||||
SEMICOLON = 305,
|
||||
TAG = 306,
|
||||
TAG_ANY = 307,
|
||||
TAG_NONE = 308,
|
||||
INT = 309,
|
||||
PERCENT_PARAM = 310,
|
||||
PERCENT_UNION = 311,
|
||||
PERCENT_EMPTY = 312
|
||||
COLON = 298,
|
||||
EPILOGUE = 299,
|
||||
EQUAL = 300,
|
||||
ID = 301,
|
||||
ID_COLON = 302,
|
||||
PERCENT_PERCENT = 303,
|
||||
PIPE = 304,
|
||||
PROLOGUE = 305,
|
||||
SEMICOLON = 306,
|
||||
TAG = 307,
|
||||
TAG_ANY = 308,
|
||||
TAG_NONE = 309,
|
||||
INT = 310,
|
||||
PERCENT_PARAM = 311,
|
||||
PERCENT_UNION = 312,
|
||||
PERCENT_EMPTY = 313
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined GRAM_STYPE && ! defined GRAM_STYPE_IS_DECLARED
|
||||
|
||||
union GRAM_STYPE
|
||||
{
|
||||
|
||||
@@ -163,9 +159,9 @@ union GRAM_STYPE
|
||||
/* "integer" */
|
||||
int INT;
|
||||
/* int.opt */
|
||||
int yytype_79;
|
||||
int yytype_80;
|
||||
/* named_ref.opt */
|
||||
named_ref* yytype_91;
|
||||
named_ref* yytype_92;
|
||||
/* "%param" */
|
||||
param_type PERCENT_PARAM;
|
||||
/* token_decl */
|
||||
@@ -181,7 +177,7 @@ union GRAM_STYPE
|
||||
/* string_as_id */
|
||||
symbol* string_as_id;
|
||||
/* string_as_id.opt */
|
||||
symbol* yytype_98;
|
||||
symbol* yytype_99;
|
||||
/* generic_symlist */
|
||||
symbol_list* generic_symlist;
|
||||
/* generic_symlist_item */
|
||||
@@ -191,15 +187,15 @@ union GRAM_STYPE
|
||||
/* token_decls */
|
||||
symbol_list* token_decls;
|
||||
/* token_decl.1 */
|
||||
symbol_list* yytype_77;
|
||||
symbol_list* yytype_78;
|
||||
/* token_decls_for_prec */
|
||||
symbol_list* token_decls_for_prec;
|
||||
/* token_decl_for_prec.1 */
|
||||
symbol_list* yytype_81;
|
||||
symbol_list* yytype_82;
|
||||
/* symbol_decls */
|
||||
symbol_list* symbol_decls;
|
||||
/* symbol_decl.1 */
|
||||
symbol_list* yytype_84;
|
||||
symbol_list* yytype_85;
|
||||
/* "%error-verbose" */
|
||||
uniqstr PERCENT_ERROR_VERBOSE;
|
||||
/* "%<flag>" */
|
||||
@@ -219,7 +215,7 @@ union GRAM_STYPE
|
||||
/* "<tag>" */
|
||||
uniqstr TAG;
|
||||
/* tag.opt */
|
||||
uniqstr yytype_71;
|
||||
uniqstr yytype_72;
|
||||
/* tag */
|
||||
uniqstr tag;
|
||||
/* variable */
|
||||
@@ -228,9 +224,8 @@ union GRAM_STYPE
|
||||
unsigned char CHAR;
|
||||
/* value */
|
||||
value_type value;
|
||||
#line 232 "src/parse-gram.h" /* yacc.c:1921 */
|
||||
};
|
||||
|
||||
};
|
||||
typedef union GRAM_STYPE GRAM_STYPE;
|
||||
# define GRAM_STYPE_IS_TRIVIAL 1
|
||||
# define GRAM_STYPE_IS_DECLARED 1
|
||||
|
||||
+34
-16
@@ -49,7 +49,7 @@
|
||||
#include "xmemdup0.h"
|
||||
|
||||
static int current_prec = 0;
|
||||
static location current_lhs_location;
|
||||
static location current_lhs_loc;
|
||||
static named_ref *current_lhs_named_ref;
|
||||
static symbol *current_lhs_symbol;
|
||||
static symbol_class current_class = unknown_sym;
|
||||
@@ -112,8 +112,13 @@
|
||||
#define YYTYPE_INT8 int_fast8_t
|
||||
#define YYTYPE_UINT16 uint_fast16_t
|
||||
#define YYTYPE_UINT8 uint_fast8_t
|
||||
|
||||
/* Add style to semantic values in traces. */
|
||||
static void tron (FILE *yyo);
|
||||
static void troff (FILE *yyo);
|
||||
}
|
||||
|
||||
%define api.header.include {"parse-gram.h"}
|
||||
%define api.prefix {gram_}
|
||||
%define api.pure full
|
||||
%define api.value.type union
|
||||
@@ -129,8 +134,8 @@
|
||||
{
|
||||
/* Bison's grammar can initial empty locations, hence a default
|
||||
location is needed. */
|
||||
boundary_set (&@$.start, current_file, 1, 1);
|
||||
boundary_set (&@$.end, current_file, 1, 1);
|
||||
boundary_set (&@$.start, current_file, 1, 1, 1);
|
||||
boundary_set (&@$.end, current_file, 1, 1, 1);
|
||||
}
|
||||
|
||||
/* Define the tokens together with their human representation. */
|
||||
@@ -188,6 +193,7 @@
|
||||
%token BRACED_PREDICATE "%?{...}"
|
||||
%token BRACKETED_ID "[identifier]"
|
||||
%token CHAR "char"
|
||||
%token COLON ":"
|
||||
%token EPILOGUE "epilogue"
|
||||
%token EQUAL "="
|
||||
%token ID "identifier"
|
||||
@@ -200,12 +206,15 @@
|
||||
%token TAG_ANY "<*>"
|
||||
%token TAG_NONE "<>"
|
||||
|
||||
/* Experimental feature, don't rely on it. */
|
||||
%code pre-printer {tron (yyo);}
|
||||
%code post-printer {troff (yyo);}
|
||||
|
||||
%type <unsigned char> CHAR
|
||||
%printer { fputs (char_name ($$), yyo); } <unsigned char>
|
||||
|
||||
%type <char*> "{...}" "%?{...}" "%{...%}" EPILOGUE STRING
|
||||
%printer { fputs (quotearg_style (c_quoting_style, $$), yyo); } STRING
|
||||
%printer { fprintf (yyo, "{\n%s\n}", $$); } <char*>
|
||||
%printer { fputs ($$, yyo); } <char*>
|
||||
|
||||
%type <uniqstr>
|
||||
BRACKETED_ID ID ID_COLON
|
||||
@@ -312,7 +321,7 @@ prologue_declaration:
|
||||
| "%defines" STRING
|
||||
{
|
||||
defines_flag = true;
|
||||
spec_defines_file = xstrdup ($2);
|
||||
spec_header_file = xstrdup ($2);
|
||||
}
|
||||
| "%error-verbose" { handle_error_verbose (&@$, $1); }
|
||||
| "%expect" INT { expected_sr_conflicts = $2; }
|
||||
@@ -626,7 +635,7 @@ rules_or_grammar_declaration:
|
||||
;
|
||||
|
||||
rules:
|
||||
id_colon named_ref.opt { current_lhs ($1, @1, $2); } rhses.1
|
||||
id_colon named_ref.opt { current_lhs ($1, @1, $2); } ":" rhses.1
|
||||
{
|
||||
/* Free the current lhs. */
|
||||
current_lhs (0, @1, 0);
|
||||
@@ -634,15 +643,15 @@ rules:
|
||||
;
|
||||
|
||||
rhses.1:
|
||||
rhs { grammar_current_rule_end (@1); }
|
||||
| rhses.1 "|" rhs { grammar_current_rule_end (@3); }
|
||||
rhs { grammar_current_rule_end (@rhs); }
|
||||
| rhses.1 "|" rhs { grammar_current_rule_end (@rhs); }
|
||||
| rhses.1 ";"
|
||||
;
|
||||
|
||||
%token PERCENT_EMPTY "%empty";
|
||||
rhs:
|
||||
%empty
|
||||
{ grammar_current_rule_begin (current_lhs_symbol, current_lhs_location,
|
||||
{ grammar_current_rule_begin (current_lhs_symbol, current_lhs_loc,
|
||||
current_lhs_named_ref); }
|
||||
| rhs symbol named_ref.opt
|
||||
{ grammar_current_rule_symbol_append ($2, @2, $3); }
|
||||
@@ -665,7 +674,7 @@ rhs:
|
||||
;
|
||||
|
||||
named_ref.opt:
|
||||
%empty { $$ = 0; }
|
||||
%empty { $$ = NULL; }
|
||||
| BRACKETED_ID { $$ = named_ref_new ($1, @1); }
|
||||
;
|
||||
|
||||
@@ -958,10 +967,9 @@ handle_require (location const *loc, char const *version)
|
||||
return;
|
||||
}
|
||||
required_version = major * 100 + minor;
|
||||
/* Pretend to be at least 3.2, even if we are only 3.1-211, as it
|
||||
allows us to check features published in 3.2 while developping
|
||||
3.2. */
|
||||
const char* api_version = "3.2";
|
||||
/* Pretend to be at least 3.4, to check features published in 3.4
|
||||
while developping it. */
|
||||
const char* api_version = "3.4";
|
||||
const char* package_version =
|
||||
strverscmp (api_version, PACKAGE_VERSION) > 0
|
||||
? api_version : PACKAGE_VERSION;
|
||||
@@ -1042,7 +1050,7 @@ void
|
||||
current_lhs (symbol *sym, location loc, named_ref *ref)
|
||||
{
|
||||
current_lhs_symbol = sym;
|
||||
current_lhs_location = loc;
|
||||
current_lhs_loc = loc;
|
||||
if (sym)
|
||||
symbol_location_as_lhs_set (sym, loc);
|
||||
/* In order to simplify memory management, named references for lhs
|
||||
@@ -1053,3 +1061,13 @@ current_lhs (symbol *sym, location loc, named_ref *ref)
|
||||
free (current_lhs_named_ref);
|
||||
current_lhs_named_ref = ref;
|
||||
}
|
||||
|
||||
static void tron (FILE *yyo)
|
||||
{
|
||||
begin_use_class ("value", yyo);
|
||||
}
|
||||
|
||||
static void troff (FILE *yyo)
|
||||
{
|
||||
end_use_class ("value", yyo);
|
||||
}
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
#include "print-graph.h"
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "LR0.h"
|
||||
#include "closure.h"
|
||||
#include "complain.h"
|
||||
#include "conflicts.h"
|
||||
@@ -30,7 +31,7 @@
|
||||
#include "gram.h"
|
||||
#include "graphviz.h"
|
||||
#include "lalr.h"
|
||||
#include "print_graph.h"
|
||||
#include "lr0.h"
|
||||
#include "reader.h"
|
||||
#include "state.h"
|
||||
#include "symtab.h"
|
||||
@@ -63,12 +64,7 @@ print_core (struct obstack *oout, state *s)
|
||||
for (size_t i = 0; i < snritems; ++i)
|
||||
{
|
||||
item_number const *sp1 = ritem + sitems[i];
|
||||
item_number const *sp = sp1;
|
||||
|
||||
while (0 <= *sp)
|
||||
sp++;
|
||||
|
||||
rule *r = &rules[item_number_as_rule_number (*sp)];
|
||||
rule const *r = item_rule (sp1);
|
||||
|
||||
obstack_printf (oout, "%3d ", r->number);
|
||||
if (previous_lhs && UNIQSTR_EQ (previous_lhs->symbol->tag,
|
||||
@@ -79,13 +75,13 @@ print_core (struct obstack *oout, state *s)
|
||||
obstack_printf (oout, "%s: ", escape (r->lhs->symbol->tag));
|
||||
previous_lhs = r->lhs;
|
||||
|
||||
for (sp = r->rhs; sp < sp1; sp++)
|
||||
for (item_number const *sp = r->rhs; sp < sp1; sp++)
|
||||
obstack_printf (oout, "%s ", escape (symbols[*sp]->tag));
|
||||
|
||||
obstack_1grow (oout, '.');
|
||||
|
||||
if (0 <= *r->rhs)
|
||||
for (/* Nothing */; *sp >= 0; ++sp)
|
||||
for (item_number const *sp = sp1; 0 <= *sp; ++sp)
|
||||
obstack_printf (oout, " %s", escape (symbols[*sp]->tag));
|
||||
else
|
||||
obstack_printf (oout, " %%empty");
|
||||
@@ -184,10 +180,8 @@ print_graph (void)
|
||||
start_graph (fgraph);
|
||||
|
||||
/* Output nodes and edges. */
|
||||
new_closure (nritems);
|
||||
for (int i = 0; i < nstates; i++)
|
||||
print_state (states[i], fgraph);
|
||||
free_closure ();
|
||||
|
||||
finish_graph (fgraph);
|
||||
xfclose (fgraph);
|
||||
+18
-37
@@ -19,21 +19,21 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
#include "print-xml.h"
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <bitset.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <bitset.h>
|
||||
|
||||
#include "LR0.h"
|
||||
#include "closure.h"
|
||||
#include "conflicts.h"
|
||||
#include "files.h"
|
||||
#include "getargs.h"
|
||||
#include "gram.h"
|
||||
#include "lalr.h"
|
||||
#include "lr0.h"
|
||||
#include "print.h"
|
||||
#include "print-xml.h"
|
||||
#include "reader.h"
|
||||
#include "reduce.h"
|
||||
#include "state.h"
|
||||
@@ -57,7 +57,6 @@ static struct escape_buf escape_bufs[num_escape_bufs];
|
||||
static void
|
||||
print_core (FILE *out, int level, state *s)
|
||||
{
|
||||
size_t i;
|
||||
item_number *sitems = s->items;
|
||||
size_t snritems = s->nitems;
|
||||
|
||||
@@ -74,18 +73,12 @@ print_core (FILE *out, int level, state *s)
|
||||
|
||||
xml_puts (out, level, "<itemset>");
|
||||
|
||||
for (i = 0; i < snritems; i++)
|
||||
for (size_t i = 0; i < snritems; i++)
|
||||
{
|
||||
bool printed = false;
|
||||
item_number *sp1 = ritem + sitems[i];
|
||||
item_number *sp = sp1;
|
||||
rule *r;
|
||||
|
||||
while (0 <= *sp)
|
||||
sp++;
|
||||
|
||||
r = &rules[item_number_as_rule_number (*sp)];
|
||||
sp = r->rhs;
|
||||
rule const *r = item_rule (sp1);
|
||||
item_number *sp = r->rhs;
|
||||
|
||||
/* Display the lookahead tokens? */
|
||||
if (item_number_is_rule_number (*sp1))
|
||||
@@ -380,15 +373,13 @@ print_state (FILE *out, int level, state *s)
|
||||
static void
|
||||
print_grammar (FILE *out, int level)
|
||||
{
|
||||
symbol_number i;
|
||||
|
||||
fputc ('\n', out);
|
||||
xml_puts (out, level, "<grammar>");
|
||||
grammar_rules_print_xml (out, level);
|
||||
|
||||
/* Terminals */
|
||||
xml_puts (out, level + 1, "<terminals>");
|
||||
for (i = 0; i < max_user_token_number + 1; i++)
|
||||
for (symbol_number i = 0; i < max_user_token_number + 1; i++)
|
||||
if (token_translations[i] != undeftoken->content->number)
|
||||
{
|
||||
char const *tag = symbols[token_translations[i]]->tag;
|
||||
@@ -411,7 +402,7 @@ print_grammar (FILE *out, int level)
|
||||
|
||||
/* Nonterminals */
|
||||
xml_puts (out, level + 1, "<nonterminals>");
|
||||
for (i = ntokens; i < nsyms + nuseless_nonterminals; i++)
|
||||
for (symbol_number i = ntokens; i < nsyms + nuseless_nonterminals; i++)
|
||||
{
|
||||
char const *tag = symbols[i]->tag;
|
||||
xml_printf (out, level + 2,
|
||||
@@ -428,8 +419,7 @@ print_grammar (FILE *out, int level)
|
||||
void
|
||||
xml_indent (FILE *out, int level)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < level; i++)
|
||||
for (int i = 0; i < level; i++)
|
||||
fputs (" ", out);
|
||||
}
|
||||
|
||||
@@ -460,14 +450,13 @@ xml_escape_string (struct escape_buf *buf, char const *str)
|
||||
{
|
||||
size_t len = strlen (str);
|
||||
size_t max_expansion = sizeof """ - 1;
|
||||
char *p;
|
||||
|
||||
if (buf->size <= max_expansion * len)
|
||||
{
|
||||
buf->size = max_expansion * len + 1;
|
||||
buf->ptr = x2realloc (buf->ptr, &buf->size);
|
||||
}
|
||||
p = buf->ptr;
|
||||
char *p = buf->ptr;
|
||||
|
||||
for (; *str; str++)
|
||||
switch (*str)
|
||||
@@ -498,11 +487,11 @@ xml_escape (char const *str)
|
||||
void
|
||||
print_xml (void)
|
||||
{
|
||||
int level = 0;
|
||||
|
||||
FILE *out = xfopen (spec_xml_file, "w");
|
||||
|
||||
fputs ("<?xml version=\"1.0\"?>\n\n", out);
|
||||
|
||||
int level = 0;
|
||||
xml_printf (out, level,
|
||||
"<bison-xml-report version=\"%s\" bug-report=\"%s\""
|
||||
" url=\"%s\">",
|
||||
@@ -517,29 +506,21 @@ print_xml (void)
|
||||
/* print grammar */
|
||||
print_grammar (out, level + 1);
|
||||
|
||||
new_closure (nritems);
|
||||
no_reduce_set = bitset_create (ntokens, BITSET_FIXED);
|
||||
no_reduce_set = bitset_create (ntokens, BITSET_FIXED);
|
||||
|
||||
/* print automaton */
|
||||
fputc ('\n', out);
|
||||
xml_puts (out, level + 1, "<automaton>");
|
||||
{
|
||||
state_number i;
|
||||
for (i = 0; i < nstates; i++)
|
||||
print_state (out, level + 2, states[i]);
|
||||
}
|
||||
for (state_number i = 0; i < nstates; i++)
|
||||
print_state (out, level + 2, states[i]);
|
||||
xml_puts (out, level + 1, "</automaton>");
|
||||
|
||||
bitset_free (no_reduce_set);
|
||||
free_closure ();
|
||||
|
||||
xml_puts (out, 0, "</bison-xml-report>");
|
||||
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < num_escape_bufs; ++i)
|
||||
free (escape_bufs[i].ptr);
|
||||
}
|
||||
for (int i = 0; i < num_escape_bufs; ++i)
|
||||
free (escape_bufs[i].ptr);
|
||||
|
||||
xfclose (out);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#ifndef PRINT_XML_H_
|
||||
# define PRINT_XML_H_
|
||||
|
||||
# include <config.h>
|
||||
|
||||
# include <stdio.h>
|
||||
|
||||
void xml_indent (FILE *out, int level);
|
||||
void xml_puts (FILE *, int, char const *);
|
||||
void xml_printf (FILE *, int, char const *, ...);
|
||||
|
||||
+38
-99
@@ -23,13 +23,13 @@
|
||||
|
||||
#include <bitset.h>
|
||||
|
||||
#include "LR0.h"
|
||||
#include "closure.h"
|
||||
#include "conflicts.h"
|
||||
#include "files.h"
|
||||
#include "getargs.h"
|
||||
#include "gram.h"
|
||||
#include "lalr.h"
|
||||
#include "lr0.h"
|
||||
#include "muscle-tab.h"
|
||||
#include "print.h"
|
||||
#include "reader.h"
|
||||
@@ -63,8 +63,6 @@ print_core (FILE *out, state *s)
|
||||
{
|
||||
item_number *sitems = s->items;
|
||||
size_t snritems = s->nitems;
|
||||
sym_content *previous_lhs = NULL;
|
||||
|
||||
/* Output all the items of a state, not only its kernel. */
|
||||
if (report_flag & report_itemsets)
|
||||
{
|
||||
@@ -78,33 +76,18 @@ print_core (FILE *out, state *s)
|
||||
|
||||
fputc ('\n', out);
|
||||
|
||||
rule const *previous_rule = NULL;
|
||||
for (size_t i = 0; i < snritems; i++)
|
||||
{
|
||||
item_number *sp1 = ritem + sitems[i];
|
||||
|
||||
item_number *sp = sp1;
|
||||
while (*sp >= 0)
|
||||
sp++;
|
||||
|
||||
rule_number r = item_number_as_rule_number (*sp);
|
||||
|
||||
rule_lhs_print (&rules[r], previous_lhs, out);
|
||||
previous_lhs = rules[r].lhs;
|
||||
|
||||
for (sp = rules[r].rhs; sp < sp1; sp++)
|
||||
fprintf (out, " %s", symbols[*sp]->tag);
|
||||
fputs (" .", out);
|
||||
if (0 <= *rules[r].rhs)
|
||||
for (/* Nothing */; 0 <= *sp; ++sp)
|
||||
fprintf (out, " %s", symbols[*sp]->tag);
|
||||
else
|
||||
fprintf (out, " %%empty");
|
||||
rule const *r = item_rule (sp1);
|
||||
item_print (sp1, previous_rule, out);
|
||||
previous_rule = r;
|
||||
|
||||
/* Display the lookahead tokens? */
|
||||
if (report_flag & report_lookahead_tokens
|
||||
&& item_number_is_rule_number (*sp1))
|
||||
state_rule_lookahead_tokens_print (s, &rules[r], out);
|
||||
|
||||
state_rule_lookahead_tokens_print (s, r, out);
|
||||
fputc ('\n', out);
|
||||
}
|
||||
}
|
||||
@@ -374,17 +357,6 @@ print_state (FILE *out, state *s)
|
||||
| Print information on the whole grammar. |
|
||||
`-----------------------------------------*/
|
||||
|
||||
#define END_TEST(End) \
|
||||
do { \
|
||||
if (column + strlen (buffer) > (End)) \
|
||||
{ \
|
||||
fprintf (out, "%s\n ", buffer); \
|
||||
column = 3; \
|
||||
buffer[0] = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
static void
|
||||
print_terminal_symbols (FILE *out)
|
||||
{
|
||||
@@ -394,29 +366,20 @@ print_terminal_symbols (FILE *out)
|
||||
if (token_translations[i] != undeftoken->content->number)
|
||||
{
|
||||
const char *tag = symbols[token_translations[i]]->tag;
|
||||
int column = strlen (tag);
|
||||
char buffer[90];
|
||||
|
||||
buffer[0] = 0;
|
||||
fputs (tag, out);
|
||||
END_TEST (65);
|
||||
fprintf (out, "%4s%s", "", tag);
|
||||
if (symbols[token_translations[i]]->content->type_name)
|
||||
{
|
||||
column += fprintf (out, " <%s>",
|
||||
symbols[token_translations[i]]->content->type_name);
|
||||
END_TEST (65);
|
||||
}
|
||||
sprintf (buffer, " (%d)", i);
|
||||
fprintf (out, " <%s>",
|
||||
symbols[token_translations[i]]->content->type_name);
|
||||
fprintf (out, " (%d)", i);
|
||||
|
||||
for (rule_number r = 0; r < nrules; r++)
|
||||
for (item_number *rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
|
||||
if (item_number_as_symbol_number (*rhsp) == token_translations[i])
|
||||
{
|
||||
END_TEST (65);
|
||||
sprintf (buffer + strlen (buffer), " %d", r);
|
||||
fprintf (out, " %d", r);
|
||||
break;
|
||||
}
|
||||
fprintf (out, "%s\n", buffer);
|
||||
fputc ('\n', out);
|
||||
}
|
||||
fputs ("\n\n", out);
|
||||
}
|
||||
@@ -429,64 +392,46 @@ print_nonterminal_symbols (FILE *out)
|
||||
for (symbol_number i = ntokens; i < nsyms; i++)
|
||||
{
|
||||
const char *tag = symbols[i]->tag;
|
||||
int column = strlen (tag);
|
||||
int left_count = 0, right_count = 0;
|
||||
bool on_left = false;
|
||||
bool on_right = false;
|
||||
|
||||
for (rule_number r = 0; r < nrules; r++)
|
||||
{
|
||||
if (rules[r].lhs->number == i)
|
||||
left_count++;
|
||||
for (item_number *rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
|
||||
if (item_number_as_symbol_number (*rhsp) == i)
|
||||
{
|
||||
right_count++;
|
||||
break;
|
||||
}
|
||||
on_left |= rules[r].lhs->number == i;
|
||||
for (item_number *rhsp = rules[r].rhs; !on_right && 0 <= *rhsp; ++rhsp)
|
||||
on_right |= item_number_as_symbol_number (*rhsp) == i;
|
||||
if (on_left && on_right)
|
||||
break;
|
||||
}
|
||||
|
||||
fputs (tag, out);
|
||||
int column = 4 + strlen (tag);
|
||||
fprintf (out, "%4s%s", "", tag);
|
||||
if (symbols[i]->content->type_name)
|
||||
column += fprintf (out, " <%s>",
|
||||
symbols[i]->content->type_name);
|
||||
char buffer[90];
|
||||
buffer[0] = 0;
|
||||
sprintf (buffer, " (%d)", i);
|
||||
END_TEST (0);
|
||||
fprintf (out, " (%d)\n", i);
|
||||
|
||||
if (left_count > 0)
|
||||
if (on_left)
|
||||
{
|
||||
END_TEST (65);
|
||||
sprintf (buffer + strlen (buffer), _(" on left:"));
|
||||
|
||||
fprintf (out, "%8s%s", "", _("on left:"));
|
||||
for (rule_number r = 0; r < nrules; r++)
|
||||
{
|
||||
if (rules[r].lhs->number == i)
|
||||
if (rules[r].lhs->number == i)
|
||||
fprintf (out, " %d", r);
|
||||
fputc ('\n', out);
|
||||
}
|
||||
|
||||
if (on_right)
|
||||
{
|
||||
fprintf (out, "%8s%s", "", _("on right:"));
|
||||
for (rule_number r = 0; r < nrules; r++)
|
||||
for (item_number *rhsp = rules[r].rhs; 0 <= *rhsp; ++rhsp)
|
||||
if (item_number_as_symbol_number (*rhsp) == i)
|
||||
{
|
||||
END_TEST (65);
|
||||
sprintf (buffer + strlen (buffer), " %d", r);
|
||||
fprintf (out, " %d", r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fputc ('\n', out);
|
||||
}
|
||||
|
||||
if (right_count > 0)
|
||||
{
|
||||
if (left_count > 0)
|
||||
sprintf (buffer + strlen (buffer), ",");
|
||||
END_TEST (65);
|
||||
sprintf (buffer + strlen (buffer), _(" on right:"));
|
||||
for (rule_number r = 0; r < nrules; r++)
|
||||
{
|
||||
item_number *rhsp;
|
||||
for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
|
||||
if (item_number_as_symbol_number (*rhsp) == i)
|
||||
{
|
||||
END_TEST (65);
|
||||
sprintf (buffer + strlen (buffer), " %d", r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf (out, "%s\n", buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,17 +452,11 @@ print_results (void)
|
||||
print_terminal_symbols (out);
|
||||
print_nonterminal_symbols (out);
|
||||
|
||||
/* If the whole state item sets, not only the kernels, are wanted,
|
||||
'closure' will be run, which needs memory allocation/deallocation. */
|
||||
if (report_flag & report_itemsets)
|
||||
new_closure (nritems);
|
||||
/* Storage for print_reductions. */
|
||||
no_reduce_set = bitset_create (ntokens, BITSET_FIXED);
|
||||
for (state_number i = 0; i < nstates; i++)
|
||||
print_state (out, states[i]);
|
||||
bitset_free (no_reduce_set);
|
||||
if (report_flag & report_itemsets)
|
||||
free_closure ();
|
||||
|
||||
xfclose (out);
|
||||
}
|
||||
|
||||
+64
-56
@@ -26,6 +26,7 @@
|
||||
#include "complain.h"
|
||||
#include "conflicts.h"
|
||||
#include "files.h"
|
||||
#include "fixits.h"
|
||||
#include "getargs.h"
|
||||
#include "gram.h"
|
||||
#include "muscle-tab.h"
|
||||
@@ -61,7 +62,7 @@ grammar_start_symbol_set (symbol *sym, location loc)
|
||||
{
|
||||
start_flag = true;
|
||||
startsymbol = sym;
|
||||
startsymbol_location = loc;
|
||||
startsymbol_loc = loc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,12 +131,12 @@ record_merge_function_type (int merger, uniqstr type, location declaration_loc)
|
||||
quote (merge_function->name), type,
|
||||
merge_function->type);
|
||||
indent += SUB_INDENT;
|
||||
complain_indent (&merge_function->type_declaration_location, complaint,
|
||||
complain_indent (&merge_function->type_declaration_loc, complaint,
|
||||
&indent,
|
||||
_("previous declaration"));
|
||||
}
|
||||
merge_function->type = uniqstr_new (type);
|
||||
merge_function->type_declaration_location = declaration_loc;
|
||||
merge_function->type_declaration_loc = declaration_loc;
|
||||
}
|
||||
|
||||
/*--------------------------------------.
|
||||
@@ -226,11 +227,9 @@ grammar_current_rule_begin (symbol *lhs, location loc,
|
||||
++nrules;
|
||||
previous_rule_end = grammar_end;
|
||||
|
||||
symbol_list *p = grammar_symbol_append (lhs, loc);
|
||||
current_rule = grammar_symbol_append (lhs, loc);
|
||||
if (lhs_name)
|
||||
assign_named_ref (p, named_ref_copy (lhs_name));
|
||||
|
||||
current_rule = grammar_end;
|
||||
assign_named_ref (current_rule, named_ref_copy (lhs_name));
|
||||
|
||||
/* Mark the rule's lhs as a nonterminal if not already so. */
|
||||
if (lhs->content->class == unknown_sym)
|
||||
@@ -293,10 +292,10 @@ grammar_rule_check_and_complete (symbol_list *r)
|
||||
if (first_rhs)
|
||||
{
|
||||
char const *lhs_type = r->content.sym->content->type_name;
|
||||
const char *rhs_type =
|
||||
char const *rhs_type =
|
||||
first_rhs->content->type_name ? first_rhs->content->type_name : "";
|
||||
if (!UNIQSTR_EQ (lhs_type, rhs_type))
|
||||
complain (&r->location, Wother,
|
||||
complain (&r->rhs_loc, Wother,
|
||||
_("type clash on default action: <%s> != <%s>"),
|
||||
lhs_type, rhs_type);
|
||||
else
|
||||
@@ -309,7 +308,7 @@ grammar_rule_check_and_complete (symbol_list *r)
|
||||
if (is_cxx)
|
||||
{
|
||||
code_props_rule_action_init (&r->action_props, "{ $$ = $1; }",
|
||||
r->location, r,
|
||||
r->rhs_loc, r,
|
||||
/* name */ NULL,
|
||||
/* type */ NULL,
|
||||
/* is_predicate */ false);
|
||||
@@ -319,7 +318,7 @@ grammar_rule_check_and_complete (symbol_list *r)
|
||||
}
|
||||
/* Warn if there is no default for $$ but we need one. */
|
||||
else
|
||||
complain (&r->location, Wother,
|
||||
complain (&r->rhs_loc, Wother,
|
||||
_("empty rule for typed nonterminal, and no action"));
|
||||
}
|
||||
|
||||
@@ -336,9 +335,9 @@ grammar_rule_check_and_complete (symbol_list *r)
|
||||
{
|
||||
warnings warn_flag = midrule_warning ? Wmidrule_values : Wother;
|
||||
if (n)
|
||||
complain (&l->location, warn_flag, _("unused value: $%d"), n);
|
||||
complain (&l->sym_loc, warn_flag, _("unused value: $%d"), n);
|
||||
else
|
||||
complain (&l->location, warn_flag, _("unset value: $$"));
|
||||
complain (&l->rhs_loc, warn_flag, _("unset value: $$"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,14 +345,23 @@ grammar_rule_check_and_complete (symbol_list *r)
|
||||
/* Check that %empty => empty rule. */
|
||||
if (r->percent_empty_loc.start.file
|
||||
&& r->next && r->next->content.sym)
|
||||
complain (&r->percent_empty_loc, complaint,
|
||||
_("%%empty on non-empty rule"));
|
||||
{
|
||||
complain (&r->percent_empty_loc, complaint,
|
||||
_("%%empty on non-empty rule"));
|
||||
fixits_register (&r->percent_empty_loc, "");
|
||||
}
|
||||
|
||||
/* Check that empty rule => %empty. */
|
||||
if (!(r->next && r->next->content.sym)
|
||||
&& !r->midrule_parent_rule
|
||||
&& !r->percent_empty_loc.start.file)
|
||||
complain (&r->location, Wempty_rule, _("empty rule without %%empty"));
|
||||
&& !r->percent_empty_loc.start.file
|
||||
&& warning_is_enabled (Wempty_rule))
|
||||
{
|
||||
complain (&r->rhs_loc, Wempty_rule, _("empty rule without %%empty"));
|
||||
location loc = r->rhs_loc;
|
||||
loc.end = loc.start;
|
||||
fixits_register (&loc, " %empty ");
|
||||
}
|
||||
|
||||
/* See comments in grammar_current_rule_prec_set for how POSIX
|
||||
mandates this complaint. It's only for identifiers, so skip
|
||||
@@ -362,12 +370,12 @@ grammar_rule_check_and_complete (symbol_list *r)
|
||||
&& r->ruleprec->tag[0] != '\'' && r->ruleprec->tag[0] != '"'
|
||||
&& r->ruleprec->content->status != declared
|
||||
&& !r->ruleprec->content->prec)
|
||||
complain (&r->location, Wother,
|
||||
complain (&r->rhs_loc, Wother,
|
||||
_("token for %%prec is not defined: %s"), r->ruleprec->tag);
|
||||
|
||||
/* Check that the (main) action was not typed. */
|
||||
if (r->action_props.type)
|
||||
complain (&r->location, Wother,
|
||||
complain (&r->rhs_loc, Wother,
|
||||
_("only midrule actions can be typed: %s"), r->action_props.type);
|
||||
}
|
||||
|
||||
@@ -380,8 +388,8 @@ void
|
||||
grammar_current_rule_end (location loc)
|
||||
{
|
||||
/* Put an empty link in the list to mark the end of this rule */
|
||||
grammar_symbol_append (NULL, grammar_end->location);
|
||||
current_rule->location = loc;
|
||||
grammar_symbol_append (NULL, grammar_end->rhs_loc);
|
||||
current_rule->rhs_loc = loc;
|
||||
}
|
||||
|
||||
|
||||
@@ -401,11 +409,11 @@ grammar_midrule_action (void)
|
||||
|
||||
/* Make a DUMMY nonterminal, whose location is that of the midrule
|
||||
action. Create the MIDRULE. */
|
||||
location dummy_location = current_rule->action_props.location;
|
||||
symbol *dummy = dummy_symbol_get (dummy_location);
|
||||
location dummy_loc = current_rule->action_props.location;
|
||||
symbol *dummy = dummy_symbol_get (dummy_loc);
|
||||
symbol_type_set(dummy,
|
||||
current_rule->action_props.type, current_rule->action_props.location);
|
||||
symbol_list *midrule = symbol_list_sym_new (dummy, dummy_location);
|
||||
symbol_list *midrule = symbol_list_sym_new (dummy, dummy_loc);
|
||||
|
||||
/* Remember named_ref of previous action. */
|
||||
named_ref *action_name = current_rule->action_props.named_ref;
|
||||
@@ -415,7 +423,7 @@ grammar_midrule_action (void)
|
||||
++nrules;
|
||||
++nritems;
|
||||
/* Attach its location and actions to that of the DUMMY. */
|
||||
midrule->location = dummy_location;
|
||||
midrule->rhs_loc = dummy_loc;
|
||||
code_props_rule_action_init (&midrule->action_props,
|
||||
current_rule->action_props.code,
|
||||
current_rule->action_props.location,
|
||||
@@ -436,14 +444,14 @@ grammar_midrule_action (void)
|
||||
grammar = midrule;
|
||||
|
||||
/* End the dummy's rule. */
|
||||
midrule->next = symbol_list_sym_new (NULL, dummy_location);
|
||||
midrule->next = symbol_list_sym_new (NULL, dummy_loc);
|
||||
midrule->next->next = current_rule;
|
||||
|
||||
previous_rule_end = midrule->next;
|
||||
|
||||
/* Insert the dummy nonterminal replacing the midrule action into
|
||||
the current rule. Bind it to its dedicated rule. */
|
||||
grammar_current_rule_symbol_append (dummy, dummy_location,
|
||||
grammar_current_rule_symbol_append (dummy, dummy_loc,
|
||||
action_name);
|
||||
grammar_end->midrule = midrule;
|
||||
midrule->midrule_parent_rule = current_rule;
|
||||
@@ -502,11 +510,11 @@ grammar_current_rule_dprec_set (int dprec, location loc)
|
||||
"%dprec");
|
||||
else if (current_rule->dprec != 0)
|
||||
duplicate_rule_directive ("%dprec",
|
||||
current_rule->dprec_location, loc);
|
||||
current_rule->dprec_loc, loc);
|
||||
else
|
||||
{
|
||||
current_rule->dprec = dprec;
|
||||
current_rule->dprec_location = loc;
|
||||
current_rule->dprec_loc = loc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,11 +529,11 @@ grammar_current_rule_merge_set (uniqstr name, location loc)
|
||||
"%merge");
|
||||
if (current_rule->merger != 0)
|
||||
duplicate_rule_directive ("%merge",
|
||||
current_rule->merger_declaration_location, loc);
|
||||
current_rule->merger_declaration_loc, loc);
|
||||
else
|
||||
{
|
||||
current_rule->merger = get_merge_function (name);
|
||||
current_rule->merger_declaration_location = loc;
|
||||
current_rule->merger_declaration_loc = loc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,11 +623,11 @@ packgram (void)
|
||||
{
|
||||
symbol_list *lhs = p;
|
||||
record_merge_function_type (lhs->merger, lhs->content.sym->content->type_name,
|
||||
lhs->merger_declaration_location);
|
||||
lhs->merger_declaration_loc);
|
||||
/* If the midrule's $$ is set or its $n is used, remove the '$' from the
|
||||
symbol name so that it's a user-defined symbol so that the default
|
||||
%destructor and %printer apply. */
|
||||
if (lhs->midrule_parent_rule
|
||||
if (lhs->midrule_parent_rule /* i.e., symbol_is_dummy (lhs->content.sym). */
|
||||
&& (lhs->action_props.is_value_used
|
||||
|| (symbol_list_n_get (lhs->midrule_parent_rule,
|
||||
lhs->midrule_parent_rhs_index)
|
||||
@@ -629,8 +637,8 @@ packgram (void)
|
||||
/* Don't check the generated rule 0. It has no action, so some rhs
|
||||
symbols may appear unused, but the parsing algorithm ensures that
|
||||
%destructor's are invoked appropriately. */
|
||||
if (p != grammar)
|
||||
grammar_rule_check_and_complete (p);
|
||||
if (lhs != grammar)
|
||||
grammar_rule_check_and_complete (lhs);
|
||||
|
||||
rules[ruleno].user_number = ruleno;
|
||||
rules[ruleno].number = ruleno;
|
||||
@@ -640,18 +648,18 @@ packgram (void)
|
||||
rules[ruleno].dprec = lhs->dprec;
|
||||
rules[ruleno].merger = lhs->merger;
|
||||
rules[ruleno].precsym = NULL;
|
||||
rules[ruleno].location = lhs->location;
|
||||
rules[ruleno].location = lhs->rhs_loc;
|
||||
rules[ruleno].useful = true;
|
||||
rules[ruleno].action = lhs->action_props.code;
|
||||
rules[ruleno].action_location = lhs->action_props.location;
|
||||
rules[ruleno].action_loc = lhs->action_props.location;
|
||||
rules[ruleno].is_predicate = lhs->action_props.is_predicate;
|
||||
rules[ruleno].expected_sr_conflicts = p->expected_sr_conflicts;
|
||||
rules[ruleno].expected_rr_conflicts = p->expected_rr_conflicts;
|
||||
rules[ruleno].expected_sr_conflicts = lhs->expected_sr_conflicts;
|
||||
rules[ruleno].expected_rr_conflicts = lhs->expected_rr_conflicts;
|
||||
|
||||
/* Traverse the rhs. */
|
||||
{
|
||||
size_t rule_length = 0;
|
||||
for (p = p->next; p->content.sym; p = p->next)
|
||||
for (p = lhs->next; p->content.sym; p = p->next)
|
||||
{
|
||||
++rule_length;
|
||||
|
||||
@@ -706,18 +714,18 @@ reader (void)
|
||||
symbols_new ();
|
||||
|
||||
/* Construct the accept symbol. */
|
||||
accept = symbol_get ("$accept", empty_location);
|
||||
accept = symbol_get ("$accept", empty_loc);
|
||||
accept->content->class = nterm_sym;
|
||||
accept->content->number = nvars++;
|
||||
|
||||
/* Construct the error token */
|
||||
errtoken = symbol_get ("error", empty_location);
|
||||
errtoken = symbol_get ("error", empty_loc);
|
||||
errtoken->content->class = token_sym;
|
||||
errtoken->content->number = ntokens++;
|
||||
|
||||
/* Construct a token that represents all undefined literal tokens.
|
||||
It is always token number 2. */
|
||||
undeftoken = symbol_get ("$undefined", empty_location);
|
||||
undeftoken = symbol_get ("$undefined", empty_loc);
|
||||
undeftoken->content->class = token_sym;
|
||||
undeftoken->content->number = ntokens++;
|
||||
|
||||
@@ -754,11 +762,12 @@ prepare_percent_define_front_end_variables (void)
|
||||
|
||||
/* Check %define front-end variables. */
|
||||
{
|
||||
static char const * const values[] = {
|
||||
"lr.type", "lalr", "ielr", "canonical-lr", NULL,
|
||||
"lr.default-reduction", "most", "consistent", "accepting", NULL,
|
||||
NULL
|
||||
};
|
||||
static char const * const values[] =
|
||||
{
|
||||
"lr.type", "lr""(0)", "lalr", "ielr", "canonical-lr", NULL,
|
||||
"lr.default-reduction", "most", "consistent", "accepting", NULL,
|
||||
NULL
|
||||
};
|
||||
muscle_percent_define_check_values (values);
|
||||
}
|
||||
}
|
||||
@@ -793,7 +802,7 @@ check_and_convert_grammar (void)
|
||||
/* If the user did not define her ENDTOKEN, do it now. */
|
||||
if (!endtoken)
|
||||
{
|
||||
endtoken = symbol_get ("$end", empty_location);
|
||||
endtoken = symbol_get ("$end", empty_loc);
|
||||
endtoken->content->class = token_sym;
|
||||
endtoken->content->number = 0;
|
||||
/* Value specified by POSIX. */
|
||||
@@ -815,11 +824,11 @@ check_and_convert_grammar (void)
|
||||
|
||||
$accept: %start $end. */
|
||||
{
|
||||
symbol_list *p = symbol_list_sym_new (accept, empty_location);
|
||||
p->location = grammar->location;
|
||||
p->next = symbol_list_sym_new (startsymbol, empty_location);
|
||||
p->next->next = symbol_list_sym_new (endtoken, empty_location);
|
||||
p->next->next->next = symbol_list_sym_new (NULL, empty_location);
|
||||
symbol_list *p = symbol_list_sym_new (accept, empty_loc);
|
||||
p->rhs_loc = grammar->rhs_loc;
|
||||
p->next = symbol_list_sym_new (startsymbol, empty_loc);
|
||||
p->next->next = symbol_list_sym_new (endtoken, empty_loc);
|
||||
p->next->next->next = symbol_list_sym_new (NULL, empty_loc);
|
||||
p->next->next->next->next = grammar;
|
||||
nrules += 1;
|
||||
nritems += 3;
|
||||
@@ -829,8 +838,7 @@ check_and_convert_grammar (void)
|
||||
aver (nsyms <= SYMBOL_NUMBER_MAXIMUM);
|
||||
aver (nsyms == ntokens + nvars);
|
||||
|
||||
/* Assign the symbols their symbol numbers. Write #defines for the
|
||||
token symbols into FDEFINES if requested. */
|
||||
/* Assign the symbols their symbol numbers. */
|
||||
symbols_pack ();
|
||||
|
||||
/* Scan rule actions after invoking symbol_check_alias_consistency (in
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ typedef struct merger_list
|
||||
struct merger_list* next;
|
||||
uniqstr name;
|
||||
uniqstr type;
|
||||
location type_declaration_location;
|
||||
location type_declaration_loc;
|
||||
} merger_list;
|
||||
|
||||
/* From the parser. */
|
||||
|
||||
+39
-39
@@ -39,13 +39,13 @@
|
||||
#include "reduce.h"
|
||||
#include "symtab.h"
|
||||
|
||||
/* Set of all nonterminals whose language is not empty. */
|
||||
/* Set of nonterminals whose language is not empty. */
|
||||
static bitset N;
|
||||
|
||||
/* Set of all rules which have no useless nonterminals in their RHS. */
|
||||
/* Set of rules that have no useless nonterminals in their RHS. */
|
||||
static bitset P;
|
||||
|
||||
/* Set of all accessible symbols. */
|
||||
/* Set of accessible symbols. */
|
||||
static bitset V;
|
||||
|
||||
/* Set of symbols used to define rule precedence (so they are
|
||||
@@ -81,9 +81,11 @@ useful_production (rule_number r, bitset N0)
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------.
|
||||
| Remember that rules are 1-origin, symbols are 0-origin. |
|
||||
`---------------------------------------------------------*/
|
||||
/*-----------------------------------------------------------------.
|
||||
| Compute N, the set of nonterminals whose language is not empty. |
|
||||
| |
|
||||
| Remember that rules are 1-origin, symbols are 0-origin. |
|
||||
`-----------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
useless_nonterminals (void)
|
||||
@@ -248,10 +250,7 @@ reduce_grammar_tables (void)
|
||||
|
||||
/* Adjust NRITEMS. */
|
||||
for (rule_number r = nrules; r < nrules + nuseless_productions; ++r)
|
||||
{
|
||||
int length = rule_rhs_length (&rules[r]);
|
||||
nritems -= length + 1;
|
||||
}
|
||||
nritems -= rule_rhs_length (&rules[r]) + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -259,22 +258,23 @@ reduce_grammar_tables (void)
|
||||
| Remove useless nonterminals. |
|
||||
`------------------------------*/
|
||||
|
||||
symbol_number *nterm_map = NULL;
|
||||
|
||||
static void
|
||||
nonterminals_reduce (void)
|
||||
{
|
||||
nterm_map = xnmalloc (nvars, sizeof *nterm_map);
|
||||
/* Map the nonterminals to their new index: useful first, useless
|
||||
afterwards. Kept for later report. */
|
||||
|
||||
symbol_number *nontermmap = xnmalloc (nvars, sizeof *nontermmap);
|
||||
{
|
||||
symbol_number n = ntokens;
|
||||
for (symbol_number i = ntokens; i < nsyms; ++i)
|
||||
if (bitset_test (V, i))
|
||||
nontermmap[i - ntokens] = n++;
|
||||
nterm_map[i - ntokens] = n++;
|
||||
for (symbol_number i = ntokens; i < nsyms; ++i)
|
||||
if (!bitset_test (V, i))
|
||||
{
|
||||
nontermmap[i - ntokens] = n++;
|
||||
nterm_map[i - ntokens] = n++;
|
||||
if (symbols[i]->content->status != used)
|
||||
complain (&symbols[i]->location, Wother,
|
||||
_("nonterminal useless in grammar: %s"),
|
||||
@@ -282,32 +282,30 @@ nonterminals_reduce (void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Shuffle elements of tables indexed by symbol number. */
|
||||
{
|
||||
symbol **symbols_sorted = xnmalloc (nvars, sizeof *symbols_sorted);
|
||||
for (symbol_number i = ntokens; i < nsyms; ++i)
|
||||
symbols[i]->content->number = nontermmap[i - ntokens];
|
||||
symbols[i]->content->number = nterm_map[i - ntokens];
|
||||
for (symbol_number i = ntokens; i < nsyms; ++i)
|
||||
symbols_sorted[nontermmap[i - ntokens] - ntokens] = symbols[i];
|
||||
symbols_sorted[nterm_map[i - ntokens] - ntokens] = symbols[i];
|
||||
for (symbol_number i = ntokens; i < nsyms; ++i)
|
||||
symbols[i] = symbols_sorted[i - ntokens];
|
||||
free (symbols_sorted);
|
||||
}
|
||||
|
||||
/* Update nonterminal numbers in the RHS of the rules. LHS are
|
||||
pointers to the symbol structure, they don't need renumbering. */
|
||||
{
|
||||
for (rule_number r = 0; r < nrules; ++r)
|
||||
for (item_number *rhsp = rules[r].rhs; 0 <= *rhsp; ++rhsp)
|
||||
if (ISVAR (*rhsp))
|
||||
*rhsp = symbol_number_as_item_number (nontermmap[*rhsp
|
||||
- ntokens]);
|
||||
accept->content->number = nontermmap[accept->content->number - ntokens];
|
||||
*rhsp = symbol_number_as_item_number (nterm_map[*rhsp - ntokens]);
|
||||
accept->content->number = nterm_map[accept->content->number - ntokens];
|
||||
}
|
||||
|
||||
nsyms -= nuseless_nonterminals;
|
||||
nvars -= nuseless_nonterminals;
|
||||
|
||||
free (nontermmap);
|
||||
}
|
||||
|
||||
|
||||
@@ -322,7 +320,7 @@ reduce_output (FILE *out)
|
||||
{
|
||||
fprintf (out, "%s\n\n", _("Nonterminals useless in grammar"));
|
||||
for (int i = 0; i < nuseless_nonterminals; ++i)
|
||||
fprintf (out, " %s\n", symbols[nsyms + i]->tag);
|
||||
fprintf (out, " %s\n", symbols[nsyms + i]->tag);
|
||||
fputs ("\n\n", out);
|
||||
}
|
||||
|
||||
@@ -334,7 +332,7 @@ reduce_output (FILE *out)
|
||||
if (!b)
|
||||
fprintf (out, "%s\n\n", _("Terminals unused in grammar"));
|
||||
b = true;
|
||||
fprintf (out, " %s\n", symbols[i]->tag);
|
||||
fprintf (out, " %s\n", symbols[i]->tag);
|
||||
}
|
||||
if (b)
|
||||
fputs ("\n\n", out);
|
||||
@@ -379,23 +377,23 @@ reduce_grammar (void)
|
||||
inaccessable_symbols ();
|
||||
|
||||
/* Did we reduce something? */
|
||||
if (!nuseless_nonterminals && !nuseless_productions)
|
||||
return;
|
||||
if (nuseless_nonterminals || nuseless_productions)
|
||||
{
|
||||
reduce_print ();
|
||||
|
||||
reduce_print ();
|
||||
if (!bitset_test (N, accept->content->number - ntokens))
|
||||
complain (&startsymbol_loc, fatal,
|
||||
_("start symbol %s does not derive any sentence"),
|
||||
startsymbol->tag);
|
||||
|
||||
if (!bitset_test (N, accept->content->number - ntokens))
|
||||
complain (&startsymbol_location, fatal,
|
||||
_("start symbol %s does not derive any sentence"),
|
||||
startsymbol->tag);
|
||||
|
||||
/* First reduce the nonterminals, as they renumber themselves in the
|
||||
whole grammar. If you change the order, nonterms would be
|
||||
renumbered only in the reduced grammar. */
|
||||
if (nuseless_nonterminals)
|
||||
nonterminals_reduce ();
|
||||
if (nuseless_productions)
|
||||
reduce_grammar_tables ();
|
||||
/* First reduce the nonterminals, as they renumber themselves in the
|
||||
whole grammar. If you change the order, nonterms would be
|
||||
renumbered only in the reduced grammar. */
|
||||
if (nuseless_nonterminals)
|
||||
nonterminals_reduce ();
|
||||
if (nuseless_productions)
|
||||
reduce_grammar_tables ();
|
||||
}
|
||||
|
||||
if (trace_flag & trace_grammar)
|
||||
{
|
||||
@@ -433,4 +431,6 @@ reduce_free (void)
|
||||
bitset_free (V);
|
||||
bitset_free (V1);
|
||||
bitset_free (P);
|
||||
free (nterm_map);
|
||||
nterm_map = NULL;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,11 @@ bool reduce_nonterminal_useless_in_grammar (const sym_content *sym);
|
||||
|
||||
void reduce_free (void);
|
||||
|
||||
/** Map initial nterm numbers to the new ones. Built by
|
||||
* reduce_grammar. Size nvars + nuseless_nonterminals. */
|
||||
extern symbol_number *nterm_map;
|
||||
|
||||
extern unsigned nuseless_nonterminals;
|
||||
extern unsigned nuseless_productions;
|
||||
|
||||
#endif /* !REDUCE_H_ */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user