Update of /cvsroot/boost/boost/libs/xpressive/proto/example
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv4329

Modified Files:
        Jamfile.v2 
Added Files:
        calc1.cpp calc2.cpp calc3.cpp 
Log Message:
some calculator examples

--- NEW FILE: calc1.cpp ---
//  Copyright 2007 Eric Niebler. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This is a simple example of how to build an arithmetic expression
// evaluator with placeholders.

#include <iostream>
#include <boost/mpl/int.hpp>
#include <boost/xpressive/proto/proto.hpp>
#include <boost/xpressive/proto/context.hpp>
using namespace boost;

template<typename I> struct arg {};

// Define some placeholders
proto::terminal< arg< mpl::int_<1> > >::type const _1 = {{}};
proto::terminal< arg< mpl::int_<2> > >::type const _2 = {{}};

// Define a calculator context, for evaluating arithmetic expressions
struct calculator_context
  : proto::callable_context< calculator_context const >
{
    // The values bound to the placeholders
    double d[2];

    // The result of evaluating arithmetic expressions
    typedef double result_type;

    explicit calculator_context(double d1 = 0., double d2 = 0.)
    {
        d[0] = d1;
        d[1] = d2;
    }

    // Handle the evaluation of the placeholder terminals
    template<typename I>
    double operator()(proto::tag::terminal, arg<I>) const
    {
        return d[ I() - 1 ];
    }
};

template<typename Expr>
double evaluate( Expr const &expr, double d1 = 0., double d2 = 0. )
{
    // Create a calculator context with d1 and d2 substituted for _1 and _2
    calculator_context const ctx(d1, d2);

    // Evaluate the calculator expression with the calculator_context
    return proto::eval(expr, ctx);
}

int main()
{
    // Displays "5"
    std::cout << evaluate( _1 + 2.0, 3.0 ) << std::endl;

    // Displays "6"
    std::cout << evaluate( _1 * _2, 3.0, 2.0 ) << std::endl;

    // Displays "1.5"
    std::cout << evaluate( (_1 - _2) / _2, 3.0, 2.0 ) << std::endl;

    return 0;
}

--- NEW FILE: calc2.cpp ---
//  Copyright 2007 Eric Niebler. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This example enhances the simple arithmetic expression evaluator
// in calc1.cpp by using proto::extends to make arithemetic
// expressions immediately evaluatable with operator(), a-la a 
// function object

#include <iostream>
#include <boost/mpl/int.hpp>
#include <boost/xpressive/proto/proto.hpp>
#include <boost/xpressive/proto/context.hpp>
using namespace boost;

// Will be used to define the placeholders _1 and _2
template<typename I> struct arg {};

// For expressions in the calculator domain, operator()
// will be special; it will evaluate the expression.
struct calculator_domain
  : proto::domain<>
{};

// Define a calculator context, for evaluating arithmetic expressions
// (This is as before, in calc1.cpp)
struct calculator_context
  : proto::callable_context< calculator_context const >
{
    // The values bound to the placeholders
    double d[2];

    // The result of evaluating arithmetic expressions
    typedef double result_type;

    explicit calculator_context(double d1 = 0., double d2 = 0.)
    {
        d[0] = d1;
        d[1] = d2;
    }

    // Handle the evaluation of the placeholder terminals
    template<typename I>
    double operator()(proto::tag::terminal, arg<I>) const
    {
        return d[ I() - 1 ];
    }
};

// Wrap all calculator expressions in this type, which defines
// operator() to evaluate the expression.
template<typename Expr>
struct calculator_expression
  : proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
{
    typedef
        proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
    base_type;
    
    explicit calculator_expression(Expr const &expr = Expr())
      : base_type(expr)
    {}

    using base_type::operator=;

    // Override operator() to evaluate the expression
    double operator()() const
    {
        calculator_context const ctx;
        return proto::eval(*this, ctx);
    }

    double operator()(double d1) const
    {
        calculator_context const ctx(d1);
        return proto::eval(*this, ctx);
    }

    double operator()(double d1, double d2) const
    {
        calculator_context const ctx(d1, d2);
        return proto::eval(*this, ctx);
    }
};

// Tell proto how to generate expressions in the calculator_domain
namespace boost { namespace proto
{
    template<typename Expr>
    struct generate<calculator_domain, Expr>
    {
        typedef calculator_expression<Expr> type;
        static type make(Expr const &expr)
        {
            return type(expr);
        }
    };
}}

// Define some placeholders (notice they're wrapped in calculator_expression<>)
calculator_expression<proto::terminal< arg< mpl::int_<1> > >::type> const _1;
calculator_expression<proto::terminal< arg< mpl::int_<2> > >::type> const _2;

// Now, our arithmetic expressions are immediately executable function objects:
int main()
{
    // Displays "5"
    std::cout << (_1 + 2.0)( 3.0 ) << std::endl;

    // Displays "6"
    std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl;

    // Displays "1.5"
    std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl;

    return 0;
}

--- NEW FILE: calc3.cpp ---
//  Copyright 2007 Eric Niebler. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This example enhances the arithmetic expression evaluator
// in calc2.cpp by using a proto transform to calculate the
// number of arguments an expression requires and using a 
// compile-time assert to guarantee that the right number of
// arguments are actually specified.

#include <iostream>
#include <boost/mpl/int.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/min_max.hpp>
#include <boost/xpressive/proto/proto.hpp>
#include <boost/xpressive/proto/context.hpp>
#include <boost/xpressive/proto/transform/arg.hpp>
#include <boost/xpressive/proto/transform/fold.hpp>
using namespace boost;

// Will be used to define the placeholders _1 and _2
template<typename I> struct arg { typedef I arity; };

// Some custom transforms for calculating the max arity of a calculator 
expression
template<typename Grammar>
struct max_arity
  : Grammar
{
    template<typename Expr, typename State, typename Visitor>
    struct apply
    {
        // Calculate the arity of the current expression.
        typedef typename Grammar::template apply<Expr, State, Visitor>::type 
arity;
        // The old maximum is passed along in the State parameter by
        // proto::trans::fold<> (see below). The new maximum is the
        // larger of the old maximum and the arity we just calculated.
        typedef typename mpl::max<arity, State>::type type;
    };

    //// If this transform had a runtime counterpart, it would look like this:
    //template<typename Expr, typename State, typename Visitor>
    //static typename apply<Expr, State, Visitor>::type 
    //call(Expr const &expr, State const &state, Visitor &visitor)
    //{
    //    ... do stuff ...
    //}
};

// Fetch the arity of a placeholder terminal
template<typename Grammar>
struct placeholder_arity
  : Grammar
{
    template<typename Expr, typename, typename>
    struct apply
    {
        typedef typename proto::result_of::arg<Expr>::type::arity type;
    };

    // As with max_arity<> above, placeholder_arity<> has no need
    // for a call() member function.
};

using proto::_;

// This grammar basically says that a calculator expression is one of:
//   - A placeholder terminal
//   - Some other terminal
//   - Some non-terminal whose children are calculator expressions
// In addition, it has transforms that say how to calculate the the
// expression arity for each of the three cases.
struct CalculatorGrammar
  : proto::or_<
        // placeholders have a non-zero arity ...
        placeholder_arity< proto::terminal< arg<_> > >
        // Any other terminals have arity 0 ...
      , proto::trans::always< proto::terminal<_>, mpl::int_<0> >
        // For any non-terminals, find the arity of the children and
        // take the maximum. This is recursive.
      , proto::trans::fold<
            // This matches any non-terminal for which the children
            // are themselves calculator expressions.
            proto::nary_expr<_, proto::vararg< max_arity< CalculatorGrammar > > 
>
        >
    >
{};

// Simple wrapper for calculating a calculator expression's arity.
// It specifies mpl::int_<0> as the initial state. The visitor, which
// is not used, is mpl::void_.
template<typename Expr>
struct calculator_arity
  : CalculatorGrammar::apply<Expr, mpl::int_<0>, mpl::void_>
{};

// For expressions in the calculator domain, operator()
// will be special; it will evaluate the expression.
struct calculator_domain
  : proto::domain<>
{};

// Define a calculator context, for evaluating arithmetic expressions
// (This is as before, in calc1.cpp and calc2.cpp)
struct calculator_context
  : proto::callable_context< calculator_context const >
{
    // The values bound to the placeholders
    double d[2];

    // The result of evaluating arithmetic expressions
    typedef double result_type;

    explicit calculator_context(double d1 = 0., double d2 = 0.)
    {
        d[0] = d1;
        d[1] = d2;
    }

    // Handle the evaluation of the placeholder terminals
    template<typename I>
    double operator()(proto::tag::terminal, arg<I>) const
    {
        return d[ I() - 1 ];
    }
};

// Wrap all calculator expressions in this type, which defines
// operator() to evaluate the expression.
template<typename Expr>
struct calculator_expression
  : proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
{
    typedef
        proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
    base_type;
    
    explicit calculator_expression(Expr const &expr = Expr())
      : base_type(expr)
    {}

    using base_type::operator=;

    // Override operator() to evaluate the expression
    double operator()() const
    {
        // Assert that the expression has arity 0
        BOOST_MPL_ASSERT_RELATION(0, ==, calculator_arity<Expr>::type::value);
        calculator_context const ctx;
        return proto::eval(*this, ctx);
    }

    double operator()(double d1) const
    {
        // Assert that the expression has arity 1
        BOOST_MPL_ASSERT_RELATION(1, ==, calculator_arity<Expr>::type::value);
        calculator_context const ctx(d1);
        return proto::eval(*this, ctx);
    }

    double operator()(double d1, double d2) const
    {
        // Assert that the expression has arity 2
        BOOST_MPL_ASSERT_RELATION(2, ==, calculator_arity<Expr>::type::value);
        calculator_context const ctx(d1, d2);
        return proto::eval(*this, ctx);
    }
};

// Tell proto how to generate expressions in the calculator_domain
namespace boost { namespace proto
{
    template<typename Expr>
    struct generate<calculator_domain, Expr>
    {
        typedef calculator_expression<Expr> type;
        static type make(Expr const &expr)
        {
            return type(expr);
        }
    };
}}

// Define some placeholders (notice they're wrapped in calculator_expression<>)
calculator_expression<proto::terminal< arg< mpl::int_<1> > >::type> const _1;
calculator_expression<proto::terminal< arg< mpl::int_<2> > >::type> const _2;

// Now, our arithmetic expressions are immediately executable function objects:
int main()
{
    // Displays "5"
    std::cout << (_1 + 2.0)( 3.0 ) << std::endl;

    // Displays "6"
    std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl;

    // Displays "1.5"
    std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl;

    // This won't compile because the arity of the
    // expression doesn't match the number of arguments
    // ( (_1 - _2) / _2 )( 3.0 );

    return 0;
}

Index: Jamfile.v2
===================================================================
RCS file: /cvsroot/boost/boost/libs/xpressive/proto/example/Jamfile.v2,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- Jamfile.v2  4 Apr 2007 07:02:00 -0000       1.1
+++ Jamfile.v2  17 Apr 2007 06:29:32 -0000      1.2
@@ -6,3 +6,19 @@
     :
         hello.cpp
     ;
+
+
+exe calc1
+    :
+        calc1.cpp
+    ;
+
+exe calc2
+    :
+        calc2.cpp
+    ;
+
+exe calc3
+    :
+        calc3.cpp
+    ;


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs

Reply via email to