Subject: bug#11419: [PATCH] yacc, lex: new 'no-ylwrap' option to prevent use of the 'ylwrap' script

From: Stefano Lattarini <[email-masked]>
Date: Mon, 25 Jun 2012 16:01:13 +0200

When used with good yacc and lex implementations, like Flex and GNU Bison,
the 'ylwarp' script (meant to work around the deficiencies of older or
inferior yacc and lex implementations) creates far more problems and
annoyances than it solves.  For more details, just see the huge amount of
related bug reports and complaints:

  <http://debbugs.gnu.org/11419>
  <http://debbugs.gnu.org/10825>
  <http://debbugs.gnu.org/9933>
  <http://debbugs.gnu.org/7648>
  <http://lists.gnu.org/archive/html/automake/2010-10/msg00073.html>
  <http://lists.gnu.org/archive/html/automake/2009-03/msg00062.html>
  <http://lists.gnu.org/archive/html/automake/2009-03/msg00061.html>

So we now offer an option ('no-ylwrap') to disable the use of ylwrap in
the Automake-generated rules.  We also offer the inverse option 'ylwrap',
to force the use of the 'ylwrap' script; it is a no-op right now, but its
use will allow us to switch the default in Automake 1.13 (i.e., we will
start *not* using ylwrap by default) while still supporting users who
 want to continue using ylwrap.

* lib/Automake/Options.pm (_is_valid_easy_option, _process_option_list):
Recognize the options 'no-ylwrap' and 'ylwrap'.
* automake.in (handle_languages): Pass the new transform '?USE-YLWRAP?'
to the processed $rule_file; this transform expands to false if the
'no-ylwrap' option is used, and to true otherwise.
(yacc_lex_finish_helper): Don't require nor copy the 'ylwrap' script if
the 'no-ylwrap' option is active.
* lib/am/lex.am, lib/am/yacc.am: Simplify rules not to use the 'ylwrap'
script if the '?USE-YLWRAP?' transform is true.  Related refactorings.
* t/lex-multiple.sh: New test, checks that if we get ylwrap out of the
way, we can build a program using several lexers at once.
* t/list-of-tests.mk (handwritten_TESTS): Add it.
* t/yacc-bison-skeleton.sh: Use the 'no-ylwrap' option.  This allow the
test to pass, at last!
* t/yacc-bison-skeleton-cxx.sh: Likewise.
* t/list-of-tests.mk (XFAIL_TESTS): Remove those two tests.

Signed-off-by: Stefano Lattarini <[email-masked]>
---

 Here's the first step in our revamping of yacc/lex rules.  It's quite
 rough and  has probably suboptimal semantics, but it will offer a simple
 and quick way out for all those users which were fighting against ylwrap.
 So, OK for maint?  I will follow up with a documentation patch (and a
 NEWS update) if this change is accepted.

 Regards,
   Stefano

 automake.in                  |    6 ++-
 lib/Automake/Options.pm      |    6 +++
 lib/am/lex.am                |   14 ++++--
 lib/am/yacc.am               |   14 ++++--
 t/lex-multiple.sh            |  106 ++++++++++++++++++++++++++++++++++++++++++
 t/list-of-tests.mk           |    3 +-
 t/yacc-bison-skeleton-cxx.sh |    5 +-
 t/yacc-bison-skeleton.sh     |    1 +
 8 files changed, 143 insertions(+), 12 deletions(-)
 create mode 100755 t/lex-multiple.sh

diff --git a/automake.in b/automake.in
index cfc48bf..939c303 100644
--- a/automake.in
+++ b/automake.in
@@ -1472,7 +1472,9 @@ sub handle_languages
 			     COMPILE   => '$(' . $lang->compiler . ')',
 			     LTCOMPILE => '$(LT' . $lang->compiler . ')',
 			     -o        => $output_flag,
-			     SUBDIROBJ => !! option 'subdir-objects');
+			     SUBDIROBJ => !! option 'subdir-objects',
+                             'USE-YLWRAP' => ! option 'no-ylwrap',
+                             );
 	}
 
 	# Now include code for each specially handled object with this
@@ -1549,6 +1551,7 @@ sub handle_languages
 			     COMPILE   => $obj_compile,
 			     LTCOMPILE => $obj_ltcompile,
 			     -o        => $output_flag,
+                             'USE-YLWRAP' => ! option 'no-ylwrap',
 			     %file_transform);
 	}
 
@@ -6084,6 +6087,7 @@ sub lang_lex_target_hook
 # This is a helper for both lex and yacc.
 sub yacc_lex_finish_helper
 {
+  return if option 'no-ylwrap';
   return if defined $language_scratch{'lex-yacc-done'};
   $language_scratch{'lex-yacc-done'} = 1;
 
diff --git a/lib/Automake/Options.pm b/lib/Automake/Options.pm
index 2f977bd..920a62f 100644
--- a/lib/Automake/Options.pm
+++ b/lib/Automake/Options.pm
@@ -285,6 +285,7 @@ sub _is_valid_easy_option ($)
     no-installinfo
     no-installman
     no-texinfo.tex
+    no-ylwrap
     nostdinc
     readme-alpha
     std-options
@@ -333,6 +334,11 @@ sub _process_option_list (\%@)
           # This is a little of an hack, but good enough for the moment.
           delete $options->{'parallel-tests'};
         }
+      elsif ($_ eq 'ylwrap')
+        {
+          # This is a little of an hack, but good enough for the moment.
+          delete $options->{'no-ylwrap'};
+        }
       elsif (/^filename-length-max=(\d+)$/)
         {
           delete $options->{$_};
diff --git a/lib/am/lex.am b/lib/am/lex.am
index 7467f4f..19555b0 100644
--- a/lib/am/lex.am
+++ b/lib/am/lex.am
@@ -23,8 +23,14 @@ endif %?MAINTAINER-MODE%
 
 ?GENERIC?%EXT%%DERIVED-EXT%:
 ?!GENERIC?%OBJ%: %SOURCE%
-?GENERIC?	%VERBOSE%$(am__skiplex) $(SHELL) $(YLWRAP) %SOURCE% $(LEX_OUTPUT_ROOT).c %OBJ% -- %COMPILE%
-?!GENERIC?	%VERBOSE% \
-?!GENERIC??DIST_SOURCE?	$(am__skiplex) \
+if %?GENERIC%
+	%VERBOSE%$(am__skiplex) \
+?USE-YLWRAP?	$(SHELL) $(YLWRAP) %SOURCE% $(LEX_OUTPUT_ROOT).c %OBJ% -- %COMPILE%
+?!USE-YLWRAP?	%COMPILE% -o $@ %SOURCE%
+else !%?GENERIC%
+	%VERBOSE% \
+?DIST_SOURCE?	$(am__skiplex) \
 ## For non-suffix rules, we must emulate a VPATH search on %SOURCE%.
-?!GENERIC?	$(SHELL) $(YLWRAP) `test -f '%SOURCE%' || echo '$(srcdir)/'`%SOURCE% $(LEX_OUTPUT_ROOT).c %OBJ% -- %COMPILE%
+?USE-YLWRAP?	$(SHELL) $(YLWRAP)  `test -f '%SOURCE%' || echo '$(srcdir)/'`%SOURCE% $(LEX_OUTPUT_ROOT).c %OBJ% -- %COMPILE%
+?!USE-YLWRAP?	%COMPILE% -o $@  `test -f '%SOURCE%' || echo '$(srcdir)/'`%SOURCE%
+endif  !%?GENERIC%
diff --git a/lib/am/yacc.am b/lib/am/yacc.am
index e74259f..77af963 100644
--- a/lib/am/yacc.am
+++ b/lib/am/yacc.am
@@ -43,8 +43,14 @@ endif %?FIRST%
 
 ?GENERIC?%EXT%%DERIVED-EXT%:
 ?!GENERIC?%OBJ%: %SOURCE%
-?GENERIC?	%VERBOSE%$(am__skipyacc) $(SHELL) $(YLWRAP) %SOURCE% y.tab.c %OBJ% y.tab.h `echo %OBJ% | $(am__yacc_c2h)` y.output %BASE%.output -- %COMPILE%
-?!GENERIC?	%VERBOSE% \
-?!GENERIC??DIST_SOURCE?	$(am__skipyacc) \
+if %?GENERIC%
+	%VERBOSE%$(am__skipyacc) \
+?USE-YLWRAP?	$(SHELL) $(YLWRAP) %SOURCE% y.tab.c %OBJ% y.tab.h `echo %OBJ% | $(am__yacc_c2h)` y.output %BASE%.output -- %COMPILE%
+?!USE-YLWRAP?	%COMPILE% -o $@ %SOURCE%
+else !%?GENERIC%
+	%VERBOSE% \
+?DIST_SOURCE?	$(am__skipyacc) \
 ## For non-suffix rules, we must emulate a VPATH search on %SOURCE%.
-?!GENERIC?	$(SHELL) $(YLWRAP) `test -f '%SOURCE%' || echo '$(srcdir)/'`%SOURCE% y.tab.c %OBJ% y.tab.h `echo %OBJ% | $(am__yacc_c2h)` y.output %BASE%.output -- %COMPILE%
+?USE-YLWRAP?	$(SHELL) $(YLWRAP)  `test -f '%SOURCE%' || echo '$(srcdir)/'`%SOURCE% y.tab.c %OBJ% y.tab.h `echo %OBJ% | $(am__yacc_c2h)` y.output %BASE%.output -- %COMPILE%
+?!USE-YLWRAP?	%COMPILE% -o $@ % `test -f '%SOURCE%' || echo '$(srcdir)/'`%SOURCE%
+endif  !%?GENERIC%
diff --git a/t/lex-multiple.sh b/t/lex-multiple.sh
new file mode 100755
index 0000000..f15b3f3
--- /dev/null
+++ b/t/lex-multiple.sh
@@ -0,0 +1,106 @@
+#! /bin/sh
+# Copyright (C) 2012 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 2, 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/>.
+
+# If we get ylwrap out of the way, we can build a program using
+# several lexers at once.
+
+required='cc flex'
+. ./defs || Exit 1
+
+cp "$am_scriptdir"/ar-lib . || fatal_ "fetching auxiliary script 'ar-lib'"
+
+cat >> configure.ac << 'END'
+AC_PROG_CC
+AC_PROG_LEX
+AM_PROG_AR
+AC_PROG_RANLIB
+AC_OUTPUT
+END
+
+cat > Makefile.am << 'END'
+AUTOMAKE_OPTIONS = no-ylwrap
+
+bin_PROGRAMS = zardoz
+
+zardoz_SOURCES = main.c
+# Convenience libraries.
+noinst_LIBRARIES = liblex.a liblex-foo.a liblex-bar.a
+zardoz_LDADD = $(noinst_LIBRARIES)
+
+liblex_a_SOURCES = 0.l
+
+liblex_foo_a_LFLAGS = -Pfoo
+liblex_foo_a_SOURCES = a.l
+
+liblex_bar_a_LFLAGS = -Pbar_
+liblex_bar_a_SOURCES = b.l
+END
+
+cat > main.c << 'END'
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main (int argc, char *argv[])
+{
+  if (argc != 2)
+    abort ();
+  else if (!strcmp(argv[1], "--vanilla"))
+    return (yylex () != 121);
+  else if (!strcmp(argv[1], "--foo"))
+    return (foolex () != 121);
+  else if (!strcmp(argv[1], "--bar"))
+    return (bar_lex () != 121);
+  else
+    abort ();
+}
+END
+
+cat > 0.l << 'END'
+%{
+#define YY_NO_UNISTD_H 1
+%}
+%%
+"VANILLA" { printf (":%s:\n", yytext); return 121; }
+. { printf (":%s:\n", yytext); return 1; }
+%%
+/* Avoid possible link errors. */
+int yywrap (void) { return 1; }
+END
+
+sed 's/VANILLA/FOO/' 0.l > a.l
+sed 's/VANILLA/BAR/' 0.l > b.l
+
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE
+test ! -f ylwrap
+
+./configure
+$MAKE
+
+if ! cross_compiling; then
+  echo VANILLA | ./zardoz --vanilla
+  echo FOO | ./zardoz --foo
+  echo BAR | ./zardoz --bar
+  #./zardoz --vanilla </dev/null && exit 1
+  echo BAR | ./zardoz --foo && Exit 1
+  : For shells with buster 'set -e'.
+fi
+
+$MAKE distcheck
+
+:
diff --git a/t/list-of-tests.mk b/t/list-of-tests.mk
index e16dd1d..a5962d9 100644
--- a/t/list-of-tests.mk
+++ b/t/list-of-tests.mk
@@ -30,8 +30,6 @@ t/pm/Version3.pl
 
 XFAIL_TESTS = \
 t/all.sh \
-t/yacc-bison-skeleton-cxx.sh \
-t/yacc-bison-skeleton.sh \
 t/cond17.sh \
 t/gcj6.sh \
 t/override-conditional-2.sh \
@@ -581,6 +579,7 @@ t/lex-depend-cxx.sh \
 t/lex-depend-grep.sh \
 t/lex-depend.sh \
 t/lex-line.sh \
+t/lex-multiple.sh \
 t/lex-nodist.sh \
 t/lex-pr204.sh \
 t/lflags.sh \
diff --git a/t/yacc-bison-skeleton-cxx.sh b/t/yacc-bison-skeleton-cxx.sh
index f5d8545..1ab3667 100755
--- a/t/yacc-bison-skeleton-cxx.sh
+++ b/t/yacc-bison-skeleton-cxx.sh
@@ -20,7 +20,10 @@
 required='c++ bison'
 . ./defs || Exit 1
 
-cat >> configure.ac << 'END'
+cat > configure.ac << 'END'
+AC_INIT([C++ skeleton], [0.1])
+AM_INIT_AUTOMAKE([no-ylwrap])
+AC_CONFIG_FILES([Makefile])
 AC_PROG_CXX
 AC_PROG_YACC
 AC_OUTPUT
diff --git a/t/yacc-bison-skeleton.sh b/t/yacc-bison-skeleton.sh
index 8cf957b..6cf7972 100755
--- a/t/yacc-bison-skeleton.sh
+++ b/t/yacc-bison-skeleton.sh
@@ -27,6 +27,7 @@ AC_OUTPUT
 END
 
 cat > Makefile.am << 'END'
+AUTOMAKE_OPTIONS = no-ylwrap
 bin_PROGRAMS = zardoz
 zardoz_SOURCES = zardoz.y foo.c
 AM_YFLAGS = -d --skeleton glr.c
-- 
1.7.9.5