bug-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: yyparse being prototyped in y.tab.h causes problems.


From: Kaz Kylheku
Subject: Re: yyparse being prototyped in y.tab.h causes problems.
Date: Tue, 18 Aug 2015 13:32:38 -0700
User-agent: Roundcube Webmail/0.9.2

On 18.08.2015 12:36, Akim Demaille wrote:
Hi!

Le 18 août 2015 à 15:35, Kaz Kylheku <address@hidden> a écrit :

While on the topic of POSIX, what does it have to say about
the y.tab.h header file?

 -d  Write the header file; by default only the code
     file is written. The #define statements associate the
     token codes assigned by yacc with the user-declared
     token names. This allows source files other than
     y.tab.c to access the token codes.

According to this, y.tab.h is supposed to just #define
the token codes!

(Unfortunately, the spec forgets the obvious: that lexers
also need YYSTYPE from y.tab.h, and traditional Yacc
implementations provide it.)

I'm not reading this as exclusive.  It should at least contain
that.

Ah, but contents of headers can break things. Do you also think
that the contents of, say, <stdio.h> or <unistd.h> are
non-exclusive?

Is it okay if <stdio.h> contains

  typedef int foo;

so that any program which uses foo as a file scope identifier
or macro will clash?

If implementors need additional identifiers
for their own use, they have a reserved namespace for that:
_[A-Z]* and __.*:

  typedef int __foo; // Okay; in implementation namespace

Of course, <stdio.h> can be extended; like POSIX adds
the fileno function to it and others. But those declarations
can be properly hidden with feature selection macros;
a strictly ISO C program not using any extensions can use
the non-reserved fileno identifier for any purpose whether
or not it includes <stdio.h>.

In any case, users who want who want additional declarations
can easily write their own header like "y.decl.h". The
%code functionality for depositing additional material in
y.tab.h is superfluous, solving a problem that is already
solved by the C preprocessor, and the fact that you can
#include your own header between %{ and %} in the grammar
file. Anyone who has needed a global declaration for yyparse
(or anything else exported by the .y file) in the past 40
years probably did exactly that.

That's not entirely true.  Things have changed in the meanwhile,
and C, for instance, now has prototypes.

Yes, and so the "own header" described above has prototype
declarations.

warning when a function is not prototype and is not static for

I use gcc -Wstrict-prototypes and -Wmissing-prototypes.

No, in fact: -Werror=missing-prototypes -Werror=strict-prototypes!

In addition, the code compiles as C++, too.

Haven't seen any of these diagnostics related to yyparse at all
from any version of Bison or Berkeley Yacc.

Why is that? Lo and behold (snippet of output of Bison 2.5):

  /* Prevent warnings from -Wmissing-prototypes.  */
  #ifdef YYPARSE_PARAM
  #if defined __STDC__ || defined __cplusplus
  int yyparse (void *YYPARSE_PARAM);

The issue is taken care of in the skeleton; there is
no need to hoist that declaration into the header file.

instance.  So I beg to disagree: Bison tries to address today's
needs.

The prototype emitted into y.tab.h may be modern, but it is
broken because it refers to types which are not
declared in that scope.

Anything that is broken doesn't address needs.

And %code is not superfluous.  For instance, we also support
Java.

%code is superfluous in the traditional Yacc + C model,
where there is no Java, because you can do this:

  %{
  #include "parser-common.h"
  %}

This common header can declare whatever you need, and provide
a full prototype for yyparse, if that function is being called
directly from other translation units.

Whatever you think you need to spit into y.tab.h with %code
can be put into parser-common.h by hand, and you get in the
parser also via the #include.

In my case, the yyparse in y.tab.h has created a circular
dependency between the "parser.h" common header and "y.tab.h".

It is my "parser.h" common header which declares the types
needed in the declaration. However, those types include the
YYSTYPE.  A sketch of what is going on:

   /* parser.h */
   typedef struct {
      /* ... */
      YYSTYPE member; /* needs y.tab.h */
   } parser_context;

   /* y.tab.h */
   int yyparse(parser_context *parser); /* needs parser.h */

So parser.h needs y.tab.h for YYSTYPE, and thanks only
to the gratuitous yyparse declaration, y.tab.h needs
parser.h for parser_context.



reply via email to

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