fsm.py(.html)

#!/usr/local/bin/python
"""Finite state Machine module

   Create class for finite state machine.  Each
   instance holds a list of states, and the set
   of rules of how to get from one state to the
   next.  This should hopefully allow consistancy
   checks to be made.
"""

class fsm:
    def __init__(self,
                 start = None,	# The state the machine
                                # will start in.
                 state = None,	# the current state.
                 table = {},    # A dictionary of lists
                 variables = {} # The dictionary of things which
				# can determine the state.
                ):
	self.start = start
	self.state = start
        self.table = table
        self.variables = variables
        self.verbose = None

    def add_state(swlf,
                 state,
                 table
                ):
	self.table[state] = transition_list

    def add_transition(self,
                       state,
                       condition,
                       action=None,
                       next_state
                      ):

        # The transtion table must be an ordered list because
        # there are some tests that must be performed before
        # others.
        if self.table.has_key(state):
	    self.table[state].append((condition, action, next_state))
        else:
            self.table[state] = [(condition, action, next_state)]


    def set_var(self,
                name,	# name of variable
	        value	# value to set it to.
               ):
        """Set an internval variable to a value"""
        if self.verbose:
            print "set_var: Name %s, Value, %s" % (name, value)
        self.variables[name]=value



    def get_var(self,
                name	# name of variable
               ):
        """Set an internval variable to a value
           Raise exception if there is a problem
        """
        if self.variables.has_key(name):
            return(self.variables[name])
        else:
            raise "Finite State Machine has no such variable", name


    def set_start(self,
                  state		# name of start state
                 ):
        """Set the start state to be a given state"""
        if self.table.has_key(state):
            self.start = state
        else:
            raise "Illegal state", state


    def check(self):
        """ Check the consitency of the transiton table
        """
        defined_states = [] # states for whichwe have
                            # defined transtions
        known_states = []   # states referenced in the 
 		           # transition tables.
        for state in self.table.keys():
            defined_states.append(state)
        for state in defined_states:
            departures = [] # ways out of this state.
	    for tuple in self.table[state]:
 	        (condition,action,next_state) = tuple
                # Check this points to somewhere we know about.
                if next_state in defined_states:
                    pass
                else:
                    print "State %s has reference to undefined state %s\n" % (state, next_state)
	        known_states.append(next_state)
                # the next state is a way out, add it to 
                # the list if necessary
                if next_state in departures:
                    pass
                else:
                    departures.append(next_state)
            # Check one of the departures points out
            # of this node, otherwise complain about it.
            for next_state in departures:
                if next_state != state:
                    break
            else:
                print "State %s has no exit points" % state
 
        # Now check that there are no states which don't have
        # pointers to them -- states we cannot get to.
        for state in defined_states:
            if state in known_states:
                pass
            else:
                print "State %s defined, but never used" % state
        # That is the best we can do for consitency checks
        # for now.
       
 
    def free_run(self):
        """set the machine running"""       
        if self.state == None:
            raise "There is no current state for ",self
        while(1):
            for (condition, action, next) in self.table[self.state]:
                if eval(condition):
                    if action != None:
                        exec action
                    self.state = next
                    break

    def reset(self):
        """ set the state to the start state."""
        self.state = self.start


    def step(self):
        """ make a transition from a state to the next.
 
            make a transition from the current state
            to the next state (maybe the same state)
            This function is needed if we have more than
            one instance of the class in a non-threaded
            program, so each instance can be stepped.
        """
        if self.state == None:
             raise "There is no current state for " % self
	for (condition, action, next) in self.table[self.state]:
            if self.verbose:
                print "Condition %s, Action %s, Next %s" % (condition, action, next) 
	    if eval(condition):
		if action != None:
		    exec action
		self.state = next
		break