Subversion Repositories programming

Rev

Rev 127 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
127 ira 1
#!/usr/bin/env python
2
# Copyright: Ira W. Snyder
123 ira 3
# Start Date: 2005-10-08
4
# End Date: 
5
# License: Public Domain
6
#
7
# Changelog Follows:
8
#   -- 2005-10-08 1830
124 ira 9
#       Wrote and debugged the entire automaton class.
10
#       Code is feature complete at this point.
123 ira 11
#
124 ira 12
#   -- 2005-10-08 2100
13
#       Changed the "Final States" entry to be on a single line.
14
#
15
#   -- 2005-10-08 2115
16
#       Commented everything that was not commented.
17
#       Trivially changed the place where the last letter of input is found.
18
#
19
#   -- 2005-10-08 2352
20
#       Changed double quotes to single quotes.
21
#       Fixed a few small errors in the error handling code.
22
#
125 ira 23
#   -- 2005-10-09 0006
24
#       Made verbose mode into a toggle.
25
#
127 ira 26
#   -- 2005-10-12 2000
27
#       Added True/False compatibility for versions of python that
28
#       are very old.
128 ira 29
#       Changed the "bad input" error handler to use try / except.
127 ira 30
#
123 ira 31
 
32
import sys, string
33
 
127 ira 34
### Define True and False to compatible values if we are running on a version
35
### of python that doesn't support them. (The SPARC's at school)
36
try:
37
    True == 1
38
except:
39
    True = 1
40
    False = 0
41
 
123 ira 42
class automaton:
128 ira 43
    """The main workhorse class. Call the main_menu() function to let the user
44
    enter and run an automaton."""
123 ira 45
 
46
    def __init__(self):
124 ira 47
        """Constructor for the automaton object"""
48
        self.clear()
123 ira 49
        self.verbose = False
50
 
124 ira 51
    def clear(self):
52
        """Clear all of the important private variables"""
53
        self.automaton_entered = False
123 ira 54
        self.num_states = 0
55
        self.num_letters = 0
56
        self.final_states = []
57
        self.trans_function = []
58
 
59
    def main_menu(self):
124 ira 60
        """Generate the main menu, and handle all selections appropriately"""
123 ira 61
        done = False
62
 
124 ira 63
        while not done:
64
            print 'Menu:'
65
            print '========================================'
66
            print '1. Enter an automaton'
67
            print '2. Run automaton'
125 ira 68
            print '3. %s Verbose Mode' % (self.verbose and 'Disable' or 'Enable', )
69
            print '4. Quit'
123 ira 70
            print
124 ira 71
            s = raw_input('Choice >>> ')
123 ira 72
            print
73
 
74
            if s == '1':
124 ira 75
                self.clear()
123 ira 76
                self.read_automaton()
77
                print
124 ira 78
                self.automaton_entered = True #we've now read an automaton
123 ira 79
            elif s == '2':
124 ira 80
                if self.automaton_entered:
81
                    input = raw_input('Enter string to test: ')
82
                    self.run_automaton(input)
83
                    print
84
                else:
85
                    print 'Enter an automaton first!'
86
                    print
123 ira 87
            elif s == '3':
125 ira 88
                self.toggle_verbose()
89
                print 'Verbose Mode %s!' % (self.verbose and 'Enabled' or 'Disabled', )
123 ira 90
                print
91
            elif s == '4':
92
                done = True
93
            else:
94
                print 'Bad Selection'
95
                print
96
 
97
    def read_automaton(self):
124 ira 98
        """Read in an entire automaton object from the user"""
123 ira 99
        done = False
100
 
101
        ### Find out the number of states
124 ira 102
        while not done:
103
            s = raw_input('How many states?: ')
123 ira 104
 
105
            try:
106
                self.num_states = int(s)
107
                done = True
108
            except (TypeError, ValueError):
124 ira 109
                print 'That wasn\'t an integer, try again!'
123 ira 110
                print
111
 
112
        ### Find out what the last letter is
113
        done = False
114
 
124 ira 115
        while not done:
116
            s = raw_input('What is the last letter?: ')
123 ira 117
 
124 ira 118
            if len(s) != 1 or not s.isalpha():
119
                print 'Only a single letter please, try again!'
123 ira 120
                print
124 ira 121
                continue
123 ira 122
 
124 ira 123
            self.num_letters = self.get_letter_num(s) + 1
124
            done = True
123 ira 125
 
126
        ### Find out which states are final states
127
        done = False
128
 
129
        print
124 ira 130
        print 'Enter the Final States on a single line, seperated by spaces'
123 ira 131
 
132
        while(not done):
124 ira 133
            s = raw_input('Final states: ')
123 ira 134
 
124 ira 135
            done = True
136
 
137
            for i in s.split():
138
                if not self.check_state(i):
139
                    print 'state %s is not valid, try again!' % i
140
                    done = False
141
 
142
            if done:
143
                self.final_states = [int(i) for i in s.split()]
123 ira 144
 
145
        ### Read each state / letter pair
146
        for i in range(self.num_states):
147
            sublist = []
148
 
149
            for j in range(self.num_letters):
150
                done = False
151
                while not done:
124 ira 152
                    s = raw_input('Enter state %d, letter %s -> state ' % (i, string.letters[j]))
123 ira 153
 
154
                    if self.check_state(s):
155
                        sublist.append(int(s))
156
                        done = True
157
                    else:
124 ira 158
                        print 'Not a valid state, try again!'
123 ira 159
                        print
160
 
161
            self.trans_function.append(sublist)
162
 
124 ira 163
        print 'Done reading the automaton!'
123 ira 164
 
165
    def check_state(self, s):
166
        """Checks the string representing a state to see if it's a valid state.
167
        Returns True if it is valid, False otherwise"""
168
        retVal = True
169
 
170
        try:
171
            state = int(s)
172
        except (TypeError, ValueError):
173
            retVal = False
174
            state = 99999999
175
 
176
        if state >= self.num_states:
177
            retVal = False
178
 
179
        return retVal
180
 
181
    def get_letter_num(self, s):
124 ira 182
        """Get the number value representing the character s"""
123 ira 183
        s = s.lower()
184
 
185
        for i in range(26):
186
            if s == string.letters[i]:
187
                return i
188
 
189
        return -1
190
 
191
    def next_state(self, cur_state, letter):
124 ira 192
        """Return the next state (as an integer) given the current state, and
193
        the next letter of input"""
123 ira 194
        letter_num = self.get_letter_num(letter)
195
 
128 ira 196
        # There is a bad letter in the input
123 ira 197
        if letter_num == -1 or letter_num >= self.num_letters:
128 ira 198
            raise ValueError
123 ira 199
 
200
        next_state = self.trans_function[cur_state][letter_num]
201
 
202
        if self.verbose:
124 ira 203
            print 'state %d letter %s -> state %d' % (cur_state, letter, next_state)
123 ira 204
 
205
        return next_state
206
 
207
    def run_automaton(self, input_string):
124 ira 208
        """Run the automaton through the input string given by input_string"""
128 ira 209
        cur_state = 0 # initial state is always q0
123 ira 210
 
128 ira 211
        try:
212
            for c in input_string:
213
                cur_state = self.next_state(cur_state, c)
214
        except ValueError:
215
            print 'There was a bad letter in the input, stopping here!'
123 ira 216
 
124 ira 217
        print 'Done Running'
123 ira 218
        print
124 ira 219
        print 'Final State: %d' % cur_state
220
        print 'Accepted: %s' % (self.is_final_state(cur_state) and 'Yes' or 'No', )
123 ira 221
        print
222
        print
223
        s = raw_input('Press ENTER to return to the main menu')
224
 
225
    def is_final_state(self, s):
226
        """Returns True if s is a final state, False otherwise"""
227
        retVal = True
228
 
229
        try:
230
            self.final_states.index(s)
231
        except ValueError:
232
            retVal = False
233
 
234
        return retVal
235
 
125 ira 236
    def toggle_verbose(self):
237
        if self.verbose:
238
            self.verbose = False
239
        else:
240
            self.verbose = True
123 ira 241
 
124 ira 242
### The "main" function
123 ira 243
if __name__ == '__main__':
244
    a = automaton()
245
    a.main_menu()
128 ira 246