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.
This commit is contained in:
Akim Demaille
2019-03-06 07:43:12 +01:00
parent 6cb612e7e3
commit 4e19ab9fcd
4 changed files with 43 additions and 5 deletions

18
NEWS
View File

@@ -15,6 +15,24 @@ GNU Bison NEWS
When given -fsyntax-only, the diagnostics are reported, but no output is
generated.
*** 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>}
** Documentation
A new example in C shows an simple infix calculator with a hand-written

View File

@@ -294,6 +294,25 @@ m4_define([b4_shared_declarations],
]b4_cpp_guard_close([b4_spec_defines_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_defines_file),
[b4_percent_define_ifdef([[api.header.include]],
[$1],
[$2])],
[$2])])
m4_if(b4_spec_defines_file, [[y.tab.h]],
[b4_percent_define_default([[api.header.include]],
[["@basename(]b4_spec_defines_file[@)"]])])
## -------------- ##
## Output files. ##
## -------------- ##
@@ -354,11 +373,10 @@ 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]])],
[/* 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

View File

@@ -7,6 +7,7 @@
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

View File

@@ -114,6 +114,7 @@
#define YYTYPE_UINT8 uint_fast8_t
}
%define api.header.include {"parse-gram.h"}
%define api.prefix {gram_}
%define api.pure full
%define api.value.type union