bison-patches
[Top][All Lists]
Advanced

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

Re: glr: include the created header


From: Akim Demaille
Subject: Re: glr: include the created header
Date: Wed, 28 Jun 2006 08:03:08 +0200


Le 28 juin 06 à 01:21, Joel E. Denny a écrit :

On Tue, 27 Jun 2006, Akim Demaille wrote:

I am not convinced this was the right move. I feel there is too many possible choices here, driven by C's model where you split definitions
and declarations.

Since Bison has at least two backend languages (C and C++) that use this
model, it seems we ought to accommodate the model.

This is not what I mean.  What I meant is that we can live without
these arcane matters, other langages have proved it.

Other languages like Java?  How does that address C and C++ support?
Again, I think I just don't know what you mean.

I am not referring to the target language :)  I'm referring to the
approach of building modules where we try to keep things as simple
as they can be, in particular avoiding zillions of different sections.


In modern languages, the order is irrelevant.

Sorry, thanks, I forgot.  So the Java user probably won't want either.
In that case, the new %*-header declarations present no complexity to him since he can easily stick to %{...%}. The %*-header declarations may only
be useful for C/C++.  What's wrong with that?

I'm not complaining about new directives that would pollute Java users.
I'm saying that we should strive to avoid the spirit that C brought
to this world, and rather try to find something comparable to more
modern and simpler trends.  Transposed to the programming language
world, that would be C# or Java, granted, but I am not referring to
them as target language, just the spirit.  Whether we target C or
C# is irrelevant.


Ok, we could drop the new declarations and provide only prologue blocks that will insert code only into the code file (for consistency with Yacc). That will accommodate languages like Java, and the C/C++ user can write a
file called parser.h that contains this:

  #include "pre-parser.tab.h"
  #include "parser.tab.h"
  #include "post-parser.tab.h"

where Bison generates parser.tab.h.  The user can then put this in his
code file:

  %{
    #include "pre-parser.tab.h"
  %}
  %union { int val };
  %{
    #include "post-parser.tab.h"
  %}

This seems less readable to me. But, without the new declarations, how
else will the C/C++ user be able to avoid repeated code and yet have
control over his header file?

In this case the user can simply put things before and things after
the %union.  What if some day we add a means to define some other
type, say %location-struct {...} defining YYLTYPE.  Would we want
to also have different pre and post primitive to order them, and
users should choose which to use?

My point is that whether there is a pre or post %union is purely
an implementation detail.  Starting we the problem that in C we
can forward declare structs and unions, but not typedefs.  The
origin is also due to the fact that original Yacc introduced
%union instead of asking the user to define YYSTYPE in some way
or another in the prologue.

Because it's an implementation detail, I don't think we should make
it user visible.



My point is that the very feature is order dependant, and I fail to
understand the point of making the interface more complex instead of
sticking to what we have:

What we had as of Bison 2.3 was limited and inconsistent among the
skeletons.  I found that more complex because the inconsistencies were
confusing and the limitations were ugly to work around.

I very much agree we should eliminate the differences between skeletons,
and I find your work very useful in this regard!  Something has to be
done, and it's great that you care to address this issue.  By no means
am I saying that the current (well, previous :) situation is satisfying.


Once a user has recognized a need for finer
control, do you think he'll find these declarations confusing or too
complex?

Yes.  I think they are too complex.  They are too low level IMHO.


order matters, just as is the most common
case.

Order matters in C/C++. That doesn't mean we can't eliminate unnecessary
order-dependence from Bison declarations.

I certainly agree for Bison matters, but in this precise case, we only
discuss declaration matters, which are certainly only related to the
target language.

Fighting the R/R reduction based on order is definitely a nice
thing to do.  Dressing the simple fact that order matters in the
introduction of types and functions in C with new directives
seems wrong to me: order matters, period.  Order matters inside,
order matters outside.


We already teach our dear users that they should prototype
in the prologue the functions they use in the core grammar, but
that are defined in the epilogue.  I have no plan to make this
commutable.  This is C!

I wouldn't suggest that either.  But there's only one epilogue and it
always has the same position in the grammar file.

Well, personally I think it would be useful nevertheless!  To be
able to group things together.  But I do not think that a new
%epilogue {...} directive should do that, rather I expect to use
some form of scoping, or to rely on %import.



That's different than
an unlimited number of prologue declarations spread throughout the
declarations section such that, for each one, you have to hunt to find out whether it's before or after the %union. And if there is no % union, then
what happens?

The difference between before and after is then irrelevant!

But maybe I have not been clear on what's on my mind.  I am not
pretending there should not be a %private {...} directive for
matters that goes only in the *.c file.  Actually, I would
also propose to introduce %public {...} as an alias for
%{...%} for symmetry.

What I'm discussing is the need for pre- and post- forms.


Why was the ability to concatenate several %union's together added? If the freedom of code organization that this allows is still appealing, then
why is the following not appealing?:

  %start-header { #include "type1.h" }
  %union { type1 field1; }
  %destructor { free1 ($$); } <type1>
  %printer { print1 ($$); } <type1>
  %type <type1> a b c

  %start-header { #include "type2.h" }
  %union { type2 field2; }
  %destructor { free2 ($$); } <type1>
  %printer { free2 ($$); } <type1>
  %type <type2> d e f

Your code demonstrates exactly my point: the order matters, and so
much to your eyes that you would never have put the %start-header
after the %union.

I think that what you try to write here should be something offered
by %import.  We need a form of global scoping, not a low-level
form of issuing code in this or that section.

I would rewrite your code into something like

%module field1
{
  %public { #include "type1.h" }
  %private { void free1 (type1); }
  %union { type1 field1; }
  %destructor { free1 ($$); } <type1>
  %printer { print1 ($$); } <type1>
  %type <type1> a b c
  %%
  a: b | c;
  %%
  void free1 (type1 t)
  {
    free (t);
  };
}

%module field2
{
  %public { #include "type1.h" }
  %private { void free1 (type1); }
  %union { type2 field2; }
  %destructor { free2 ($$); } <type2>
  %printer { free2 ($$); } <type2>
  %type <type2> d e f
  %%
  d: e | f;
  %%
  void free2 (type2 t)
  {
    free (t);
  };
}


As an aside, I would like to introduce %type {...} in addition
to %union + %type <>, because I think that the name of the fields
is a private matter that the user should not know about.  In
particular because it might cause troublesome conflicts between
modules.  (BTW, it is so tempting that in the examples above we
have used type1 in %destructor, %printer, and %type!)

So:

%module field1
{
  %public { typedef int type1; }
  %private { void free1 (type1); }
  %type {type1} a b c
  %destructor { free1 ($$);  } a b c
  %printer    { print1 ($$); } a b c
  %%
  a: b | c;
  %%
  void free1 (type1 t)
  {
    free (t);
  };
}


Now we're streching that to such an extend that we consider four parts! Fortunately we did not introduce %location-definition, the combinatorial
explosion would have led to quite a linguistic challenge to name all
these sections.

A user can #define YYLTYPE in a %start-header and use its definition as well as the enum in a %end-header or %after-header. I see no explosion. All these Bison-generated declarations/definitions are grouped together
between the %start-header and %end-header.

I mean that the existence of pre and post- prologue is an internal
detail due to the fact that %union splits it in two parts.  If
we had, or if we have in the future, other type introducing primitive,
they to be consistent we would also need pre and post primitives for
that.  And *of course* we don't want that.  We want our interface
to remain simple and rely on its natural order.


Currently I am still not convinced we need something more than a
means to keep information private to the generated *.c/*.cc files.
The rest is just prologue, and it should go into the header, in
the order in which it appears.

When there's no %union, where does the prologue go in the header?

Everything declared with %{...%} aka %public {...} goes into the
header.



I think it's convenient to have one for before the header as well.
Currently we call it %before-header. Is there a better way to `#include "system.h"' in the code file? Yes, this is a C/C++ problem, but I think
it's nice to accommodate it, and it keeps the full symmetry of these
declarations.

But why don't you put it into the header file anyway?  Headers are
expected to be self contained.  That's the current trend, and
it's by far saner, safer, simpler.

I didn't know that was the current trend for system.h. Maybe Bison should follow this trend internally as well? If you were trying to move to this
trend, I'm afraid I undid your work earlier this month.  Sorry.


I'm not saying this is the trend for system.h, I'm saying this is the
trend in C/C++ programming.  Now that the use of double inclusion
protection is wide spread, one writes self-contained header, and
no longer header with pre-#include requirements.






reply via email to

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