From a53c6026cd367c75d5594e6e649ee1cdda93d5ae Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 9 Jun 2020 07:08:11 +0200 Subject: [PATCH] api.header.include: document it, and fix its default value While defining api.header.include worked as expected, its default value was incorrectly defined. As a result, by default, the generated parsers still duplicated the content of the generated header instead of including it. * data/skeletons/yacc.c (api.header.include): Fix its default value. * tests/output.at: Check it. * doc/bison.texi (%define Summary): Document api.header.include. While at it, move the definition of api.namespace at the proper place. --- NEWS | 20 +++++++++ TODO | 8 ---- data/skeletons/yacc.c | 2 +- doc/bison.texi | 96 +++++++++++++++++++++++++++++++++---------- tests/output.at | 20 +++++++-- 5 files changed, 112 insertions(+), 34 deletions(-) diff --git a/NEWS b/NEWS index 712b2b7a..1cec2252 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,26 @@ GNU Bison NEWS When installed to be relocatable (via configure --enable-relocatable), bison will now also look for a relocated m4. +** Bug fixes + +*** Include the generated header (yacc.c) + + Historically, when --defines was used, bison generated a header and pasted + an exact copy of it into the generated parser implementation file. Since + Bison 3.4 it is possible to specify that the header should be `#include`d, + and how. For instance + + %define api.header.include {"parse.h"} + + or + + %define api.header.include {} + + Now api.header.include defaults to `"header-basename"`, as was intended in + Bison 3.4, where `header-basename` is the basename of the generated + header. This is disabled when the generated header is `y.tab.h`, to + comply with Automake's ylwrap. + ** New features *** File prefix mapping diff --git a/TODO b/TODO index 96459653..5d440169 100644 --- a/TODO +++ b/TODO @@ -15,16 +15,11 @@ list_get_end (gl_list_t list) ** Bistromathic - Hitting tab on a line with a syntax error is ugly -- Be robust to existing ~/.inputrc - - How about not evaluating incomplete lines when the text is not finished (as shells do). - Caret diagnostics -** Doc -*** api.header.include - ** Questions *** Java - Should i18n be part of the Lexer? Currently it's a static method of @@ -54,9 +49,6 @@ enough. *** calc.at Stop hard-coding "Calc". Adjust local.at (look for FIXME). -** Counter example generation -See https://github.com/akimd/bison/pull/15. - ** Clean up Rename endtoken as eoftoken. diff --git a/data/skeletons/yacc.c b/data/skeletons/yacc.c index ffc02efd..a9c84a33 100644 --- a/data/skeletons/yacc.c +++ b/data/skeletons/yacc.c @@ -335,7 +335,7 @@ m4_define([b4_header_include_if], [$2])], [$2])]) -m4_if(b4_spec_header_file, [[y.tab.h]], +m4_if(b4_spec_header_file, [y.tab.h], [], [b4_percent_define_default([[api.header.include]], [["@basename(]b4_spec_header_file[@)"]])]) diff --git a/doc/bison.texi b/doc/bison.texi index 5a08fa92..c60897bc 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -5922,44 +5922,58 @@ Unaccepted @var{variable}s produce an error. Some of the accepted @var{variable}s are described below. -@c ================================================== api.namespace -@deffn Directive {%define api.namespace} @{@var{namespace}@} +@c ================================================== api.header.include +@deffn Directive {%define api.header.include} @{"header.h"@} +@deffnx Directive {%define api.header.include} @{@} @itemize -@item Languages(s): C++ +@item Languages(s): C (@file{yacc.c}) -@item Purpose: Specify the namespace for the parser class. -For example, if you specify: +@item Purpose: Specify how the generated parser should include the generated header. + +Historically, when option @option{-D}/@option{--defines} was used, +@command{bison} generated a header and pasted an exact copy of it into the +generated parser implementation file. Since Bison 3.6, it is +@code{#include}d as @samp{"@var{basename}.h"}, instead of duplicated, unless +@var{file} is @samp{y.tab}, see below. + +The @code{api.header.include} variable allows to control how the generated +parser @code{#include}s the generated header. For instance: @example -%define api.namespace @{foo::bar@} +%define api.header.include @{"parse.h"@} @end example -Bison uses @code{foo::bar} verbatim in references such as: +@noindent +or @example -foo::bar::parser::semantic_type +%define api.header.include @{@} @end example -However, to open a namespace, Bison removes any leading @code{::} and then -splits on any remaining occurrences: +Using @code{api.header.include} does not change the name of the generated +header, only how it is included. -@example -namespace foo @{ namespace bar @{ - class position; - class location; -@} @} -@end example +To work around limitations of Automake's @command{ylwrap} (which runs +@command{bison} with @option{--yacc}), @code{api.header.include} is +@emph{not} predefined when the output file is @file{y.tab.c}. Define it to +avoid the duplication. @item Accepted Values: -Any absolute or relative C++ namespace reference without a trailing -@code{"::"}. For example, @code{"foo"} or @code{"::foo::bar"}. +An argument for @code{#include}. @item Default Value: -@code{yy}, unless you used the obsolete @samp{%name-prefix "@var{prefix}"} -directive. +@samp{"@var{header-basename}"}, unless the header file is @file{y.tab.h}, +where @var{header-basename} is the name of the generated header, without +directory part. For instance with @command{bison -d calc/parse.y}, +@code{api.header.include} defaults to @samp{"parse.h"}, not +@samp{"calc/parse.h"}. + +@item History: +Introduced in Bison 3.4. Defaults to @samp{"@var{basename}.h"} since Bison +3.7, unless the header file is @file{y.tab.h}. @end itemize @end deffn -@c api.namespace +@c api.header.include @c ================================================== api.location.file @@ -6043,6 +6057,46 @@ Introduced in Bison 2.7 for C++ and Java, in Bison 3.4 for C. @end deffn +@c ================================================== api.namespace +@deffn Directive {%define api.namespace} @{@var{namespace}@} +@itemize +@item Languages(s): C++ + +@item Purpose: Specify the namespace for the parser class. +For example, if you specify: + +@example +%define api.namespace @{foo::bar@} +@end example + +Bison uses @code{foo::bar} verbatim in references such as: + +@example +foo::bar::parser::semantic_type +@end example + +However, to open a namespace, Bison removes any leading @code{::} and then +splits on any remaining occurrences: + +@example +namespace foo @{ namespace bar @{ + class position; + class location; +@} @} +@end example + +@item Accepted Values: +Any absolute or relative C++ namespace reference without a trailing +@code{"::"}. For example, @code{"foo"} or @code{"::foo::bar"}. + +@item Default Value: +@code{yy}, unless you used the obsolete @samp{%name-prefix "@var{prefix}"} +directive. +@end itemize +@end deffn +@c api.namespace + + @c ================================================== api.parser.class @deffn Directive {%define api.parser.class} @{@var{name}@} @itemize @bullet diff --git a/tests/output.at b/tests/output.at index 4e9a4409..11dcceb7 100644 --- a/tests/output.at +++ b/tests/output.at @@ -30,9 +30,10 @@ m4_define([AT_CHECK_FILES], [], [$1 ])]) -# AT_CHECK_OUTPUT(INPUT-FILE, [DIRECTIVES], [FLAGS], EXPECTED-FILES, [STATUS], -# [ADDITIONAL-TESTS], [PRE-TESTS]) -# ----------------------------------------------------------------------------- +# AT_CHECK_OUTPUT($1 = INPUT-FILE, $2 = [DIRECTIVES], $3 = [FLAGS], +# $4 = EXPECTED-FILES, $5 = [STATUS], +# $6 = [ADDITIONAL-TESTS], $7 = [PRE-TESTS]) +# ----------------------------------------------------------------- m4_define([AT_CHECK_OUTPUT], [AT_SETUP([[Output files: ]$2 $3])[ ]$7[ @@ -73,8 +74,19 @@ AT_CHECK_OUTPUT([foo.y], [], [-dv >&-], [], [], [AT_CHECK([[case "$PREBISON" in *valgrind*) exit 77;; esac]])]) + +# Check how api.header.include. AT_CHECK_OUTPUT([foo.y], [], [-dv -o foo.c], - [foo.c foo.h foo.output]) + [foo.c foo.h foo.output], [], + [AT_CHECK([grep '#include "foo.h"' foo.c], [0], [ignore])]) +AT_CHECK_OUTPUT([foo.y], [], [-dv -y], + [y.output y.tab.c y.tab.h], [], + [AT_CHECK([grep '#include "y.tab.h"' y.tab.c], [1], [ignore])]) +AT_CHECK_OUTPUT([foo.y], [%define api.header.include {"./foo.h"}], [-dv -y], + [y.output y.tab.c y.tab.h], [], + [AT_CHECK([grep '#include "./foo.h"' y.tab.c], [0], [ignore])]) + + AT_CHECK_OUTPUT([foo.y], [], [-dv -o foo.tab.c], [foo.output foo.tab.c foo.tab.h])