Boost logo

Proto :

Subject: Re: [proto] Using Phoenix inside eUML: mixing grammars
From: Thomas Heller (thom.heller_at_[hidden])
Date: 2011-03-22 02:41:19


On Wed, Mar 16, 2011 at 9:56 PM, Christophe Henry
<christophe.j.henry_at_[hidden]> wrote:
> Hi,

Sorry for the late reply ...

> I have my eUML grammar, defing, for example a transition as:
>
> SourceState+ Event [some_guard] == TargetState
>
> I want to write for some_guard an expression of a phoenix grammar. The
> relevant part of the expression is:
> Event [some_guard]
>
> Where the corresponding part of my grammar is:
>
> struct BuildEventPlusGuard
>    : proto::when<
>            proto::subscript<proto::terminal<event_tag>,BuildGuards >,
>            TempRow<none,proto::_left,none,none,BuildGuards(proto::_right)>()
>        >
> {};
>
> BuildGuards is, at the moment, a proto::switch_ grammar, which I want
> to replace with something matching a phoenix grammar and returning me
> a phoenix::actor<Expr>, which I will then save into TempRow.
> I suppose I could typeof/decltype the phoenix expression but it
> doesn't seem like the best solution, I'd prefer to delay this.
> Is there something like a phoenix grammar which I can call to check if
> the expression is valid, and if yes, which will return me the correct
> phoenix::actor?

There is boos::phoenix::meta_grammar which can be used to check for
valid phoenix expressions. It is really just the grammar, you can't
use it as a transform.
In your case you can reuse the meta grammar in a great way to restrict
certain constructs:

struct my_custom_phoenix_grammar
    : proto::switch_<my_custom_phoenix_grammar>
{
    template <typename Tag>
    struct case_ : meta_grammar::case_<Tag> {};
};

The above, by default allows everything that's in meta_grammar with
the ability to override some of meta_grammar's rules.

If you want to use it as a transform you need the evaluator with an
appropriate action that does the desired transform... here is an
example:

 struct BuildEventPlusGuard
 Â   : proto::when<
 Â           proto::subscript<proto::terminal<event_tag>,
phoenix::meta_grammar >,
 Â           TempRow<none,proto::_left,none,none,
phoenix::evaluator(proto::_right, some_cool_action())>()
 Â       >
 {};

Now, some_cool_action can do the transform that BuildGuards was doing.

> Second question. Now it's becoming more "interesting". And not easy to
> explain :(
>
> For eUML, a guard can be defined as "g1 && g2", where g1 and g2 are
> functors, taking 4 arguments. For example (to make short):
> struct g1_
> {
>    template <class FSM,class EVT,class SourceState,class TargetState>
>    void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
>    {
>        ...
>    }
> };
>  g1_ g1;
>
> The fact that there are 4 arguments is the condition to make this work
> without placeholders.
>
> I 'm pretty sure that, while this clearly should be a function for
> phoenix, I would not like the syntax:
> g1(arg1,arg2,arg3,arg4) && g2(arg1,arg2,arg3,arg4).
>
> Is it possible to define g1 and g2 as custom terminals, but still get
> them treated like functions?

Yes!

Here is an example:

template <typename G>
struct msm_guard
{};

template <typename Expr>
struct msm_guard_actor;

template <typename G>
struct msm_guard_expression
    : phoenix::terminal<msm_guard<G>, msm_guard_actor>
{};

template <typename Expr>
struct msm_guard_actor
{
        typedef actor<Expr> base_type;
        base_type expr;
        msm_guard_actor(base_type const & base) : expr(base) {}

        // define the operator() overloads here to allow something
        // that michael suggested. The result should be full blown phoenix
        // expressions (BOOST_PHOENIX_DEFINE_EXPRESSION)
};

namespace boost { namespace phoenix {
    namespace result_of
    {
        template <template G>
        is_nullary<custom_terminal<msm_guard<G> > : mpl::false_ {};
    }
    template <typename G>
    struct is_custom_terminal<msm_guard<G> > : mpl::true_ {};

    template <typename G>
    struct custom_terminal<msm_guard<G> >
        : proto::call<
            G(
                proto::functional::at(_env, mpl::int_<1>())
              , proto::functional::at(_env, mpl::int_<2>())
              , proto::functional::at(_env, mpl::int_<3>())
              , proto::functional::at(_env, mpl::int_<4>())
           )
>
    {};
}}

I hope that above example helps you and clarifies how to customize
phoenix V3 even further.
Note on that terminal thing: It's not in trunk yet ... I did on
another computer, cause the spirit port needed it ... I don't have
access to that computer right now ... I will commit it later today.

> (To solve the problem, my current implementation generates me a
> functor of type And_<g1,g2> which has an operator () with 4
> arguments).
>
> Thanks,
> Christophe
> _______________________________________________
> proto mailing list
> proto_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/proto
>


Proto list run by eric at boostpro.com