-
Notifications
You must be signed in to change notification settings - Fork 0
/
grammaranalyzer.py
102 lines (77 loc) · 2.55 KB
/
grammaranalyzer.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
"""
A class used to test strings against a given grammar to see if the grammar
can generate the string.
An instance of GrammarAnalyzer is initialized with a passed Grammar object
and is capable of testing that grammar against test strings (input strings)
using the test_string method.
"""
class GrammarAnalyzer:
def __init__(self, grammar):
self.verbose = False
self.grammar = grammar
self.stack = []
self.input = []
self.verbalize("Grammar analyzer initialized.")
self.verbalize("Imported grammar: " + grammar.get_desc())
self.verbalize(self.hr())
def test_string(self, string):
"""
Takes a given string and tests if the grammar can generate it.
:param string: The string to test.
:return bool: True if the grammar can generate it; false otherwise.
"""
if not len(string):
return False
self.stack = ["$", "S"]
self.input = list(string)
self.input.reverse()
self.verbalize("Testing string: " + string)
self.verbalize("Starting stack: " + self.stack_to_string())
return self.parse_input()
def parse_input(self):
"""
Use the grammar ruleset to parse the string and determine language
membership.
:return: True if the grammar can generate it; false otherwise.
"""
self.verbalize(self.hr())
self.verbalize("Input stack: " + self.input_to_string())
self.verbalize("Stack: " + self.stack_to_string())
# Pop the next symbol off the stack.
stack_symbol = self.stack.pop()
# If the stack is empty and the input is too, accept.
# Otherwise, reject.
if stack_symbol == "$":
return True if not self.input else False
# If the input is empty, reject.
if not self.input:
return False
# Peek at the next input symbol.
input_symbol = self.input[-1]
# If we have a variable...
if stack_symbol.isalpha() and stack_symbol.isupper():
# Grab the next rule to apply.
rule = self.grammar.get_rule(stack_symbol, input_symbol)
if not rule:
self.verbalize("There was no rule to push.")
return False
# Push the rule onto the stack.
symbols = list(rule)
for symbol in reversed(symbols):
self.stack.append(symbol)
# If we have a terminal and it matches the next input symbol...
elif stack_symbol == input_symbol:
# Turn the peek into a pop.
self.input.pop()
else:
return False
return self.parse_input()
def stack_to_string(self):
return "".join(reversed(self.stack))
def input_to_string(self):
return "".join(reversed(self.input))
def verbalize(self, output):
if self.verbose:
print(output)
def hr(self):
return "--------------------------------------------------"