-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.py
144 lines (116 loc) · 3.47 KB
/
parser.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
import token
from parseTreeNode import parseTreeNode
class LL1Parser:
def __init__(self, grammar, verbose=False):
self.grammar = grammar
self.M = grammar.actionTable()
self.input = None
self.parseTree = None
self.currentNode = None
self.verbose = verbose
self.error = False
self.success = False
self.output = None
def parse(self, inputText):
self.input = inputText # list of symbols
self.output = []
self.error = False
self.success = False
self.parseTree = parseTreeNode(token.token(self.grammar.startSymbol))
self.currentNode = self.parseTree
self.parse_recursiveCall()
return self.output
def parse_recursiveCall(self):
if (self.error):
return
if (self.verbose):
print "-----"
print "input", self.input
print "output", self.output
print "parseTree :\n", self.parseTree
print "currentNode", self.currentNode.value
#print "first", self.grammar.first_1()
#print "follow", self.grammar.follow_1()
#print "action", self.grammar.actionTable()
stack_token = self.currentNode.value
input_token = self.input[0] # only one character as we have an LL1-parser
# notation from the syllabus - pp. 116
X = stack_token.name
u = input_token.name
assert X in self.grammar.symbols
if (self.verbose):
print "from stack", stack_token
print "from input", input_token
if (u in self.M[X]):
self.produce(self.M[X][u])
elif (X in self.grammar.terminals and X == u):
self.match()
else:
self.trigger_error(X, u)
def trigger_error(self, X, u):
self.output.append("E")
if (self.verbose):
print "------ error"
print "currentNode", self.currentNode.value
print "input", self.input
print "output", self.output
if u not in self.grammar.symbols:
raise ParseError("Unknown symbol", u)
else:
raise ParseError("Misplaced symbol", u)
def trigger_accept(self):
self.output.append("A")
self.success = True
if (self.verbose):
print "accept"
def produce(self, i):
if (self.verbose):
print "produce", i
self.output.append("P" + str(i))
saved_current = self.currentNode
for produced in self.grammar.rules[i][1:]:
if (produced != self.grammar.emptySymbol):
self.currentNode.giveChild(token.token(produced))
self.currentNode = self.currentNode.children[-1]
self.parse_recursiveCall()
self.currentNode = saved_current
self.currentNode = saved_current
def match(self):
if (self.verbose):
print "match"
parseTreeToken = self.currentNode.value
inputToken = self.input.pop(0)
assert parseTreeToken.name == inputToken.name, "match : input and stack does not match"
parseTreeToken.value = inputToken.value
self.output.append("M")
if (len(self.input) == 0):
self.trigger_accept()
class ParseError(Exception):
def __init__(self, errorType, symbol):
self.errorType = errorType
self.symbol = symbol
def __str__(self):
return "ParseError : " + repr(self.errorType) + " " + repr(self.symbol)
if __name__ == '__main__':
from grammars_examples import g6
import scanner
import re
import sys
import getopt
try:
opts, args = getopt.getopt(sys.argv[1:], "i:", ["help", "input="])
except getopt.GetoptError as err:
print(err)
sys.exit(2)
perlFile = None
for o, a in opts:
if o in ("-i", "--input"):
perlFile = a
else:
print("Option {} unknow".format(o))
sys.exit(2)
ll1_parser = LL1Parser(g6, verbose=False)
perl_scanner = scanner.PerlScanner()
inputTokens = perl_scanner.scans(perlFile)
ll1_parser.parse(inputTokens)
print ll1_parser.parseTree