Compare commits

...
193 Commits
Author SHA1 Message Date
Akim Demaille 5163803a63 version 3.3.91
* NEWS: Record release date.
2019-05-12 14:09:10 +02:00
Akim Demaille fee7c78a83 NEWS: update 2019-05-12 14:07:43 +02:00
Akim Demaille 8fc544b03c gnulib: update 2019-05-12 11:39:27 +02:00
Akim Demaille d62d5c4b33 style: remove incorrect comment
* src/getargs.c: here.
It's documented in getargs.h anyway.
2019-05-11 09:19:16 +02:00
Akim Demaille ab3eaff7c4 doc: use colors for diagnostics in TeX too
Thanks to Gavin Smith and Patrice Dumas.
http://lists.gnu.org/archive/html/help-texinfo/2019-04/msg00015.html

* doc/bison.texi (@colorWarning, @colorError, @colorNotice)
(@colorOff): Define for TeX and HTML.
(@dwarning, @derror, @dnotice): Use them.
2019-05-09 19:21:02 +02:00
Akim Demaille 85e83ea968 gnulib: update to fix location tracking in UTF-8 on Solaris
This update contains Bruno Haible's fix for the location tracking
issue reported by Kiyoshi Kanazawa.

https://lists.gnu.org/archive/html/bug-gnulib/2019-05/msg00020.html
https://lists.gnu.org/archive/html/bug-bison/2019-04/msg00020.html
2019-05-08 16:34:31 +02:00
Akim Demaille 0269c6fb03 diagnostics: rename --style=debug as --color=debug
It is more consistent with --color=html, --color=test, etc.

* src/getargs.h, src/getargs.c (style_debug): Rename as...
(color_debug): this.
(getargs_colors): Rename --style=debug as --color=debug.
Adjust dependencies.
2019-05-08 13:36:47 +02:00
Akim Demaille 23e536af49 diagnostics: support --color=html
Based on a message from Bruno Haible.
https://git.savannah.gnu.org/gitweb/?p=gettext.git;a=commitdiff;h=fe18e92743b7226791a5f28d7c786941a1bf8cc9

This does not generate proper HTML: special characters are not escaped
for instance.  This is a hidden feature meant for Bison developers,
not end users.

* src/complain.c (complain_init_color): Support --color=html.
2019-05-08 13:36:47 +02:00
Akim Demaille cd56929097 tests: use %empty instead of comments
* tests/c++.at, tests/glr-regression.at: here.
2019-05-08 09:11:37 +02:00
Akim Demaille 7aa38561f7 fixits: sort them before applying them
An experimental commit introduced a fix-it hint that changes comments
such as "/* empty */" into %empty.  But in some case, because
diagnostics are not necessarily emitted in order, the fixits also come
in disorder, which must never happen, as the fixes are installed in
one pass.

* src/fixits.c (fixits_register): Insert them in order.
2019-05-08 09:10:28 +02:00
Akim Demaille 22a00cfbf2 style: use warning_is_enabled instead of duplicating it
* src/complain.c (deprecated_directive): Here.
2019-05-04 17:50:57 +02:00
Akim Demaille 8c06cb9130 fixits: be sure to preserve the action when adding %empty
Currently we remove the rhs to install %empty instead.

* src/reader.c (grammar_rule_check_and_complete): Insert the missing
%empty in front of the rhs, not in replacement thereof.
* tests/actions.at (Add missing %empty): Check that.
2019-05-03 16:28:28 +02:00
Akim Demaille b5233ba323 tests: don't duplicate the portability prologue
* tests/actions.at, tests/input.at: Don't repeat the prologue, skip it.
* tests/diagnostics.at, tests/local.at: Comment changes.
2019-05-03 16:28:28 +02:00
Akim Demaille 013720f0e7 style: use consistently *_loc for locations
Some members are called foo_location, others are foo_loc.  Stick to
the latter.

* src/gram.h, src/location.h, src/location.c, src/output.c,
* src/parse-gram.y, src/reader.h, src/reader.c, src/reduce.c,
* src/scan-gram.l, src/symlist.h, src/symlist.c, src/symtab.h,
* src/symtab.c:
Use _loc consistently, not _location.
2019-05-03 16:28:28 +02:00
Akim Demaille 365b4d95a4 style: clarify the use of symbol_lists' locations
symbol_list features a 'location' and a 'sym_loc' member.  The former
is expected to be set only for symbol_lists that denote a symbol (not
a type name), and the latter should only denote the location of the
symbol/type name.  Yet both are set, and the name "location" is too
unprecise.

* src/symlist.h, src/symlist.c (symbol_list::location): Rename as
rhs_loc for clarity.  Move it to the "section" of data valid only
for rules.
* src/reader.c, src/scan-code.l: Adjust.
2019-05-03 16:28:28 +02:00
Akim Demaille 5bb44cca81 maint: update gnulib-po/.gitignore 2019-05-03 16:28:28 +02:00
Akim Demaille 15f9f8c853 tests: don't require a D compiler
Reported by Kiyoshi Kanazawa.
http://lists.gnu.org/archive/html/bug-bison/2019-04/msg00018.html

* tests/atlocal.in (BISON_DC_WORKS): New.
* tests/local.at (AT_COMPILE_D): Use it.
2019-04-29 22:27:01 +02:00
Akim Demaille 04676a5085 doc: use svg instead of png
* doc/bison.texi, doc/local.mk: here.
2019-04-29 07:44:19 +02:00
Akim Demaille cf44351dd7 doc: use colors
* doc/bison.texi (dwarning, derror, dnotice): New.
Use them in the diagnostics.
* doc/local.mk (AM_MAKEINFOFLAGS): Pass customization variables.
2019-04-29 07:44:19 +02:00
Akim Demaille 614e0bbe23 maint: post-release administrivia
* NEWS: Add header line for next release.
* .prev-version: Record previous version.
* cfg.mk (old_NEWS_hash): Auto-update.
2019-04-28 12:02:35 +02:00
Akim Demaille 3eb7b0ee78 version 3.3.90
* NEWS: Record release date.
2019-04-28 11:45:38 +02:00
Akim Demaille 02a1600994 package: add missing CLEANFILES
* examples: here.
2019-04-28 11:39:10 +02:00
Akim Demaille f6868c5a77 build: don't generate the graph reports
Revert "build: also generate the graph
reports" (4ec413da32).  The problem is
Automake's ylwrap which does not rename y.dot with the appropriate
name.  We should completely stop using Automake's support for Yacc,
which is not something I will do right now.  So step back.

* Makefile.am (AM_YFLAGS_WITH_LINES): Don't pass --graph.
2019-04-28 11:39:10 +02:00
Akim Demaille f92f2f8afe package: don't regen the parser during dist if unneeded
* Makefile.am (gen-synclines): New.
2019-04-28 11:39:10 +02:00
Akim Demaille 0cc04eaa2a package: don't ship the sources generated from the parser
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.

* examples/c/calc/local.mk, examples/c/lexcalc/local.mk,
* examples/c/reccalc/local.mk: Always use nodist_*SOURCES for parsers,
let the dist_*_DATA rules do their job.
2019-04-28 11:39:10 +02:00
Akim Demaille 57290d63fd package: various fixes for syntax-check
* cfg.mk: Disable checks where needed (e.g., we do want to check the
behavior with tabs).
(sc_at_parser_check): Remove.  Unfortunately since
a11c144609 we no longer use the './'
prefix to run programs in the current directory.  That was so that we
could run Java programs like the other, although they are no run with
the `./` prefix (see 967a59d2c0).
As a consequence this sc check no longer makes sense.
However, since now AT_PARSER_CHECK passes the `./` prefix itself, this
sc-check was superfluous.
* examples/c/reccalc/scan.l: Use memcpy, not strncpy.
* src/ielr.c, src/reader.c: Obfuscate "lr(0)" so that the sc-check for
"space before paren" does not fire.
* tests/diagnostics.at: Avoid space-tab, use tab-tab.
2019-04-28 08:24:31 +02:00
Akim Demaille 33b246a624 doc: clarify -fsyntax-error
* NEWS, doc/bison.texi: here.
2019-04-27 18:27:04 +02:00
Akim Demaille dc5ce5989f regen 2019-04-27 18:27:04 +02:00
Akim Demaille 7ea108fa67 traces: use colors for the semantic values
This makes reading the trace slightly easier.  It would be very nice
to highlight the "big steps", especially reductions.  But this is a
private experiment: do not use it.

* data/diagnostics.css (value): New.
* src/parse-gram.y: Use no delimiters and no c quotation for strings
to facilitate debugging.
(tron, troff, TRACE): New.
Not very elegant, but until there is support for printf-formats in
libtextstyle, it shall be enough.
2019-04-27 18:27:04 +02:00
Akim Demaille 386cf25088 diagnostics: give m4 precise locations
Currently we pass only the columns based on the screen-width, which is
important for the carets.  But we don't pass the bytes-based columns,
which is important for the colors.  Pass both.

* src/muscle-tab.c (muscle_boundary_grow): Also pass the byte-based column.
* src/location.c (location_caret): Clarify.
(boundary_set_from_string): Adjust to the new format.
* tests/diagnostics.at (Tabulations and multibyte characters from M4): New.
2019-04-27 18:27:04 +02:00
Akim Demaille a514c51e55 diagnostics: fix locations coming from M4
Locations issued from M4 need the byte-based column for the
diagnostics to work properly.  Currently they were unassigned, which
typically resulted in partially non-colored diagnostics.

* src/location.c (boundary_set_from_string): Fix the parsed location.
* src/muscle-tab.c (muscle_percent_define_default): Set the byte values.
* tests/diagnostics.at (Locations from M4): New.
2019-04-27 18:12:23 +02:00
Akim Demaille 91b8f3f171 diagnostics: show locations in full when debugging
This is meant for developers, not end users, that's why I attached it
to --trace.

* src/getargs.h, src/getargs.c (trace_locations): New.
* src/location.c (location_print): Use it.
2019-04-27 18:11:41 +02:00
Akim Demaille 8f5d475079 diagnostics: use flush, not fflush
* src/complain.c: here.
2019-04-27 18:09:52 +02:00
Akim Demaille f5a4e279bc build: use gettext-h
We were using the gnulib's gettext module with tricks in
bootstrap.conf to avoid useless files.  Instead, use gnulib's
gettext-h module.

* .travis.yml: Force Gettext 0.18.3 on Trusty.
* bootstrap.conf: Use gettext-h instead of gettext.
(excluded_files): Remove.
* configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.19.
2019-04-25 22:09:41 +02:00
Akim Demaille 571447afe8 NEWS: update 2019-04-25 22:09:39 +02:00
Akim Demaille 9260e5ca4f api.location.type: support it in C
Reported by Balázs Scheidler.

* data/skeletons/c.m4 (b4_location_type_define): Use api.location.type
if defined.
* doc/bison.texi: Document it.
* tests/local.at (AT_C_IF, AT_LANG_CASE): New.
Support Span in C.
* tests/calc.at (Span): Convert it to be usable in C and C++.
Check api.location.type with yacc.c and glr.c.
2019-04-25 20:20:59 +02:00
Akim Demaille 971e72514f updates: insert/remove %empty
* src/reader.c (grammar_rule_check_and_complete): Generate fixits for
adding/removing %empty.
* tests/actions.at, tests/diagnostics.at, tests/existing.at: Adjust.
2019-04-24 13:21:24 +02:00
Akim Demaille 0ee5ac5367 regen 2019-04-24 13:08:51 +02:00
Akim Demaille 935d119c82 diagnostics: better rule locations
The "identifier and colon" of a rule is implemented as a single token,
but whose location is only that of the identifier (so that messages
about the lhs of a rule are accurate).  When reducing empty rules, the
default location is the single point location on the end of the
previous symbol.  As a consequence, when Bison parses a grammar, the
location of the right-hand side of an empty rule is based on the
lhs, *independently of the position of the colon*.  And the colon can
be way farther, separated by comments, white spaces, including empty
lines.

As a result, some messages look really bad.  For instance:

    $ cat foo.y
    %%
    foo     : /* empty */
    bar
    : /* empty */

gives

    $ bison -Wall foo.y
    foo.y:2.4: warning: empty rule without %empty [-Wempty-rule]
        2 | foo     : /* empty */
          |    ^
    foo.y:3.4: warning: empty rule without %empty [-Wempty-rule]
        3 | bar
          |    ^

The carets are not at the right column, not even the right line.

This commit passes the colon "again" after the "id colon" token, which
gives more accurate locations for these messages:

    $ bison -Wall foo.y
    foo.y:2.10: warning: empty rule without %empty [-Wempty-rule]
        2 | foo     : /* empty */
          |          ^
    foo.y:4.2: warning: empty rule without %empty [-Wempty-rule]
        4 | : /* empty */
          |  ^

* src/scan-gram.l (SC_AFTER_IDENTIFIER): Rollback the colon, so that
we scan it again afterwards.
(INITIAL): Scan colons.
* src/parse-gram.y (COLON): New.
(rules): Parse the colon after the rule's id_colon (and possible
named reference).
* tests/actions.at, tests/conflicts.at, tests/diagnostics.at,
* tests/existing.at: Adjust.
2019-04-24 13:08:51 +02:00
Akim Demaille 01fe32ee53 fixits: track byte-columns, not character-columns
Because the fix-its were ready the character-based columns, but were
applied on byte-based columns, the result with multibyte characters or
tabs could be "interesting".  For instance

	    %fixed-output_files
            %fixed_output-files
    %fixed-output-files
    %define api.prefix {foo}
    %no-default-prec

would give

         %fixed-%fixed-output-files  %fixed_output-files
    %fixed-orefix= "foo"
    o_default-prec

* src/fixits.c (fixit_print, fixits_run): Work on byte-base columns.
* tests/input.at: Check it.
2019-04-24 07:18:22 +02:00
Akim Demaille 19ea6b1405 diagnostics: expose a means to know whether a warning is enabled
* src/complain.h, src/complain.c (warning_is_enabled): New.
2019-04-24 07:18:22 +02:00
Akim Demaille a4d33cdf48 gnulib: let it use its own PO domain
See
https://www.gnu.org/software/gnulib/manual/html_node/Localization.html.

* bootstrap.conf: Create gnulib-po.
* Makefile.am, configure.ac: Use it.
* po/POTFILES.in: Remove files now in gnulib.
* src/main.c: Open the bison-gnulib domain.
2019-04-23 19:28:08 +02:00
Akim Demaille a992a3cb9e diagnostics: don't try to quote special files
Based on a report by Todd Freed.
http://lists.gnu.org/archive/html/bug-bison/2019-04/msg00000.html
See also https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90034

* src/location.c (caret_info): Also track the file name.
(location_caret): Don't quote special files.
2019-04-23 18:29:10 +02:00
Akim Demaille 95d688957f diagnostics: document the change of format
* doc/bison.texiL Adjust output.
Also, Graphviz has no uppercsae V.
* NEWS: Explain the format change.
2019-04-23 18:29:10 +02:00
Akim Demaille a9b350fb3a diagnostics: copy GCC9's format
Currently, when we quote the source file, we indent it with one space,
and preserve tabulations, so there is a discrepancy and the visual
rendering is bad.  One way out is to indent with a tab instead of a
space, but then this space can be used for more information.  This is
what GCC9 does.  Let's play copy cats.

See
https://lists.gnu.org/archive/html/bison-patches/2019-04/msg00025.html
https://developers.redhat.com/blog/2019/03/08/usability-improvements-in-gcc-9/
https://gcc.gnu.org/onlinedocs/gccint/Guidelines-for-Diagnostics.html#Guidelines-for-Diagnostics

* src/location.c (location_caret): Prefix quoted lines with the line
number and a pipe, fitting 8 columns.

* tests/actions.at, tests/c++.at, tests/conflicts.at,
* tests/diagnostics.at, tests/input.at, tests/java.at,
* tests/named-refs.at, tests/reduce.at, tests/regression.at,
* tests/sets.at: Adjust expectations.
Partly by "./build-aux/update-test tests/testsuite.dir/*/testsuite.log"
repeatedly, and partly by hand.
2019-04-23 18:29:10 +02:00
Akim Demaille afe7dfd3b9 diagnostics: fix the handling of multibyte characters
This is a pity: efforts were invested in computing correctly the
number of screen columns consumed by multibyte characters, but the
routines that do that were fed by single-byte inputs...

As a consequence Bison never displayed correctly locations when there
are multibyte characters.

* src/scan-gram.l (mbchar): New.
Use it instead of . in the catch-all clause.
* tests/diagnostics.at (Tabulations): Enhance into...
(Tabulations and multibyte characters): this.
2019-04-23 18:29:10 +02:00
Akim Demaille 6b6c3de2ae diagnostics: check the handling of tabulations
* tests/diagnostics.at (Tabulations): here.
2019-04-23 18:29:10 +02:00
Akim Demaille 1b70f687fa diagnostics: fix styling issues
Single point locations (equal boundaries) are troublesome, and we were
incorrectly ending the style in their case.  Which results in an abort
in libtextstyle.

There is also a confusion between columns as displayed on the
screen (which take into account multibyte characters and tabulations),
and the number of bytes.  Counting the screen-column
incrementally (character by character) is uneasy (because of multibyte
characters), and I don't want to maintain a buffer of the current line
when displaying the diagnostic.  So I believe the simplest solution is
to track the byte number in addition to the screen column.

* src/location.h, src/location.c (boundary): Add the byte-column.
Adjust dependencies.
* src/getargs.c, src/scan-gram.l: Adjust.
* tests/diagnostics.at: Check zero-width locations.
2019-04-23 18:29:10 +02:00
Akim Demaille 520d474ec6 diagnostics: check the styling
Enable checking of styles even when libtextstyle is not installed.

* src/getargs.h, src/getargs.c (style_debug): New.
(getargs_colors): Set it when --style=debug.
* src/complain.c (begin_use_class, end_use_class): Use it.
* tests/diagnostics.at: New.
2019-04-23 18:29:10 +02:00
Akim Demaille deec7ca65c TODO: update
Let's prepare 3.4 with more or less what we have.  Schedule some
features for 3.5 and 3.6.  Remove obsolete stuff.
2019-04-23 18:25:30 +02:00
Akim Demaille dff7454371 doc: sort the warning categories
* doc/bison.texi, src/getargs.c: here.
2019-04-19 20:16:32 +02:00
Akim Demaille e50eedf3c5 style: formatting changes
* tests/actions.at, tests/calc.at, tests/input.at: here.
2019-04-19 20:16:32 +02:00
Akim Demaille 341776b03b graphviz: move constant computation out of a loop
* src/graphviz.c (output_red): here.
2019-04-19 20:16:32 +02:00
Akim Demaille 79f7afb125 diagnostics: fix memory leak in libtextstyle
* src/complain.h, src/complain.c (complain_free): New.
* src/main.c: Use it.
2019-04-18 22:19:18 +02:00
Akim Demaille 2f3d9717ee tests: remove useless feature
* tests/calc.at (read_signed_integer): Rename as...
(read_integer): this.
We never read signs here.
2019-04-17 08:50:22 +02:00
Akim Demaille 9ad7524659 traces: make closure() less verbose
* src/getargs.h, src/getargs.c (trace_closure): New.
* src/closure.c (closure): Use it.
2019-04-14 18:27:17 +02:00
Akim Demaille 4ec413da32 build: also generate the graph reports
* Makefile.am (AM_YFLAGS_WITH_LINES): here.
2019-04-14 16:04:23 +02:00
Akim Demaille 61d53e606d yacc.c: minor style change
* data/skeletons/yacc.c: To improve consistency with other similar
pieces of code.
2019-04-12 08:38:30 +02:00
Akim Demaille d67b7daa1d style: scope reduction in lalr.c
* src/lalr.c (initialize_goto_follows): here.
2019-04-12 08:38:30 +02:00
Akim Demaille 2ab70cf0c6 style: comment changes
* src/closure.h, src/closure.c, src/lalr.c: here.
2019-04-12 08:38:30 +02:00
Akim Demaille 99664706e2 traces: improve logs
* src/lalr.c: Move logs to a better place to understand the chronology
of events.
* src/symlist.c (symbol_list_syms_print): Don't dump core on type
elements.
2019-04-12 08:33:34 +02:00
Akim Demaille a745041b7d doc: minor fixes
* doc/bison.texi: Use consistently $ and @kbd in shell examples.
Prefer sticking to English words: output and file instead of outfile
and infile.
2019-04-07 12:45:45 +02:00
Akim Demaille 0dd97f7c87 regen 2019-04-03 19:20:39 +02:00
Akim Demaille 69a823c72d bison: use no-lines
The 'regen' commit in Bison's history are a nuisance.  They are
especially big because of the #lines.  Let's generate our parse
without these lines in the repository, but generate them in the
tarball.

* Makefile.am (AM_YFLAGS_WITH_LINES): New.
(AM_YFLAGS): Use it.
(dist-hook): Regenerate the parser with #lines.
2019-04-03 19:20:39 +02:00
Akim Demaille 0f193d2d21 no-lines: avoid leaving an empty line instead of the syncline
Currently, with --no-lines, instead of "#line file line\n", we emit
"\n".  Let's emit nothing.

* data/skeletons/bison.m4 (b4_syncline): Emit at end-of-line when enabled.
* data/skeletons/bison.m4, data/skeletons/c.m4, data/skeletons/glr.cc,
* data/skeletons/lalr1.cc, src/output.c: Use dnl after b4_syncline to
avoid spurious empty lines.

* tests/synclines.at (Sync Lines): Make sure that --no-lines is like
grep -v #line.
* tests/calc.at: Make sure that a rich grammar file behaves properly
with %no-lines.
2019-04-03 19:20:39 +02:00
Akim Demaille 9832fdd6ef java: use full locations for diagnostics about destructors
Currently we use the syncline to report errors about a symbol's
destructor/printer.  This is not accurate (only file and line), and
this is incorrect: the file name is double quotes (a recent change,
needed to make sure we escape properly double quotes in it).  And
worst of all: with --no-line, b4_syncline expands to nothing.

Rather, push the locations into the backend, and use them.

* src/muscle-tab.h, src/muscle-tab.c (muscle_location_grow): Make it
public.
* src/output.c (prepare_symbol_definitions): Use it to pubish the
location of the printer and destructor.
* data/skeletons/lalr1.java: Use complain_at instead of complain.
* tests/java.at (Java invalid directives): Adjust expectations.
* data/skeletons/bison.m4 (b4_symbol_action_location): Remove.
We should not use b4_syncline this way.
2019-04-03 19:20:39 +02:00
Akim Demaille 507c679b9b java: prefer errors to fatal errors
Fatal errors are inconvenient, and should be reserved to cases where
we cannot continue.  Here, it could even be warnings actually: these
directives will simply be ignored.

* data/skeletons/lalr1.java: Prefer error (b4_complain) to fatal
errors (b4_fatal).
* tests/java.at (Java invalid directives): New.
2019-04-03 19:20:39 +02:00
Akim Demaille 0b42cf8a36 tests: formatting changes
* tests/javapush.at: here.
2019-04-03 19:20:39 +02:00
Akim Demaille 10175e4a65 lalr: offer more flexibility in debugging routines
* src/state.h, src/state.c (state_transitions_print): New, extracted
from...
(state_transitions_set): here.
2019-04-03 07:29:54 +02:00
Akim Demaille 18831f985c lalr: don't overbook memory
I never understood why we book ngotos+1 slots for relations between
gotos: there are at most ngotos images, not ngotos+1 (and "includes"
does have cases where a goto is in relation with itself, so it's not
ngotos-1).

Maybe bbf37f2534 explains the +1: a bug
left us register a goto several times on occasion, and the +1 might
have been a means to avoid this problem in most cases.  Now that this
bug is addressed, we should no longer overbook memory, if only for the
clarity of the code ("why ngotos+1 instead of ngotos?").

* src/lalr.c: A goto has at most ngotos images, not ngotos+1.
While at it, avoid useless repeated call to map_goto introduced in
bbf37f2534.
2019-03-31 13:59:28 +02:00
Akim Demaille 6d4e6bf118 lalr: show lookback for debug
* src/lalr.c (lookback_print): New.
(build_relations): Use it.
Also show edges.
2019-03-30 17:34:56 +01:00
Akim Demaille a8558bc5a6 diagnostics: don't crash when declaring the error token as an nterm
Reported by wcventure.
http://lists.gnu.org/archive/html/bug-bison/2019-03/msg00008.html

* src/symtab.c (complain_class_redeclared): Don't print empty
locations.
There can only be empty locations for predefined symbols.  And the
only symbol that is lexically available is the error token.  So this
appears to be the only possible way to have an error involving an
empty location.
* tests/input.at (Symbol class redefinition): Check it.
2019-03-30 16:37:47 +01:00
Akim Demaille bbf37f2534 lalr: fix segmentation violation
The "includes" relation [DeRemer 1982] is between gotos, so of course,
for a given goto, there cannot be more that ngotos (number of gotos)
images.  But we manipulate the set of images of a goto as a list,
without checking that an image was not already introduced.  So we can
"register" way more images than ngotos, leading to a crash (heap
buffer overflow).

Reported by wcventure.
http://lists.gnu.org/archive/html/bug-bison/2019-03/msg00007.html

For the records, this bug is present in the first committed version of
Bison.

* src/lalr.c (build_relations): Don't insert the same goto several
times.
* tests/sets.at (Build Relations): New.
2019-03-30 10:10:39 +01:00
Akim Demaille d332ff3c77 state: more debug traces
* src/state.c (state_transitions_set): Show the transitions.
2019-03-30 10:10:39 +01:00
Akim Demaille eb92ec3dc6 style: rename variables for consistency
* src/lalr.c: Use trans for transitions, and reds for reductions, as
elsewhere in the code.
* src/state.h: Comment changes.
2019-03-30 10:10:39 +01:00
Akim Demaille dee8fbbc1e gram: fix and improve log message
It seems that not many people read these logs: the error was
introduced in 2001 (3067fbef53),

* src/gram.c (grammar_dump): Fix the headers of the table: remove
duplicate display of "Ritem Range".
While at it, remove duplicate display of the rule number (and remove
an incorrect comment about it: these numbers _are_ equal).
* tests/sets.at (Reduced Grammar): Use useless rule, nterm and token
in the example.
2019-03-30 10:10:39 +01:00
Akim Demaille 75303c61d8 tests: add a tool for mass updates
When we update some output format, too many adjustements must be made
by hand.  This script updates most tests based on the actual output
made during the tests.

* build-aux/update-test: New.
2019-03-30 08:20:31 +01:00
Akim Demaille af99826ef4 style: remove now useless _GL_UNUSED
* src/getargs.c (getargs_colors): Here.
Useless since 4d34b06fb3.
2019-03-25 08:39:50 +01:00
Theophile RanquetandAkim Demaille af1c6f973a tables: use bitsets for a performance boost
Suggested by Yuri at
<http://lists.gnu.org/archive/html/bison-patches/2012-01/msg00000.html>.

The improvement is marginal for most grammars, but notable for large
grammars (e.g., PosgreSQL's postgre.y), and very large for the
sample.y grammar submitted by Yuri in
http://lists.gnu.org/archive/html/bison-patches/2012-01/msg00012.html.
Measured with --trace=time -fsyntax-only.

parser action tables    postgre.y     sample.y
Before                 0,129 (44%)  37,095 (99%)
After                  0,117 (42%)   5,046 (93%)

* src/tables.c (pos): Replace this set of integer coded as an unsorted
array or integers with...
(pos_set): this bitset.
2019-03-24 19:16:19 +01:00
Akim Demaille b5cd777ad6 yacc.c: don't suggest api.header.include when --defines is not used
See 4e19ab9fcd: the suggestion to
include the header file should not be emitted when the header is not
generated.

* data/skeletons/yacc.c: Here.
2019-03-24 18:52:58 +01:00
Akim Demaille ae91c3cce3 reader: clarify variable names
* src/reader.c (grammar_rule_check_and_complete): When 'p' and 'lhs'
are aliases, prefer the latter, for clarity and consistency.
(grammar_current_rule_begin): Avoid 'p', current_rule suffices.
* src/gram.h, src/gram.c: Comment changes.

ptdr#	calc.tab.c
2019-03-24 18:40:46 +01:00
Akim Demaille 5de4e79fc8 diagnostics: style changes
* src/location.c (location_caret): Clarify a bit.
2019-03-24 18:40:46 +01:00
Akim Demaille 4d34b06fb3 diagnostics: use gnulib's libtextstyle-optional
Bruno Haible just added a default implementation of libtextstyle's
interface when the library is not available.
https://lists.gnu.org/archive/html/bison-patches/2019-03/msg00025.html

* gnulib: Update.
* bootstrap.conf: Replace libtextstyle with libtextstyle-optional.
* src/complain.c, src/getargs.c: Remove now useless cpp guards.
2019-03-24 18:40:46 +01:00
Akim Demaille 22a413ce9f diagnostics: fix handling of style in limit cases
* src/location.c (location_caret): Beware of the cases where the start
and end columns are the same, or when the location is multilines.
2019-03-23 10:21:18 +01:00
Akim Demaille 01855ca328 warnings: don't use _Noreturn with G++ 4.7 in C++98 mode
The timevar and bitset modules now use the c99 module which causes
$CXX to now include -std=gnu++11 when possible.  Unfortunately, G++
4.7 does not implement [[noreturn]] in C++11 mode, so our tests of
glr.cc (which uses _Noreturn) fail with

    input.cc:954:1: error: expected unqualified-id before '[' token

right before [[noreturn]].  4.8 works fine.

* data/skeletons/c.m4 (b4_attribute_define): Do not use [[noreturn]]
with GCC 4.7.
2019-03-23 10:15:11 +01:00
Akim Demaille 225bc5836a d: tests: use more a natural approach for the scanner
See f8408562f8.

* tests/calc.at: Stop imitating the C API.
Prepare more tests to run in the future.
%verbose works as expected (what a surprise, it's unrelated to the
skeleton...).
2019-03-17 16:43:36 +01:00
Akim Demaille 941cdf921d regen 2019-03-17 16:36:05 +01:00
Akim Demaille 58ae95670b style: rename spec_defines_file as spec_header_file
The variable spec_defines_file denotes the name of the generated
header.  Its name is derived from --defines/%defines, whose name in
turn is derived from the fact that the header, in Yacc, contained the

Not only does the header now contain a lot more than just the token
definitions, but we no longer even generate macros, but an enum...

Let's modernize our vocabulary.

* src/files.h, src/files.c (spec_defines_file): Rename as...
(spec_header_file): this.
2019-03-17 16:36:05 +01:00
Akim Demaille 4e19ab9fcd yacc.c: provide a means to include the header in the implementation
Currently when --defines is used, we generate a header, and paste an
exact copy of it into the generated parser implementation file.  Let's
provide a means to #include it instead.

We don't do it by default because of the Autotools' ylwrap.  This
program wraps invocations of yacc (that uses a fixed output name:
y.tab.c, y.tab.h, y.output) to support a more modern naming
scheme (dir/foo.y -> dir/foo.tab.c, dir/foo.tab.h, etc.).  It does
that by renaming the generated files, and then by running sed to
propagate these renamings inside the files themselves.

Unfortunately Automake's Makefiles uses Bison as if it were Yacc (with
--yacc or with -o y.tab.c) and invoke bison via ylwrap.  As a
consequence, as far as Bison is concerned, the output files are
y.tab.c and y.tab.h, so it emits '#include "y.tab.h"'.  So far, so
good.  But now ylwrap processes this '#include "y.tab.h"' into
'#include "dir/foo.tab.h"', which is not guaranteed to always work.

So, let's do the Right Thing when the output file is not y.tab.c, in
which case the user should %define api.header.include.  Binding this
behavior to --yacc is tempting, but we recently told people to stop
using --yacc (as it also enables the Yacc warnings), but rather to use
-o y.tab.c.

Yacc.c is the only skeleton concerned: all the others do include their
header.

* data/skeletons/yacc.c (b4_header_include_if): New.
(api.header.include): Provide a default value when the output is not
y.tab.c.
* src/parse-gram.y (api.header.include): Define.
2019-03-17 16:36:05 +01:00
Akim Demaille 6cb612e7e3 d: don't link against LIBS
* tests/local.at (AT_COMPILE_D): Don't pass LIBS, dmd does not like
being given -lintl.
2019-03-17 13:21:25 +01:00
Akim Demaille 35add841ee address warnings from GCC's UB sanitizer
Running with CC='gcc-mp-8 -fsanitize=undefined' revealed Undefined
Behaviors.
https://lists.gnu.org/archive/html/bison-patches/2019-03/msg00008.html

* src/state.c (errs_new): Don't call memcpy with NULL as source.
* src/location.c (add_column_width): Don't assume that the column
argument is nonnegative: the scanner sometimes "backtracks" (e.g., see
ROLLBACK_CURRENT_TOKEN and DEPRECATED) in which case we can have
negative column numbers (temporarily).
Found in test 3 (Invalid inputs).
2019-03-17 13:21:25 +01:00
Akim Demaille f6e38d7ac9 diagnostics: use libtextstyle for colored output
Bruno Haible released libtextstyle, a library for colored output based
on CSS.  Let's use it to generate colored diagnostics, provided
libtextstyle is available.

See
https://lists.gnu.org/archive/html/bug-gnulib/2019-01/msg00176.html
https://lists.gnu.org/archive/html/bison-patches/2019-02/msg00073.html
https://lists.gnu.org/archive/html/bison-patches/2019-02/msg00084.html
https://lists.gnu.org/archive/html/bison-patches/2019-03/msg00007.html

* bootstrap.conf (gnulib_modules): Use libtextstyle when possible.
* data/diagnostics.css: New.
* src/complain.c (begin_use_class, end_use_class, flush)
(severity_style, complain_init_color): New.
Use them.
* src/getargs.c (getargs_colors): New.
(getargs): Use it.
Skip --color and --style.
* src/location.h, src/location.c (location_print): Use a style.

* tests/bison.in: Force --color=yes when stderr is a tty.
* tests/local.at: Disable colors during the test suite.
* tests/input.at: Adjust expectations to the extra options passed on
the command line.
2019-03-16 16:46:17 +01:00
Akim Demaille 855fbf1c11 style: clean up complain.c
* src/complain.c (severity_prefix): New.
(error_message): Take the severity as argument, instead of the prefix.
2019-03-16 16:46:17 +01:00
Akim Demaille e5ec21215e yacc.c: emit the header before the implementation file
* data/skeletons/yacc.c: here.
This is more logical for the time stamps, but it's also required by
following patches: the shared declarations are also in charge of
handling api.value.type=union.  So far, they are run in the
implementation file in both cases (with or without header).  But if we
run them only in the header, then the implementation file is emited
with incorrect support for api.value.type=union.
Arguably we should not have such dependencies.  This is because we
have side-effects in our backend (redefining the symbols' type and
type_tag).  In the future we should find a better solution for this,
without sacrificing the independence of the backend from bison
itself (i.e., I don't think we should handle api.value.type=union in
bison, leave it to m4).
2019-03-16 10:14:18 +01:00
Akim Demaille 91bbf4219d simplify the generated #line
Currently we generate things like:

    #line 683 "src/parse-gram.y" /* yacc.c:316  */

The first part is of course very important: compilers point the users
to their grammar file rather than into the generated parser.  The
second part points to the place in the skeletons that generated this
piece of code.

This dependency on the Bison skeletons generates 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 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.

So now, generate:

    #line 683 "src/parse-gram.y"

* data/skeletons/bison.m4 (b4_sync_end): Emit nothing.
2019-03-16 10:12:09 +01:00
Akim Demaille f4c1586454 gnulib: update 2019-03-13 08:21:34 +01:00
Akim Demaille 9a71d9d1c6 tests: remove duplicates
* tests/regression.at (Invalid inputs, Invalid inputs with {}):
Remove, there are exact copies of them in input.at.
2019-03-13 08:21:34 +01:00
Akim Demaille bb0310a353 d: simplify the API to build the scanner of the example
* examples/d/calc.y (calcLexer): Add an overload for File.
Use it.
2019-03-02 09:56:41 +01:00
H. S. TeohandAkim Demaille f8408562f8 d: modernize the scanner of the example
https://lists.gnu.org/archive/html/bison-patches/2019-02/msg00121.html

* examples/d/calc.y (CalcLexer): Stop shoehorning C's API into D: use
a range based approach in the scanner, rather than some imitation of
getc/ungetc.
(main): Adjust.
2019-03-01 21:56:06 +01:00
Akim Demaille 8eac78f8ef d: tests: use fewer global variables
* tests/calc.at: Move 'input' into the scanner.
2019-03-01 21:56:06 +01:00
Akim Demaille d57751d2fb lalr: clarify the count of lookaheads
* src/lalr.c (state_lookahead_tokens_count): Remove wierd `+=` that is
actually an `=`.
2019-02-28 06:47:19 +01:00
Akim Demaille e062b9f70d lalr: clarify the API
* src/state.h, src/state.c (state_reduction_find): Clarify.
Die on errors.
* src/lalr.c (goto_list_new): New.
Use it.
2019-02-28 06:47:19 +01:00
Akim Demaille c837141832 lalr: improve traces
* src/lalr.c (follows_print): Just print the symbol tag.
Take and print a title.
Indent the output.
Use it to print the various steps of the computation.
(lookahead_tokens_print): Fix a lie: the number displayed is not the
number of tokens.
Don't display states that don't even have reductions.
2019-02-28 06:47:19 +01:00
Akim Demaille a415a78d71 lalr: print the 'reads' relation
* src/relation.h, src/relation.c (relation_print): Accept and use a
title.
Don't print empty rows.
Indent the output.
Adjust dependencies.
* src/lalr.c (initialize_goto_follows): Print 'reads' in traces.
2019-02-27 19:06:32 +01:00
Akim Demaille 5255b919ae style: comment changes
* src/lr0.c: here.
2019-02-27 19:06:32 +01:00
Akim Demaille b12f9c76e2 dlang: initial changes to run the calc tests on it
* configure.ac (DCFLAGS): Define.
* tests/atlocal.in: Receive it.
* data/skeletons/d.m4 (api.parser.class): Remove spurious YY.
* data/skeletons/lalr1.d (yylex): Return an int instead of a
YYTokenType, so that we can use characters as tokens.
* examples/d/calc.y: Adjust.
* tests/local.at: Initial support for D.
(AT_D_IF, AT_DATA_GRAMMAR(D), AT_YYERROR_DECLARE(d))
(AT_YYERROR_DECLARE_EXTERN(d), AT_YYERROR_DEFINE(d))
(AT_MAIN_DEFINE(d), AT_COMPILE_D, AT_LANG_COMPILE(d), AT_LANG_EXT(d)):
New.
* tests/calc.at: Initial support for D.
* tests/headers.at
2019-02-26 18:27:13 +01:00
Akim Demaille 575b814119 d: improve the example
* examples/d/calc.y: Exit with failure on errors.
Remove useless operators (=, !) meant for the test suite.
Add unary + for symmetry.
* examples/d/calc.test: Adjust expectations.
2019-02-26 08:42:24 +01:00
Akim Demaille 661bbacfc7 tests: style changes
* tests/local.at AT_YYERROR_DEFINE(java): Use more consistent names.
2019-02-26 08:42:24 +01:00
Akim Demaille d04962f788 style: eliminate useless indirection
* src/relation.h, src/relation.c (relation_digraph): Don't take the
biteetv as a pointer, it is already a pointer (as it's an array).
2019-02-25 06:19:55 +01:00
Akim Demaille ec8142391a style: rename function for clarity
Commit db34f79889 renames the variable F
as goto_follows, but forgot to rename this function.

* src/lalr.c (initialize_F): Rename as...
(initialize_goto_follows): this.
2019-02-25 06:19:55 +01:00
Akim Demaille 59bec5fade lalr: more debug traces
I need to be able to read includes and goto_follows.

* src/relation.h, src/relation.c (relation_print): Provide a means to
pretty-print the nodes of the relation.
* src/lalr.c (goto_print, follows_print): New.
(set_goto_map): Use goto_print.
(build_relations): Show INCLUDES.
(compute_FOLLOWS): Rename as...
(compute_follows): this.
Show FOLLOWS.
2019-02-25 06:19:54 +01:00
Akim Demaille 5230e610fc style: minor changes
* examples/c/calc/calc.y, src/lalr.c: Reduce scope.
* src/gram.c: Prefer < to >.
2019-02-24 19:08:01 +01:00
Akim Demaille b81419a9fd style: clarify the computation of the lookback edges
* src/lalr.c (build_relations): Reduce the scopes.
Instead of keeping rp alive in two different loops, clarify the second
one by having an index on the path we traverse (i.e., use that index
to compute the source state _and_ the symbol that labels the
transition).
This allows to turn an obscure 'while'-loop in a clearer (IMHO)
'for'-loop.  We also consume more variables (by introducing p instead
of making more side effects on length), but we're in 2019, I don't
think this matters.  What does matter is that (IMHO again), this is
now clearer.
Also, use clearer names.
2019-02-24 19:07:32 +01:00
Akim Demaille 2b9ee006d8 style: scope reduction in tables.c
* src/tables.c: here.
* src/lalr.c: Prefer < to >.
2019-02-24 12:00:44 +01:00
Akim Demaille 609b40f1a1 d: formatting changes
* data/skeletons/d.m4, data/skeletons/lalr1.d: Avoid trailing spaces.
2019-02-24 07:03:59 +01:00
Akim Demaille 1e76448ced examples: remove stray examples
* examples/c/reentrant-calc: Remove.
I did not mean to include this example, it was replaced by
examples/c/reccalc.
2019-02-23 11:42:55 +01:00
Akim Demaille 967a59d2c0 tests: factor the execution of Java parsers
* tests/local.at (AT_MAIN_DEFINE(java)): Exit failure on failure.
(AT_PARSER_CHECK): If in Java, run AT_JAVA_PARSER_CHECK.
* tests/conflicts.at (AT_CONSISTENT_ERRORS_CHECK): Simplify.
2019-02-21 17:46:11 +01:00
Akim Demaille fbf94ac900 tests: fix a Java tests
* tests/conflicts.at (AT_CONSISTENT_ERRORS_CHECK): Fix quotation error.
2019-02-21 17:46:11 +01:00
Akim Demaille a11c144609 tests: simplify AT_PARSER_CHECK usage
Currently the caller must specify the ./ prefix to its command.  Let's
avoid that: it will be nicer to read, make it easier to have a version
that works for Java and C/C++.

* tests/local.at (AT_PARSER_CHECK): Prefix the command with ./.
Adjust callers.
2019-02-21 17:46:11 +01:00
Akim Demaille 4848092bf8 tests: java: factor the definition of Position
* tests/local.at (AT_JAVA_POSITION_DEFINE): New.
* tests/java.at, tests/javapush.at: Use it.
2019-02-21 17:46:11 +01:00
Akim Demaille 948f3decb4 tests: dispatch per lang on AT_DATA_GRAMMAR
* tests/java.at: Do that.
* tests/conflicts.at: Simplify.

* tests/actions.at, tests/c++.at, tests/input.at, tests/local.at,
* tests/named-refs.at:
Use AT_BISON_OPTION_PUSHDEFS/AT_BISON_OPTION_POPDEFS.
2019-02-21 17:46:11 +01:00
Akim Demaille 7d6747cec9 tests: dispatch per lang on the definition of yylex
* tests/local.at (AT_YYLEX_DEFINE): Dispatch on the language.
(AT_YYLEX_DEFINE(java)): New.
* tests/conflicts.at, tests/java.at: Use it.
2019-02-21 17:46:11 +01:00
Akim Demaille 420e7b03ec tests: de-duplicate
* tests/conflicts.at (AT_YYLEX_PROTOTYPE): Don't define it, leave that
task to AT_DATA_GRAMMAR.
But be honest: tell AT_BISON_OPTION_PUSHDEFS all the options we use.
2019-02-21 17:46:11 +01:00
Akim Demaille b31015a927 tests: formatting changes
* tests/local.at: here.
2019-02-21 17:46:11 +01:00
Akim Demaille bd55d43333 graph: prefer *.gv to *.dot
Reported by Hans Åberg.
https://lists.gnu.org/archive/html/help-bison/2019-02/msg00064.html

* src/files.c (spec_graph_file): Use `*.gv` when 3.4 or better,
otherwise `*.dot`.
* src/parse-gram.y (handle_require): Pretend we are already 3.4.
* doc/bison.texi: Adjust.
* tests/local.at, tests/output.at: Exercise this.
2019-02-21 06:46:07 +01:00
Akim Demaille 98020cedf7 doc: fixes to please older versions of Texinfo
Currently, we have errors:

    ./doc/bison.texi:13005: node `History' lacks menu item for `Yacc' despite being its Up target

* doc/bison.texi (History): Add the local menu.
While at it, add a few index entries.
2019-02-21 06:46:07 +01:00
Akim Demaille cbf213915c doc: style changes
* doc/bison.texi (Bibliography): Add [Corbett 1984] and [Johnson
1978].
(History): Use them.
And other minor changes.
2019-02-17 12:20:40 +01:00
Eric S. RaymondandAkim Demaille 93371999ee doc: a history section
* bison.texi (A Brief History of the Greater Ungulates): New section.
2019-02-17 11:37:14 +01:00
Akim Demaille 6289d673a0 examples: add an example with a reentrant parser in Flex+Bison
Suggested by Eric S. Raymond.
https://lists.gnu.org/archive/html/bison-patches/2019-02/msg00066.html

* examples/c/reentrant-calc/Makefile, examples/c/reentrant-calc/README.md,
* examples/c/reentrant-calc/parse.y, examples/c/reentrant-calc/scan.l
* examples/c/reentrant-calc/lexcalc.test,
* examples/c/reentrant-calc/local.mk:
New.
2019-02-17 11:31:51 +01:00
Akim Demaille 0adda755a2 examples: fixes in lexcalc
* examples/c/lexcalc/parse.y: Formatting/comment changes.
(line): Don't return a value.
Print the result here, which avoids printing a value for lines with an
error.
(yyerror): Be sure to increment the pointed, not the pointer...
* examples/c/lexcalc/lexcalc.test: Check errors.
* examples/c/lexcalc/local.mk: Fix a dependency.
2019-02-16 16:51:15 +01:00
Akim Demaille 0782ed3274 build: fix distcheck
Regression introduced in 05a8097779.

* doc/local.mk (bison.help): Don't depend on the path of the bison
executable.
2019-02-16 15:54:38 +01:00
Akim Demaille d7ec136ffb style: move pkgdatadir to files.*
Let's move it to a more logical place.

* src/output.h, src/output.c (pkgdatadir): Move to...
* src/files.h, src/files.c: here.
2019-02-16 07:26:16 +01:00
Akim Demaille dbdf2878ab style: rename cleanup_caret as caret_free
* src/location.c, src/location.h, src/main.c: here.
2019-02-14 18:53:01 +01:00
Akim Demaille 8654fca058 style: avoid default in switch on enums
* src/assoc.c (assoc_to_string): here.
2019-02-14 06:27:03 +01:00
Akim Demaille 05a8097779 doc: run tests/bison, not src/bison
* doc/local.mk: Don't run src/bison, as it expects to find all its
files installed.  Instead, run tests/bison which is ready to run in
builddir.
2019-02-14 06:26:48 +01:00
Akim Demaille c06ec1f132 gnulib: update 2019-02-13 07:26:38 +01:00
Akim Demaille fb83319d9c style: comment and names changes in map_goto
* src/lalr.h, src/lalr.c: Use clearer names.
2019-02-12 06:19:10 +01:00
Akim Demaille e42a7a1862 yacc: support parse.assert
While hacking on the computation of the automaton, I had yystate being
equal to -1, and the parser loops.  Let's catch this when
parser.assert is enabled.

* data/skeletons/yacc.c (YY_ASSERT): New.
Use it.
Not using the name YYASSERT, to make it clear that this is private.
glr.c should probably move to YY_ASSERT too.
Also, while at it, report 'Entering state...' even before growing the
stacks.
2019-02-12 06:19:10 +01:00
Akim Demaille 8cbf3ce22c examples: depend on Bison's sources
* examples/c/calc/local.mk, examples/c/lexcalc/local.mk,
* examples/c/mfcalc/local.mk, examples/c/rpcalc/local.mk:
Regenerate the files if dependencies have changed.
2019-02-12 06:19:10 +01:00
Eric S. RaymondandAkim Demaille 1997093e21 README: point to README-hacking
* README (Build from git): New.
* README-hacking: Describe easier submodule update.
2019-02-12 06:19:10 +01:00
Akim Demaille f23b879ff5 doc: a single space before closing comments
I don't think this style:

    /* If buffer is full, make it bigger.        */
    if (i == length)
      {
        length *= 2;
        symbuf = (char *) realloc (symbuf, length + 1);
      }
    /* Add this character to the buffer.         */
    symbuf[i++] = c;
    /* Get another character.                    */
    c = getchar ();

or more readable than

    /* If buffer is full, make it bigger. */
    if (i == length)
      {
        length *= 2;
        symbuf = (char *) realloc (symbuf, length + 1);
      }
    /* Add this character to the buffer. */
    symbuf[i++] = c;
    /* Get another character. */
    c = getchar ();

Actually, I think the latter is more readable, and helps with width
issues in the PDF.  As a matter of fact, I would happily move to //
only for single line comments.

* doc/bison.texi: A single space before closing comments.
2019-02-10 17:44:23 +01:00
Akim Demaille 8b2d233283 doc: modernize the examples
* doc/bison.texi: Prefer 'fun' to 'fnct'.
Reduce local variable scopes.
Prefer strdup to malloc + strcpy.
Avoid gratuitous casts.
Use simpler names (e.g., 'name' instead of 'fname').
Avoid uses of 0 for NULL.
Avoid using NULL when possible (e.g., 'p' instead of 'p != NULL').
Prefer union names to casts (e.g. 'yylval.VAR = s' instead of
'*((symrec**) &yylval) = s').
Give arguments a name in fun declarations.
Use our typedefs instead of duplicating them (func_t).
Stop promoting an explicit $$ = $1;, it should be implicit (Bison
might be able to eliminate useless chain rules).
Help a bit Texinfo by making smaller groups.
Rely on the C compiler to call function pointers (prefer
'$1->value.fun ($3)' to (*($1->value.fnctptr))($3)').
2019-02-10 17:44:23 +01:00
Akim Demaille 40fc688765 examples: add a simple infix calculator in C
Currently we have no simple example: rpcalc in reverse Polish, mfcalc
has functions, and lexcalc is using lex.

* examples/c/calc/Makefile, examples/c/calc/calc.y,
* examples/c/calc/calc.test, examples/c/calc/local.mk: New.
2019-02-10 17:44:23 +01:00
Akim Demaille 30f61b0549 examples: fix annoying off-by-one errors
* examples/extexi: Since we issue #lines only at the beginning of
@example, leave empty line when removing content (such as @comment
lines), otherwise the lines that follow have incorrect source line
location.  This leaves ugly empty lines, but they are removed when you
tidy the output for the end user: sequences of \n are mapped to at
most two sucessive \n.
2019-02-10 16:41:50 +01:00
Akim Demaille ad7d8af6d1 style: factor printing of rules
* src/gram.h, src/gram.c (rule_print): New.
Use it.
2019-02-09 08:59:55 +01:00
Akim Demaille f293345aa8 style: use lower case for variable names
* src/relation.c (INDEX, VERTICES): Rename as...
(indexes, vertices): these.
2019-02-09 08:58:12 +01:00
Akim Demaille e18ad5a96b style: scope reduction in relation.c 2019-02-09 08:58:12 +01:00
Akim Demaille dd232b95b7 report: stop counting uselessly
* src/print.c (print_nonterminal_symbols): Replace left_count and
right_count with on_left and on_right.
2019-02-09 08:23:50 +01:00
Akim Demaille 51861998c7 report: clean up its format
The format is inconsistent.  For instance most sections are
indented (including "Terminals unused in grammar" for instance), but
the sections "Terminals, with rules where they appear" and
"Nonterminals, with rules where they appear" are not.  Let's indent
them.  Also, these two sections try to wrap the output to avoid lines
too long.  Yet we don't do that in the rest of the file, for instance
when listing the lookaheads of an item.

For instance in the case of Bison's parse-gram.output we go from:

    Terminals, with rules where they appear

    "end of file" (0) 0
    error (256) 28 88
    "string" <char*> (258) 9 13 16 17 20 23 24 109 116
    [...]

    Nonterminals, with rules where they appear

    $accept (58)
        on left: 0
    input (59)
        on left: 1, on right: 0
    prologue_declarations (60)
        on left: 2 3, on right: 1 3
    prologue_declaration (61)
        on left: 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 22 23 24
        25 26 27 28 29, on right: 3
    [...]

to

    Terminals, with rules where they appear

    "end of file" (0) 0
    error (256) 28 88
    "string" <char*> (258) 9 13 16 17 20 23 24 109 116
    [...]

    Nonterminals, with rules where they appear

        $accept (58)
            on left: 0
        input (59)
            on left: 1
            on right: 0
        prologue_declarations (60)
            on left: 2 3
            on right: 1 3
        prologue_declaration (61)
            on left: 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 22 23 24 25 26 27 28 29
            on right: 3
    [...]

* src/print.c (END_TEST): Remove.
(print_terminal_symbols): Don't try to wrap the output.
(print_nonterminal_symbols): Likewise.
Make two different lines for occurrences on the left, and occurrence
on the rhs of the rules.
Indent by 4 and 8, not 3.
* src/reduce.c (reduce_output): Indent by 4, not 3.

* tests/conflicts.at, tests/existing.at, tests/reduce.at,
* tests/regression.at, tests/report.at:
Adjust.
2019-02-09 08:23:50 +01:00
Akim Demaille e346210c03 add LR(0) output
This should not be used to generate parsers.  My point is actually to
facilitate debugging (when tweaking the generation of the LR(0)
automaton for instance, not carying -yet- about lookaheads).

* src/reader.c (prepare_percent_define_front_end_variables): Add lr(0).
* src/conflicts.c (set_conflicts): Be robust to reds not having
lookaheads at all.
* src/ielr.c (LrType, lr_type_get): Adjust.
(ielr): Implement support for LR(0).
* src/lalr.c (lalr_free): Don't free LA when it's not computed.
2019-02-05 19:02:09 +01:00
Akim Demaille 0d44f83fcc style: scope reduction in derives.c
* src/derives.c: here.
2019-02-05 08:45:52 +01:00
Akim Demaille 40b5f89ee0 style: comment changes and refactoring in state.c
* src/state.h, src/state.c: Comment changes.
(transitions_to): Take a state* as argument.
* src/lalr.h, src/lalr.c: Comment changes.
(initialize_F): Use clear variable names.
2019-02-05 08:45:52 +01:00
Akim Demaille eed9550993 tests: fix typos
* tests/reduce.at: here.
2019-02-05 08:45:52 +01:00
Akim Demaille cf96d1b0af Merge branch maint
* maint:
  maint: post-release administrivia
  version 3.3.2
  style: minor fixes
  NEWS: named constructors are preferable to symbol_type ctors
  gram: fix handling of nterms in actions when some are unused
  style: rename local variable
  CI: update the ICC serial number for travis-ci.org
2019-02-03 15:23:54 +01:00
Akim Demaille 3d25b52a10 maint: post-release administrivia
* NEWS: Add header line for next release.
* .prev-version: Record previous version.
* cfg.mk (old_NEWS_hash): Auto-update.
2019-02-03 14:56:05 +01:00
Akim Demaille 437f6250c5 version 3.3.2
* NEWS: Record release date.
2019-02-03 14:42:30 +01:00
Akim Demaille 334cb8f222 style: minor fixes
* NEWS, src/reduce.c, src/reduce.h: Use 'nonterminal'.
Fix comments.
2019-02-03 14:42:22 +01:00
Akim Demaille 03878edf77 NEWS: named constructors are preferable to symbol_type ctors
Reported by Frank Heckenbach.
http://lists.gnu.org/archive/html/bug-bison/2019-01/msg00043.html
2019-02-03 10:06:25 +01:00
Akim Demaille cacdfc2f6e gram: fix handling of nterms in actions when some are unused
Since Bison 3.3, semantic values in rule actions (i.e., '$...') are
passed to the m4 backend as the symbol number.  Unfortunately, when
there are unused symbols, the symbols are renumbered _after_ the
numbers were used in the rule actions.  As a result, the evaluation of
the skeleton failed because it used non existing symbol numbers.
Which is the happy scenario: we could use numbers of other existing
symbols...

Reported by Balázs Scheidler.
http://lists.gnu.org/archive/html/bug-bison/2019-01/msg00044.html

Translating the rule actions after the symbol renumbering moves too
many parts in bison.  Relying on the symbol identifiers is more
troublesome than it might first seem: some don't have an
identifier (tokens with only a literal string), some might have a
complex one (tokens with a literal string with characters special for
M4).  Well, these are tokens, but nterms also have issues: "dummy"
nterms (for midrule actions) are named $@32 etc. which is risky for
M4.

Instead, let's simply give M4 the mapping between the old numbers and
the new ones.  To avoid confusion between old and new numbers, always
emit pre-renumbering numbers as "orig NUM".

* data/README: Give details about "orig NUM".
* data/skeletons/bison.m4 (__b4_symbol, _b4_symbol): Resolve the
"orig NUM".
* src/output.c (prepare_symbol_definitions): Pass nterm_map to m4.
* src/reduce.h, src/reduce.c (nterm_map): Extract it from
nonterminals_reduce, to make it public.
(reduce_free): Free it.
* src/scan-code.l (handle_action_dollar): When referring to a nterm,
use "orig NUM".
* tests/reduce.at (Useless Parts): New, based Balázs Scheidler's
report.
2019-02-03 10:05:53 +01:00
Akim Demaille 56c00ed1ea tests: strengthen some of them
* tests/reduce.at: Check that the generated parsers are proper C.
2019-02-03 08:00:23 +01:00
Akim Demaille 513d2f723f package: rename data/README as data/README.md
So that it is properly rendered by online git services.
2019-02-03 07:28:57 +01:00
Akim Demaille 48429252c1 style: reduce scopes
* src/symlist.c (symbol_list_free): New.
2019-02-03 07:28:57 +01:00
Akim Demaille d459a5b8e6 style: prefer snprintf to sprintf
* src/symtab.c (dummy_symbol_get): There's no need for the buffer to
be so big and static.
Use snprintf for safety.
2019-02-03 07:28:57 +01:00
Akim Demaille 9566232422 style: comment and name changes
* src/output.c (prepare_symbol_names): here.
* src/reader.c: Remove obsolete comment.
* src/scan-code.l: Use || for Boolean or.
2019-02-02 17:32:10 +01:00
Akim Demaille dc654a925c style: comment changes
* src/reader.c, src/scan-code.l: here.
2019-02-02 17:32:04 +01:00
Akim Demaille 76366e8e5c make: regenerate the example parsers when bison changes
* Makefile.am (dependencies): Also depend on Bison's sources.
2019-02-02 17:31:58 +01:00
Akim Demaille 31788ed4c7 style: rename local variable
* src/reduce.c (nonterminals_reduce): Rename nontermmap as nterm_map.
We will expose it.
2019-02-02 16:37:25 +01:00
Akim Demaille 781d2b02de gram: detect and report (in debug traces) useless chain rules
A rule is a useless chain iff it's a chain (aka unit, or injection)
rule (i.e., the RHS has length 1), and it's useless (it has no used
defined semantic action).

* src/gram.h, src/gram.c (rule_useless_chain_p): New.
(grammar_dump): Report useless chain rules.
* tests/sets.at: Check the traces.
2019-01-30 07:08:09 +01:00
Akim Demaille 8b5fc2143f lr(0): more debug traces
* src/lr0.c (core_print, kernel_print): New.
Use them.
2019-01-30 07:08:09 +01:00
Akim Demaille 5670677cb6 lr(0): remove useless conditional
* src/lr0.c (new_itemsets): There's no harm in setting a Boolean
several times.
2019-01-30 07:08:08 +01:00
Akim Demaille 32b9dcecc7 style: sort includes and avoid assignments
* src/symtab.c: Sort includes.
* src/gram.c (grammar_rules_print_xml): Avoid assignments to define
'usefulness'.
2019-01-30 07:08:00 +01:00
Akim Demaille ac12b725ea style: use item_rule
* src/print-graph.c, src/print-xml.c: here.
2019-01-30 07:06:48 +01:00
Akim Demaille e1783bc686 gram: factor the printing of items and the computation of their rule
There are several places where we need to recover the rule from an
item, let's factor that into item_rule.  We also want to print items
in a nice way: we do it when generating the *output file, but it is
also useful in debug messages.

* src/gram.h, src/gram.c (item_rule, item_print): New.
* src/print.c (print_core): Use them.
* src/state.h, src/state.c: Propagate constness.
2019-01-30 07:06:48 +01:00
Akim Demaille c4f143eb96 style: scope reduction in print-xml
* src/print-xml.c: here.
2019-01-30 07:06:48 +01:00
Akim Demaille 94054924a9 tests: check XML and dot reports
* tests/report.at: Here.
2019-01-30 07:06:48 +01:00
Akim Demaille c639611002 CI: update the ICC serial number for travis-ci.org
On travis-ci.org, there are five concurrent slaves, instead of three
on travis-ci.com.
2019-01-28 19:53:25 +01:00
Akim Demaille 69061fed82 CI: update the ICC serial number for travis-ci.org
On travis-ci.org, there are five concurrent slaves, instead of three
on travis-ci.com.
2019-01-28 08:12:13 +01:00
Akim Demaille 3075d96d44 style: comment changes
* src/lr0.c, src/state.c, src/state.h: here.
2019-01-28 07:00:23 +01:00
Akim Demaille 7fec997ecf closure: initialize it once for all
The memory allocated by 'closure' (and some data such as 'fderives')
is used to computed a state's full itemset from its core.  This is
needed during the construction of the LR(0) automaton, and the memory
is reclaimed immediately afterwards.

Unfortunately the reports (graph, text, xml) also need this
information when describing the states with their full itemsets.  As a
consequence the memory was allocated again, fderives computed again
too, and more --trace reports are generated which only duplicate what
was already reported.

Stop that.  It does mean that we release the memory later (hence the
peak memory usage is higher now), but I don't think that's a problem
today.

* src/lr0.c (generate_states): Don't call closure_free.
* src/state.c (states_free): Do it here.
(for symmetry with closure_new which is called in generate_states).
* src/print-graph.c, src/print-xml.c, src/print.c: You can now expect
the closure module to be functional.
2019-01-28 06:57:31 +01:00
Akim Demaille 7355a35e4b style: rename closure_* functions as closure_*
This is more consistent with the other files.

* closure.h, closure.c (new_closure, free_closure): Rename as...
(closure_new, closure_free): this.
Adjust dependencies.
2019-01-28 06:47:33 +01:00
Akim Demaille e585377e68 lr0: use a bitset for the set of "shiftable symbols"
This will make it easier to add new elements (that might already be
part of shift_symbol) without having to worry about the size of
shift_symbol (which is currently a fixed size vector).

I could not measure any significant differences in performances in the
generation of LR(0) automaton (benched on gramamrs of Ruby, C, and C++).

* src/lr0.c (shift_symbol): Make it a bitset.
2019-01-28 06:47:33 +01:00
Akim Demaille 9cd7bd4d5f add -fsyntax-only
When debugging Bison itself, this is very handy, especially when
tweaking the frontend badly enough to break the backends. It can also
be used to check a grammar.

* src/getargs.h, src/getargs.c (feature_syntax_only): New.
(feature_args, feature_types): Adjust.
* src/main.c (main): Use it.
2019-01-28 06:47:07 +01:00
Akim Demaille a108d84f88 style: beware of collisions on status
* src/symtab.h (status): Rename as...
(declaration_status): this, to avoid colliding with status, the
argument of 'usage'.
'status' seems a tad too general to be used only here.
2019-01-27 20:07:08 +01:00
Akim Demaille 1e83dd2229 gnulib: update 2019-01-27 19:48:09 +01:00
Akim Demaille d02ca923e2 usage: document -ffixit
* src/getargs.c (usage): Document -ffixit.
Document the aliases of -f.
2019-01-27 18:08:55 +01:00
Akim Demaille f82f7eb1d8 style: reduce scopes in state.c and ielr.c 2019-01-27 18:08:47 +01:00
Akim Demaille 0d472b29ec Merge branch 'maint'
* maint:
  maint: post-release administrivia
  version 3.3.1
  yacc: issue warnings, not errors, for Bison extensions
  style: formatting changes in NEWS and complain.c
  tests: don't depend on the user's definition of SHELL
2019-01-27 16:44:56 +01:00
Akim Demaille 7a21067bb9 maint: post-release administrivia
* NEWS: Add header line for next release.
* .prev-version: Record previous version.
* cfg.mk (old_NEWS_hash): Auto-update.
2019-01-27 16:17:28 +01:00
Akim Demaille 21a7fa8063 traces: always print the reduced grammar and fix it
* src/gram.c (grammar_dump): Print the effective number first instead
of last.  And fix it (remove the incorrect "+1").
Use t/f for Booleans.
* src/reduce.c: When asked, always print the reduced grammar, even if
there was nothing useless.
* tests/sets.at (Reduced Grammar): Check that.
2019-01-26 16:21:35 +01:00
Akim Demaille 83463dfbee style: rename LR0.* as lr0.*
Let's stick to lower case for file names.

* src/LR0.h, src/LR0.c: Rename as...
* src/lr0.h, src/lr0.c: these.
2019-01-26 16:21:35 +01:00
Akim Demaille c3c50c0030 style: rename print_graph.* as print-graph.*
These are the only files with _.

* src/print_graph.h, src/print_graph.c: Rename as...
* src/print-graph.h, src/print-graph.c: these.
2019-01-26 16:16:47 +01:00
Akim Demaille e85ab7ac9b style: various fixes
* src/gram.c: Use consistent variable names.
Prefix prefix unary operators.
(grammar_dump): Use rule_rhs_length instead of duplicating it.
* src/reduce.c: Avoid useless variables.
2019-01-26 16:16:47 +01:00
Akim Demaille a11463a02f style: comment changes in gram.h
* src/gram.h: Shorten comments.
2019-01-26 16:16:47 +01:00
140 changed files with 6769 additions and 3726 deletions
+1
View File
@@ -1,3 +1,4 @@
/ABOUT-NLS~
*.eps
*.log
*.o
+1 -1
View File
@@ -1 +1 @@
3.3
3.3.90
+7 -3
View File
@@ -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
View File
@@ -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 \
+157 -11
View File
@@ -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"
+12 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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.]
+6
View File
@@ -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]
+75 -44
View File
@@ -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
View File
@@ -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()
{
+1
View File
@@ -27,3 +27,4 @@
/install-reloc
/reloc-ldflags
/relocatable.sh.in
/libtool-reloc
+93
View File
@@ -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)
+7 -14
View File
@@ -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
View File
@@ -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])
+50 -22
View File
@@ -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.
+10
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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])])
+6 -6
View File
@@ -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. */
+8 -8
View File
@@ -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
+9 -9
View File
@@ -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
View File
@@ -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
+5 -7
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+18 -11
View File
@@ -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 $@
## -------------- ##
+1 -2
View File
@@ -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
+3 -1
View File
@@ -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
View File
@@ -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
--->
+28
View File
@@ -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)
+28
View File
@@ -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/>.
--->
+37
View File
@@ -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
+93
View File
@@ -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 ();
}
+33
View File
@@ -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
+1 -1
View File
@@ -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)
+5
View File
@@ -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'
+3 -2
View File
@@ -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
View File
@@ -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)
+2
View File
@@ -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
+1
View File
@@ -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
+35
View File
@@ -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)
+45
View File
@@ -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/>.
--->
+52
View File
@@ -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
+183
View File
@@ -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;
}
+57
View File
@@ -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'
+85
View File
@@ -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). */
+1
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+15
View File
@@ -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
+3
View File
@@ -318,3 +318,6 @@
/rename.c
/rmdir.c
/same-inode.h
/assure.h
/fsync.c
/textstyle.in.h
+23 -18
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+23
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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. */
View File
+17 -13
View File
@@ -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
View File
@@ -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);
}
+5
View File
@@ -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
View File
@@ -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);
}
}
-3
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+25 -30
View File
@@ -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
View File
@@ -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);
}
+6 -12
View File
@@ -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
View File
@@ -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 "&quot;" - 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);
}
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+5
View File
@@ -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