diff options
Diffstat (limited to 'libs/msm/doc/HTML/ch03s04.html')
-rw-r--r-- | libs/msm/doc/HTML/ch03s04.html | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/libs/msm/doc/HTML/ch03s04.html b/libs/msm/doc/HTML/ch03s04.html new file mode 100644 index 0000000000..f70bd93ab4 --- /dev/null +++ b/libs/msm/doc/HTML/ch03s04.html @@ -0,0 +1,487 @@ +<html><head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> + <title>eUML (experimental)</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 (experimental)</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 (experimental)"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e1361"></a><span class="command"><strong><a name="eUML-front-end"></a></strong></span>eUML (experimental)</h2></div></div></div><p><span class="underline">Important note</span>: eUML requires a compiler + supporting Boost.Typeof. More generally, eUML has experimental status 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="d0e1394"></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="d0e1435"></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.</p><p>The <a class="link" href="examples/CompositeTutorialWithEumlTable.cpp" target="_top">composite</a> implementation is slightly trickier because the submachine + has to be a msm::back::state_machine and a msm::front::euml::state. For + example:</p><pre class="programlisting">// front-end like always +struct front_end : public boost::msm::front::state_machine_def<front_end> +{ +... +}; +// back-end like always +typedef boost::msm::back::state_machine<front_end> back_end; +// this is new: make the submachine a eUML type +struct submachine : public back_end, + public boost::msm::front::euml::euml_state<back_end> +{ +};</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="d0e1466"></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="d0e1469"></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="d0e1500"></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="d0e1523"></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="d0e1579"></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="d0e1627"></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="d0e1643"></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="d0e1743"></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="d0e1855"></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="d0e1890"></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="d0e1908"></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="Other state types"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1939"></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="d0e2003"></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="d0e2106"></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="d0e2159"></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>
\ No newline at end of file |