Boost logo

Boost :

Subject: Re: [boost] [Spirit/Qi] Sequential-or attribute access in semantic action
From: Adam Butcher (dev.lists_at_[hidden])
Date: 2009-12-04 11:21:37


Hi Hartmut,

Thanks for responding so quickly.

On Fri, December 4, 2009 2:37 pm, Hartmut Kaiser wrote:
>Adam Butcher wrote:
>> My real problem is that applying a semantic action to [what I think
>> is] an expression returning a sequential-or parser, results in the
>> _1 referring to the attribute of the last parser on the
>> right-hand-side of the sequential-or rather than the attribute of
>> the sequential-or parser itself. In the following snippet (assume
>> 'start' has an attribute of type S),
>>
>> idxspec = '[' >> (start || (':' >> -start))
>> [
>> _val = access_index (_r1,lvalue,_1)
>> ]
>> >> ']';
>>
>> the function 'access_index' is called with an arg3 of type
>> 'optional<S>' rather than the expected 'tuple<optional<S>,
>> optional<optional<S>>>'.
>
> Well, a sequential-or is (attribute-wise) very much the same as a
> plain sequence: a >> b. That means if you attach an action to the
> whole thing _1 will refer to the attribute of the first and _2 to
> the attribute of the second element in that sequence. I'll add a
> note to the documentation making this clear.
>
Ah I see. So in the above snippet _1 will refer to an attribute of
type optional<S> and _2 to an attribute of type optional<optional<S>>.
Thanks for clearing my misunderstanding up.

I use multi-argument sequences elsewhere so I should have really
thought to try that (hindsight is such a wonderful thing!) In my
experiments I had switched the '-start' for 'int_' and was convinced
that my _1 had become 'int' by the time it reached the function --
this is what confused me into thinking that it was the right-hand-side
that was being delivered as _1. I assume now that this must have been
to do with my change causing some earlier error and the compiler had
substituted 'int' for some unresolved type which had arrived in my
function. 'int_' was probably a bad choice for the test!

>> My final rule is now
>>
>> idxspec = '[' >> identity[start || (':' >> -start)]
>> [
>> _val = access_index (_r1,lvalue,_1)
>> ]
>> >> ']';
>>
>> which is working fine; the _1 delivers an argument of type
>>
>> tuple<optional<S>, optional<optional<S>>>
>>
>> as required. However, I would have expected this behaviour from
>> the first expression. Is this a a proto issue, a spirit issue or
>> have I completely misunderstood something somewhere?
>
> That's expected as well, as your identity[] directive exposes the
> _whole_ attribute of the embedded parser as its own attribute.
>
I understood that my identity[] directive had effectively wrapped the
contained parser into a single 'atom' which yielded a single
'flattened' attribute. I had assumed that the basic behaviour without
the identity[] directive would have yielded the same. I had not
twigged that the sequential-or was behaving as a sequence and was
confused by my earlier erroneous experiment.

So, avoiding the identity[] directive the following

       idxspec = '[' >> (start || (':' >> -start))
                  [
                     _val = access_index (_r1,lvalue,_1,_2)
                  ]
>> ']';

does as I originally intended. Thanks very much for your help.

This lead me on to the following, rather pedantic, musing on the
provision of the identity[] directive in the core library to 'flatten'
composed attributes. In re-implementing my action function with two
arguments I had difficultly naming the first argument as it has
logically distinct semantics based on whether the second (range
specifier) is provided. Previously (with identity[]) it was one
argument named 'access_spec' and gave rise to the following
implementation:

   optional<optional<S>> const& range_spec = at_c<1>(access_spec);

   if (range_spec)
   {
      optional<S> const& range_min = at_c<0>(access_spec);
      optional<S> const& range_max = *range_spec;

      // ...
   }
   else
   {
      S const& index = *at_c<0>(access_spec);

      // ...
   }

In the above the first element of 'access_spec' is effectively
unnamed until it is resolved to be either 'range_min' or 'index'.
Using two arguments I was forced to name the first even though its
semantics are conditional on the second. Going for arguments named
'range_min' and 'range_spec' gave rise to the following:

   if (range_spec)
   {
      optional<S> const& range_max = *range_spec;

      // ...
   }
   else
   {
      exp_attr const& index = *range_min;

      // ...
   }

which leans toward the range alternative -- effectively changing the
meaning of 'range_min' in the else case. I wondered if providing
identity[] for situations like these may result in more logical user
code. Perhaps I just think too much -- or perhaps I should just have
two functions to start with (though that would probably affect the
elegance of the grammar spec)!

Thanks again.
Regards,
Adam


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk