-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathget_predict_table.py
197 lines (177 loc) · 6.01 KB
/
get_predict_table.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
"""
使用非递归的预测分析表做语法分析————预测分析表的生成
作者:刘金明
博客:me.idealli.com
Github:github.com/flymysql
"""
import sys, os, re
sys.path.append(os.pardir)
from lexer import word_list,k_list
grammars = {
"Program":["type M C Pro"],
"C":["( cc )"],
"cc":["null"],
"Pro":["{ Pr }"],
"Pr":["P Pr", "null"],
"P":["type L ;", "L ;", "printf OUT ;", "Pan"],
"L":["M LM"],
"LM":["= FE", "Size AM","null"],
"FE":["E", "TEXT", "CHAR"],
"M":["name"],
"E":["T ET"],
"ET":["+ T ET", "- T ET", "null"],
"T":["F TT"],
"TT":["* F TT", "/ F TT", "null"],
"F":["number", "BRA", "M MS"],
"MS":["Size", "null"],
"BRA": ["( E )"],
"OUT":["( TXT V )"],
"TXT":['TEXT'],
"V":[", E VV", "null"],
"VV":[", E VV", "null"],
"Pan":["Ptype P_block Pro"],
"Ptype":["if", "while"],
"P_block":["( Pbc )"],
"Pbc":["E PM"],
"PM":["Cmp E", "null"],
"Size":["[ E ]"],
"AM":["= E", "null"]
}
first_table = {}
follow_table = {}
predict_table = {}
observer = {}
"""
初始化订阅者
订阅者: 用于求follow集合的过程中特殊情况:
非终结符的后继非终结符的first集合可能存在null
eg: A -> BC C -> D | null D -> (A) | i
那么在一次遍历过程中,因为C的first集合存在null,所以需要将follow(A)加入follow(B)
(重点)但是!此时的follow(A),并不是完整的,它可能在后续的遍历中会继续更新自身的follow集合
所以此时会出现遗漏的follow
所以我在这里用到一个订阅者模式
订阅者为一个字典,字典键值为产生式左部,字典内容为产生式右部
"""
def init_observer():
for k in grammars:
follow_table[k] = []
observer[k] = []
for next_grammar in grammars[k]:
last_k = next_grammar.split()[-1]
if last_k in grammars and last_k != k:
observer[k].append(last_k)
"""
刷新订阅
检测到某个follow集合更新时,对其订阅的所有产生式左部的follow集合进行更新
简而言之:follow(A)发生了更新,那么曾经将follow(A)加入自身的B,C也更新其follow
并且,这是一个递归过程
"""
def refresh(k):
for lk in observer[k]:
newlk = U(follow_table[k], follow_table[lk])
if newlk != follow_table[lk]:
follow_table[lk] = newlk
refresh(lk)
"""
合并两个list并且去重
"""
def U(A,B):
return list(set(A+B))
"""
查找指定非终结符的first集合
"""
def find_first(key):
if key not in grammars:
return [key]
l = []
for next_grammar in grammars[key]:
next_k = next_grammar.split()[0]
l.extend(find_first(next_k))
return l
"""
查找所有非终结符follow
"""
def find_follow():
init_observer()
follow_table["Program"] = ["#"]
for k in grammars:
for next_grammar in grammars[k]:
next_k = next_grammar.split()
for i in range(0,len(next_k)-1):
if next_k[i] in grammars:
if next_k[i+1] not in grammars:
"""
如果后继字符不是终结符,加入
"""
new_follow = U([next_k[i+1]], follow_table[next_k[i]])
if new_follow != follow_table[next_k[i]]:
follow_table[next_k[i]] = new_follow
refresh(next_k[i])
else:
new_follow = U(first_table[next_k[i+1]], follow_table[next_k[i]])
"""
如果后继字符的first集合中含有null,通知所有订阅者更新follow集合
"""
if "null" in first_table[next_k[i+1]]:
new_follow = U(follow_table[k], new_follow)
observer[k].append(next_k[i])
if new_follow != follow_table[next_k[i]]:
follow_table[next_k[i]] = new_follow
refresh(next_k[i])
"""
产生式左部的follow集合加入最后一个非终结符的follow集合
"""
if next_k[-1] in grammars:
if next_k[-1] not in follow_table:
follow_table[next_k[-1]] = []
if next_k[-1] != k:
follow_table[next_k[-1]] = U(follow_table[next_k[-1]], follow_table[k])
for k in follow_table:
if "null" in follow_table[k]:
follow_table[k].remove("null")
"""
获取所有非终结符的first集合
在此同时直接将first集合加入predict表中
"""
def get_first_table():
for k in grammars:
predict_table[k] = {}
first_table[k] = []
for next_grammar in grammars[k]:
next_k = next_grammar.split()[0]
kl = find_first(next_k)
first_table[k].extend(kl)
for kk in kl:
if kk != "null":
predict_table[k][kk] = next_grammar
"""
将follow集合中的部分内容加入predict表中
"""
def get_predict_table():
for k in grammars:
for next_grammar in grammars[k]:
next_k = next_grammar.split()[0]
if next_k in grammars and "null" in first_table[next_k] or next_k == "null":
for fk in follow_table[k]:
predict_table[k][fk] = next_grammar
def creat_predict_table():
get_first_table()
find_follow()
get_predict_table()
return predict_table
def show_tables():
get_first_table()
find_follow()
get_predict_table()
print("\nfirst集合如下\n")
for k in first_table:
print(k, first_table[k])
print("\nfollow集合如下\n")
for k in follow_table:
print(k, follow_table[k])
# print(first_table)
print("\n预测表如下\n")
for k in predict_table:
print(k, predict_table[k])
if __name__ == "__main__":
show_tables()