Boost logo

Proto :

Subject: Re: [proto] Manipulating an expression tree
From: Bart Janssens (bart.janssens_at_[hidden])
Date: 2011-04-10 04:32:26


On Sun, Apr 10, 2011 at 10:59 AM, Karsten Ahnert
<karsten.ahnert_at_[hidden]> wrote:
> Ok, I think I understand how you replace the nodes, but I don't
> understand how you parse the tree and how you access the value member.
> Do you use contexts and eval()? Could you please show a small piece of
> code? Thanks,

No, I'm not using contexts, I access the value member from a primitive
transform. My transform to evaluate multiplications looks like this:

/// Primitive transform for evaluating multiplication and store the
result back in the multiplies node
template<typename GrammarT>
struct EigenProductEval :
  boost::proto::transform< EigenProductEval<GrammarT> >
{
  template<typename ExprT, typename StateT, typename DataT>
  struct impl : boost::proto::transform_impl<ExprT, StateT, DataT>
  {
    // Skipped series of typedefs here, result_type can be defined as
double for the example below
    result_type operator ()(typename impl::expr_param expr, typename
impl::state_param state, typename impl::data_param data) const
    {
      expr.value = GrammarT()(boost::proto::left(expr), state, data) *
GrammarT()(boost::proto::right(expr), state, data);
      return expr.value;
    }
  };
};

// This grammar matches the multiplications and evaluates them using
the above primitive transform:
template<typename GrammarT>
struct EigenMultiplication :
  boost::proto::when
  <
    boost::proto::multiplies<GrammarT, GrammarT>,
    EigenProductEval<GrammarT>
>
{
};

//To add a concrete example on how to use this to multiply two
doubles, storing the value in the mult expression (untested):
struct MultDoubles :
boost::proto::or_
<
  boost::proto::when // Double terminals are replaced by their value
  <
    boost::proto::terminal<double>,
    boost::proto::_value
>,
  EigenMultiplication<MultDoubles> // Evaluates multiplication
>
{
};

// Now evaluate an expression
MultDoubles()(WrapExpression()(boost::proto::lit(2.) * boost::proto::lit(2.)));

The template parameter GrammarT allows me to embed these into a larger
grammar, enforcing that the left and right term of the product match
this grammar (MultDoubles in the example).

I don't see an easy way to do this with contexts, I've started out
with contexts as well, but I found that my code got very complex and
unreadable in the end. The grammars are much more powerful, and in the
end result in much cleaner code. The trick is to read them like they
use their own special language, not try and interpret them as C++.
When making the switch, I moved the data that I used to store in the
contexts to the data argument of the transforms (the 3rd argument of
operator()).

Cheers,

-- 
Bart

Proto list run by eric at boostpro.com