Csaba Raduly | 5 Feb 17:01
Picon

yyprint does not work with glr-parser

The C code generated from the following grammar will not compile,
because yytoknum is not defined when glr-parser is in use.

%{
// C header part
#include <stdio.h>

static int yylex();

#define YYERROR_VERBOSE

void yyerror(const char *s)
{
puts(s);
}

union YYSTYPE;
static void yyprint(FILE *file, int type, const YYSTYPE& value);
#define YYPRINT(f,t,v) yyprint(f,t,v)

//static int yytoknum[500] = {0};
// Hack to get it  compile
%}

%verbose
%glr-parser

%start GrammarRoot

%token foo
%token bar
%token baz

%union {
  int i;
  char *s;
}

%%

GrammarRoot:
foo
| bar
| baz
;

%%

int yylex()
{
  static int index = 0, tokens[] = { bar, -1 };
  return tokens[index++];
}

void yyprint(FILE *file, int type, const YYSTYPE& value)
{
  (void)value;
  fprintf(file, "printing type %3d", type);
  switch (type) {
  case foo:
  fputs(" foo", file);
  break;

  case bar:
  fputs(" bar", file);
  break;

  default:
  break;
  }
}

int main()
{
  yydebug = 1;
  return yyparse();
}

Discovered, with bison 2.3; verified present with bison 2.4.1

Csaba
--

-- 
Life is complex, with real and imaginary parts

Joel E. Denny | 6 Feb 23:05
Favicon

Re: yyprint does not work with glr-parser


On Fri, 5 Feb 2010, Csaba Raduly wrote: > The C code generated from the following grammar will not compile, > because yytoknum is not defined when glr-parser is in use.
You should have better luck with %printer, which is the modern version of YYPRINT. Actually, our %printer documentation is poor. It has the same syntax as %destructor. You print to yyoutput, which is a FILE*. For example: %printer { fprintf (yyoutput, "%d", $$); } BOOL <integer> It's not clear to me whether we should add YYPRINT support to GLR or if we should just document the lack of support.
Csaba Raduly | 8 Feb 19:37
Picon

Re: yyprint does not work with glr-parser

On Sat, Feb 6, 2010 at 11:05 PM, Joel E. Denny <jdenny <at> clemson.edu> wrote:
> On Fri, 5 Feb 2010, Csaba Raduly wrote:
>
>> The C code generated from the following grammar will not compile,
>> because yytoknum is not defined when glr-parser is in use.
>
> You should have better luck with %printer, which is the modern version of
> YYPRINT.  Actually, our %printer documentation is poor.

Make that non-existent, bar some examples :)

> It has the same
> syntax as %destructor.  You print to yyoutput, which is a FILE*.  For
> example:
>
>  %printer { fprintf (yyoutput, "%d", $$); } BOOL <integer>
>
> It's not clear to me whether we should add YYPRINT support to GLR or if we
> should just document the lack of support.
>

At least it (seems to) work with 2.3 too so I don't have to hack yyprint.
Pity that only 2.4 seems to accept the "<integer>" form.

--

-- 
Life is complex, with real and imaginary parts

Joel E. Denny | 8 Feb 19:59
Favicon

Re: yyprint does not work with glr-parser


On Mon, 8 Feb 2010, Csaba Raduly wrote: > >  %printer { fprintf (yyoutput, "%d", $$); } BOOL <integer> > Pity that only 2.4 seems to accept the "<integer>" form.
Right, that was added in 2.3a.
Albert Chin | 1 Feb 21:06

Test 52 failure on AIX, HP-UX, Solaris

Test 52 fails on AIX, HP-UX, and Solaris:
52. output.at:159: testing ...
./output.at:159: VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=summary --show-reachable=no";
export VALGRIND_OPTS; bison -o foo.y foo.y
2c2,3
< 
---
> /opt/TWWfsw/m414/bin/gm4:/opt/build/bison-2.4.1a/data/yacc.c:694: ERROR: copying inserted
file: Broken pipe
> /opt/TWWfsw/m414/bin/gm4: write error
52. output.at:159: 52. Conflicting output files:  -o foo.y (output.at:159): FAILED (output.at:159)

We're seeing the same failure on AIX and HP-UX.

--

-- 
albert chin (china <at> thewrittenword.com)

Joel E. Denny | 2 Feb 00:56
Favicon

Re: Test 52 failure on AIX, HP-UX, Solaris

On Mon, 1 Feb 2010, Albert Chin wrote:

> Test 52 fails on AIX, HP-UX, and Solaris:
> 52. output.at:159: testing ...
> ./output.at:159: VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=summary --show-reachable=no";
export VALGRIND_OPTS; bison -o foo.y foo.y
> 2c2,3
> < 
> ---
> > /opt/TWWfsw/m414/bin/gm4:/opt/build/bison-2.4.1a/data/yacc.c:694: ERROR: copying inserted
file: Broken pipe
> > /opt/TWWfsw/m414/bin/gm4: write error
> 52. output.at:159: 52. Conflicting output files:  -o foo.y (output.at:159): FAILED (output.at:159)
> 
> We're seeing the same failure on AIX and HP-UX.

I'm pretty sure this means your m4 is broken.  Please confirm that you're 
running at least GNU M4 1.4.6.

Albert Chin | 2 Feb 06:27

Re: Test 52 failure on AIX, HP-UX, Solaris

On Mon, Feb 01, 2010 at 06:56:03PM -0500, Joel E. Denny wrote:
> On Mon, 1 Feb 2010, Albert Chin wrote:
> 
> > Test 52 fails on AIX, HP-UX, and Solaris:
> > 52. output.at:159: testing ...
> > ./output.at:159: VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=summary --show-reachable=no";
export VALGRIND_OPTS; bison -o foo.y foo.y
> > 2c2,3
> > < 
> > ---
> > > /opt/TWWfsw/m414/bin/gm4:/opt/build/bison-2.4.1a/data/yacc.c:694: ERROR: copying inserted
file: Broken pipe
> > > /opt/TWWfsw/m414/bin/gm4: write error
> > 52. output.at:159: 52. Conflicting output files:  -o foo.y (output.at:159): FAILED (output.at:159)
> > 
> > We're seeing the same failure on AIX and HP-UX.
> 
> I'm pretty sure this means your m4 is broken.  Please confirm that you're 
> running at least GNU M4 1.4.6.

We're running 1.4.12.

--

-- 
albert chin (china <at> thewrittenword.com)

Joel E. Denny | 2 Feb 06:42
Favicon

Re: Test 52 failure on AIX, HP-UX, Solaris

On Mon, 1 Feb 2010, Albert Chin wrote:

> On Mon, Feb 01, 2010 at 06:56:03PM -0500, Joel E. Denny wrote:
> > On Mon, 1 Feb 2010, Albert Chin wrote:
> > 
> > > Test 52 fails on AIX, HP-UX, and Solaris:
> > > 52. output.at:159: testing ...
> > > ./output.at:159: VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=summary --show-reachable=no";
export VALGRIND_OPTS; bison -o foo.y foo.y
> > > 2c2,3
> > > < 
> > > ---
> > > > /opt/TWWfsw/m414/bin/gm4:/opt/build/bison-2.4.1a/data/yacc.c:694: ERROR: copying inserted
file: Broken pipe
> > > > /opt/TWWfsw/m414/bin/gm4: write error
> > > 52. output.at:159: 52. Conflicting output files:  -o foo.y (output.at:159): FAILED (output.at:159)
> > > 
> > > We're seeing the same failure on AIX and HP-UX.
> > 
> > I'm pretty sure this means your m4 is broken.  Please confirm that you're 
> > running at least GNU M4 1.4.6.
> 
> We're running 1.4.12.

You're saying that /opt/TWWfsw/m414/bin/gm4, which is mentioned in the 
error message, is GNU M4 1.4.12?

I should point out that M4 in your environment would cause Bison to use a 
different m4 than the one discovered by configure.

Do any other test cases fail?  Attaching a complete tests/testsuite.log 
and config.log might help us debug this.

Joel E. Denny | 2 Feb 07:19
Favicon

Re: Test 52 failure on AIX, HP-UX, Solaris

On Tue, 2 Feb 2010, Joel E. Denny wrote:

> On Mon, 1 Feb 2010, Albert Chin wrote:
> 
> > On Mon, Feb 01, 2010 at 06:56:03PM -0500, Joel E. Denny wrote:
> > > On Mon, 1 Feb 2010, Albert Chin wrote:
> > > 
> > > > Test 52 fails on AIX, HP-UX, and Solaris:
> > > > 52. output.at:159: testing ...
> > > > ./output.at:159: VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=summary --show-reachable=no";
export VALGRIND_OPTS; bison -o foo.y foo.y
> > > > 2c2,3
> > > > < 
> > > > ---
> > > > > /opt/TWWfsw/m414/bin/gm4:/opt/build/bison-2.4.1a/data/yacc.c:694: ERROR: copying
inserted file: Broken pipe
> > > > > /opt/TWWfsw/m414/bin/gm4: write error
> > > > 52. output.at:159: 52. Conflicting output files:  -o foo.y (output.at:159): FAILED (output.at:159)
> > > > 
> > > > We're seeing the same failure on AIX and HP-UX.
> > > 
> > > I'm pretty sure this means your m4 is broken.  Please confirm that you're 
> > > running at least GNU M4 1.4.6.
> > 
> > We're running 1.4.12.
> 
> You're saying that /opt/TWWfsw/m414/bin/gm4, which is mentioned in the 
> error message, is GNU M4 1.4.12?
> 
> I should point out that M4 in your environment would cause Bison to use a 
> different m4 than the one discovered by configure.

Never mind.  I think I see the problem now.  This test group produces a 
fatal error, which invokes exit, while the m4 subpipe is still open.  
Apparently that causes ugly error messages on some platforms.

We should probably change bison not to do this... and there are many other 
places where fatal errors might occur while the m4 subpipe is open.  For 
release 2.4.2, it might be better just to detect the problem and skip the 
associated test groups.  I'll have to give it more thought.

> Do any other test cases fail?  Attaching a complete tests/testsuite.log 
> and config.log might help us debug this.

That would still be helpful.

While the following patch is obviously not a good solution, would you 
please confirm that it does allow the test group to pass on the affected 
platforms?

diff --git a/src/files.c b/src/files.c
index 9761de9..63c9e2a 100644
--- a/src/files.c
+++ b/src/files.c
@@ -350,11 +350,15 @@ compute_output_file_names (void)
   free (header_extension);
 }

-void
+bool
 output_file_name_check (char const *file_name)
 {
   if (0 == strcmp (file_name, grammar_file))
-    fatal (_("refusing to overwrite the input file %s"), quote (file_name));
+    {
+      complain (_("fatal error: refusing to overwrite the input file %s"),
+                quote (file_name));
+      return true;
+    }
   {
     int i;
     for (i = 0; i < file_names_count; i++)
@@ -363,6 +367,7 @@ output_file_name_check (char const *file_name)
   }
   file_names = xnrealloc (file_names, ++file_names_count, sizeof *file_names);
   file_names[file_names_count-1] = xstrdup (file_name);
+  return false;
 }

 void
diff --git a/src/files.h b/src/files.h
index e8f28bf..5e114bf 100644
--- a/src/files.h
+++ b/src/files.h
@@ -63,7 +63,7 @@ extern char *all_but_ext;

 void compute_output_file_names (void);
 void output_file_names_free (void);
-void output_file_name_check (char const *file_name);
+bool output_file_name_check (char const *file_name);

 FILE *xfopen (const char *name, const char *mode);
 void xfclose (FILE *ptr);
diff --git a/src/scan-skel.l b/src/scan-skel.l
index 90a52dd..92cab2a 100644
--- a/src/scan-skel.l
+++ b/src/scan-skel.l
@@ -276,8 +276,10 @@ void at_directive_perform (int at_directive_argc,
           xfclose (yyout);
         }
       *outnamep = xstrdup (at_directive_argv[1]);
-      output_file_name_check (*outnamep);
-      yyout = xfopen (*outnamep, "w");
+      if (output_file_name_check (*outnamep))
+        yyout = xfopen ("bogus.tmp", "w");
+      else
+        yyout = xfopen (*outnamep, "w");
       *out_linenop = 1;
     }
   else

Albert Chin | 2 Feb 07:37

Re: Test 52 failure on AIX, HP-UX, Solaris


On Tue, Feb 02, 2010 at 01:19:38AM -0500, Joel E. Denny wrote: > While the following patch is obviously not a good solution, would you > please confirm that it does allow the test group to pass on the > affected platforms?
Confirmed on RHEL4/x86-64. -- -- albert chin (china <at> thewrittenword.com)
Joel E. Denny | 2 Feb 10:30
Favicon

Re: Test 52 failure on AIX, HP-UX, Solaris

On Tue, 2 Feb 2010, Albert Chin wrote:

> On Tue, Feb 02, 2010 at 01:19:38AM -0500, Joel E. Denny wrote:
> > While the following patch is obviously not a good solution, would you
> > please confirm that it does allow the test group to pass on the
> > affected platforms?
> 
> Confirmed on RHEL4/x86-64.

Thanks.

Here's an attempt at fixing this.  Not yet pushed.  I now need to decide 
whether this fix is too much for 2.4.2.  If so, I suppose I could just 
comment out the affected test group for 2.4.2, but I'm suspicious that 
there's a race condition that could sometimes affect other test groups.  
I'd appreciate comments from anyone.

>From 09f99a629f7aa0d696646d28d23cde47588f4e38 Mon Sep 17 00:00:00 2001
From: Joel E. Denny <jdenny <at> clemson.edu>
Date: Tue, 2 Feb 2010 04:10:30 -0500
Subject: [PATCH] portability: don't exit before reaping m4 child.

This was happening at fatal errors during scan_skel.  Broken
pipe messages were seen on at least AIX, HP-UX, Solaris, and
RHEL4, and this caused failures in the test suite.  Is this more
a race condition than a portability issue?
Reported by Albert Chin at
<http://lists.gnu.org/archive/html/bug-bison/2010-02/msg00004.html>.
* NEWS (2.4.2): Document.
* lib/subpipe.c, lib/subpipe.h (reap_subpipe): Add
ignore_failure argument to avoid a redundant error message after
already reporting a fatal error.
* src/complain.c, src/complain.h (fatal_at_delayed,
fatal_delayed): New functions.
* src/files.c (compute_output_file_names): Update invocations
of output_file_name_check.
(output_file_name_check): In the case that the grammar file
would be overwritten, use complain instead of fatal, but replace
the output file name with /dev/null.  Use the /dev/null solution
for case of two conflicting output files as well because it
seems safer in case Bison one day tries to open both files at
the same time.
* src/files.h (output_file_name_check): Update prototype.
* src/output.c (output_skeleton): On a fatal error from
scan_skel, reap m4 process before exiting.
* src/scan-skel.h (scan_skel): Update prototype.
* src/scan-skel.l (skel_lex): Delay fatal errors and return
false iff there were any.
(scan_skel): Propagate skel_lex's return.
(at_directive_perform): Delay fatal errors and return false iff
there were any.  Update output_file_name_check invocation.
(fail_for_at_directive_too_few_args): Delay fatal error.
(fail_for_at_directive_too_many_args): Delay fatal error.
(fail_for_invalid_at): Delay fatal error.
* output.at (AT_CHECK_CONFLICTING_OUTPUT): Check that the
grammar file actually isn't overwritten.
(Conflicting output files: -o foo.y): Update expected output.
---
 ChangeLog       |   39 ++++++++++++++++++++++++++
 NEWS            |    5 ++-
 lib/subpipe.c   |    4 +-
 lib/subpipe.h   |    2 +-
 src/complain.c  |   12 ++++++++
 src/complain.h  |    8 +++++
 src/files.c     |   47 ++++++++++++++++++++++---------
 src/files.h     |    2 +-
 src/output.c    |   10 +++++--
 src/scan-skel.h |    2 +-
 src/scan-skel.l |   81 ++++++++++++++++++++++++++++++++++++-------------------
 tests/output.at |    4 ++-
 12 files changed, 163 insertions(+), 53 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b54880b..8d665b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2010-02-02  Joel E. Denny  <jdenny <at> ces.clemson.edu>
+
+	portability: don't exit before reaping m4 child.
+	This was happening at fatal errors during scan_skel.  Broken
+	pipe messages were seen on at least AIX, HP-UX, Solaris, and
+	RHEL4, and this caused failures in the test suite.  Is this more
+	a race condition than a portability issue?
+	Reported by Albert Chin at
+	<http://lists.gnu.org/archive/html/bug-bison/2010-02/msg00004.html>.
+	* NEWS (2.4.2): Document.
+	* lib/subpipe.c, lib/subpipe.h (reap_subpipe): Add
+	ignore_failure argument to avoid a redundant error message after
+	already reporting a fatal error.
+	* src/complain.c, src/complain.h (fatal_at_delayed,
+	fatal_delayed): New functions.
+	* src/files.c (compute_output_file_names): Update invocations
+	of output_file_name_check.
+	(output_file_name_check): In the case that the grammar file
+	would be overwritten, use complain instead of fatal, but replace
+	the output file name with /dev/null.  Use the /dev/null solution
+	for case of two conflicting output files as well because it
+	seems safer in case Bison one day tries to open both files at
+	the same time.
+	* src/files.h (output_file_name_check): Update prototype.
+	* src/output.c (output_skeleton): On a fatal error from
+	scan_skel, reap m4 process before exiting.
+	* src/scan-skel.h (scan_skel): Update prototype.
+	* src/scan-skel.l (skel_lex): Delay fatal errors and return
+	false iff there were any.
+	(scan_skel): Propagate skel_lex's return.
+	(at_directive_perform): Delay fatal errors and return false iff
+	there were any.  Update output_file_name_check invocation.
+	(fail_for_at_directive_too_few_args): Delay fatal error.
+	(fail_for_at_directive_too_many_args): Delay fatal error.
+	(fail_for_invalid_at): Delay fatal error.
+	* output.at (AT_CHECK_CONFLICTING_OUTPUT): Check that the
+	grammar file actually isn't overwritten.
+	(Conflicting output files: -o foo.y): Update expected output.
+
 2010-02-01  Joel E. Denny  <jdenny <at> ces.clemson.edu>

 	tests: link lib/libbison.a for gnulib.
diff --git a/NEWS b/NEWS
index 9b33d13..8f33793 100644
--- a/NEWS
+++ b/NEWS
@@ -3,8 +3,9 @@ Bison News

 * Changes in version 2.4.2 (????-??-??):

-** Some portability problems in the testsuite that resulted in failures
-   on at least Solaris 2.7 have been fixed.
+** Some portability problems that resulted in testsuite failures on
+   some versions of at least Solaris, AIX, HP-UX, and RHEL4 have been
+   fixed.

 ** `%prec IDENTIFIER' requires IDENTIFIER to be defined separately.

diff --git a/lib/subpipe.c b/lib/subpipe.c
index 1b7c36d..cdbd353 100644
--- a/lib/subpipe.c
+++ b/lib/subpipe.c
@@ -147,13 +147,13 @@ create_subpipe (char const * const *argv, int fd[2])
 /* Wait for the subprocess to exit.  */

 void
-reap_subpipe (pid_t pid, char const *program)
+reap_subpipe (pid_t pid, char const *program, int ignore_failure)
 {
 #if HAVE_WAITPID || defined waitpid
   int wstatus;
   if (waitpid (pid, &wstatus, 0) < 0)
     error (EXIT_FAILURE, errno, "waitpid");
-  else
+  else if (!ignore_failure)
     {
       int status = WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : -1;
       if (status)
diff --git a/lib/subpipe.h b/lib/subpipe.h
index ff791a8..708a447 100644
--- a/lib/subpipe.h
+++ b/lib/subpipe.h
@@ -25,4 +25,4 @@
 void init_subpipe (void);
 pid_t create_subpipe (char const * const *, int[2]);
 void end_of_output_subpipe (pid_t, int[2]);
-void reap_subpipe (pid_t, char const *);
+void reap_subpipe (pid_t, char const *, int);
diff --git a/src/complain.c b/src/complain.c
index d187624..7b53aaa 100644
--- a/src/complain.c
+++ b/src/complain.c
@@ -137,3 +137,15 @@ fatal (const char *message, ...)
   ERROR_MESSAGE (NULL, _("fatal error"), message);
   exit (EXIT_FAILURE);
 }
+
+void
+fatal_at_delayed (location loc, const char *message, ...)
+{
+  ERROR_MESSAGE (&loc, _("fatal error"), message);
+}
+
+void
+fatal_delayed (const char *message, ...)
+{
+  ERROR_MESSAGE (NULL, _("fatal error"), message);
+}
diff --git a/src/complain.h b/src/complain.h
index 9d24f25..29120cd 100644
--- a/src/complain.h
+++ b/src/complain.h
@@ -48,6 +48,14 @@ void fatal (char const *format, ...)
 void fatal_at (location loc, char const *format, ...)
   __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)));

+/** A fatal error, but assume the caller will immediately exit.  */
+
+void fatal_delayed (char const *format, ...)
+  __attribute__ ((__format__ (__printf__, 1, 2)));
+
+void fatal_at_delayed (location loc, char const *format, ...)
+  __attribute__ ((__format__ (__printf__, 2, 3)));
+
 /** Whether an error was reported.  */
 extern bool complaint_issued;

diff --git a/src/files.c b/src/files.c
index 9761de9..e8bb200 100644
--- a/src/files.c
+++ b/src/files.c
@@ -328,21 +328,21 @@ compute_output_file_names (void)
     {
       if (! spec_graph_file)
 	spec_graph_file = concat2 (all_but_tab_ext, ".dot");
-      output_file_name_check (spec_graph_file);
+      output_file_name_check (&spec_graph_file);
     }

   if (xml_flag)
     {
       if (! spec_xml_file)
 	spec_xml_file = concat2 (all_but_tab_ext, ".xml");
-      output_file_name_check (spec_xml_file);
+      output_file_name_check (&spec_xml_file);
     }

   if (report_flag)
     {
       if (!spec_verbose_file)
         spec_verbose_file = concat2 (all_but_tab_ext, OUTPUT_EXT);
-      output_file_name_check (spec_verbose_file);
+      output_file_name_check (&spec_verbose_file);
     }

   free (all_but_tab_ext);
@@ -351,18 +351,37 @@ compute_output_file_names (void)
 }

 void
-output_file_name_check (char const *file_name)
+output_file_name_check (char **file_name)
 {
-  if (0 == strcmp (file_name, grammar_file))
-    fatal (_("refusing to overwrite the input file %s"), quote (file_name));
-  {
-    int i;
-    for (i = 0; i < file_names_count; i++)
-      if (0 == strcmp (file_names[i], file_name))
-        warn (_("conflicting outputs to file %s"), quote (file_name));
-  }
-  file_names = xnrealloc (file_names, ++file_names_count, sizeof *file_names);
-  file_names[file_names_count-1] = xstrdup (file_name);
+  bool conflict = false;
+  if (0 == strcmp (*file_name, grammar_file))
+    {
+      complain (_("refusing to overwrite the input file %s"),
+                quote (*file_name));
+      conflict = true;
+    }
+  else
+    {
+      int i;
+      for (i = 0; i < file_names_count; i++)
+        if (0 == strcmp (file_names[i], *file_name))
+          {
+            warn (_("conflicting outputs to file %s"),
+                  quote (*file_name));
+            conflict = true;
+          }
+    }
+  if (conflict)
+    {
+      free (*file_name);
+      *file_name = strdup ("/dev/null");
+    }
+  else
+    {
+      file_names = xnrealloc (file_names, ++file_names_count,
+                              sizeof *file_names);
+      file_names[file_names_count-1] = xstrdup (*file_name);
+    }
 }

 void
diff --git a/src/files.h b/src/files.h
index e8f28bf..5366783 100644
--- a/src/files.h
+++ b/src/files.h
@@ -63,7 +63,7 @@ extern char *all_but_ext;

 void compute_output_file_names (void);
 void output_file_names_free (void);
-void output_file_name_check (char const *file_name);
+void output_file_name_check (char **file_name);

 FILE *xfopen (const char *name, const char *mode);
 void xfclose (FILE *ptr);
diff --git a/src/output.c b/src/output.c
index 6a05704..b5d661d 100644
--- a/src/output.c
+++ b/src/output.c
@@ -581,9 +581,13 @@ output_skeleton (void)
   if (! in)
     error (EXIT_FAILURE, get_errno (),
 	   "fdopen");
-  scan_skel (in);
-  xfclose (in);
-  reap_subpipe (pid, m4);
+  {
+    bool fatal_error = !scan_skel (in);
+    xfclose (in);
+    reap_subpipe (pid, m4, fatal_error);
+    if (fatal_error)
+      exit (EXIT_FAILURE);
+  }
   timevar_pop (TV_M4);
 }

diff --git a/src/scan-skel.h b/src/scan-skel.h
index bef1a33..1cb2138 100644
--- a/src/scan-skel.h
+++ b/src/scan-skel.h
@@ -17,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

-void scan_skel (FILE *);
+bool scan_skel (FILE *);

 /* Pacify "make syntax-check".  */
 extern FILE *skel_in;
diff --git a/src/scan-skel.l b/src/scan-skel.l
index 90a52dd..bd91cbd 100644
--- a/src/scan-skel.l
+++ b/src/scan-skel.l
@@ -38,13 +38,13 @@
 #include "files.h"
 #include "scan-skel.h"

-#define YY_DECL static int skel_lex (void)
+#define YY_DECL static bool skel_lex (void)
 YY_DECL;

 #define QPUTS(String) \
    fputs (quotearg_style (c_quoting_style, String), yyout)

-static void at_directive_perform (int at_directive_argc,
+static bool at_directive_perform (int at_directive_argc,
                                   char *at_directive_argv[],
                                   char **outnamep, int *out_linenop);
 static void fail_for_at_directive_too_many_args (char const *at_directive_name);
@@ -88,7 +88,7 @@ static void fail_for_invalid_at (char const *at);
 }

   /* This pattern must not match more than the previous @ patterns. */
-@[^@{}`(\n]* fail_for_invalid_at (yytext);
+@[^@{}`(\n]* fail_for_invalid_at (yytext); return false;
 \n	   out_lineno++; ECHO;
 [^@\n]+	   ECHO;

@@ -98,7 +98,7 @@ static void fail_for_invalid_at (char const *at);
       free (outname);
       xfclose (yyout);
     }
-  return EOF;
+  return true;
 }

 <SC_AT_DIRECTIVE_ARGS>{
@@ -107,13 +107,16 @@ static void fail_for_invalid_at (char const *at);
   "@@" { obstack_1grow (&obstack_for_string, '@'); }
   "@{" { obstack_1grow (&obstack_for_string, '['); }
   "@}" { obstack_1grow (&obstack_for_string, ']'); }
-  "@`" /* Emtpy.  Useful for starting an argument
+  "@`" /* Empty.  Useful for starting an argument
           that begins with whitespace. */
   @\n  /* Empty.  */

   @[,)] {
     if (at_directive_argc >= AT_DIRECTIVE_ARGC_MAX)
-      fail_for_at_directive_too_many_args (at_directive_argv[0]);
+      {
+        fail_for_at_directive_too_many_args (at_directive_argv[0]);
+        return false;
+      }

     obstack_1grow (&obstack_for_string, '\0');
     at_directive_argv[at_directive_argc++] =
@@ -124,15 +127,16 @@ static void fail_for_invalid_at (char const *at);
       BEGIN SC_AT_DIRECTIVE_SKIP_WS;
     else
       {
-        at_directive_perform (at_directive_argc, at_directive_argv,
-                              &outname, &out_lineno);
+        if (!at_directive_perform (at_directive_argc, at_directive_argv,
+                                   &outname, &out_lineno))
+          return false;
         obstack_free (&obstack_for_string, at_directive_argv[0]);
         at_directive_argc = 0;
         BEGIN INITIAL;
       }
   }

-  @.? { fail_for_invalid_at (yytext); }
+  @.? { fail_for_invalid_at (yytext); return false; }
 }

 <SC_AT_DIRECTIVE_SKIP_WS>{
@@ -142,7 +146,9 @@ static void fail_for_invalid_at (char const *at);

 <SC_AT_DIRECTIVE_ARGS,SC_AT_DIRECTIVE_SKIP_WS>{
   <<EOF>> {
-    fatal (_("unclosed %s directive in skeleton"), at_directive_argv[0]);
+    fatal_delayed (_("unclosed %s directive in skeleton"),
+                   at_directive_argv[0]);
+    return false;
   }
 }

@@ -152,7 +158,7 @@ static void fail_for_invalid_at (char const *at);
 | Scan a Bison skeleton.  |
 `------------------------*/

-void
+bool
 scan_skel (FILE *in)
 {
   static bool initialized = false;
@@ -163,7 +169,7 @@ scan_skel (FILE *in)
     }
   skel_in = in;
   skel__flex_debug = trace_flag & trace_skeleton;
-  skel_lex ();
+  return skel_lex ();
 }

 void
@@ -174,15 +180,18 @@ skel_scanner_free (void)
   yylex_destroy ();
 }

-static
-void at_directive_perform (int at_directive_argc,
-                           char *at_directive_argv[],
-                           char **outnamep, int *out_linenop)
+static bool
+at_directive_perform (int at_directive_argc,
+                      char *at_directive_argv[],
+                      char **outnamep, int *out_linenop)
 {
   if (0 == strcmp (at_directive_argv[0], "@basename"))
     {
       if (at_directive_argc > 2)
-        fail_for_at_directive_too_many_args (at_directive_argv[0]);
+        {
+          fail_for_at_directive_too_many_args (at_directive_argv[0]);
+          return false;
+        }
       fputs (last_component (at_directive_argv[1]), yyout);
     }
   else if (0 == strcmp (at_directive_argv[0], "@warn")
@@ -194,7 +203,7 @@ void at_directive_perform (int at_directive_argc,
         {
           case 'w': func = warn; break;
           case 'c': func = complain; break;
-          case 'f': func = fatal; break;
+          case 'f': func = fatal_delayed; break;
           default: aver (false); break;
         }
       switch (at_directive_argc)
@@ -220,8 +229,11 @@ void at_directive_perform (int at_directive_argc,
             break;
           default:
             fail_for_at_directive_too_many_args (at_directive_argv[0]);
+            return false;
             break;
         }
+      if (func == fatal_delayed)
+        return false;
     }
   else if (0 == strcmp (at_directive_argv[0], "@warn_at")
            || 0 == strcmp (at_directive_argv[0], "@complain_at")
@@ -230,12 +242,15 @@ void at_directive_perform (int at_directive_argc,
       void (*func)(location, char const *, ...);
       location loc;
       if (at_directive_argc < 4)
-        fail_for_at_directive_too_few_args (at_directive_argv[0]);
+        {
+          fail_for_at_directive_too_few_args (at_directive_argv[0]);
+          return false;
+        }
       switch (at_directive_argv[0][1])
         {
           case 'w': func = warn_at; break;
           case 'c': func = complain_at; break;
-          case 'f': func = fatal_at; break;
+          case 'f': func = fatal_at_delayed; break;
           default: aver (false); break;
         }
       boundary_set_from_string (&loc.start, at_directive_argv[1]);
@@ -263,43 +278,53 @@ void at_directive_perform (int at_directive_argc,
             break;
           default:
             fail_for_at_directive_too_many_args (at_directive_argv[0]);
+            return false;
             break;
         }
+      if (func == fatal_at_delayed)
+        return false;
     }
   else if (0 == strcmp (at_directive_argv[0], "@output"))
     {
       if (at_directive_argc > 2)
-        fail_for_at_directive_too_many_args (at_directive_argv[0]);
+        {
+          fail_for_at_directive_too_many_args (at_directive_argv[0]);
+          return false;
+        }
       if (*outnamep)
         {
           free (*outnamep);
           xfclose (yyout);
         }
       *outnamep = xstrdup (at_directive_argv[1]);
-      output_file_name_check (*outnamep);
+      output_file_name_check (outnamep);
       yyout = xfopen (*outnamep, "w");
       *out_linenop = 1;
     }
   else
-    fail_for_invalid_at (at_directive_argv[0]);
+    {
+      fail_for_invalid_at (at_directive_argv[0]);
+      return false;
+    }
+  return true;
 }

 static void
 fail_for_at_directive_too_few_args (char const *at_directive_name)
 {
-  fatal (_("too few arguments for %s directive in skeleton"),
-         at_directive_name);
+  fatal_delayed (_("too few arguments for %s directive in skeleton"),
+                 at_directive_name);
 }

 static void
 fail_for_at_directive_too_many_args (char const *at_directive_name)
 {
-  fatal (_("too many arguments for %s directive in skeleton"),
-         at_directive_name);
+  fatal_delayed (_("too many arguments for %s directive in skeleton"),
+                 at_directive_name);
 }

 static void
 fail_for_invalid_at (char const *at)
 {
-  fatal ("invalid @ in skeleton: %s", at);
+  fatal_delayed ("invalid @ in skeleton: %s", at);
 }
diff --git a/tests/output.at b/tests/output.at
index f8e1653..999ca18 100644
--- a/tests/output.at
+++ b/tests/output.at
@@ -137,7 +137,9 @@ AT_DATA([$1],
 foo: {};
 ]])

+[cp ]$1[ expout]
 AT_BISON_CHECK([$3 $1], $5, [], [$4])
+AT_CHECK([[cat $1]], [[0]], [expout])
 AT_CLEANUP
 ])

@@ -157,7 +159,7 @@ AT_CHECK_CONFLICTING_OUTPUT([foo.y],
 ])

 AT_CHECK_CONFLICTING_OUTPUT([foo.y], [], [-o foo.y],
-[foo.y: fatal error: refusing to overwrite the input file `foo.y'
+[foo.y: refusing to overwrite the input file `foo.y'
 ], 1)

 
--

-- 
1.5.4.3


Gmane