bison-patches
[Top][All Lists]
Advanced

[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])])
 
 
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]