statemap.h
Go to the documentation of this file.
00001 #ifndef _H_STATEMAP
00002 #define _H_STATEMAP
00003 
00004 //
00005 // The contents of this file are subject to the Mozilla Public
00006 // License Version 1.1 (the "License"); you may not use this file
00007 // except in compliance with the License. You may obtain a copy
00008 // of the License at http://www.mozilla.org/MPL/
00009 // 
00010 // Software distributed under the License is distributed on an
00011 // "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00012 // implied. See the License for the specific language governing
00013 // rights and limitations under the License.
00014 // 
00015 // The Original Code is State Machine Compiler (SMC).
00016 // 
00017 // The Initial Developer of the Original Code is Charles W. Rapp.
00018 // Portions created by Charles W. Rapp are
00019 // Copyright (C) 2000 - 2007. Charles W. Rapp.
00020 // All Rights Reserved.
00021 //
00022 // Contributor(s): 
00023 //
00024 // Namespace
00025 //      statemap
00026 //
00027 // Description
00028 //  This namespace contains the finite state machine context
00029 //  class. The user can derive FSM contexts from this class and
00030 //  interface to them with the methods of this class.
00031 //
00032 // Notes
00033 //  The finite state machine needs to be initialized to the
00034 //  starting state of the FSM.  This must be done manually in
00035 //  the constructor of the derived class. 
00036 //
00037 // Author
00038 //      C. W. Rapp
00039 //
00040 // RCS ID
00041 // $Id: statemap.h,v 1.15 2009/11/24 20:42:39 cwrapp Exp $
00042 //
00043 // CHANGE LOG
00044 // (See bottom of file)
00045 //
00046 
00047 #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
00048 #include <iostream>
00049 #if defined(SMC_NO_EXCEPTIONS)
00050 #include <cassert>
00051 #endif // SMC_NO_EXCEPTIONS
00052 #include <cstdio>
00053 #elif defined(WIN32)
00054 #include <iostream>
00055 #include <windows.h>
00056 #if defined(SMC_NO_EXCEPTIONS)
00057 #include <cassert>
00058 #endif // SMC_NO_EXCEPTIONS
00059 #else
00060 #include <iostream.h>
00061 #if defined(SMC_NO_EXCEPTIONS)
00062 #include <assert.h>
00063 #endif // SMC_NO_EXCEPTIONS
00064 #include <stdio.h>
00065 #endif
00066 #if ! defined(SMC_NO_EXCEPTIONS)
00067 #include <stdexcept>
00068 #include <cstring>
00069 #endif
00070 
00071 // Limit names to 100 ASCII characters.
00072 // Why 100? Because it is a round number.
00073 #define MAX_NAME_LEN 100
00074 
00075 namespace statemap
00076 {
00077 //---------------------------------------------------------------
00078 // Routines.
00079 //
00080 
00081     inline char* copyString(const char *s)
00082     {
00083         char *retval = NULL;
00084 
00085         if (s != NULL)
00086         {
00087             retval = new char[MAX_NAME_LEN + 1];
00088             retval[MAX_NAME_LEN] = '\0';
00089             (void) std::strncpy(retval, s, MAX_NAME_LEN);
00090         }
00091 
00092         return (retval);
00093     }
00094 
00095 //---------------------------------------------------------------
00096 // Exception Classes.
00097 //
00098 
00099 #ifndef SMC_NO_EXCEPTIONS
00100     // Base class for all SMC exceptions.
00101     class SmcException :
00102         public std::runtime_error
00103     {
00104     //-----------------------------------------------------------
00105     // Member methods
00106     //
00107     public:
00108 
00109         // Destructor.
00110         virtual ~SmcException() throw()
00111         {};
00112 
00113     protected:
00114 
00115         // Constructor.
00116         SmcException(const std::string& reason)
00117         : std::runtime_error(reason)
00118         {};
00119 
00120     private:
00121 
00122         // Default construction not allowed.
00123         SmcException();
00124 
00125     //-----------------------------------------------------------
00126     // Member data.
00127     //
00128     public:
00129     protected:
00130     private:
00131     };
00132 
00133     // This class is thrown when a pop is issued on an empty
00134     // state stack.
00135     class PopOnEmptyStateStackException :
00136         public SmcException
00137     {
00138     //-----------------------------------------------------------
00139     // Member methods.
00140     //
00141     public:
00142 
00143         // Default constructor.
00144         PopOnEmptyStateStackException()
00145         : SmcException("no state to pop from state stack")
00146         {};
00147 
00148         // Destructor.
00149         virtual ~PopOnEmptyStateStackException() throw()
00150         {};
00151 
00152     protected:
00153     private:
00154 
00155     //-----------------------------------------------------------
00156     // Member data.
00157     //
00158     public:
00159     protected:
00160     private:
00161     };
00162 
00163     // This class is thrown when a transition is issued
00164     // but there is no current state. This happens when
00165     // a transition is issued from within a transition
00166     // action.
00167     class StateUndefinedException :
00168         public SmcException
00169     {
00170     //-----------------------------------------------------------
00171     // Member methods.
00172     //
00173     public:
00174 
00175         // Default constructor.
00176         StateUndefinedException()
00177         : SmcException("transition invoked while in transition")
00178         {};
00179 
00180         // Destructor.
00181         virtual ~StateUndefinedException() throw()
00182         {};
00183 
00184     protected:
00185     private:
00186 
00187     //-----------------------------------------------------------
00188     // Member data.
00189     //
00190     public:
00191     protected:
00192     private:
00193     };
00194 
00195     // This class is thrown when a transition is issued
00196     // but there is no code to handle it.
00197     class TransitionUndefinedException :
00198         public SmcException
00199     {
00200     //-----------------------------------------------------------
00201     // Member methods.
00202     //
00203     public:
00204 
00205         // Default constructor.
00206         TransitionUndefinedException()
00207         : SmcException("no such transition in current state"),
00208           _state(NULL),
00209           _transition(NULL)
00210         {};
00211 
00212         // Construct an exception using the specified state
00213         // and transition.
00214         TransitionUndefinedException(const char *state,
00215                                      const char *transition)
00216         : SmcException("no such transition in current state"),
00217           _state(copyString(state)),
00218           _transition(copyString(transition))
00219         {};
00220 
00221         // Copy constructor.
00222         TransitionUndefinedException(
00223             const TransitionUndefinedException& ex)
00224         : SmcException("no such transition in current state"),
00225           _state(copyString(ex._state)),
00226           _transition(copyString(ex._transition))
00227         {};
00228 
00229         // Destructor.
00230         virtual ~TransitionUndefinedException() throw()
00231         {
00232             if (_state != NULL)
00233             {
00234                 delete[] _state;
00235                 _state = NULL;
00236             }
00237 
00238             if (_transition != NULL)
00239             {
00240                 delete[] _transition;
00241                 _transition = NULL;
00242             }
00243         };
00244 
00245         // Assignment operator.
00246         const TransitionUndefinedException&
00247             operator=(const TransitionUndefinedException& ex)
00248         {
00249             // Don't do self assignment.
00250             if (this != &ex)
00251             {
00252                 if (_state != NULL)
00253                 {
00254                     delete[] _state;
00255                     _state = NULL;
00256                 }
00257 
00258                 if (_transition != NULL)
00259                 {
00260                     delete[] _transition;
00261                     _transition = NULL;
00262                 }
00263 
00264                 _state = copyString(ex._state);
00265                 _transition = copyString(ex._transition);
00266             }
00267 
00268             return (*this);
00269         };
00270 
00271         // Returns the state. May be NULL.
00272         const char* getState() const
00273         {
00274             return(_state);
00275         };
00276 
00277         // Returns the transition. May be NULL.
00278         const char* getTransition() const
00279         {
00280             return (_transition);
00281         };
00282 
00283     protected:
00284     private:
00285 
00286     //-----------------------------------------------------------
00287     // Member data.
00288     //
00289     public:
00290     protected:
00291     private:
00292 
00293                 char *_state;
00294                 char *_transition;
00295     };
00296 
00297     // This class is thrown when a state ID is either less than
00298     // the minimal value or greater than the maximal value.
00299     class IndexOutOfBoundsException :
00300         public SmcException
00301     {
00302     //-----------------------------------------------------------
00303     // Member methods.
00304     //
00305     public:
00306 
00307         // Default constructor.
00308         IndexOutOfBoundsException()
00309         : SmcException("index out of bounds"),
00310           _index(0),
00311           _minIndex(0),
00312           _maxIndex(0)
00313         {};
00314 
00315         // Constructs an exception using the specified index,
00316         // minimum index and maximum index.
00317         IndexOutOfBoundsException(const int index,
00318                                   const int minIndex,
00319                                   const int maxIndex)
00320         : SmcException("index out of bounds"),
00321           _index(index),
00322           _minIndex(minIndex),
00323           _maxIndex(maxIndex)
00324         {};
00325 
00326         // Copy constructor.
00327         IndexOutOfBoundsException(
00328             const IndexOutOfBoundsException& ex)
00329         : SmcException("index out of bounds"),
00330           _index(ex._index),
00331           _minIndex(ex._minIndex),
00332           _maxIndex(ex._maxIndex)
00333         {};
00334 
00335         // Destructor.
00336         virtual ~IndexOutOfBoundsException() throw()
00337         {};
00338 
00339         // Assignment operator.
00340         const IndexOutOfBoundsException&
00341             operator=(const IndexOutOfBoundsException& ex)
00342         {
00343             // Don't do self assignment.
00344             if (this != &ex)
00345             {
00346                 _index = ex._index;
00347                 _minIndex = ex._minIndex;
00348                 _maxIndex = ex._maxIndex;
00349             }
00350 
00351             return (*this);
00352         };
00353 
00354         // Returns the out-of-bounds index.
00355         int getIndex() const
00356         {
00357             return(_index);
00358         };
00359 
00360         // Returns the minimum allowed index value.
00361         int getMinIndex() const
00362         {
00363             return (_minIndex);
00364         };
00365 
00366         // Returns the maximum allowed index value.
00367         int getMaxIndex() const
00368         {
00369             return (_maxIndex);
00370         };
00371 
00372     protected:
00373     private:
00374 
00375     //-----------------------------------------------------------
00376     // Member data.
00377     //
00378     public:
00379     protected:
00380     private:
00381 
00382                 int _index;
00383                 int _minIndex;
00384         int _maxIndex;
00385     };
00386 #endif // !SMC_NO_EXCEPTIONS
00387 
00388 //
00389 // end of Exception Classes.
00390 //---------------------------------------------------------------
00391 
00392     class State
00393     {
00394     //-----------------------------------------------------------
00395     // Member functions.
00396     //
00397     public:
00398 
00399         const char* getName() const
00400         {
00401             return (_name);
00402         };
00403 
00404         int getId() const
00405         {
00406             return (_stateId);
00407         }
00408 
00409     protected:
00410 
00411         State(const char *name, int stateId)
00412         : _name(NULL),
00413           _stateId(stateId)
00414         {
00415             if (name != NULL)
00416             {
00417                 _name = copyString(name);
00418             }
00419             else
00420             {
00421                 _name = copyString("NAME NOT SET");
00422             }
00423         };
00424 
00425         virtual ~State()
00426         {
00427             if (_name != NULL)
00428             {
00429                 delete[] _name;
00430                 _name = NULL;
00431             }
00432         };
00433 
00434     private:
00435 
00436         // Make the default and copy constructors private to
00437         // prevent their use.
00438         State() {};
00439         State(const State&) {};
00440 
00441     //-----------------------------------------------------------
00442     // Member data.
00443     //
00444     public:
00445     protected:
00446 
00447         // This state's printable name.
00448         char *_name;
00449 
00450         // This state's unique identifier.
00451         int _stateId;
00452 
00453     private:
00454     };
00455 
00456     class FSMContext
00457     {
00458     //-----------------------------------------------------------
00459     // Nested classes.
00460     //
00461     public:
00462     protected:
00463     private:
00464 
00465         // Implements the state stack.
00466         class StateEntry
00467         {
00468         //-------------------------------------------------------
00469         // Member functions.
00470         //
00471         public:
00472             StateEntry(State *state, StateEntry *next)
00473             : _state(state),
00474               _next(next)
00475             {};
00476 
00477             ~StateEntry()
00478             {
00479                 _state = NULL;
00480                 _next = NULL;
00481             };
00482 
00483             State* getState()
00484             {
00485                 return(_state);
00486             };
00487 
00488             StateEntry* getNext()
00489             {
00490                 return(_next);
00491             };
00492 
00493         protected:
00494         private:
00495 
00496         //-------------------------------------------------------
00497         // Member data.
00498         //
00499         public:
00500         protected:
00501         private:
00502             State *_state;
00503             StateEntry *_next;
00504 
00505         //-------------------------------------------------------
00506         // Friends
00507         //
00508             friend class FSMContext;
00509         }; // end of class StateEntry
00510 
00511     //-----------------------------------------------------------
00512     // Member functions
00513     //
00514     public:
00515 
00516         // Destructor.
00517         virtual ~FSMContext()
00518         {
00519             StateEntry *state;
00520 
00521             if (_transition != NULL)
00522             {
00523                 delete[] _transition;
00524                 _transition = NULL;
00525             }
00526 
00527             // But we did allocate the state stack.
00528             while (_state_stack != NULL)
00529             {
00530                 state = _state_stack;
00531                 _state_stack = _state_stack->_next;
00532                 delete state;
00533             }
00534         };
00535 
00536         // Comparison and assignment operators
00537         // Assignment operator
00538         FSMContext& operator=(const FSMContext& fsm)
00539         {
00540             // Don't do the assignment if the left and right
00541             // hand sides are the same object.
00542             if (this != &fsm)
00543             {
00544                 _state = fsm._state;
00545             }
00546 
00547             return(*this);
00548         };
00549 
00550         // Starts the finite state machine running by executing
00551         // the initial state's entry actions.
00552         virtual void enterStartState()=0;
00553 
00554         // Exact same object (is it me?)
00555         int same(const FSMContext& fsm) const
00556         {
00557             return(this == &fsm);
00558         };
00559 
00560         // Returns the debug flag's current setting.
00561         bool getDebugFlag()
00562         {
00563             return(_debug_flag);
00564         };
00565 
00566         // Sets the debug flag. A true value means debugging
00567         // is on and false means off.
00568         void setDebugFlag(bool flag)
00569         {
00570             _debug_flag = flag;
00571             return;
00572         };
00573 
00574 #ifdef SMC_USES_IOSTREAMS
00575         // Returns the stream to which debug output is written.
00576         std::ostream& getDebugStream()
00577         {
00578             return (*_debug_stream);
00579         };
00580 
00581         // Sets the debug output stream.
00582         void setDebugStream(std::ostream& debug_stream)
00583         {
00584             _debug_stream = &debug_stream;
00585             return;
00586         }
00587 #endif // SMC_USES_IOSTREAMS
00588 
00589         // Is this state machine already inside a transition?
00590         // Yes if state is null.
00591         bool isInTransition() const
00592         {
00593             return(_state == NULL ? true : false);
00594         };
00595 
00596         // Returns the current transition's name.
00597         // Used only for debugging purposes.
00598         char* getTransition()
00599         {
00600             return (_transition);
00601         };
00602 
00603         // Saves away the transition name only if debugging
00604         // is turned on.
00605         void setTransition(const char *transition)
00606         {
00607             if (_transition != NULL)
00608             {
00609                 delete[] _transition;
00610                 _transition = NULL;
00611             }
00612 
00613             _transition = copyString(transition);
00614 
00615             return;
00616         };
00617 
00618         // Clears the current state.
00619         void clearState()
00620         {
00621             _previous_state = _state;
00622             _state = NULL;
00623         };
00624 
00625         // Returns the state which a transition left.
00626         // May be NULL.
00627         State* getPreviousState()
00628         {
00629             return (_previous_state);
00630         }
00631 
00632         // Sets the current state to the specified state.
00633         void setState(const State& state)
00634         {
00635             _state = const_cast<State *>(&state);
00636 
00637             if (_debug_flag == true)
00638             {
00639 #ifdef SMC_USES_IOSTREAMS
00640                 *_debug_stream << "ENTER STATE     : "
00641                                << _state->getName()
00642                                << std::endl;
00643 #else
00644                 TRACE("ENTER STATE     : %s\n\r",
00645                       _state->getName());
00646 #endif // SMC_USES_IOSTREAMS
00647             }
00648         };
00649 
00650         // Returns true if the state stack is empty and false
00651         // otherwise.
00652         bool isStateStackEmpty() const
00653         {
00654             return (_state_stack == NULL);
00655         }
00656 
00657         // Returns the state stack's depth.
00658         int getStateStackDepth() const
00659         {
00660             StateEntry *state_ptr;
00661             int retval;
00662 
00663             for (state_ptr = _state_stack, retval = 0;
00664                  state_ptr != NULL;
00665                  state_ptr = state_ptr->getNext(), ++retval)
00666                 ;
00667 
00668             return (retval);
00669         }
00670 
00671         // Push the current state on top of the state stack
00672         // and make the specified state the current state.
00673         void pushState(const State& state)
00674         {
00675             StateEntry *new_entry;
00676 
00677             // Do the push only if there is a state to be pushed
00678             // on the stack.
00679             if (_state != NULL)
00680             {
00681                 new_entry = new StateEntry(_state, _state_stack);
00682                 _state_stack = new_entry;
00683             }
00684 
00685             _state = const_cast<State *>(&state);
00686 
00687             if (_debug_flag == true)
00688             {
00689 #ifdef SMC_USES_IOSTREAMS
00690                 *_debug_stream << "PUSH TO STATE   : "
00691                                << _state->getName()
00692                                << std::endl;
00693 #else
00694                 TRACE("PUSH TO STATE   : %s\n\r",
00695                       _state->getName());
00696 #endif // SMC_USES_IOSTREAMS
00697             }
00698         };
00699 
00700         // Make the state on top of the state stack the
00701         // current state.
00702         void popState()
00703         {
00704             StateEntry *entry;
00705 
00706             // Popping when there was no previous push is an error.
00707 #ifdef SMC_NO_EXCEPTIONS
00708             assert(_state_stack != NULL);
00709 #else
00710             if (_state_stack == NULL)
00711             {
00712                 throw PopOnEmptyStateStackException();
00713             }
00714 #endif // SMC_NO_EXCEPTIONS
00715 
00716             _state = _state_stack->getState();
00717             entry = _state_stack;
00718             _state_stack = _state_stack->getNext();
00719             delete entry;
00720 
00721             if (_debug_flag == true)
00722             {
00723 #ifdef SMC_USES_IOSTREAMS
00724                 *_debug_stream << "POP TO STATE    : "
00725                                << _state->getName()
00726                                << std::endl;
00727 #else
00728                 TRACE("POP TO STATE    : %s\n\r",
00729                       _state->getName());
00730 #endif // SMC_USES_IOSTREAMS
00731             }
00732         };
00733 
00734         // Remove all states from the state stack.
00735         void emptyStateStack()
00736         {
00737             StateEntry *state_ptr,
00738                        *next_ptr;
00739 
00740             for (state_ptr = _state_stack;
00741                  state_ptr != NULL;
00742                  state_ptr = next_ptr)
00743             {
00744                 next_ptr = state_ptr->getNext();
00745                 delete state_ptr;
00746             }
00747 
00748             _state_stack = NULL;
00749         };
00750 
00751     protected:
00752 
00753         // Default constructor.
00754         FSMContext(const State& state)
00755         : _state(const_cast<State *>(&state)),
00756           _previous_state(NULL),
00757           _state_stack(NULL),
00758           _transition(NULL),
00759 #ifdef SMC_USES_IOSTREAMS
00760           _debug_flag(false),
00761           _debug_stream(&std::cerr)
00762 #else
00763           _debug_flag(false)
00764 #endif // SMC_USES_IOSTREAMS
00765         {};
00766 
00767     private:
00768 
00769         // I don't believe that it makes sense to copy a
00770         // context. It may make sense to copy the application
00771         // class but the new object is *not* in the same
00772         // state as the old - the new object must start in
00773         // the FSM's initial state. Therefore, the copy
00774         // constructor is private in order to prevent it
00775         // being used.
00776         FSMContext(const FSMContext&)
00777         {};
00778 
00779     //-----------------------------------------------------------
00780     // Member data
00781     //
00782     public:
00783     protected:
00784 
00785         // The current state of the finite state machine.
00786         State *_state;
00787 
00788         // Remember which state a transition left.
00789         State *_previous_state;
00790 
00791         // The stack of pushed states.
00792         StateEntry *_state_stack;
00793 
00794         // The current transition *name*. Use for debugging
00795         // purposes.
00796         char *_transition;
00797 
00798     private:
00799 
00800         // When this flag is set to true, this class will print
00801         // out debug messages.
00802         bool _debug_flag;
00803 
00804 // Include the following only if C++ iostreams are being used.
00805 #ifdef SMC_USES_IOSTREAMS
00806         // When FSM debugging is on, debug messages will be
00807         // written to this output stream. This stream is set to
00808         // standard error by default.
00809         std::ostream *_debug_stream;
00810 #endif // SMC_USES_IOSTREAMS
00811 
00812     }; // end of class FSMContext
00813 }
00814 
00815 //
00816 // CHANGE LOG
00817 // $Log: statemap.h,v $
00818 // Revision 1.15  2009/11/24 20:42:39  cwrapp
00819 // v. 6.0.1 update
00820 //
00821 // Revision 1.14  2009/03/01 18:20:40  cwrapp
00822 // Preliminary v. 6.0.0 commit.
00823 //
00824 // Revision 1.13  2008/05/20 18:31:12  cwrapp
00825 // ----------------------------------------------------------------------
00826 //
00827 // Committing release 5.1.0.
00828 //
00829 // Modified Files:
00830 //      Makefile README.txt smc.mk tar_list.txt bin/Smc.jar
00831 //      examples/Ant/EX1/build.xml examples/Ant/EX2/build.xml
00832 //      examples/Ant/EX3/build.xml examples/Ant/EX4/build.xml
00833 //      examples/Ant/EX5/build.xml examples/Ant/EX6/build.xml
00834 //      examples/Ant/EX7/build.xml examples/Ant/EX7/src/Telephone.java
00835 //      examples/Java/EX1/Makefile examples/Java/EX4/Makefile
00836 //      examples/Java/EX5/Makefile examples/Java/EX6/Makefile
00837 //      examples/Java/EX7/Makefile examples/Ruby/EX1/Makefile
00838 //      lib/statemap.jar lib/C++/statemap.h lib/Java/Makefile
00839 //      lib/Php/statemap.php lib/Scala/Makefile
00840 //      lib/Scala/statemap.scala net/sf/smc/CODE_README.txt
00841 //      net/sf/smc/README.txt net/sf/smc/Smc.java
00842 // ----------------------------------------------------------------------
00843 //
00844 // Revision 1.12  2007/12/28 12:34:40  cwrapp
00845 // Version 5.0.1 check-in.
00846 //
00847 // Revision 1.11  2007/08/05 12:58:54  cwrapp
00848 // Version 5.0.1 check-in. See net/sf/smc/CODE_README.txt for more information.
00849 //
00850 // Revision 1.10  2007/01/15 00:23:50  cwrapp
00851 // Release 4.4.0 initial commit.
00852 //
00853 // Revision 1.9  2006/07/11 18:28:22  cwrapp
00854 // Move SmcException::copyString() to a package-wide routine.
00855 //
00856 // Revision 1.8  2006/04/22 12:45:24  cwrapp
00857 // Version 4.3.1
00858 //
00859 // Revision 1.7  2005/06/08 11:09:14  cwrapp
00860 // + Updated Python code generator to place "pass" in methods with empty
00861 //   bodies.
00862 // + Corrected FSM errors in Python example 7.
00863 // + Removed unnecessary includes from C++ examples.
00864 // + Corrected errors in top-level makefile's distribution build.
00865 //
00866 // Revision 1.6  2005/05/28 18:44:13  cwrapp
00867 // Updated C++, Java and Tcl libraries, added CSharp, Python and VB.
00868 //
00869 // Revision 1.2  2005/02/21 19:01:42  charlesr
00870 // Changed State::_id to State::_stateId because of Object-C++
00871 // reserved word conflict.
00872 //
00873 // Revision 1.1  2004/05/31 13:44:41  charlesr
00874 // Added support for non-iostreams output.
00875 //
00876 // Revision 1.0  2003/12/14 20:37:49  charlesr
00877 // Initial revision
00878 
00879 #endif


smclib
Author(s): Various
autogenerated on Fri Aug 28 2015 10:10:52