123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- <html><head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>eUML</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="ch03.html" title="Chapter 3. Tutorial"><link rel="prev" href="ch03s03.html" title="Functor front-end"><link rel="next" href="ch03s05.html" title="Back-end"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">eUML</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s03.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Tutorial</th><td width="20%" align="right"> <a accesskey="n" href="ch03s05.html">Next</a></td></tr></table><hr></div><div class="sect1" title="eUML"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e1429"></a><span class="command"><strong><a name="eUML-front-end"></a></strong></span>eUML</h2></div></div></div><p><span class="underline">Important note</span>: eUML requires a compiler
- supporting Boost.Typeof. Full eUML has experimental status (but not if only the
- transition table is written using eUML) because some compilers will start
- crashing when a state machine becomes too big (usually when you write huge
- actions).</p><p>The previous front-ends are simple to write but still force an amount of
- noise, mostly MPL types, so it would be nice to write code looking like C++
- (with a C++ action language) directly inside the transition table, like UML
- designers like to do on their state machine diagrams. If it were functional
- programming, it would be even better. This is what eUML is for.</p><p>eUML is a Boost.Proto and Boost.Typeof-based compile-time domain specific
- embedded language. It provides grammars which allow the definition of
- actions/guards directly inside the transition table or entry/exit in the state
- definition. There are grammars for actions, guards, flags, attributes, deferred
- events, initial states.</p><p>It also relies on Boost.Typeof as a wrapper around the new decltype C++0x
- feature to provide a compile-time evaluation of all the grammars. Unfortunately,
- all the underlying Boost libraries are not Typeof-enabled, so for the moment,
- you will need a compiler where Typeof is supported (like VC9-10, g++ >=
- 4.3).</p><p>Examples will be provided in the next paragraphs. You need to include eUML
- basic features: </p><p>
- </p><pre class="programlisting">#include <msm/front/euml/euml.hpp></pre><p>
- </p><p>To add STL support (at possible cost of longer compilation times), include: </p><p>
- </p><pre class="programlisting">#include <msm/front/euml/stl.hpp></pre><p>
- </p><p>eUML is defined in the namespace <code class="code">msm::front::euml</code>.</p><div class="sect2" title="Transition table"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1462"></a>Transition table</h3></div></div></div><p>A transition can be defined using eUML as: </p><p>
- </p><pre class="programlisting">source + event [guard] / action == target</pre><p>
- </p><p>or as</p><p>
- </p><pre class="programlisting">target == source + event [guard] / action</pre><p>
- </p><p>The first version looks like a drawn transition in a diagram, the second
- one seems natural to a C++ developer.</p><p>The simple transition table written with the <span class="command"><strong><a class="command" href="ch03s03.html#functor-front-end">functor front-end</a></strong></span> can now be
- written as:</p><pre class="programlisting">BOOST_MSM_EUML_TRANSITION_TABLE((
- Stopped + play [some_guard] / (some_action , start_playback) == Playing ,
- Stopped + open_close/ open_drawer == Open ,
- Stopped + stop == Stopped ,
- Open + open_close / close_drawer == Empty ,
- Empty + open_close / open_drawer == Open ,
- Empty + cd_detected [good_disk_format] / store_cd_info == Stopped
- ),transition_table) </pre><p>Or, using the alternative notation, it can be:</p><pre class="programlisting">BOOST_MSM_EUML_TRANSITION_TABLE((
- Playing == Stopped + play [some_guard] / (some_action , start_playback) ,
- Open == Stopped + open_close/ open_drawer ,
- Stopped == Stopped + stop ,
- Empty == Open + open_close / close_drawer ,
- Open == Empty + open_close / open_drawer ,
- Stopped == Empty + cd_detected [good_disk_format] / store_cd_info
- ),transition_table) </pre><p>The transition table now looks like a list of (readable) rules with little
- noise.</p><p>UML defines guards between “[ ]” and actions after a “/”, so the chosen
- syntax is already more readable for UML designers. UML also allows designers
- to define several actions sequentially (our previous ActionSequence_)
- separated by a comma. The first transition does just this: two actions
- separated by a comma and enclosed inside parenthesis to respect C++ operator
- precedence.</p><p>If this seems to you like it will cost you run-time performance, don't
- worry, eUML is based on typeof (or decltype) which only evaluates the
- parameters to BOOST_MSM_EUML_TRANSITION_TABLE and no run-time cost occurs.
- Actually, eUML is only a metaprogramming layer on top of "standard" MSM
- metaprogramming and this first layer generates the previously-introduced
- <span class="command"><strong><a class="command" href="ch03s03.html#functor-front-end">functor
- front-end</a></strong></span>.</p><p>UML also allows designers to define more complicated guards, like
- [good_disk_format && (some_condition || some_other_condition)]. This
- was possible with our previously defined functors, but using a complicated
- template syntax. This syntax is now possible exactly as written, which means
- without any syntactic noise at all.</p></div><div class="sect2" title="A simple example: rewriting only our transition table"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1503"></a>A simple example: rewriting only our transition table </h3></div></div></div><p>As an introduction to eUML, we will rewrite our tutorial's transition
- table using eUML. This will require two or three changes, depending on the compiler:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>events must inherit from msm::front::euml::euml_event<
- event_name ></p></li><li class="listitem"><p>states must inherit from msm::front::euml::euml_state<
- state_name ></p></li><li class="listitem"><p>with VC, states must be declared before the front-end</p></li></ul></div><p>We now can write the transition table like just shown, using
- BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE instead of
- BOOST_MSM_EUML_TRANSITION_TABLE. The <a class="link" href="examples/SimpleTutorialWithEumlTable.cpp" target="_top">implementation</a> is pretty straightforward. The only required
- addition is the need to declare a variable for each state or add parenses (a
- default-constructor call) in the transition table.</p><p>The <a class="link" href="examples/CompositeTutorialWithEumlTable.cpp" target="_top">
- <span class="command"><strong></strong></span></a><a name="eUML-composite-table"></a><a class="link" href="examples/CompositeTutorialWithEumlTable.cpp" target="_top"><span class="command"><strong>composite</strong></span></a> implementation is also natural:</p><pre class="programlisting">// front-end like always
- struct sub_front_end : public boost::msm::front::state_machine_def<sub_front_end>
- {
- ...
- };
- // back-end like always
- typedef boost::msm::back::state_machine<sub_front_end> sub_back_end;
- sub_back_end const sub; // sub can be used in a transition table.</pre><p>Unfortunately, there is a bug with VC, which appears from time to time and
- causes in a stack overflow. If you get a warning that the program is
- recursive on all paths, revert to either standard eUML or another front-end
- as Microsoft doesn't seem to intend to fix it.</p><p>We now have a new, more readable transition table with few changes to our
- example. eUML can do much more so please follow the guide.</p></div><div class="sect2" title="Defining events, actions and states with entry/exit actions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1536"></a>Defining events, actions and states with entry/exit actions</h3></div></div></div><div class="sect3" title="Events"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1539"></a>Events</h4></div></div></div><p>Events must be proto-enabled. To achieve this, they must inherit from
- a proto terminal (euml_event<event-name>). eUML also provides a macro
- to make this easier:</p><p>
- </p><pre class="programlisting">BOOST_MSM_EUML_EVENT(play)</pre><p>
- </p><p>This declares an event type and an instance of this type called
- <code class="code">play</code>, which is now ready to use in state or transition
- behaviors.</p><p>There is a second macro, BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES, which
- takes as second parameter the attributes an event will contain, using
- the <span class="command"><strong><a class="command" href="ch03s04.html#eUML-attributes">attribute
- syntax</a></strong></span>.</p><p><span class="underline">Note</span>: as we now have events
- defined as instances instead of just types, can we still process an
- event by creating one on the fly, like:
- <code class="code">fsm.process_event(play());</code> or do we have to write:
- <code class="code">fsm.process_event(play);</code></p><p>The answer is you can do both. The second one is easier but unlike
- other front-ends, the second uses a defined operator(), which creates an
- event on the fly.</p></div><div class="sect3" title="Actions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1570"></a>Actions</h4></div></div></div><p>Actions (returning void) and guards (returning a bool) are defined
- like previous functors, with the difference that they also must be
- proto-enabled. This can be done by inheriting from euml_action<
- functor-name >. eUML also provides a macro:</p><pre class="programlisting">BOOST_MSM_EUML_ACTION(some_condition)
- {
- template <class Fsm,class Evt,class SourceState,class TargetState>
- bool operator()(Evt const& ,Fsm& ,SourceState&,TargetState& )
- { return true; }
- }; </pre><p>Like for events, this macro declares a functor type and an instance
- for use in transition or state behaviors.</p><p>It is possible to use the same action grammar from the transition
- table to define state entry and exit behaviors. So
- <code class="code">(action1,action2)</code> is a valid entry or exit behavior
- executing both actions in turn.</p><p>The state functors have a slightly different signature as there is no
- source and target state but only a current state (entry/exit actions are
- transition-independent), for example:</p><pre class="programlisting">BOOST_MSM_EUML_ACTION(Empty_Entry)
- {
- template <class Evt,class Fsm,class State>
- void operator()(Evt const& ,Fsm& ,State& ) { ... }
- }; </pre><p><span class="command"><strong><a name="eUML-reuse-functor"></a></strong></span>It is also possible to reuse the functors from the functor front-end.
- The syntax is however slightly less comfortable as we need to pretend
- creating one on the fly for typeof. For example:</p><pre class="programlisting">struct start_playback
- {
- template <class Fsm,class Evt,class SourceState,class TargetState>
- void operator()(Evt const& ,Fsm&,SourceState& ,TargetState& )
- {
- ...
- }
- };
- BOOST_MSM_EUML_TRANSITION_TABLE((
- Playing == Stopped + play / start_playback() ,
- ...
- ),transition_table)</pre></div><div class="sect3" title="States"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1593"></a>States</h4></div></div></div><p>There is also a macro for states. This macro has 2 arguments, first
- the expression defining the state, then the state (instance)
- name:</p><pre class="programlisting">BOOST_MSM_EUML_STATE((),Paused)</pre><p>This defines a simple state without entry or exit action. You can
- provide in the expression parameter the state behaviors (entry and exit)
- using the action grammar, like in the transition table:</p><pre class="programlisting">BOOST_MSM_EUML_STATE(((Empty_Entry,Dummy_Entry)/*2 entryactions*/,
- Empty_Exit/*1 exit action*/ ),
- Empty)</pre><p>This means that Empty is defined as a state with an entry action made
- of two sub-actions, Empty_Entry and Dummy_Entry (enclosed inside
- parenthesis), and an exit action, Empty_Exit.</p><p>There are several possibilitites for the <span class="command"><strong><a name="eUML-build-state"></a></strong></span> expression syntax:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(): state without entry or exit action.</p></li><li class="listitem"><p>(Expr1): state with entry but no exit action.</p></li><li class="listitem"><p>(Expr1,Expr2): state with entry and exit action.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes): state with entry and exit
- action, defining some attributes (read further on).</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure): state with entry and
- exit action, defining some attributes (read further on) and
- flags (standard MSM flags) or deferred events (standard MSM
- deferred events).</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure,Base): state with entry
- and exit action, defining some attributes (read further on),
- flags and deferred events (plain msm deferred events) and a
- non-default base state (as defined in standard MSM).</p></li></ul></div><p>no_action is also defined, which does, well, nothing except being a
- placeholder (needed for example as entry action if we have no entry but
- an exit). Expr1 and Expr2 are a sequence of actions, obeying the same
- action grammar as in the transition table (following the “/”
- symbol).</p><p>The BOOST_MSM_EUML_STATE macro will allow you to define most common
- states, but sometimes you will need more, for example provide in your
- states some special behavior. In this case, you will have to do the
- macro's job by hand, which is not very complicated. The state will need
- to inherit from <code class="code">msm::front::state<></code>, like any state, and
- from <code class="code">euml_state<state-name></code> to be proto-enabled. You
- will then need to declare an instance for use in the transition table.
- For example:</p><pre class="programlisting">struct Empty_impl : public msm::front::state<> , public euml_state<Empty_impl>
- {
- void activate_empty() {std::cout << "switching to Empty " << std::endl;}
- template <class Event,class Fsm>
- void on_entry(Event const& evt,Fsm&fsm){...}
- template <class Event,class Fsm>
- void on_exit(Event const& evt,Fsm&fsm){...}
- };
- //instance for use in the transition table
- Empty_impl const Empty;</pre><p>Notice also that we defined a method named activate_empty. We would
- like to call it inside a behavior. This can be done using the
- BOOST_MSM_EUML_METHOD macro. </p><pre class="programlisting">BOOST_MSM_EUML_METHOD(ActivateEmpty_,activate_empty,activate_empty_,void,void)</pre><p>The first parameter is the name of the underlying functor, which you
- could use with the functor front-end, the second is the state method
- name, the third is the eUML-generated function, the fourth and fifth the
- return value when used inside a transition or a state behavior. You can
- now use this inside a transition:</p><pre class="programlisting">Empty == Open + open_close / (close_drawer,activate_empty_(target_))</pre></div></div><div class="sect2" title="Wrapping up a simple state machine and first complete examples"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1649"></a>Wrapping up a simple state machine and first complete examples</h3></div></div></div><p>You can reuse the state machine definition method from the standard
- front-end and simply replace the transition table by this new one. You can
- also use eUML to define a state machine "on the fly" (if, for example, you
- need to provide an on_entry/on_exit for this state machine as a functor).
- For this, there is also a macro, <span class="command"><strong><a name="eUML-build-sm"></a></strong></span>BOOST_MSM_EUML_DECLARE_STATE_MACHINE, which has 2 arguments, an expression
- describing the state machine and the state machine name. The expression has
- up to 8 arguments:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(Stt, Init): simplest state machine where only the transition
- table and initial state(s) are defined.</p></li><li class="listitem"><p>(Stt, Init, Expr1): state machine where the transition table,
- initial state and entry action are defined.</p></li><li class="listitem"><p>(Stt, Init, Expr1, Expr2): state machine where the transition
- table, initial state, entry and exit actions are defined.</p></li><li class="listitem"><p>(Stt, Init, Expr1, Expr2, Attributes): state machine where the
- transition table, initial state, entry and exit actions are
- defined. Furthermore, some attributes are added (read further
- on).</p></li><li class="listitem"><p>(Stt, Init, Expr1, Expr2, Attributes, Configure): state
- machine where the transition table, initial state, entry and
- exit actions are defined. Furthermore, some attributes (read
- further on), flags, deferred events and <a class="link" href="ch03s04.html#eUML-Configuration">configuration
- capabilities</a> (no message queue / no exception
- catching) are added.</p></li><li class="listitem"><p>(Stt, Init, Expr1, Expr2, Attributes, Flags, Deferred , Base):
- state machine where the transition table, initial state, entry
- and exit actions are defined. Furthermore, attributes (read
- further on), flags , deferred events and configuration
- capabilities (no message queue / no exception catching) are
- added and a non-default base state (see the <a class="link" href="ch03s05.html#backend-base-state">back-end
- description</a>) is defined.</p></li></ul></div><p>For example, a minimum state machine could be defined
- as:</p><pre class="programlisting">BOOST_MSM_EUML_TRANSITION_TABLE((
- ),transition_table) </pre><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,init_ << Empty ),
- player_)</pre><p>Please have a look at the player tutorial written using eUML's <a class="link" href="examples/SimpleTutorialEuml2.cpp" target="_top">first syntax</a> and
- <a class="link" href="examples/SimpleTutorialEuml.cpp" target="_top">second syntax</a>.
- The BOOST_MSM_EUML_DECLARE_ATTRIBUTE macro, to which we will get back
- shortly, declares attributes given to an eUML type (state or event) using
- the <span class="command"><strong><a class="command" href="ch03s04.html#eUML-attributes">attribute
- syntax</a></strong></span>.</p></div><div class="sect2" title="Defining a submachine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1697"></a>Defining a submachine</h3></div></div></div><p>Defining a submachine (see <a class="link" href="examples/CompositeTutorialEuml.cpp" target="_top">tutorial</a>) with
- other front-ends simply means using a state which is a state machine in the
- transition table of another state machine. This is the same with eUML. One
- only needs define a second state machine and reference it in the transition
- table of the containing state machine.</p><p>Unlike the state or event definition macros,
- BOOST_MSM_EUML_DECLARE_STATE_MACHINE defines a type, not an instance because
- a type is what the back-end requires. This means that you will need to
- declare yourself an instance to reference your submachine into another state
- machine, for example:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE_MACHINE(...,Playing_)
- typedef msm::back::state_machine<Playing_> Playing_type;
- Playing_type const Playing;</pre><p>We can now use this instance inside the transition table of the containing
- state machine:</p><pre class="programlisting">Paused == Playing + pause / pause_playback</pre></div><div class="sect2" title="Attributes / Function call"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1713"></a>
- <span class="command"><strong><a name="eUML-attributes"></a></strong></span>Attributes / Function call</h3></div></div></div><p>We now want to make our grammar more useful. Very often, one needs only
- very simple action methods, for example ++Counter or Counter > 5 where
- Counter is usually defined as some attribute of the class containing the
- state machine. It seems like a waste to write a functor for such a simple
- action. Furthermore, states within MSM are also classes so they can have
- attributes, and we would also like to provide them with attributes. </p><p>If you look back at our examples using the <a class="link" href="examples/SimpleTutorialEuml2.cpp" target="_top">first</a> and <a class="link" href="examples/SimpleTutorialEuml.cpp" target="_top">second</a> syntaxes, you
- will find a BOOST_MSM_EUML_DECLARE_ATTRIBUTE and a BOOST_MSM_EUML_ATTRIBUTES
- macro. The first one declares possible attributes:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
- BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)</pre><p>This declares two attributes: cd_name of type std::string and cd_type of
- type DiskTypeEnum. These attributes are not part of any event or state in
- particular, we just declared a name and a type. Now, we can add attributes
- to our cd_detected event using the second one:</p><pre class="programlisting">BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ),
- cd_detected_attributes)</pre><p>This declares an attribute list which is not linked to anything in
- particular yet. It can be attached to a state or an event. For example, if
- we want the event cd_detected to have these defined attributes we
- write:</p><pre class="programlisting">BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)</pre><p>For states, we use the BOOST_MSM_EUML_STATE macro, which has an expression
- form where one can provide attributes. For example:</p><pre class="programlisting">BOOST_MSM_EUML_STATE((no_action /*entry*/,no_action/*exit*/,
- attributes_ << cd_detected_attributes),
- some_state)</pre><p>OK, great, we now have a way to add attributes to a class, which we could
- have done more easily, so what is the point? The point is that we can now
- reference these attributes directly, at compile-time, in the transition
- table. For example, in the example, you will find this transition:</p><pre class="programlisting">Stopped==Empty+cd_detected[good_disk_format&&(event_(cd_type)==Int_<DISK_CD>())] </pre><p>Read event_(cd_type) as event_->cd_type with event_ a type generic for
- events, whatever the concrete event is (in this particular case, it happens
- to be a cd_detected as the transition shows).</p><p>The main advantage of this feature is that you do not need to define a new
- functor and you do not need to look inside the functor to know what it does,
- you have all at hand.</p><p>MSM provides more generic objects for state machine types:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>event_ : used inside any action, the event triggering the
- transition</p></li><li class="listitem"><p>state_: used inside entry and exit actions, the entered /
- exited state</p></li><li class="listitem"><p>source_: used inside a transition action, the source
- state</p></li><li class="listitem"><p>target_: used inside a transition action, the target
- state</p></li><li class="listitem"><p>fsm_: used inside any action, the (lowest-level) state machine
- processing the transition</p></li><li class="listitem"><p>Int_<int value>: a functor representing an int</p></li><li class="listitem"><p>Char_<value>: a functor representing a char</p></li><li class="listitem"><p>Size_t_<value>: a functor representing a size_t</p></li><li class="listitem"><p>String_<mpl::string> (boost >= 1.40): a functor
- representing a string.</p></li></ul></div><p>These helpers can be used in two different ways:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>helper(attribute_name) returns the attribute with name
- attribute_name</p></li><li class="listitem"><p>helper returns the state / event type itself.</p></li></ul></div><p>The second form is helpful if you want to provide your states with their
- own methods, which you also want to use inside the transition table. In the
- <a class="link" href="examples/SimpleTutorialEuml.cpp" target="_top">above
- tutorial</a>, we provide Empty with an activate_empty method. We would
- like to create a eUML functor and call it from inside the transition table.
- This is done using the MSM_EUML_METHOD / MSM_EUML_FUNCTION macros. The first
- creates a functor to a method, the second to a free function. In the
- tutorial, we write:</p><pre class="programlisting">MSM_EUML_METHOD(ActivateEmpty_,activate_empty,activate_empty_,void,void)</pre><p>The first parameter is the functor name, for use with the functor
- front-end. The second is the name of the method to call. The third is the
- function name for use with eUML, the fourth is the return type of the
- function if used in the context of a transition action, the fifth is the
- result type if used in the context of a state entry / exit action (usually
- fourth and fifth are the same). We now have a new eUML function calling a
- method of "something", and this "something" is one of the five previously
- shown generic helpers. We can now use this in a transition, for
- example:</p><pre class="programlisting">Empty == Open + open_close / (close_drawer,activate_empty_(target_))</pre><p>The action is now defined as a sequence of two actions: close_drawer and
- activate_empty, which is called on the target itself. The target being Empty
- (the state defined left), this really will call Empty::activate_empty().
- This method could also have an (or several) argument(s), for example the
- event, we could then call activate_empty_(target_ , event_).</p><p>More examples can be found in the <a class="link" href="examples/CompilerStressTestEuml.cpp" target="_top">terrible compiler
- stress test</a>, the <a class="link" href="examples/SimpleTimer.cpp" target="_top">timer example</a> or in the <a class="link" href="examples/iPodSearchEuml.cpp" target="_top">iPodSearch with eUML</a>
- (for String_ and more).</p></div><div class="sect2" title="Orthogonal regions, flags, event deferring"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1813"></a>Orthogonal regions, flags, event deferring</h3></div></div></div><p>Defining orthogonal regions really means providing more initial states. To
- add more initial states, “shift left” some, for example, if we had another
- initial state named AllOk :</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,
- init_ << Empty << AllOk ),
- player_)</pre><p>You remember from the <span class="command"><strong><a class="command" href="ch03s04.html#eUML-build-state">BOOST_MSM_EUML_STATE </a></strong></span> and <span class="command"><strong><a class="command" href="ch03s04.html#eUML-build-sm">BOOST_MSM_EUML_DECLARE_STATE_MACHINE</a></strong></span> signatures that just
- after attributes, we can define flags, like in the basic MSM front-end. To
- do this, we have another "shift-left" grammar, for example:</p><pre class="programlisting">BOOST_MSM_EUML_STATE((no_action,no_action, attributes_ <<no_attributes_,
- /* flags */ configure_<< PlayingPaused << CDLoaded),
- Paused)</pre><p>We now defined that Paused will get two flags, PlayingPaused and CDLoaded,
- defined, with another macro:</p><pre class="programlisting">BOOST_MSM_EUML_FLAG(CDLoaded)</pre><p>This corresponds to the following basic front-end definition of
- Paused:</p><pre class="programlisting">struct Paused : public msm::front::state<>
- {
- typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
- };</pre><p>Under the hood, what you get really is a mpl::vector2.</p><p><span class="underline">Note</span>: As we use the version of
- BOOST_MSM_EUML_STATE's expression with 4 arguments, we need to tell eUML
- that we need no attributes. Similarly to a <code class="code">cout << endl</code>,
- we need a <code class="code">attributes_ << no_attributes_</code> syntax.</p><p>You can use the flag with the is_flag_active method of a state machine.
- You can also use the provided helper function is_flag_ (returning a bool)
- for state and transition behaviors. For example, in the <a class="link" href="examples/iPodEuml.cpp" target="_top">iPod implementation with eUML</a>,
- you find the following transition:</p><pre class="programlisting">ForwardPressed == NoForward + EastPressed[!is_flag_(NoFastFwd)]</pre><p>The function also has an optional second parameter which is the state
- machine on which the function is called. By default, fsm_ is used (the
- current state machine) but you could provide a functor returning a reference
- to another state machine.</p><p>eUML also supports defining deferred events in the state (state machine)
- definition. To this aim, we can reuse the flag grammar. For example:</p><pre class="programlisting">BOOST_MSM_EUML_STATE((Empty_Entry,Empty_Exit, attributes_ << no_attributes_,
- /* deferred */ configure_<< play ),Empty) </pre><p>The configure_ left shift is also responsible for deferring events. Shift
- inside configure_ a flag and the state will get a flag, shift an event and
- it will get a deferred event. This replaces the basic front-end
- definition:</p><pre class="programlisting">typedef mpl::vector<play> deferred_events;</pre><p>In <a class="link" href="examples/OrthogonalDeferredEuml.cpp" target="_top">this
- tutorial</a>, player is defining a second orthogonal region with
- AllOk as initial state. The <code class="code">Empty</code> and <code class="code">Open</code> states
- also defer the event <code class="code">play</code>. <code class="code">Open</code>,
- <code class="code">Stopped</code> and <code class="code">Pause</code> also support the flag
- <code class="code">CDLoaded</code> using the same left shift into
- <code class="code">configure_</code>.</p><p>In the functor front-end, we also had the possibility to defer an event
- inside a transition, which makes possible conditional deferring. This is
- also possible with eUML through the use of the defer_ order, as shown in
- <a class="link" href="examples/OrthogonalDeferredEuml.cpp" target="_top">this
- tutorial</a>. You will find the following transition:</p><pre class="programlisting">Open + play / defer_</pre><p>This is an <span class="command"><strong><a class="command" href="ch03s04.html#eUML-internal">internal
- transition</a></strong></span>. Ignore it for the moment. Interesting is, that
- when the event <code class="code">play</code> is fired and <code class="code">Open</code> is active,
- the event will be deferred. Now add a guard and you can conditionally defer
- the event, for example:</p><pre class="programlisting">Open + play [ some_condition ] / defer_</pre><p>This is similar to what we did with the functor front-end. This means that
- we have the same constraints. Using defer_ instead of a state declaration,
- we need to tell MSM that we have deferred events in this state machine. We
- do this (again) using a configure_ declaration in the state machine
- definition in which we shift the deferred_events configuration flag:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,
- init_ << Empty << AllOk,
- Entry_Action,
- Exit_Action,
- attributes_ << no_attributes_,
- configure_<< deferred_events ),
- player_)</pre><p>A <a class="link" href="examples/OrthogonalDeferredEuml2.cpp" target="_top">tutorial</a>
- illustrates this possibility.</p></div><div class="sect2" title="Customizing a state machine / Getting more speed"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1925"></a>
- <span class="command"><strong><a name="eUML-Configuration"></a></strong></span>Customizing a state machine / Getting
- more speed</h3></div></div></div><p>We just saw how to use configure_ to define deferred events or flags. We
- can also use it to configure our state machine like we did with the other front-ends:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">configure_ << no_exception</code>: disables
- exception handling</p></li><li class="listitem"><p><code class="code">configure_ << no_msg_queue</code> deactivates the
- message queue</p></li><li class="listitem"><p><code class="code">configure_ << deferred_events</code> manually
- enables event deferring</p></li></ul></div><p>Deactivating the first two features and not activating the third if not
- needed greatly improves the event dispatching speed of your state machine.
- Our <a class="link" href="examples/EumlSimple.cpp" target="_top">speed testing</a> example
- with eUML does this for the best performance.</p><p><span class="underline">Important note</span>: As exit pseudo
- states are using the message queue to forward events out of a submachine,
- the <code class="code">no_message_queue</code> option cannot be used with state machines
- containing an exit pseudo state.</p></div><div class="sect2" title="Completion / Anonymous transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1960"></a>Completion / Anonymous transitions</h3></div></div></div><p>Anonymous transitions (See <span class="command"><strong><a class="command" href="ch02s02.html#uml-anonymous">UML
- tutorial</a></strong></span>) are transitions without a named event, which are
- therefore triggered immediately when the source state becomes active,
- provided a guard allows it. As there is no event, to define such a
- transition, simply omit the “+” part of the transition (the event), for
- example: </p><pre class="programlisting">State3 == State4 [always_true] / State3ToState4
- State4 [always_true] / State3ToState4 == State3</pre><p>Please have a look at <a class="link" href="examples/AnonymousTutorialEuml.cpp" target="_top">this example</a>,
- which implements the <span class="command"><strong><a class="command" href="ch03s02.html#anonymous-transitions">previously
- defined</a></strong></span> state machine with eUML.</p></div><div class="sect2" title="Internal transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1978"></a><span class="command"><strong><a name="eUML-internal"></a></strong></span>Internal transitions</h3></div></div></div><p>Like both other front-ends, eUML supports two ways of defining internal transitions:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>in the state machine's transition table. In this case, you
- need to specify a source state, event, actions and guards but no
- target state, which eUML will interpret as an internal
- transition, for example this defines a transition internal to
- Open, on the event open_close:</p><pre class="programlisting">Open + open_close [internal_guard1] / internal_action1</pre><p><a class="link" href="examples/EumlInternal.cpp" target="_top">A full
- example</a> is also provided.</p></li><li class="listitem"><p>in a state's <code class="code">internal_transition_table</code>. For
- example:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE((Open_Entry,Open_Exit),Open_def)
- struct Open_impl : public Open_def
- {
- BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
- open_close [internal_guard1] / internal_action1
- ))
- };</pre><p>Notice how we do not need to repeat that the transition
- originates from Open as we already are in Open's context. </p><p>The <a class="link" href="examples/EumlInternalDistributed.cpp" target="_top">implementation</a> also shows the added bonus offered
- for submachines, which can have both the standard
- transition_table and an internal_transition_table (which has
- higher priority). This makes it easier if you decide to make a
- full submachine from a state. It is also slightly faster than
- the standard alternative, adding orthogonal regions, because
- event dispatching will, if accepted by the internal table, not
- continue to the subregions. This gives you a O(1) dispatch
- instead of O(number of regions).</p></li></ul></div></div><div class="sect2" title="Kleene(any) event)"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2009"></a><span class="command"><strong><a name="kleene-event"></a></strong></span>Kleene(any) event)</h3></div></div></div><p>As for the functor front-end, eUML supports the concept of an <span class="italic"><span class="command"><strong><a class="command" href="ch03s03.html#any-event">any</a></strong></span></span>
- event, but boost::any is not an acceptable eUML terminal. If you need an
- <span class="italic">any</span> event, use
- msm::front::euml::kleene, which inherits boost::any. The same transition as
- with boost:any would be: </p><pre class="programlisting">State1 + kleene == State2</pre></div><div class="sect2" title="Other state types"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2024"></a>Other state types</h3></div></div></div><p>We saw the <span class="command"><strong><a class="command" href="ch03s04.html#eUML-build-state">build_state</a></strong></span>
- function, which creates a simple state. Likewise, eUML provides other
- state-building macros for other types of states:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>BOOST_MSM_EUML_TERMINATE_STATE takes the same arguments as
- BOOST_MSM_EUML_STATE and defines, well, a terminate
- state.</p></li><li class="listitem"><p>BOOST_MSM_EUML_INTERRUPT_STATE takes the same arguments as
- BOOST_MSM_EUML_STATE and defines an interrupt state. However,
- the expression argument must contain as first element the event
- ending the interruption, for example:
- <code class="code">BOOST_MSM_EUML_INTERRUPT_STATE(( end_error /*end
- interrupt event*/,ErrorMode_Entry,ErrorMode_Exit
- ),ErrorMode)</code></p></li><li class="listitem"><p>BOOST_MSM_EUML_EXIT_STATE takes the same arguments as
- BOOST_MSM_EUML_STATE and defines an exit pseudo state. However,
- the expression argument must contain as first element the event
- propagated from the exit point:
- <code class="code">BOOST_MSM_EUML_EXIT_STATE(( event6 /*propagated
- event*/,PseudoExit1_Entry,PseudoExit1_Exit
- ),PseudoExit1)</code></p></li><li class="listitem"><p>BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE defines an entry pseudo
- state. It takes 3 parameters: the region index to be entered is
- defined as an int argument, followed by the configuration
- expression like BOOST_MSM_EUML_STATE and the state name, so that
- <code class="code">BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(0 /*region
- index*/,( SubState2_Entry,SubState2_Exit ),SubState2)</code>
- defines an entry state into the first region of a
- submachine.</p></li><li class="listitem"><p>BOOST_MSM_EUML_ENTRY_STATE defines an entry pseudo state. It
- takes 3 parameters: the region index to be entered is defined as
- an int argument, followed by the configuration expression like
- BOOST_MSM_EUML_STATE and the state name, so that
- <code class="code">BOOST_MSM_EUML_ENTRY_STATE(0,(
- PseudoEntry1_Entry,PseudoEntry1_Exit ),PseudoEntry1)</code>
- defines a pseudo entry state into the first region of a
- submachine.</p></li></ul></div><p>To use these states in the transition table, eUML offers the functions
- <code class="code">explicit_</code>, <code class="code">exit_pt_</code> and
- <code class="code">entry_pt_</code>. For example, a direct entry into the substate
- SubState2 from SubFsm2 could be:</p><pre class="programlisting">explicit_(SubFsm2,SubState2) == State1 + event2</pre><p>Forks being a list on direct entries, eUML supports a logical syntax
- (state1, state2, ...), for example:</p><pre class="programlisting">(explicit_(SubFsm2,SubState2),
- explicit_(SubFsm2,SubState2b),
- explicit_(SubFsm2,SubState2c)) == State1 + event3 </pre><p>An entry point is entered using the same syntax as explicit entries:
- </p><pre class="programlisting">entry_pt_(SubFsm2,PseudoEntry1) == State1 + event4</pre><p>For exit points, it is again the same syntax except that exit points are
- used as source of the transition:
- </p><pre class="programlisting">State2 == exit_pt_(SubFsm2,PseudoExit1) + event6 </pre><p>The <a class="link" href="examples/DirectEntryEuml.cpp" target="_top">entry tutorial</a>
- is also available with eUML.</p></div><div class="sect2" title="Helper functions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2088"></a>Helper functions</h3></div></div></div><p>We saw a few helpers but there are more, so let us have a more complete description:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>event_ : used inside any action, the event triggering the
- transition</p></li><li class="listitem"><p>state_: used inside entry and exit actions, the entered /
- exited state</p></li><li class="listitem"><p>source_: used inside a transition action, the source
- state</p></li><li class="listitem"><p>target_: used inside a transition action, the target
- state</p></li><li class="listitem"><p>fsm_: used inside any action, the (deepest-level) state
- machine processing the transition</p></li><li class="listitem"><p>These objects can also be used as a function and return an
- attribute, for example event_(cd_name)</p></li><li class="listitem"><p>Int_<int value>: a functor representing an int</p></li><li class="listitem"><p>Char_<value>: a functor representing a char</p></li><li class="listitem"><p>Size_t_<value>: a functor representing a size_t</p></li><li class="listitem"><p>True_ and False_ functors returning true and false
- respectively</p></li><li class="listitem"><p>String_<mpl::string> (boost >= 1.40): a functor
- representing a string.</p></li><li class="listitem"><p>if_then_else_(guard, action, action) where action can be an
- action sequence</p></li><li class="listitem"><p>if_then_(guard, action) where action can be an action
- sequence</p></li><li class="listitem"><p>while_(guard, action) where action can be an action
- sequence</p></li><li class="listitem"><p>do_while_(guard, action) where action can be an action
- sequence</p></li><li class="listitem"><p>for_(action, guard, action, action) where action can be an
- action sequence</p></li><li class="listitem"><p>process_(some_event [, some state machine] [, some state
- machine] [, some state machine] [, some state machine]) will
- call process_event (some_event) on the current state machine or
- on the one(s) passed as 2nd , 3rd, 4th, 5th argument. This allow
- sending events to several external machines</p></li><li class="listitem"><p>process_(event_): reprocesses the event which triggered the
- transition</p></li><li class="listitem"><p>reprocess_(): same as above but shorter to write</p></li><li class="listitem"><p>process2_(some_event,Value [, some state machine] [, some
- state machine] [, some state machine]) will call process_event
- (some_event(Value)) on the current state machine or on the
- one(s) passed as 3rd, 4th, 5th argument</p></li><li class="listitem"><p>is_ flag_(some_flag[, some state machine]) will call
- is_flag_active on the current state machine or on the one passed
- as 2nd argument</p></li><li class="listitem"><p>Predicate_<some predicate>: Used in STL algorithms. Wraps
- unary/binary functions to make them eUML-compatible so that they
- can be used in STL algorithms</p></li></ul></div><p>This can be quite fun. For example, </p><pre class="programlisting">/( if_then_else_(--fsm_(m_SongIndex) > Int_<0>(),/*if clause*/
- show_playing_song, /*then clause*/
- (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay))/*else clause*/
- )
- )</pre><p>means: if (fsm.SongIndex > 0, call show_playing_song else
- {fsm.SongIndex=1; process EndPlay on fsm;}</p><p>A few examples are using these features:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>the iPod example introduced at the BoostCon09 <a class="link" href="examples/iPodEuml.cpp" target="_top">has been rewritten</a>
- with eUML (weak compilers please move on...)</p></li><li class="listitem"><p>the iPodSearch example also introduced at the BoostCon09 <a class="link" href="examples/iPodSearchEuml.cpp" target="_top">has been
- rewritten</a> with eUML. In this example, you will also
- find some examples of STL functor usage.</p></li><li class="listitem"><p><a class="link" href="examples/SimpleTimer.cpp" target="_top">A simpler
- timer</a> example is a good starting point. </p></li></ul></div><p>There is unfortunately a small catch. Defining a functor using
- MSM_EUML_METHOD or MSM_EUML_FUNCTION will create a correct functor. Your own
- eUML functors written as described at the beginning of this section will
- also work well, <span class="underline">except</span>, for the
- moment, with the while_, if_then_, if_then_else_ functions.</p></div><div class="sect2" title="Phoenix-like STL support"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2191"></a>Phoenix-like STL support</h3></div></div></div><p>eUML supports most C++ operators (except address-of). For example it is
- possible to write event_(some_attribute)++ or [source_(some_bool) &&
- fsm_(some_other_bool)]. But a programmer needs more than operators in his
- daily programming. The STL is clearly a must have. Therefore, eUML comes in
- with a lot of functors to further reduce the need for your own functors for
- the transition table. For almost every algorithm or container method of the
- STL, a corresponding eUML function is defined. Like Boost.Phoenix, “.” And
- “->” of call on objects are replaced by a functional programming paradigm,
- for example:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>begin_(container), end_(container): return iterators of a
- container.</p></li><li class="listitem"><p>empty_(container): returns container.empty()</p></li><li class="listitem"><p>clear_(container): container.clear()</p></li><li class="listitem"><p>transform_ : std::transform</p></li></ul></div><p>In a nutshell, almost every STL method or algorithm is matched by a
- corresponding functor, which can then be used in the transition table or
- state actions. The <a class="link" href="pt02.html#Reference-begin">reference</a>
- lists all eUML functions and the underlying functor (so that this
- possibility is not reserved to eUML but also to the functor-based
- front-end). The file structure of this Phoenix-like library matches the one
- of Boost.Phoenix. All functors for STL algorithms are to be found in:</p><pre class="programlisting">#include <msm/front/euml/algorithm.hpp></pre><p>The algorithms are also divided into sub-headers, matching the phoenix
- structure for simplicity:</p><pre class="programlisting">#include < msm/front/euml/iteration.hpp>
- #include < msm/front/euml/transformation.hpp>
- #include < msm/front/euml/querying.hpp> </pre><p>Container methods can be found in:</p><pre class="programlisting">#include < msm/front/euml/container.hpp></pre><p>Or one can simply include the whole STL support (you will also need to
- include euml.hpp):</p><pre class="programlisting">#include < msm/front/euml/stl.hpp></pre><p>A few examples (to be found in <a class="link" href="examples/iPodSearchEuml.cpp" target="_top">this tutorial</a>):</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">push_back_(fsm_(m_tgt_container),event_(m_song))</code>:
- the state machine has an attribute m_tgt_container of type
- std::vector<OneSong> and the event has an attribute m_song of
- type OneSong. The line therefore pushes m_song at the end of
- m_tgt_container</p></li><li class="listitem"><p><code class="code">if_then_( state_(m_src_it) !=
- end_(fsm_(m_src_container)),
- process2_(OneSong(),*(state_(m_src_it)++)) )</code>: the
- current state has an attribute m_src_it (an iterator). If this
- iterator != fsm.m_src_container.end(), process OneSong on fsm,
- copy-constructed from state.m_src_it which we
- post-increment</p></li></ul></div></div><div class="sect2" title="Writing actions with Boost.Phoenix (in development)"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2244"></a><span class="command"><strong><a name="eUML-phoenix"></a></strong></span>Writing actions with Boost.Phoenix (in development)</h3></div></div></div><p> It is also possible to write actions, guards, state entry and exit
- actions using a reduced set of Boost.Phoenix capabilities. This feature
- is still in development stage, so you might get here and there some
- surprise. Simple cases, however, should work well. What will not work
- will be mixing of eUML and Phoenix functors. Writing guards in one
- language and actions in another is ok though.</p><p>Phoenix also supports a larger syntax than what will ever be possible
- with eUML, so you can only use a reduced set of phoenix's grammar. This
- is due to the nature of eUML. The run-time transition table definition
- is translated to a type using Boost.Typeof. The result is a "normal" MSM
- transition table made of functor types. As C++ does not allow mixing
- run-time and compile-time constructs, there will be some limit (trying
- to instantiate a template class MyTemplateClass<i> where i is an int
- will give you an idea). This means following valid Phoenix constructs
- will not work:</p><p>
- </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>literals</p></li><li class="listitem"><p>function pointers</p></li><li class="listitem"><p>bind</p></li><li class="listitem"><p>->*</p></li></ul></div><p>
- </p><p>MSM also provides placeholders which make more sense in its context
- than arg1.. argn:</p><p>
- </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>_event: the event triggering the transition</p></li><li class="listitem"><p>_fsm: the state machine processing the event</p></li><li class="listitem"><p>_source: the source state of the transition</p></li><li class="listitem"><p>_target: the target state of the transition</p></li><li class="listitem"><p>_state: for state entry/exit actions, the entry/exit
- state</p></li></ul></div><p>
- </p><p>Future versions of MSM will support Phoenix better. You can contribute
- by finding out cases which do not work but should, so that they can be
- added.</p><p>Phoenix support is not activated by default. To activate it, add
- before any MSM header: #define BOOST_MSM_EUML_PHOENIX_SUPPORT.</p><p>A <a class="link" href="examples/SimplePhoenix.cpp" target="_top">simple example</a> shows some basic capabilities.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03s03.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch03.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch03s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Functor front-end </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Back-end</td></tr></table></div></body></html>
|