Boost logo

Boost :

From: Eric Niebler (eric_at_[hidden])
Date: 2007-07-01 18:24:41


David A. Greene wrote:
> On Sunday 01 July 2007 10:13, Eric Niebler wrote:
>
>> Oh wait, that's not quite what you want, because then if_[e1].else_[e2]
>> will chop off the if_ part of the tree. What you need instead is a
>> member like (untested):
>>
>> template<typename Expr ...>
>> struct phoenix_expr
>>
>> : proto::extends<Expr ...>
>>
>> {
>> phoenix_expr(...)
>>
>> : else_(proto::make_expr<phoenix::tag::else_>(*this))
>>
>> {}
>>
>> // ...
>>
>> proto::result_of::make_expr<
>> pheonix::tag::else_ // else is now an "operator"
>> , phoenix_expr const
>>
>> >::type const else_;
>>
>> };
>>
>> Then, if_/else_ statements would conform to the following grammar:
>>
>> subscript<
>> unary_expr<
>> phoenix::tag::else_
>> ,subscript<terminal<phoenix::tag::if_>,_>
>>
>> ,_
>
> Ok, that makes sense to me, modulo the current lack of make_expr
> documentation. :)

Patience! :)

>
> I'm looking to do something similar to what Dan is doing so I'm glad he
> asked the question. I was just about to.
>
> One thing that's not clear to me is how he would handle the
> if_(expr)[...] syntax. In your first message you have:
>
> // Here is the grammar for if_ expressions
> struct IfGrammar
> : proto::subscript<
> proto::terminal<phoenix::tag::if_>
> proto::_
> >
> {};
>
> I don't understand the derivation from proto::subscript. What about the
> call operator?

D'oh! I forgot that part.

   // matches if_(e1)[e2]
   struct IfGrammar
     : subscript<
           function<
               terminal<phoenix::tag::if_>
             , _
>
         , _
>
   {};

This assumes that if_ is defined like:
   terminal<phoenix::tag::if_>::type const if_ = {{}};

But now that I think about it some more, Dan probably wants if_ to be an
actual function instead of a Proto terminal, because phoenix expressions
have an operator() that does something special. You can use the
BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE macro for this.

   BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE(
       1
     , if_
     , phoenix::phoenix_domain
     , (phoenix::tag::if_)
     , BOOST_PP_SEQ_NIL
   )

This creates a function template called if_() that takes one argument
and returns a unary proto tree with an op tag of phoenix::tag::if_ in
the phoenix_domain. If Dan goes this route, the IfGrammar changes to:

   // matches if_(e1)[e2]
   struct IfGrammar
     : subscript<
           unary_expr<
               phoenix::tag::if_
             , _
>
         , _
>
   {};

Derivation is just the way to give a name to a proto grammar rule. A
typedef would work just as well in this case, but using a struct is
preferred, because in body of the grammar rule, the name of the struct
can be used to recurse.

<snip>

> I'm going to be doing something different. Rather than evaluate the
> expression, I'm going to want to run a transformation on it. Given the
> example from your second message:
>
> template<typename Expr ...>
> struct phoenix_expr
> : proto::extends<Expr ...>
> {
> phoenix_expr(...)
> : else_(proto::make_expr<phoenix::tag::else_>(*this))
> {}
>
> // ...
>
> proto::result_of::make_expr<
> pheonix::tag::else_ // else is now an "operator"
> , phoenix_expr const
> >::type const else_;
> };
>
> how do I match the new "else_ operator" and transform it?

Well, if you use the BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE macro like I
show above, the IfElseGrammar might look like this:

   // matches if_(e1)[e2].else_[e3]
   struct IfElseGrammar
     : subscript<
           unary_expr<
               phoenix::tag::else_
             , subscript<
                   unary_expr<
                       phoenix::tag::if_
                     , PhoenixBooleanGrammar
>
                 , PhoenixGrammar
>
>
         , PhoenixGrammar
>
   {};

Where PhoenixBooleanGrammar is some other grammar that defines what it
means to be a boolean expression, and PhoenixGrammar is the whole
shebang -- any valid phoenix expression. (The recursion here is implied.
PhoenixGrammar is undoubtedly implemented in terms of IfElseGrammar.)

As for how to transform it, that depends on what you're trying to do,
but it would involve decorating the above grammar with transforms that
Proto provides, or writing your own. Probably a little of both. And
PhoenixBooleanGrammar and PhoenixGrammar would have their own transforms.

HTH,

-- 
Eric Niebler
Boost Consulting
www.boost-consulting.com

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