Boost logo

Boost :

From: Brian McNamara (lorgon_at_[hidden])
Date: 2003-11-06 14:54:11

On Thu, Nov 06, 2003 at 07:37:55AM +0800, Joel de Guzman wrote:
> I tried to avoid making it seem long and winding, but this is the best
> I can do. I hope this doesn't cause more confusion?

No; I found your explanation again very helpful.

So, based on my understanding, it seems to me that the simplest fix is
to change from my original idea of

    template <class T>
    class match {
        optional<T> data;
        void value( T y ) {
            *data = y;
        // and your other fixes to deal with various nits

to this:

    template <class T>
    class match {
        optional<T> data;
        void value( T y ) {
            if( data )
               *data = y;
               data = y;

Basically value() says: if it isn't initialized yet, initialize it,
otherwise just update its value. I am pretty sure this will now work
with all of your test cases.

This feels a little kludgy to me, but I think it is reflective of how
the parsers are currently using the interface. Apparently non-reference
parameters don't have to be originally initialized, but reference
parameters do. We need the "special case" (the if-then-else) to deal
with the possibility of non-reference types starting out in the
"invalid" state.

An alternative solution, which may or may not be useful, would be to,
somewhere in this logic:

> d) eps' semantic action stores 123 into r's closure member val.
> e) r is about to return with an invalid attribute
> f) the closure 'decorator's post-parse function is called.
> g) closure member val (with a value of 123) is places in the match<int>
> h) r returns the match<int> with a value of 123

wherever value() is being called, change it to a call to a different
method named "initialize". Then value() could do

   *data = y;

whereas initialize() could do

   data = y;

The idea is that closures (or, at least, "something" on the parser
interface end of things--see below) would re-initialize the data,
rather than updating its value.

It's unclear to me in this code

    r = epsilon_p[ r.val = 123 ];

how r decided to return a match<int>; I presume it deduced it from
"123", and it always deduces non-reference types when assigning to the
"val" member? It seems to me that you could also have a way to bind
references here; I dunno what the syntax should be, but you ought to be
able to make it so that, for instance,

    r = epsilon_p[ r.refval = x ]; // x is some global variable

will generate a call to initialize() and "reset the reference" inside
the match, whereas

    r = epsilon_p[ r.val = x ];

will generate a call to value() and just update the value inside the
match. That is, assigning to "val" captures a value, whereas assigning
to "refval" captures a reference.

I don't know if that made much sense, and even if it did, I don't know
if this capability would actually be useful in practice. But I just
wanted to share the idea that, since "under the hood" there are two
kinds of meanings for "assignment of reference types" (reset the
reference, or update the value), you could export both of these out to
users. My guess is that, in practice, this is probably not very useful.
In that case, I think I would just stick with the original solution I
suggested above (where value() is implemented with an if-then-else

-Brian McNamara (lorgon_at_[hidden])

Boost list run by bdawes at, gregod at, cpdaniel at, john at