Rev 124 | Rev 127 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#!/usr/bin/python
#Copyright: Ira W. Snyder
# Start Date: 2005-10-08
# End Date:
# License: Public Domain
#
# Changelog Follows:
# -- 2005-10-08 1830
# Wrote and debugged the entire automaton class.
# Code is feature complete at this point.
#
# -- 2005-10-08 2100
# Changed the "Final States" entry to be on a single line.
#
# -- 2005-10-08 2115
# Commented everything that was not commented.
# Trivially changed the place where the last letter of input is found.
#
# -- 2005-10-08 2352
# Changed double quotes to single quotes.
# Fixed a few small errors in the error handling code.
#
# -- 2005-10-09 0006
# Made verbose mode into a toggle.
#
import sys, string
class automaton:
def __init__(self):
"""Constructor for the automaton object"""
self.clear()
self.verbose = False
def clear(self):
"""Clear all of the important private variables"""
self.automaton_entered = False
self.num_states = 0
self.num_letters = 0
self.final_states = []
self.trans_function = []
def main_menu(self):
"""Generate the main menu, and handle all selections appropriately"""
done = False
while not done:
print 'Menu:'
print '========================================'
print '1. Enter an automaton'
print '2. Run automaton'
print '3. %s Verbose Mode' % (self.verbose and 'Disable' or 'Enable', )
print '4. Quit'
s = raw_input('Choice >>> ')
if s == '1':
self.clear()
self.read_automaton()
self.automaton_entered = True #we've now read an automaton
elif s == '2':
if self.automaton_entered:
input = raw_input('Enter string to test: ')
self.run_automaton(input)
else:
print 'Enter an automaton first!'
elif s == '3':
self.toggle_verbose()
print 'Verbose Mode %s!' % (self.verbose and 'Enabled' or 'Disabled', )
elif s == '4':
done = True
else:
print 'Bad Selection'
def read_automaton(self):
"""Read in an entire automaton object from the user"""
done = False
### Find out the number of states
while not done:
s = raw_input('How many states?: ')
try:
self.num_states = int(s)
done = True
except (TypeError, ValueError):
print 'That wasn\'t an integer, try again!'
### Find out what the last letter is
done = False
while not done:
s = raw_input('What is the last letter?: ')
if len(s) != 1 or not s.isalpha():
print 'Only a single letter please, try again!'
continue
self.num_letters = self.get_letter_num(s) + 1
done = True
### Find out which states are final states
done = False
print 'Enter the Final States on a single line, seperated by spaces'
while(not done):
s = raw_input('Final states: ')
done = True
for i in s.split():
if not self.check_state(i):
print 'state %s is not valid, try again!' % i
done = False
if done:
self.final_states = [int(i) for i in s.split()]
### Read each state / letter pair
for i in range(self.num_states):
sublist = []
for j in range(self.num_letters):
done = False
while not done:
s = raw_input('Enter state %d, letter %s -> state ' % (i, string.letters[j]))
if self.check_state(s):
sublist.append(int(s))
done = True
else:
print 'Not a valid state, try again!'
self.trans_function.append(sublist)
print 'Done reading the automaton!'
def check_state(self, s):
"""Checks the string representing a state to see if it's a valid state.
Returns True if it is valid, False otherwise"""
retVal = True
try:
state = int(s)
except (TypeError, ValueError):
retVal = False
state = 99999999
if state >= self.num_states:
retVal = False
return retVal
def get_letter_num(self, s):
"""Get the number value representing the character s"""
s = s.lower()
for i in range(26):
if s == string.letters[i]:
return i
return -1
def next_state(self, cur_state, letter):
"""Return the next state (as an integer) given the current state, and
the next letter of input"""
letter_num = self.get_letter_num(letter)
if letter_num == -1 or letter_num >= self.num_letters:
print 'Bad letter in the input *** I WILL STAY AT THE CURRENT STATE ***'
return cur_state
#sys.exit(1)
next_state = self.trans_function[cur_state][letter_num]
if self.verbose:
print 'state %d letter %s -> state %d' % (cur_state, letter, next_state)
return next_state
def run_automaton(self, input_string):
"""Run the automaton through the input string given by input_string"""
cur_state = 0 #initial state is always q0
for c in input_string:
cur_state = self.next_state(cur_state, c)
print 'Done Running'
print 'Final State: %d' % cur_state
print 'Accepted: %s' % (self.is_final_state(cur_state) and 'Yes' or 'No', )
s = raw_input('Press ENTER to return to the main menu')
def is_final_state(self, s):
"""Returns True if s is a final state, False otherwise"""
retVal = True
try:
self.final_states.index(s)
except ValueError:
retVal = False
return retVal
def toggle_verbose(self):
if self.verbose:
self.verbose = False
else:
self.verbose = True
### The "main" function
if __name__ == '__main__':
a = automaton()
a.main_menu()