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::plusproto::_ >
,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
struct result
: proto::result_of::as_expr
{};
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::type,
BOOST_TYPEOF(result)>) );
Is this enough and is this necessary?
Here is the full program:
#include <iostream>
#include
#include
#include
#include
#include
#include
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
#define _right(x) call
#define _make_minus(x,y) call
#define _make_plus(x,y) call
#define _make_assign(x,y) call
#define _make_divides(x,y) call
#define _make_multiplies(x,y)
call
#define _make_terminal(x) call
#endif
struct ReturnAsTerminal : proto::callable
{
template<class Sig>
struct result;
template
struct result
: proto::result_of::as_expr
{};
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::plusproto::_ >
,proto::_make_assign(
proto::_left
,proto::_make_divides(proto::_make_minus(Zero
,proto::_right),One )
)
>
,proto::when<
//var_-a
proto::minusproto::_ >
,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::terminalproto::_ >
,proto::_make_assign(
proto::_right
,proto::_make_divides(Zero,proto::_right )
)
>
,proto::when<
//var_/a
proto::divides< proto::terminal<placeholder>,
proto::terminalproto::_ >
,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_MPL_ASSERT( (boost::is_same<
boost::result_of::type,
BOOST_TYPEOF(result)>) );
std::cout<<" \n ----------------------------------------------------
\n";
return 0;
}
Thanks for any and all help and comments.
Cheers,
Kim