Program Listing for File statemap.hpp
↰ Return to documentation for file (include/smclib/statemap.hpp
)
// Copyright (C) 2000 - 2007. Charles W. Rapp.
// All Rights Reserved.
//
// The contents of this file are subject to the Mozilla Public
// License Version 1.1 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy
// of the License at http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is State Machine Compiler (SMC).
//
// The Initial Developer of the Original Code is Charles W. Rapp.
// Portions created by Charles W. Rapp are
// Copyright (C) 2000 - 2007. Charles W. Rapp.
// All Rights Reserved.
//
// Contributor(s):
//
// Namespace
// statemap
//
// Description
// This namespace contains the finite state machine context
// class. The user can derive FSM contexts from this class and
// interface to them with the methods of this class.
//
// Notes
// The finite state machine needs to be initialized to the
// starting state of the FSM. This must be done manually in
// the constructor of the derived class.
//
// Author
// C. W. Rapp
//
// RCS ID
// $Id: statemap.h,v 1.15 2009/11/24 20:42:39 cwrapp Exp $
//
// CHANGE LOG
// (See bottom of file)
//
#ifndef SMCLIB__STATEMAP_HPP_
#define SMCLIB__STATEMAP_HPP_
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#if defined(SMC_NO_EXCEPTIONS)
#include <cassert>
#endif // SMC_NO_EXCEPTIONS
#include <cstdio>
#elif defined(WIN32)
#include <windows.h>
#if defined(SMC_NO_EXCEPTIONS)
#include <cassert>
#endif // SMC_NO_EXCEPTIONS
#else
#if defined(SMC_NO_EXCEPTIONS)
#include <assert.h>
#endif // SMC_NO_EXCEPTIONS
#include <stdio.h>
#endif
#if !defined(SMC_NO_EXCEPTIONS)
#include <stdexcept>
#include <cstring>
#endif
#include <string>
#include <iostream>
// Limit names to 100 ASCII characters.
// Why 100? Because it is a round number.
#define MAX_NAME_LEN 100
// using namespace std;
namespace statemap
{
// ---------------------------------------------------------------
// Routines.
//
inline char * copyString(const char * s)
{
char * retval = NULL;
if (s != NULL) {
retval = new char[MAX_NAME_LEN + 1];
retval[MAX_NAME_LEN] = '\0';
(void) std::strncpy(retval, s, MAX_NAME_LEN);
}
return retval;
}
// ---------------------------------------------------------------
// Exception Classes.
//
#ifndef SMC_NO_EXCEPTIONS
// Base class for all SMC exceptions.
class SmcException
: public std::runtime_error
{
// -----------------------------------------------------------
// Member methods
//
public:
protected:
// Constructor.
explicit SmcException(const std::string & reason)
: std::runtime_error(reason)
{}
private:
// Default construction not allowed.
SmcException();
// -----------------------------------------------------------
// Member data.
//
public:
protected:
private:
};
// This class is thrown when a pop is issued on an empty
// state stack.
class PopOnEmptyStateStackException
: public SmcException
{
// -----------------------------------------------------------
// Member methods.
//
public:
// Default constructor.
PopOnEmptyStateStackException()
: SmcException("no state to pop from state stack")
{}
protected:
private:
// -----------------------------------------------------------
// Member data.
//
public:
protected:
private:
};
// This class is thrown when a transition is issued
// but there is no current state. This happens when
// a transition is issued from within a transition
// action.
class StateUndefinedException
: public SmcException
{
// -----------------------------------------------------------
// Member methods.
//
public:
// Default constructor.
StateUndefinedException()
: SmcException("transition invoked while in transition")
{}
protected:
private:
// -----------------------------------------------------------
// Member data.
//
public:
protected:
private:
};
// This class is thrown when a transition is issued
// but there is no code to handle it.
class TransitionUndefinedException
: public SmcException
{
// -----------------------------------------------------------
// Member methods.
//
public:
// Default constructor.
TransitionUndefinedException()
: SmcException("no such transition in current state"),
_state(NULL),
_transition(NULL)
{}
// Construct an exception using the specified state
// and transition.
TransitionUndefinedException(
const char * state,
const char * transition)
: SmcException("no such transition in current state"),
_state(copyString(state)),
_transition(copyString(transition))
{}
// Copy constructor.
TransitionUndefinedException(
const TransitionUndefinedException & ex)
: SmcException("no such transition in current state"),
_state(copyString(ex._state)),
_transition(copyString(ex._transition))
{}
// Destructor.
virtual ~TransitionUndefinedException() noexcept
{
if (_state != NULL) {
delete[] _state;
_state = NULL;
}
if (_transition != NULL) {
delete[] _transition;
_transition = NULL;
}
}
// Assignment operator.
const TransitionUndefinedException &
operator=(const TransitionUndefinedException & ex)
{
// Don't do self assignment.
if (this != &ex) {
if (_state != NULL) {
delete[] _state;
_state = NULL;
}
if (_transition != NULL) {
delete[] _transition;
_transition = NULL;
}
_state = copyString(ex._state);
_transition = copyString(ex._transition);
}
return *this;
}
// Returns the state. May be NULL.
const char * getState() const
{
return _state;
}
// Returns the transition. May be NULL.
const char * getTransition() const
{
return _transition;
}
protected:
private:
// -----------------------------------------------------------
// Member data.
//
public:
protected:
private:
char * _state;
char * _transition;
};
// This class is thrown when a state ID is either less than
// the minimal value or greater than the maximal value.
class IndexOutOfBoundsException
: public SmcException
{
// -----------------------------------------------------------
// Member methods.
//
public:
// Default constructor.
IndexOutOfBoundsException()
: SmcException("index out of bounds"),
_index(0),
_minIndex(0),
_maxIndex(0)
{}
// Constructs an exception using the specified index,
// minimum index and maximum index.
IndexOutOfBoundsException(
const int index,
const int minIndex,
const int maxIndex)
: SmcException("index out of bounds"),
_index(index),
_minIndex(minIndex),
_maxIndex(maxIndex)
{}
// Copy constructor.
IndexOutOfBoundsException(
const IndexOutOfBoundsException & ex)
: SmcException("index out of bounds"),
_index(ex._index),
_minIndex(ex._minIndex),
_maxIndex(ex._maxIndex)
{}
// Destructor.
virtual ~IndexOutOfBoundsException() noexcept
{}
// Assignment operator.
const IndexOutOfBoundsException &
operator=(const IndexOutOfBoundsException & ex)
{
// Don't do self assignment.
if (this != &ex) {
_index = ex._index;
_minIndex = ex._minIndex;
_maxIndex = ex._maxIndex;
}
return *this;
}
// Returns the out-of-bounds index.
int getIndex() const
{
return _index;
}
// Returns the minimum allowed index value.
int getMinIndex() const
{
return _minIndex;
}
// Returns the maximum allowed index value.
int getMaxIndex() const
{
return _maxIndex;
}
protected:
private:
// -----------------------------------------------------------
// Member data.
//
public:
protected:
private:
int _index;
int _minIndex;
int _maxIndex;
};
#endif // !SMC_NO_EXCEPTIONS
//
// end of Exception Classes.
//---------------------------------------------------------------
class State
{
//-----------------------------------------------------------
// Member functions.
//
public:
const char * getName() const
{
return _name;
}
int getId() const
{
return _stateId;
}
protected:
State(const char * name, int stateId)
: _name(NULL),
_stateId(stateId)
{
if (name != NULL) {
_name = copyString(name);
} else {
_name = copyString("NAME NOT SET");
}
}
virtual ~State()
{
if (_name != NULL) {
delete[] _name;
_name = NULL;
}
}
private:
// Make the default and copy constructors private to
// prevent their use.
State() {}
State(const State &) {}
// -----------------------------------------------------------
// Member data.
//
public:
protected:
// This state's printable name.
char * _name;
// This state's unique identifier.
int _stateId;
private:
};
class FSMContext
{
//-----------------------------------------------------------
// Nested classes.
//
public:
protected:
private:
// Implements the state stack.
class StateEntry
{
//-------------------------------------------------------
// Member functions.
//
public:
StateEntry(State * state, StateEntry * next)
: _state(state),
_next(next)
{}
~StateEntry()
{
_state = NULL;
_next = NULL;
}
State * getState()
{
return _state;
}
StateEntry * getNext()
{
return _next;
}
protected:
private:
//-------------------------------------------------------
// Member data.
//
public:
protected:
private:
State * _state;
StateEntry * _next;
//-------------------------------------------------------
// Friends
//
friend class FSMContext;
}; // end of class StateEntry
// -----------------------------------------------------------
// Member functions
//
public:
// Destructor.
virtual ~FSMContext()
{
StateEntry * state;
if (_transition != NULL) {
delete[] _transition;
_transition = NULL;
}
// But we did allocate the state stack.
while (_state_stack != NULL) {
state = _state_stack;
_state_stack = _state_stack->_next;
delete state;
}
}
// Comparison and assignment operators
// Assignment operator
FSMContext & operator=(const FSMContext & fsm)
{
// Don't do the assignment if the left and right
// hand sides are the same object.
if (this != &fsm) {
_state = fsm._state;
}
return *this;
}
// Starts the finite state machine running by executing
// the initial state's entry actions.
virtual void enterStartState() = 0;
// Exact same object (is it me?)
int same(const FSMContext & fsm) const
{
return this == &fsm;
}
// Returns the debug flag's current setting.
bool getDebugFlag()
{
return _debug_flag;
}
// Sets the debug flag. A true value means debugging
// is on and false means off.
void setDebugFlag(bool flag)
{
_debug_flag = flag;
}
#ifdef SMC_USES_IOSTREAMS
// Returns the stream to which debug output is written.
std::ostream & getDebugStream()
{
return *_debug_stream;
}
// Sets the debug output stream.
void setDebugStream(std::ostream & debug_stream)
{
_debug_stream = &debug_stream;
}
#endif // SMC_USES_IOSTREAMS
// Is this state machine already inside a transition?
// Yes if state is null.
bool isInTransition() const
{
return _state == NULL ? true : false;
}
// Returns the current transition's name.
// Used only for debugging purposes.
char * getTransition()
{
return _transition;
}
// Saves away the transition name only if debugging
// is turned on.
void setTransition(const char * transition)
{
if (_transition != NULL) {
delete[] _transition;
_transition = NULL;
}
_transition = copyString(transition);
}
// Clears the current state.
void clearState()
{
_previous_state = _state;
_state = NULL;
}
// Returns the state which a transition left.
// May be NULL.
State * getPreviousState()
{
return _previous_state;
}
// Sets the current state to the specified state.
void setState(const State & state)
{
_state = const_cast<State *>(&state);
if (_debug_flag == true) {
#ifdef SMC_USES_IOSTREAMS
*_debug_stream << "ENTER STATE : " <<
_state->getName() <<
std::endl;
#else
TRACE(
"ENTER STATE : %s\n\r",
_state->getName());
#endif // SMC_USES_IOSTREAMS
}
}
// Returns true if the state stack is empty and false
// otherwise.
bool isStateStackEmpty() const
{
return _state_stack == NULL;
}
// Returns the state stack's depth.
int getStateStackDepth() const
{
StateEntry * state_ptr;
int retval;
for (state_ptr = _state_stack, retval = 0;
state_ptr != NULL;
state_ptr = state_ptr->getNext(), ++retval) {}
return retval;
}
// Push the current state on top of the state stack
// and make the specified state the current state.
void pushState(const State & state)
{
StateEntry * new_entry;
// Do the push only if there is a state to be pushed
// on the stack.
if (_state != NULL) {
new_entry = new StateEntry(_state, _state_stack);
_state_stack = new_entry;
}
_state = const_cast<State *>(&state);
if (_debug_flag == true) {
#ifdef SMC_USES_IOSTREAMS
*_debug_stream << "PUSH TO STATE : " <<
_state->getName() <<
std::endl;
#else
TRACE(
"PUSH TO STATE : %s\n\r",
_state->getName());
#endif // SMC_USES_IOSTREAMS
}
}
// Make the state on top of the state stack the
// current state.
void popState()
{
StateEntry * entry;
// Popping when there was no previous push is an error.
#ifdef SMC_NO_EXCEPTIONS
assert(_state_stack != NULL);
#else
if (_state_stack == NULL) {
throw PopOnEmptyStateStackException();
}
#endif // SMC_NO_EXCEPTIONS
_state = _state_stack->getState();
entry = _state_stack;
_state_stack = _state_stack->getNext();
delete entry;
if (_debug_flag == true) {
#ifdef SMC_USES_IOSTREAMS
*_debug_stream << "POP TO STATE : " <<
_state->getName() <<
std::endl;
#else
TRACE(
"POP TO STATE : %s\n\r",
_state->getName());
#endif // SMC_USES_IOSTREAMS
}
}
// Remove all states from the state stack.
void emptyStateStack()
{
StateEntry * state_ptr,
* next_ptr;
for (state_ptr = _state_stack;
state_ptr != NULL;
state_ptr = next_ptr)
{
next_ptr = state_ptr->getNext();
delete state_ptr;
}
_state_stack = NULL;
}
protected:
// Default constructor.
explicit FSMContext(const State & state)
: _state(const_cast<State *>(&state)),
_previous_state(NULL),
_state_stack(NULL),
_transition(NULL),
#ifdef SMC_USES_IOSTREAMS
_debug_flag(false),
_debug_stream(&std::cerr)
#else
_debug_flag(false)
#endif // SMC_USES_IOSTREAMS
{}
private:
// I don't believe that it makes sense to copy a
// context. It may make sense to copy the application
// class but the new object is *not* in the same
// state as the old - the new object must start in
// the FSM's initial state. Therefore, the copy
// constructor is private in order to prevent it
// being used.
FSMContext(const FSMContext &)
{}
// -----------------------------------------------------------
// Member data
//
public:
protected:
// The current state of the finite state machine.
State * _state;
// Remember which state a transition left.
State * _previous_state;
// The stack of pushed states.
StateEntry * _state_stack;
// The current transition *name*. Use for debugging
// purposes.
char * _transition;
private:
// When this flag is set to true, this class will print
// out debug messages.
bool _debug_flag;
// Include the following only if C++ iostreams are being used.
#ifdef SMC_USES_IOSTREAMS
// When FSM debugging is on, debug messages will be
// written to this output stream. This stream is set to
// standard error by default.
std::ostream * _debug_stream;
#endif // SMC_USES_IOSTREAMS
}; // end of class FSMContext
} // namespace statemap
//
// CHANGE LOG
// $Log: statemap.h,v $
// Revision 1.15 2009/11/24 20:42:39 cwrapp
// v. 6.0.1 update
//
// Revision 1.14 2009/03/01 18:20:40 cwrapp
// Preliminary v. 6.0.0 commit.
//
// Revision 1.13 2008/05/20 18:31:12 cwrapp
// ----------------------------------------------------------------------
//
// Committing release 5.1.0.
//
// Modified Files:
// Makefile README.txt smc.mk tar_list.txt bin/Smc.jar
// examples/Ant/EX1/build.xml examples/Ant/EX2/build.xml
// examples/Ant/EX3/build.xml examples/Ant/EX4/build.xml
// examples/Ant/EX5/build.xml examples/Ant/EX6/build.xml
// examples/Ant/EX7/build.xml examples/Ant/EX7/src/Telephone.java
// examples/Java/EX1/Makefile examples/Java/EX4/Makefile
// examples/Java/EX5/Makefile examples/Java/EX6/Makefile
// examples/Java/EX7/Makefile examples/Ruby/EX1/Makefile
// lib/statemap.jar lib/C++/statemap.h lib/Java/Makefile
// lib/Php/statemap.php lib/Scala/Makefile
// lib/Scala/statemap.scala net/sf/smc/CODE_README.txt
// net/sf/smc/README.txt net/sf/smc/Smc.java
// ----------------------------------------------------------------------
//
// Revision 1.12 2007/12/28 12:34:40 cwrapp
// Version 5.0.1 check-in.
//
// Revision 1.11 2007/08/05 12:58:54 cwrapp
// Version 5.0.1 check-in. See net/sf/smc/CODE_README.txt for more information.
//
// Revision 1.10 2007/01/15 00:23:50 cwrapp
// Release 4.4.0 initial commit.
//
// Revision 1.9 2006/07/11 18:28:22 cwrapp
// Move SmcException::copyString() to a package-wide routine.
//
// Revision 1.8 2006/04/22 12:45:24 cwrapp
// Version 4.3.1
//
// Revision 1.7 2005/06/08 11:09:14 cwrapp
// + Updated Python code generator to place "pass" in methods with empty
// bodies.
// + Corrected FSM errors in Python example 7.
// + Removed unnecessary includes from C++ examples.
// + Corrected errors in top-level makefile's distribution build.
//
// Revision 1.6 2005/05/28 18:44:13 cwrapp
// Updated C++, Java and Tcl libraries, added CSharp, Python and VB.
//
// Revision 1.2 2005/02/21 19:01:42 charlesr
// Changed State::_id to State::_stateId because of Object-C++
// reserved word conflict.
//
// Revision 1.1 2004/05/31 13:44:41 charlesr
// Added support for non-iostreams output.
//
// Revision 1.0 2003/12/14 20:37:49 charlesr
// Initial revision
#endif // SMCLIB__STATEMAP_HPP_