#include #include #include #include #include namespace proto = boost::proto; namespace fusion = boost::fusion; namespace mpl = boost::mpl; using proto::_; # 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< name >::type const name = {{}} 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); PRECISION_MAKE_tag(prod_approx); PRECISION_MAKE_tag(prod_error); struct Grammar : proto::or_< proto::plus< Grammar, Grammar >, proto::minus< Grammar, Grammar >, proto::multiplies< Grammar, Grammar >, proto::terminal< _ > > {}; namespace cons_utility { template< typename _Left_sequence, typename _Right_sequence > struct Join { typedef typename _Left_sequence::car_type First_left_term_; typedef typename _Left_sequence::cdr_type Rest_of_left_sequence_; typedef typename Join< Rest_of_left_sequence_, _Right_sequence >::type Rest_of_joined_sequence_; typedef fusion::cons< First_left_term_, Rest_of_joined_sequence_ > type; }; template< typename _Right_sequence > struct Join< fusion::nil, _Right_sequence > { typedef _Right_sequence type; }; template< typename _Left_sequence > struct Join< _Left_sequence, fusion::nil > { typedef _Left_sequence type; }; }; namespace distributive { template< typename _Scalar, typename _Sequence > struct Scale { typedef typename _Sequence::car_type First_term_; typedef typename _Sequence::cdr_type Rest_of_sequence_; typedef typename boost::result_of< proto::_make_function( prod_approx, _Scalar, First_term_ ) >::type Product_expr_; typedef typename boost::result_of< proto::_make_function( prod_error, _Scalar, First_term_ ) >::type Error_expr_; typedef typename Scale< _Scalar, Rest_of_sequence_ >::type Remaining_scale_; typedef fusion::cons< Product_expr_, fusion::cons< Error_expr_, Remaining_scale_ > > type; }; template< typename _Sequence > struct Scale< fusion::nil, _Sequence > { typedef fusion::nil type; }; template< typename _Scalar > struct Scale< _Scalar, fusion::nil > { typedef fusion::nil type; }; template< typename _Left_sequence, typename _Right_sequence > struct Expand { typedef typename _Left_sequence::car_type First_left_term_; typedef typename _Left_sequence::cdr_type Rest_of_left_sequence_; typedef typename Scale< First_left_term_, _Right_sequence >::type First_term_expansion_; typedef typename Expand< Rest_of_left_sequence_, _Right_sequence >::type Remaining_expansion_; typedef typename cons_utility::Join< First_term_expansion_, Remaining_expansion_ >::type type; }; template< typename _Left_sequence > struct Expand< _Left_sequence, fusion::nil > { typedef fusion::nil type; }; template< typename _Right_sequence > struct Expand< fusion::nil, _Right_sequence > { typedef fusion::nil type; }; } struct Multiply { BOOST_PROTO_CALLABLE(); template< typename _Sig > struct result; template< typename _Left, typename _Right > struct result< Multiply( _Left, _Right ) > : distributive::Expand< _Left, _Right > {}; }; #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) #define sum_approx() proto::make #define sum_error() proto::make #define diff_approx() proto::make #define diff_error() proto::make #define prod_approx() proto::make #define prod_error() proto::make #endif struct Transform : proto::or_< proto::when< proto::plus< proto::terminal< _ >, proto::terminal< _ > > , fusion::cons< proto::_make_function( sum_approx() , proto::_left , proto::_right ) , fusion::cons< proto::_make_function( sum_error() , proto::_left , proto::_right ) > >() > , proto::when< proto::minus< proto::terminal< _ >, proto::terminal< _ > > , fusion::cons< proto::_make_function( diff_approx() , proto::_left , proto::_right ) , fusion::cons< proto::_make_function( diff_error() , proto::_left , proto::_right ) > >() > , proto::when< proto::multiplies< proto::terminal< _ >, proto::terminal< _ > > , fusion::cons< proto::_make_function( prod_approx() , proto::_left , proto::_right ) , fusion::cons< proto::_make_function( prod_error() , proto::_left , proto::_right ) > >() > , proto::when< proto::multiplies< Grammar, Grammar > , Multiply( Transform( proto::_left ) , Transform( proto::_right ) ) > /* TODO * / , proto::when< proto::plus< Grammar, Grammar > , ... > , proto::when< proto::minus< Grammar, Grammar > , ... > /**/ > {}; template< typename _Expr > void display_raw_expr( _Expr const & _expr ) { BOOST_MPL_ASSERT(( proto::matches< _Expr, Grammar > )); proto::display_expr( _expr ); } template< typename _Expr > void display_transform_expr( _Expr const & _expr ) { BOOST_MPL_ASSERT(( proto::matches< _Expr, Transform > )); typedef boost::result_of< Transform( _Expr ) >::type Trans_expr; fusion::for_each( Trans_expr(), proto::functional::display_expr() ); } 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() { BOOST_PROTO_AUTO( expr, (a + b)*(c - d) ); display_raw_expr( expr ); std::cout << "--------------------\n"; display_transform_expr( expr ); return boost::exit_success; }