Hi Andrew,
just my thoughts on this chat.
Andrew Durward schrieb:
The central concept is that for any expression (a # b) where # is {+, -, *},
the result can be expressed as (x + y) where x is the floating-point
How about transform the expression a+b to sum_approx(a,b)+sum_diff(a,b)
instead to fusion::cons > ?
The advantage of this approach is that you still get an ast where childs
are held in terminal (instead in cons).
approximation of (a # b), and y is an error term whose value can also be
computed as a floating-point value.
In toying with proto, I've been able to transform simple expressions
successfully but I can't seem to figure out how to define a grammar that
will handle arbitrary combinations of {+, -, *} recursively. Here's what
I've got so far:
struct sum_approx{/* */};
struct sum_error{/* */};
struct diff_approx{/* */};
struct diff_error{/* */};
struct prod_approx{/* */};
struct prod_error{/* */};
struct Transform :
proto::or_<
proto::when<
proto::plus< proto::terminal< _ >, proto::terminal< _ > >
, fusion::cons<
proto::_make_function(
sum_approx()
, proto::_left
, proto::_right
)
I dont see the meaning behind this step. If you use
proto::_make_function you create a child in the ast, but you put this
child in a fusion::cons.
, fusion::cons<
proto::_make_function(
sum_error()
, proto::_left
, proto::_right
)
>
>()
>
// ... similar substitutions for minus and multiplies
>
{};
So the expression (a + b) yields the sequence:
sum_approx(a,b)
sum_error(a,b)
Here's where I'm stuck. In the case of the expression (a + b)*(c - d), the
addition and subtraction should be replaced by the appropriate sequences
before the multiplication gets expanded to yield the final sequence:
prod_approx( sum_approx(a,b), diff_approx(c,d) )
prod_error( sum_approx(a,b), diff_approx(c,d) )
prod_approx( sum_approx(a,b), diff_error(c,d) )
prod_error( sum_approx(a,b), diff_error(c,d) )
prod_approx( sum_error(a,b), diff_approx(c,d) )
prod_error( sum_error(a,b), diff_approx(c,d) )
prod_approx( sum_error(a,b), diff_error(c,d) )
prod_error( sum_error(a,b), diff_error(c,d) )
Are you sure that you want to get a sequence of expression instead an
ast. In case you really want to get a sequence you can use
proto::tag::comma to separate your child.
Obviously I need a recursive transform here but I'm not sure how to pass it
the sequences generated by both the left and right subtrees.
Cheers,
Kim
Here is a toy project.
Hth.
# include
# include
# include
# include
# include
# define PRECISION_MAKE_tag(name) \
struct name \
{ \
friend std::ostream& operator<< (std::ostream& s, name const&) \
{ \
return s<< #name; \
} \
};
# define PRECISION_MAKE_terminal(name) \
proto::terminal< tag::name >::type const name = {{}}
namespace proto = boost::proto;
namespace tag{
PRECISION_MAKE_tag(a);
PRECISION_MAKE_tag(b);
PRECISION_MAKE_tag(c);
PRECISION_MAKE_tag(d);
PRECISION_MAKE_tag(sum_approx);
PRECISION_MAKE_tag(sum_error);
PRECISION_MAKE_tag(diff_approx);
PRECISION_MAKE_tag(diff_error);
}
namespace mpl = boost::mpl;
namespace fusion = boost::fusion;
using proto::_;
struct transform
{
BOOST_PROTO_CALLABLE()
template<typename Sig>
struct result;
template
struct result
: proto::result_of::make_expr<
proto::tag::plus
, typename proto::result_of::make_expr<
proto::tag::function ,tag::sum_approx, A0, A1
>::type
, typename proto::result_of::make_expr<
proto::tag::function ,tag::sum_error, A0, A1
>::type
>
{};
template
struct result
: proto::result_of::make_expr<
proto::tag::minus, A0, A1
>
{};
template
typename result::type
operator()(proto::tag::plus const ,A0 const& a0,A1 const& a1) const
{
return proto::make_exprproto::tag::plus(
proto::make_exprproto::tag::function(
tag::sum_approx()
, boost::ref(a0)
, boost::ref(a1))
,proto::make_exprproto::tag::function(
tag::sum_error()
, boost::ref(a0)
, boost::ref(a1))
);
//return proto::make_exprproto::tag::plus(boost::ref(a0), boost::ref(a1));
};
template
typename result::type
operator()(proto::tag::minus const ,A0 const& a0, A1 const& a1) const
{
return proto::make_exprproto::tag::minus(boost::ref(a0), boost::ref(a1));
};
};
struct Transform
: proto::or_<
proto::when<
proto::plus< proto::terminal< _ >, proto::terminal< _ > >
, transform(
proto::tag::plus()
, proto::_value(proto::_left)
, proto::_value(proto::_right)
)
>
,proto::when<
proto::minus< proto::terminal< _ >, proto::terminal< _ > >
, transform(
proto::tag::minus()
, proto::_value(proto::_left)
, proto::_value(proto::_right)
)
>
, proto::otherwise >
>
{};
PRECISION_MAKE_terminal(a);
PRECISION_MAKE_terminal(b);
PRECISION_MAKE_terminal(c);
PRECISION_MAKE_terminal(d);
# undef PRECISION_MAKE_tag
# undef PRECISION_MAKE_terminal
int main()
{
proto::display_expr(a+b);
BOOST_AUTO(expr, Transform()( (a+b)*(c-d) ) );
proto::display_expr(expr);
return boost::exit_success;
}