[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] Allow Bison-generated C++ parsers to compile with -fno-excep
From: |
Akim Demaille |
Subject: |
Re: [PATCH] Allow Bison-generated C++ parsers to compile with -fno-exceptions. |
Date: |
Sat, 18 Aug 2018 07:27:47 +0200 |
Hi!
> Le 17 août 2018 à 09:13, Brooks Moses <address@hidden> a écrit :
>
> Akim,
>
> Thanks for the comments! And no worries on the delay; I've certainly been
> on the "maintainer" side of this sort of delay many times.
>
> Your proposed patch seems reasonable to me, and we could add "magic" for
> other compilers (and it also allows people to set YY_EXCEPTIONS directly if
> it doesn't do the magic they want). I can confirm it will work for Clang
> as well as GCC.
Yep, I used #ifndef so that people can spell out what they want, yet
I don’t want to document this just yet. This is not really mature,
I want to be able to change this if it is not satisfactory.
> I'd be happy with either this or a new Bison variable. However, I think
> this way may be a bit better -- it's entirely possible that someone may
> write a parser that chooses to either throw an exception or abort depending
> on whether exceptions are enabled, so this can be a choice of the person
> compiling the parser, as well as a choice of the person writing the parser.
So the Bison variable should have three values I guess :)
If we introduce it.
Here is a more mature version of the patch.
commit d835f484e04eef07ede1844c152bfff52f50896d
Author: Akim Demaille <address@hidden>
Date: Fri Aug 17 19:28:50 2018 +0200
lalr1.cc: support compilation with disabled support for exceptions
Reported by Brooks Moses <address@hidden>
http://lists.gnu.org/archive/html/bison-patches/2018-02/msg00000.html
* data/lalr1.cc (YY_EXCEPTIONS): New.
Use it to disable try/catch clauses.
* doc/bison.texi (C++ Parser Interface): Document it.
* configure.ac (CXXFLAGS_NO_EXCEPTIONS): New.
* tests/atlocal.in: Receive it.
* tests/local.at (AT_FULL_COMPILE, AT_LANG_COMPILE):
Accept a new argument, extra compiler flags.
* tests/calc.at: Run the C++ calculator with exception support disabled.
diff --git a/NEWS b/NEWS
index 9135184a..a47bbc09 100644
--- a/NEWS
+++ b/NEWS
@@ -74,6 +74,13 @@ GNU Bison NEWS
input: '0' | exp
^^^
+*** C++: Generated parsers can be compiled with -fno-exceptions (lalr1.cc)
+
+ When compiled with exceptions disabled, the generated parsers no longer
+ uses try/catch clauses.
+
+ Currently only GCC and Clang are supported.
+
** Bug fixes
*** GLR: Predicates support broken by #line directives
diff --git a/THANKS b/THANKS
index 9d37dc84..d42504a2 100644
--- a/THANKS
+++ b/THANKS
@@ -25,6 +25,7 @@ Bert Deknuydt address@hidden
Bill Allombert address@hidden
Bob Rossi address@hidden
Brandon Lucia address@hidden
+Brooks Moses address@hidden
Bruce Lilly address@hidden
Bruno Haible address@hidden
Charles-Henri de Boysson address@hidden
diff --git a/configure.ac b/configure.ac
index 99f6ad43..1a9dcb00 100644
--- a/configure.ac
+++ b/configure.ac
@@ -153,6 +153,7 @@ if test "$enable_gcc_warnings" = yes; then
# ... possiby in std=c++11 mode.
gl_WARN_ADD([-Wno-zero-as-null-pointer-constant], [FLEX_SCANNER_CXXFLAGS])
CXXFLAGS=$save_CXXFLAGS
+ gl_WARN_ADD([-fno-exceptions], [CXXFLAGS_NO_EXCEPTIONS])
AC_LANG_POP([C++])
fi
diff --git a/data/lalr1.cc b/data/lalr1.cc
index 053875de..637a92cf 100644
--- a/data/lalr1.cc
+++ b/data/lalr1.cc
@@ -424,6 +424,15 @@ m4_if(b4_prefix, [yy], [],
# endif
#endif
+// Whether we are compiled with exception support.
+#ifndef YY_EXCEPTIONS
+# if defined __GNUC__ && !defined __EXCEPTIONS
+# define YY_EXCEPTIONS 0
+# else
+# define YY_EXCEPTIONS 1
+# endif
+#endif
+
]b4_locations_if([dnl
[#define YYRHSLOC(Rhs, K) ((Rhs)[K].location)
]b4_yylloc_default_define])[
@@ -717,9 +726,11 @@ m4_if(b4_prefix, [yy], [],
/// The return value of parse ().
int yyresult;
+#if YY_EXCEPTIONS
// FIXME: This shoud be completely indented. It is not yet to
// avoid gratuitous conflicts when merging into the master branch.
try
+#endif // YY_EXCEPTIONS
{
YYCDEBUG << "Starting parse\n";
@@ -758,17 +769,21 @@ b4_dollar_popdef])[]dnl
if (yyla.empty ())
{
YYCDEBUG << "Reading a token: ";
+#if YY_EXCEPTIONS
try
+#endif // YY_EXCEPTIONS
{]b4_token_ctor_if([[
symbol_type yylookahead (]b4_lex[);
yyla.move (yylookahead);]], [[
yyla.type = yytranslate_ (]b4_lex[);]])[
}
+#if YY_EXCEPTIONS
catch (const syntax_error& yyexc)
{
error (yyexc);
goto yyerrlab1;
}
+#endif // YY_EXCEPTIONS
}
YY_SYMBOL_PRINT ("Next token is", yyla);
@@ -838,7 +853,9 @@ b4_dollar_popdef])[]dnl
// Perform the reduction.
YY_REDUCE_PRINT (yyn);
+#if YY_EXCEPTIONS
try
+#endif // YY_EXCEPTIONS
{
switch (yyn)
{
@@ -847,11 +864,13 @@ b4_dollar_popdef])[]dnl
break;
}
}
+#if YY_EXCEPTIONS
catch (const syntax_error& yyexc)
{
error (yyexc);
YYERROR;
}
+#endif // YY_EXCEPTIONS
YY_SYMBOL_PRINT ("-> $$ =", yylhs);
yypop_ (yylen);
yylen = 0;
@@ -976,6 +995,7 @@ b4_dollar_popdef])[]dnl
return yyresult;
}
+#if YY_EXCEPTIONS
catch (...)
{
YYCDEBUG << "Exception caught: cleaning lookahead and stack\n";
@@ -991,6 +1011,7 @@ b4_dollar_popdef])[]dnl
}
throw;
}
+#endif // YY_EXCEPTIONS
}
void
diff --git a/doc/bison.texi b/doc/bison.texi
index 1a7a495b..f56320b2 100644
--- a/doc/bison.texi
+++ b/doc/bison.texi
@@ -10888,13 +10888,12 @@ use @code{yy::parser::token::FOO}. The scanner can
use
@defcv {Type} {parser} {syntax_error}
This class derives from @code{std::runtime_error}. Throw instances of it
-from the scanner or from the user actions to raise parse errors. This is
-equivalent with first
-invoking @code{error} to report the location and message of the syntax
-error, and then to invoke @code{YYERROR} to enter the error-recovery mode.
-But contrary to @code{YYERROR} which can only be invoked from user actions
-(i.e., written in the action itself), the exception can be thrown from
-function invoked from the user action.
+from the scanner or from the actions to raise parse errors. This is
+equivalent with first invoking @code{error} to report the location and
+message of the syntax error, and then to invoke @code{YYERROR} to enter the
+error-recovery mode. But contrary to @code{YYERROR} which can only be
+invoked from user actions (i.e., written in the action itself), the
+exception can be thrown from function invoked from the user action.
@end defcv
@deftypemethod {parser} {} parser (@var{type1} @var{arg1}, ...)
@@ -10914,6 +10913,10 @@ Run the syntactic analysis, and return 0 on success, 1
otherwise.
The whole function is wrapped in a @code{try}/@code{catch} block, so that
when an exception is thrown, the @code{%destructor}s are called to release
the lookahead symbol, and the symbols pushed on the stack.
+
+Exception related code in the generated parser is protected by CPP guards
+(@code{#if}) and disabled when exception support is disabled (i.e., passing
address@hidden to the C++ compiler).
@end deftypemethod
@deftypemethod {parser} {std::ostream&} debug_stream ()
diff --git a/tests/atlocal.in b/tests/atlocal.in
index 5db32669..93ba7613 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -50,6 +50,9 @@ CXXFLAGS="$NO_WERROR_CXXFLAGS @WERROR_CXXFLAGS@"
# If 'exit 77'; skip all C++ tests; otherwise ':'.
BISON_CXX_WORKS='@BISON_CXX_WORKS@'
+# Compiler flags to disable exception support.
+CXXFLAGS_NO_EXCEPTIONS='@CXXFLAGS_NO_EXCEPTIONS@'
+
# Be sure that the C++ compiler is not broken because of gnulib. This
# cannot be checked in configure (gnulib is not parameterized yet),
# and checking this in every C++ test in AC_COMPILE_CXX is too costly.
diff --git a/tests/calc.at b/tests/calc.at
index 3d83ba72..acc27da2 100644
--- a/tests/calc.at
+++ b/tests/calc.at
@@ -481,20 +481,20 @@ m4_define([AT_CHECK_SPACES],
])
-# AT_CHECK_CALC([BISON-OPTIONS])
-# ------------------------------
+# AT_CHECK_CALC([BISON-OPTIONS], [COMPILER-OPTIONS])
+# --------------------------------------------------
# Start a testing chunk which compiles 'calc' grammar with
# BISON-OPTIONS, and performs several tests over the parser.
m4_define([AT_CHECK_CALC],
-[m4_ifval([$2], [m4_fatal([$0: expected a single argument])])
+[m4_ifval([$3], [m4_fatal([$0: expected at most two arguments])])
# We use integers to avoid dependencies upon the precision of doubles.
-AT_SETUP([Calculator $1])
+AT_SETUP([Calculator $1 $2])
AT_BISON_OPTION_PUSHDEFS([$1])
AT_DATA_CALC_Y([$1])
-AT_FULL_COMPILE([calc], AT_DEFINES_IF([[lex], [main]]))
+AT_FULL_COMPILE([calc], AT_DEFINES_IF([[lex], [main]]), [], [$2])
AT_CHECK_SPACES(m4_join([ ],
[calc.AT_SKEL_CC_IF([cc], [c])],
[AT_DEFINES_IF([calc.AT_SKEL_CC_IF([hh], [h])])]))
@@ -677,10 +677,11 @@ AT_CHECK_CALC([%skeleton "lalr1.cc" %defines])
# Start a testing chunk which compiles 'calc' grammar with
# the C++ skeleton, and performs several tests over the parser.
m4_define([AT_CHECK_CALC_LALR1_CC],
-[AT_CHECK_CALC([%language "C++"] $@)])
+[AT_CHECK_CALC([%language "C++" $1], [$2])])
AT_CHECK_CALC_LALR1_CC([])
AT_CHECK_CALC_LALR1_CC([%locations])
+AT_CHECK_CALC_LALR1_CC([%locations], [$CXXFLAGS_NO_EXCEPTIONS])
AT_CHECK_CALC_LALR1_CC([%locations %define api.location.type {Span}])
AT_CHECK_CALC_LALR1_CC([%defines %locations %define parse.error verbose
%name-prefix "calc" %verbose %yacc])
diff --git a/tests/local.at b/tests/local.at
index b1bdb4da..5341549e 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -740,8 +740,8 @@ m4_define([AT_QUELL_VALGRIND],
## ------------------------ ##
-# AT_COMPILE(OUTPUT, [SOURCES = OUTPUT.c])
-# ----------------------------------------
+# AT_COMPILE(OUTPUT, [SOURCES = OUTPUT.c], [EXTRA-COMPILER-FLAGS])
+# ----------------------------------------------------------------
# Compile SOURCES into OUTPUT.
#
# If OUTPUT does not contain '.', assume that we are linking too,
@@ -758,8 +758,8 @@ AT_CHECK(m4_join([ ],
0, [ignore], [ignore])])
-# AT_COMPILE_CXX(OUTPUT, [SOURCES = OUTPUT.cc])
-# ---------------------------------------------
+# AT_COMPILE_CXX(OUTPUT, [SOURCES = OUTPUT.cc], [EXTRA-COMPILER-FLAGS])
+# ---------------------------------------------------------------------
# Compile SOURCES into OUTPUT. If the C++ compiler does not work,
# ignore the test.
#
@@ -770,7 +770,7 @@ m4_define([AT_COMPILE_CXX],
[AT_KEYWORDS(c++)
AT_CHECK([$BISON_CXX_WORKS], 0, ignore, ignore)
AT_CHECK(m4_join([ ],
- [$CXX $CXXFLAGS $CPPFLAGS],
+ [$CXX $CXXFLAGS $CPPFLAGS $3],
[m4_bmatch([$1], [[.]], [-c], [$LDFLAGS])],
[-o $1],
[m4_default([$2], [m4_bpatsubst([$1], [\.o$]).cc])],
@@ -790,21 +790,21 @@ AT_CHECK([[$SHELL ../../../javacomp.sh ]$1],
[[0]], [ignore], [ignore])])
-# AT_LANG_COMPILE(OUTPUT, [SOURCES = OUTPUT.c]
-# --------------------------------------------
+# AT_LANG_COMPILE(OUTPUT, [SOURCES = OUTPUT.c], [EXTRA-COMPILER-FLAGS])
+# ---------------------------------------------------------------------
# Compile SOURCES into OUTPUT. Skip if compiler does not work.
#
# If OUTPUT does not contain '.', assume that we are linking too,
# otherwise pass "-c"; this is a hack. The default SOURCES is OUTPUT
# with trailing .o removed, and ".c"/".cc" appended.
m4_define([AT_LANG_COMPILE], [AT_LANG_DISPATCH([$0], $@)])
-m4_define([AT_LANG_COMPILE(c)], [AT_COMPILE([$1], [$2])])
-m4_define([AT_LANG_COMPILE(c++)], [AT_COMPILE_CXX([$1], [$2])])
-m4_define([AT_LANG_COMPILE(java)], [AT_JAVA_COMPILE([$1.java], [$2])])
+m4_define([AT_LANG_COMPILE(c)], [AT_COMPILE([$1], [$2], [$3])])
+m4_define([AT_LANG_COMPILE(c++)], [AT_COMPILE_CXX([$1], [$2], [$3])])
+m4_define([AT_LANG_COMPILE(java)], [AT_JAVA_COMPILE([$1.java], [$2], [$3])])
-# AT_FULL_COMPILE(OUTPUT, [OTHER1], [OTHER2])
-# -------------------------------------------
+# AT_FULL_COMPILE(OUTPUT, [OTHER1], [OTHER2], [EXTRA-COMPILER-FLAGS)
+# ------------------------------------------------------------------
# Compile OUTPUT.y to OUTPUT.c, OUTPUT.cc, or OUTPUT.java, and then
# compile it to OUTPUT or OUTPUT.class. If OTHER is specified, compile
# OUTPUT-OTHER.c, OUTPUT-OTHER.cc, or OUTPUT-OTHER.java to OUTPUT or
@@ -817,7 +817,8 @@ m4_define([AT_FULL_COMPILE(c)],
m4_join([ ],
[$1.c],
m4_ifval($2, [[$1-$2.c]]),
- m4_ifval($3, [[$1-$3.c]])))])
+ m4_ifval($3, [[$1-$3.c]])),
+ [$4])])
m4_define([AT_FULL_COMPILE(c++)],
[AT_BISON_CHECK([-o $1.cc $1.y])
@@ -825,7 +826,8 @@ m4_define([AT_FULL_COMPILE(c++)],
m4_join([ ],
[$1.cc],
m4_ifval($2, [[$1-$2.cc]]),
- m4_ifval($3, [[$1-$3.cc]])))])
+ m4_ifval($3, [[$1-$3.cc]])),
+ [$4])])
m4_define([AT_FULL_COMPILE(java)],
[AT_BISON_CHECK([-o $1.java $1.y])
@@ -833,7 +835,8 @@ m4_define([AT_FULL_COMPILE(java)],
m4_join([ ],
[$1.java],
m4_ifval($2, [[$1-$2.java]]),
- m4_ifval($3, [[$1-$3.java]])))])
+ m4_ifval($3, [[$1-$3.java]])),
+ [$4])])