
Hi Dave and Eric, i have written an grammar to do some transformations on an expression and would like to know your opinions. If the grammar matches the pattern var_+a, then it should transform the tree to var_=(0-a)/1. So the resulting callable transform would be : proto::when< //var_+a proto::plus<proto::terminal<placeholder>, proto::terminal<proto::_> > ,proto::_make_assign( proto::_left ,proto::_make_divides(proto::_make_minus(Zero ,proto::_right),One ) ) How should one implement the two macros Zero and One. My solution is to implement a callable transform like this struct ReturnAsTerminal : proto::callable { template<class Sig> struct result; template<class This, class T> struct result<This(T)> : proto::result_of::as_expr<typename boost::remove_reference<T>::type > {}; template<class T> typename result< ReturnAsTerminal(T const&) >::type operator()(T const& t) const { return proto::as_expr(t); } }; with #define Zero ReturnAsTerminal(mpl::int_<0>() ) #define One ReturnAsTerminal(mpl::int_<1>() ) But is this implementation necessary? Can we use predefined functions in proto to reduce the number of codes? My second question regards the issue of testing the correctness of my transformation. I understand that with proto::matches i am able to test whether a given expression type matches a grammar. But what if i want to test the correctness of my transformation? Is the transformation of the above code really var_=(0-a)/1 and not something else? To test the correctness i use boost::is_same to test the type of the transformation. BOOST_PROTO_AUTO( expr ,var_+a ); BOOST_PROTO_AUTO( result, var_=(ReturnAsTerminal()(mpl::int_<0>())-a)/ReturnAsTerminal()(mpl::int_<1>())); BOOST_MPL_ASSERT( (boost::is_same< boost::result_of<BeginLeft(BOOST_TYPEOF(expr))>::type, BOOST_TYPEOF(result)>) ); Is this enough and is this necessary? Here is the full program: #include <iostream> #include <boost/proto/proto.hpp> #include <boost/proto/proto_typeof.hpp> #include <boost/mpl/int.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/typeof/typeof.hpp> namespace mpl=boost::mpl; namespace proto=boost::proto; namespace fusion=boost::fusion; struct placeholder { friend std::ostream& operator<<(std::ostream& out, placeholder) { return out<<"var_"; } }; proto::terminal<placeholder>::type const var_={{}}; proto::terminal<char>::type const a={'a'}; #if BOOST_WORKAROUND( BOOST_MSVC,BOOST_TESTED_AT(1500) ) #define _left(x) call<proto::_left( proto::call<x> )> #define _right(x) call<proto::_right( proto::call<x> )> #define _make_minus(x,y) call<proto::_make_minus(proto::call<x>, proto::call<y> )> #define _make_plus(x,y) call<proto::_make_plus(proto::call<x>, proto::call<y>)> #define _make_assign(x,y) call<proto::_make_assign(proto::call<x>, proto::call<y>)> #define _make_divides(x,y) call<proto::_make_divides(proto::call<x>, proto::call<y>)> #define _make_multiplies(x,y) call<proto::_make_multiplies(proto::call<x>, proto::call<y>)> #define _make_terminal(x) call<proto::_make_terminal(proto::call<x>)> #endif struct ReturnAsTerminal : proto::callable { template<class Sig> struct result; template<class This, class T> struct result<This(T)> : proto::result_of::as_expr<typename boost::remove_reference<T>::type > {}; template<class T> typename result< ReturnAsTerminal(T const&) >::type operator()(T const& t) const { return proto::as_expr(t); } }; #define Zero ReturnAsTerminal(mpl::int_<0>() ) #define One ReturnAsTerminal(mpl::int_<1>() ) // struct BeginLeft : proto::or_< proto::when< //var_+a proto::plus<proto::terminal<placeholder>, proto::terminal<proto::_> > ,proto::_make_assign( proto::_left ,proto::_make_divides(proto::_make_minus(Zero ,proto::_right),One ) ) > ,proto::when< //var_-a proto::minus<proto::terminal<placeholder>, proto::terminal<proto::_> > ,proto::_make_assign( proto::_left ,proto::_make_divides(proto::_make_plus(Zero,proto::_right),One ) ) > ,proto::when< //var_*a proto::multiplies< proto::terminal<placeholder>, proto::terminal<proto::_> > ,proto::_make_assign( proto::_right ,proto::_make_divides(Zero,proto::_right ) ) > ,proto::when< //var_/a proto::divides< proto::terminal<placeholder>, proto::terminal<proto::_> > ,proto::_make_assign( proto::_left ,proto::_make_divides(Zero,proto::_make_divides(One,proto::_right) ) ) > > {}; int main() { BOOST_PROTO_AUTO( expr ,var_+a ); BOOST_PROTO_AUTO( result, var_=(ReturnAsTerminal()(mpl::int_<0>())-a)/ReturnAsTerminal()(mpl::int_<1>())); BOOST_MPL_ASSERT( (proto::matches<BOOST_TYPEOF(expr) ,BeginLeft>) ); BOOST_MPL_ASSERT( (boost::is_same< boost::result_of<BeginLeft(BOOST_TYPEOF(expr))>::type, BOOST_TYPEOF(result)>) ); std::cout<<" \n ---------------------------------------------------- \n"; return 0; } Thanks for any and all help and comments. Cheers, Kim