-
Notifications
You must be signed in to change notification settings - Fork 0
/
master.py
357 lines (332 loc) · 13.6 KB
/
master.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Jason Ma
# August 1, 2016
lamb = '☐'
import JFFWriterv2
import StateMachine
import time
import sys
if sys.version_info < (3,0):
#This allows my code to work with both python 2 and 3
input = raw_input
DEBUG = False
def main():
"""Main interface for students to choose between converting
a JSFLAP file or creating a new Finite Automata from scratch
"""
while(True):
print("Hello, this is a JSFLAP to JFLAP converter that converts JSFLAP Automaton definition files to JFLAP files, which are in .jff format")
print("1. Convert JSFLAP File to .jff Format")
print("2. Create a state machine from command line")
print("3. Quit")
decision = input("What do you want to do? (Pick a number)\n")
if str(decision) == '1':
convertJSFLAPToJFLAP()
elif str(decision) == '2':
createStateMachine()
elif str(decision) == '3':
print("Goodbye!")
break
else:
print("Invalid input, please select a valid command(1-3)")
return
def test():
main()
def createStateMachine():
print("Hello, welcome to Jason's CLI for state machine")
typeOfMachine = ''
deterministic = ''
print()
while(True):
print("What type of machine are you making?")
print("Enter 'fa' for Finite Automata's (Read string and determines if it's in the language")
print("Enter 'tm' to create a Turing Machine")
typeOfMachine = input()
if typeOfMachine != 'fa' and typeOfMachine != 'tm':
print("Invalid input, try again.")
else:
break
while(True):
print('Is your machine deterministic (Does it accept lambda/empty transitions)?')
deterministic = str(input("Enter 'd' if yes, and 'n' if not:\n"))
if deterministic != 'd' and deterministic != 'n':
print('Invalid input, please try again.\n')
else:
break
# stateMech = StateMachine.StateMachine([], [], [], [], typeOfMachine, deterministic)
nodeL = []
edgeL = []
initial = None
accepting = []
while(True):
print("What do you want to do with your state machine?")
print("1. Add Node")
print("2. Add Edge")
print("3. Declare Initial Node (Will rewrite previous initial node")
print("4. Add Accepting/Final Node")
print("5. Remove Accepting/Final Node (Makes it a nonaccepting node)")
print("6. Remove a node")
print("7. Remove an edge")
print("8. Generate JFLAP file (.jff format)")
print("9. Quit")
decision = str(input())
if decision == '1':
nodeL = addNode(nodeL)
elif decision =='2':
edgeL = addEdge(nodeL, edgeL, typeOfMachine, deterministic)
elif decision == '3':
initial = declareStartNode(nodeL)
elif decision == '4':
accepting = declareAcceptingNode(nodeL, accepting)
elif decision == '5':
accepting = removeAcceptingNode(accepting)
elif decision == '6':
nodeL, initial, accepting, edgeL = deleteNode(nodeL, initial, accepting, edgeL)
elif decision == '7':
edgeL = removeEdge(edgeL, typeOfMachine)
elif decision == '8':
try:
generateJFLAPFile(deterministic, typeOfMachine, nodeL, edgeL, initial, accepting)
except NameError:
print("Try entering a better filename next time")
#print("Goodbye! Thanks for using my program!")
#break
elif decision == '9':
print("Goodbye!")
break
elif DEBUG and '-1':
print(nodeL)
print(edgeL)
print(initial)
print(accepting)
else:
print("Invalid input, Try again.")
time.sleep(0.1)
print("")
def addNode(nodeL):
"""Given a list nodeL - strings of the names of each node -
Asks user for name of a new node until a valid one is given, and checks if it's a new name
if so, add it to the list. """
print("Entering a new node. Enter q at anytime to quit.")
while(True):
nodeName = input("Enter the name of the node:\n")
if nodeName == 'q':
return nodeL
validNode = True
for node in nodeL:
if node == nodeName:
print("This name has been used before! Try again with a new name")
validNode = False
if validNode:
nodeL.append(nodeName)
break
return nodeL
def addEdge(nodeL, edgeL, typeOfMachine, deterministic):
"""Asks user for an edge between ndoes until a valid one is given"""
print("Entering a new edge. Enter q at anytime to quit.")
startNode = None
while(True):
startNode = input("From which node does the edge start?:\n")
validNode = False
if startNode == 'q':
return nodeL, edgeL
for node in nodeL:
if node == startNode:
validNode = True
if not validNode:
print("This is not a valid start node, enter a new one!")
continue
else:
break
while(True):
endNode = input("At which node does the edge end?:\n")
validNode = False
if endNode == 'q':
return nodeL, edgeL
for node in nodeL:
if node == endNode:
validNode = True
if not validNode:
print("This is not a valid ending node, enter a new one.")
continue
else:
break
if typeOfMachine == 'fa':
readVal = getReadVal(deterministic)
elif typeOfMachine == 'tm':
readVal = getReadWriteVal(deterministic)
if readVal == 'q':
return edgeL
edgeL.append([startNode, endNode, readVal])
return edgeL
def getReadVal(deterministic):
"""Get a value the edge accepts for FA's"""
while(True):
if deterministic == 'd':
readVal = input('What value does this edge read?:\n')
else:
readVal = input('What value does this edge read? (Enter lambda for lambda transitions):\n')
if readVal == 'q':
return 'q'
if readVal == 'lambda' and deterministic == 'd':
print("You can't have lambda transitions on deterministic machines.")
print("Enter a new read value, please!")
if len(readVal) > 1:
print("Edges only read one character at a time! Enter in one character next time.")
else:
return readVal
def getReadWriteVal(deterministic):
"""Get a value that the edge accepts, writes, and direction to head to
for turing machines """
while(True):
if deterministic == 'd':
readVal = input('What value does this edge read?:\n')
else:
readVal = input('What value does this edge read? (Enter lambda for lambda transitions):\n')
if readVal == 'q':
return 'q'
if readVal == 'lambda' and deterministic == 'd':
print("You can't have lambda transitions on deterministic machines.")
print("Enter a new read value, please!")
if readVal == 'lambda':
readVal = lamb
if len(readVal) > 1:
print("Edges only read one character at a time! Enter in one character next time.")
else:
break
while(True):
if deterministic == 'd':
writeVal = input('What value does this edge write?:\n')
else:
writeVal = input('What value does this edge read? (Enter lambda for lambda transitions):')
if writeVal == 'q':
return 'q'
if writeVal == 'lambda' and deterministic == 'd':
print("You can't have lambda transitions on deterministic machines.")
print("Enter a new read value, please!")
if len(writeVal) > 1:
print("Edges only read one character at a time! Enter in one character next time.")
else:
break
while(True):
direction = input("Where does the turing machine move to next? (l/s/r):\n")
if direction == 'q':
return 'q'
elif direction == 's' or direction =='r' or direction =='l':
break
else:
print("Not a valid direction")
return [readVal, writeVal, direction]
def declareStartNode(nodeL):
"""Asks users which node should be the starting node"""
while(True):
for a0 in range(len(nodeL)):
print(str(a0) + ". " + nodeL[a0])
start = input("Enter the Index of the node to make initial. 0 - " + str(len(nodeL) - 1) + ".\n")
if start == 'q':
return None
if int(start) >= len(nodeL):
print("Node specified not in range. Try again.")
else:
return nodeL[int(start)]
def declareAcceptingNode(nodeL, acceptingL):
"""Asks uers which node should be the final node and returns a new final list"""
while(True):
for a0 in range(len(nodeL)):
print(str(a0) + ". " + nodeL[a0])
acc = input("Enter the index of the node you want to make accepting. 0 - " + str(len(nodeL) - 1) + ".\n")
if acc == 'q':
return acceptingL
elif int(acc) >= len(nodeL):
print("Node specified not in range. Try again.")
else:
acceptingL.append(nodeL[int(acc)])
return acceptingL
def removeAcceptingNode(acceptingL):
"""Remove a node from the list of acceptable final nodes"""
for a0 in range(len(acceptingL)):
print(str(a0) + ". " + acceptingL[a0])
delete = input("Enter the index of the node to remove from accepting nodes. 0 - " + str(len(acceptingL) - 1) + ".\n")
if delete == 'q':
return acceptingL
elif int(delete) >= len(acceptingL):
print("Node specified not in range. Try again.")
else:
return [acceptNode for acceptNode in acceptingL if acceptNode != acceptingL[int(delete)]]
def deleteNode(nodeL, initial, acceptingL, edgeL):
"""Remove a node from the graph completely
Also removes related dependencies"""
while(True):
for a0 in range(len(nodeL)):
print(str(a0) + ". " + nodeL[a0])
delete = input("Enter the index of the node to remove from accepting nodes. 0 - " + str(len(nodeL) - 1) + ".\n")
if delete == 'q':
return nodeL, initial, acceptingL
elif int(delete) >= len(nodeL):
print("Node specified not in range. Try again.")
else:
if initial == nodeL[int(delete)]:
initial = None
if nodeL[int(delete)] in acceptingL:
acceptingL = [accept for accept in acceptingL if accept != nodeL[int(delete)]]
edgeL = [edge for edge in edgeL if edge[0] != nodeL[int(delete)]] and edge[1] != nodeL[(int(delete))]
nodeL = [nodeL[a0] for a0 in range(len(nodeL)) if a0 != int(delete)]
return nodeL, initial, acceptingL, edgeL
def removeEdge(edgeL, typeOfMachine):
"""Removes an edge from the list of edges"""
while(True):
print("The edges will be listed in the following format:")
print("starting state / ending state / read value")
if typeOfMachine == 'tm':
for a0 in range(len(edgeL)):
print(str(a0) + ". " + edgeL[a0][0] + "/" + edgeL[a0][1] + "/ (" + edgeL[a0][2][0] + "/" + edgeL[a0][2][1] + "/" + edgeL[a0][2][2] + ")")
else:
for a0 in range(len(edgeL)):
print(str(a0) + ". " + edgeL[a0][0] + "/" + edgeL[a0][1] + "/" + edgeL[a0][2])
delete = input("Enter the index of the edge to delete. 0 - " + str(len(edgeL) - 1) + '.\n')
if delete == 'q':
return edgeL
elif int(delete) >= len(edgeL):
print("Edge specified not in range. Try again.")
else:
return [edge for edge in edgeL if edge != edgeL[int(delete)]]
def generateJFLAPFile(deterministic, typeOfMachine, nodeL, edgeL, initial, accepting):
"""Using the list of nodes, edges, and the starting/final nodes
Generates a state machine and outputs it to a .jjf file"""
newNodeL = [StateMachine.Node(node, [], node == initial, node in accepting) for node in nodeL]
if DEBUG:
print(newNodeL)
newEdgeL = [StateMachine.Edge( StateMachine.findNode(edge[0], newNodeL), StateMachine.findNode(edge[1], newNodeL), edge[2]) for edge in edgeL]
if DEBUG:
print(newEdgeL)
for node in newNodeL:
node.addEdge(newEdgeL)
if DEBUG:
print(newNodeL)
initNode = StateMachine.findNode( initial, newNodeL )
if DEBUG:
print(initNode)
finalNodeL = [StateMachine.findNode( name, newNodeL) for name in accepting]
if DEBUG:
print(finalNodeL)
stateMech = StateMachine.StateMachine( newNodeL, newEdgeL, initNode, finalNodeL, typeOfMachine, deterministic)
filename = input("What do you want the output to be named?\n")
filename+='.txt'
JFFWriterv2.writeJFFFile(stateMech, filename)
def convertJSFLAPToJFLAP():
"""Asks user the name of the file to convert"""
filename = input("What is the name of the JSFLAP file you want to convert? (Don't forget the file extension)\n")
if filename == 'q':
return
JFFWriterv2.convertFromJSFLAP2JFLAP(filename)
def fixFile(filename):
"""Adds some encoding details to headers of .jff file
Not really needed, but may be necessary for bug fixing later on """
file = open(filename, 'w+')
string = file.read()
string = string[:19] + 'encoding="UTF-8" standalone="no"' + string[19:]
f = open('Fixed' + filename, 'w')
f.write(string)
if __name__ == '__main__':
main()