[Top][All Lists]

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

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

From: Akim Demaille
Subject: Re: yyparse being prototyped in y.tab.h causes problems.
Date: Wed, 19 Aug 2015 08:24:07 +0200

Hi Kaz!

Thanks for taking the time to write a detailed answer.

> Le 18 août 2015 à 22:32, Kaz Kylheku <address@hidden> a écrit :
> 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>.

I agree with all that.  That's also why we pay attention to
avoid useless includes in both *.tab.c and *.tab.h.  But here,
I'm referring to defining useless bits of information: the
various types (tokens, semantic value, location, yydebug, ...),
and the prototype of yyparse.

As you reported, the standard does not even report YYSTYPE,
which is clearly needed.

>> 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!

yacc.c (the skeleton used for -y), for historical reasons,
_duplicates_ y.tab.h instead of including it.  That's why
even if you remove the declaration from *.tab.h, compiling
*.tab.c won't complain.  But that's a different story
for the other skeletons.

>> 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.

:)  I agree.  But I guess our opinions diverge on the definition
of brokenness.

>> And %code is not superfluous.  For instance, we also support
>> Java.
> %code is superfluous in the traditional Yacc + C model,

Again, I disagree here.  There are plenty of things that
were done with macros before, and it was badly done.  Consider
YYPARSE_PARAM for instance: because it's a macro. bison
can't see it, so it does not know the name of the argument,
so it's can't pass it to yyerror and the like.  So in the past,
YYPARSE_PARAM was just the name of the argument, but it had to
be void*.  And it was limited to a single argument.

It was an improvement to be able to read these definitions that
were before hidden by cpp.

> 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.

Yes, yes, you can.  When one is able to play regexp tricks
in a Makefile, then I am sure that he can do whatever he
wants.  However, beginners have a hard time starting to use
bison, the amount of boilerplate code was amazing (and remains
too high today imho).  Really, the point is to make
simple things simple, and more complex things easy.

> 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.

But really, what's wrong with adding

  typedef struct parser_context parser_context;

in your parser.h before the #include "y.tab.h"?  There is
no need for this mutual inclusion.

reply via email to

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