我的SLR(1)分析表生成程序【Python】

文法如下

0 S' -> S
1 S  -> G
2 S  -> A
3 G  -> D;
4 D  -> int id
5 D  -> float id
6 D -> char id
7 D  -> D, id
8 A  -> id=E;
9 E  -> E + T
10 E ->E - T
11  E  -> T
12 T  -> T * F
13 T  -> T / F
14 T  -> T % F
15 T  -> F
16 F  -> (E)
17 F  -> id


[code=Python]

#!/usr/bin/env python

VN = ('s', 'S', 'G', 'A', 'D', 'E', 'T', 'F')
VT = (',', ';', 'int', 'float', 'char', 'id', '=', '+', '-', '*', '/' ,'%', '(', ')', '#')

generators = (
    ('s', 'S', 2),('S', 'G', 2), ('S', 'A', 2), ('G', 'D', ';', 3),
    ('D', 'int', 'id', 3), ('D', 'float', 'id', 3), ('D', 'char', 'id', 3), ('D', 'D', ',', 'id', 4),
    ('A', 'id', '=', 'E', ';', 5), ('E', 'E', '+', 'T', 4), ('E', 'E', '-', 'T', 4), ('E', 'T', 2), ('T', 'T', '*', 'F', 4),
    ('T', 'T', '/', 'F', 4), ('T', 'T', '%', 'F', 4), ('T', 'F', 2), ('F','(', 'E', ')', 4), ('F', 'id', 2))


'''
如何生成FIRST,FOLLOW SET
'''

first = { vn:set() for vn in VN}
follow = { vn:set() for vn in VN}

[first[i].add(j[1]) for i in VN for j in generators if j[0] == i and j[1] not in VN]

#print(follow)
'''
first  set, the dict, which VN, the VN list
'''
#構造FIRST SET
#print(first)
#第一步獲取只有終結符的產生式的符號
NOVT = []
for i in first:
    if len(first[i]) == 0:
        continue
    for j in VN:
        if j in first[i]:
            break
    else :
        NOVT.append([i])
#print(NOVT)
#第二步填充NOVT

for j in NOVT:
    for k in j:
        for i in generators:
            if i[1] == k and i[0] not in j:
                j.append(i[0])
#print(NOVT)
for i in NOVT:
    for j in range(1, len(i)):
        first[i[j]] |= first[i[j-1]]
        
#print(first)


[follow[j[k]].add(j[k+1]) for j in generators for k in range(1, len(j)-1) if j[k] in VN and j[k+1] in VT]
follow['s'].add('#')
for i in generators :
    for j in range(1,len(i) - 2):
        if i[j] in VN and i[j+1] in VN:
            follow[i[j]] |= first[i[j + 1]]

#構造FOLLOW SET
#第一步獲取關係表
relation = {i[0]:set() for i in generators if i[-2] in VN}
for i in generators:
    if i[-2] in VN:
        relation[i[0]].add(i[-2])

#print(relation)
#第二步生成FOLLOWSET
for i in relation:
    for j in relation[i]:
        follow[j] |= follow[i]

#print(follow)

#(a, b) means a how many chars has passed , and b means generators[b][a]
analyze_table = [[[],(1, 0)]]
for i in analyze_table:
    d = {}
    for j in i:
        if j is i[0]:
            continue
        if j[0] >= generators[j[1]][-1] :
            continue
        tmp = generators[j[1]]
        for k in generators:
            if k[0] == tmp[j[0]] and k is not tmp and (1, generators.index(k)) not in i :
                #print('k =', k, 'tmp', tmp)
                i.append((1, generators.index(k)))
            #else :
                #because all the same VN are all negolate each other
                #break
        
        if generators[j[1]][j[0]] not in d:
            tmp1 = [n[1] for n in analyze_table]
            tmp2 = (j[0] + 1, j[1])
            tmp3 = [[],tmp2]
            if tmp2 not in tmp1:
                analyze_table.append(tmp3)
                tmp1 = [n[1] for n in analyze_table]
                i[0].append(tmp1.index(tmp2))
            else :
                i[0].append(tmp1.index(tmp2))
            d[generators[j[1]][j[0]]] = tmp1.index(tmp2)
        elif generators[j[1]][-1] > j[0]:
            tmp2 = (j[0] + 1, j[1])
            if tmp2 not in analyze_table[d[generators[j[1]][j[0]]]]:
                analyze_table[d[generators[j[1]][j[0]]]].append(tmp2)
            i[0].append(d[generators[j[1]][j[0]]])


action = {i:[ 0 for j in range(0, len(analyze_table))] for i in VT}
goto =  {i:[-1 for j in range(0, len(analyze_table))] for i in VN}
for i in range(0, len(analyze_table)) :
    map = analyze_table[i][0]
    for j in analyze_table[i][1:]:
        #可歸約項目
        if j[0] == generators[j[1]][-1] :
            #對任何終結符或'#'用產生式進行歸約
            if j[1] == 0 and j[0] == generators[0][-1] :
                action['#'][i] = 'acc'
            else :
                for key in action:
                    if key in follow[generators[j[1]][0]]:
                        action[key][i] = -1 * j[1];
        elif generators[j[1]][j[0]] in VT:
            #移進項目
            action[generators[j[1]][j[0]]][i] = map[0]
            map = map[1:]
        else :
            goto[generators[j[1]][j[0]]][i] = map[0]
            map = map[1:]

print('  ',end='')
[print('%5s' % i, end=' ') for i in VT]
print()
for i in range(len(analyze_table)) :
    print('%2s' % i, end='')
    for j in VT:
        print('%5s' % action[j][i], end = ' ')
    print()



//生成Qt下的定義語句
f = open("action.txt", "w")
f.write('QStringList ')
for i in range(0, len(analyze_table)):
    f.write('a' + str(i) + ',')
f.write(';\n')
for i in range(0, len(analyze_table)) :
    f.write('a' + str(i) + '<<')
    for key in VT[:-1] :
        f.write('"' + str(action[key][i]) + '"<<')
    f.write('"' + str(action[VT[-1]][i]) + '";\n')
for i in range(0, len(analyze_table)) :
    f.write('analyze_table->append(a' + str(i) + ');\n')
f.close()

f = open('goto.txt','w')
f.write('QStringList ')
for i in range(0, len(analyze_table)) :
    f.write('g' + str(i) + ',')
f.write(';\n')
for i in range(0, len(analyze_table)) :
    f.write('g' + str(i) + '<<')
    for key in VN[:-1] :
        f.write('"' + str(goto[key][i]) + '"<<')
    f.write('"' + str(goto[VN[-1]][i]) + '";\n')
for i in range(0, len(analyze_table)) :
    f.write('goto_table->append(g' + str(i) + ');\n')
f.close()

f = open("syntax.txt",'w')
f.write('QStringList ')
for i in range(0, len(generators)):
    f.write('s' + str(i) + ',')
f.write(';')
for i in range(len(generators)):
    f.write('s' + str(i) + '<<');
    for j in generators[i][:-2]:
        f.write('"' + j + '"<<')
    f.write('"' + generators[i][-2] + '";\n')
for i in range(len(generators)) :
    f.write('syntax->append(s' + str(i) + ');\n')

f.close()

[/code]


這個也只是生成了一個初步的分析表,錯誤處理沒有用程序實現,而是手工實現,分析後的結果如下


e0 -- empty def
e1 -- extra
e2 -- missing this line
e3 -- missing ;
e4 -- missing ,
e5 -- missing
e6 -- missing id
e7 -- redefine
e8 -- not define sentence, replace int or float or char to id
e9 -- illageal end of define replace , with ;
e10 -- missing operator or ; must look back two chars
e11 -- illeageal operator change * / % to + -
e12 --missing operator
 
 
         ,        ;   int float  char  id     =     +     -        *        /       %     (        )     #
 0   e1    e1     6     7     8     5    e1    e1    e1    e1    e1    e1    e1    e1    e0  
 1   e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1   acc  
 2   e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    -1  
 3   e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    -2  
 4   10     9    e3    e3    e3    e4    e1    e1    e1    e1    e1    e1    e1    e1    e3  
 5   e5    e1    e1    e1    e1    e1    11    e1    e1    e1    e1    e1    e1    e1    e0  
 6   e6    e6    e7    e7    e7    12    e8    e1    e1    e1    e1    e1    e1    e1    e0  
 7   e6    e6    e7    e7    e7    13    e8    e1    e1    e1    e1    e1    e1    e1    e0  
 8   e6    e6    e7    e7    e7    14    e8    e1    e1    e1    e1    e1    e1    e1    e0  
 9   e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    -3  
10   e1    e1    e1    e1    e1    15    e1    e1    e1    e1    e1    e1    e1    e1    e9
11   e1    e6    e1    e1    e1    20    e1    e6    e6    e6    e6    e6    19    e1    e6  
12   -4    -4    e3    e3    e3    e4    e1    e1    e1    e1    e1    e1    e1    e1    e3  
13   -5    -5    e3    e3    e3    e4    e1    e1    e1    e1    e1    e1    e1    e1    e3  
14   -6    -6    e3    e3    e3    e4    e1    e1    e1    e1    e1    e1    e1    e1    e3  
15   -7    -7    e3    e3    e3    e4    e1    e1    e1    e1    e1    e1    e1    e1    e3  
16   e1    21    e1    e1    e1   e10    e1    22    23   e11   e11   e11    e1    e1    e3  
17   e1   -11    e1    e1    e1    e3    e1   -11   -11    24    25    26    e1   -11    e3  
18   e1   -15    e1    e1    e1    e3    e1   -15   -15   -15   -15   -15    e1   -15    e3  
19   e1    e6    e1    e1    e1    20    e1    e6    e6    e6    e6    e6    19    e1    e6  
20   e1   -17    e1    e1    e1    e1    e1   -17   -17   -17   -17   -17    e1   -17    e6  
21   e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    e1    -8  
22   e1    e6    e1    e1    e1    20    e1    e6    e6    e6    e6    e6    19    e1    e6  
23   e1    e6    e1    e1    e1    20    e1    e6    e6    e6    e6    e6    19    e1    e6  
24   e1    e6    e1    e1    e1    20    e1    e6    e6    e6    e6    e6    19    e1    e6  
25   e1    e6    e1    e1    e1    20    e1    e6    e6    e6    e6    e6    19    e1    e6  
26   e1    e6    e1    e1    e1    20    e1    e6    e6    e6    e6    e6    19    e1    e6  
27   e1   e12    e1    e1    e1   e12    e1    22    23   e11   e11   e11   e12    33   e12  
28   e1    -9    e1    e1    e1   e12    e1    -9    -9    24    25    26   e12    -9   e12  
29   e1   -10    e1    e1    e1   e12    e1   -10   -10    24    25    26   e12   -10   e12  
30   e1   -12    e1    e1    e1    e6    e1   -12   -12   -12   -12   -12   e12   -12    e6  
31   e1   -13    e1    e1    e1    e6    e1   -13   -13   -13   -13   -13   e12   -13    e6  
32   e1   -14    e1    e1    e1    e6    e1   -14   -14   -14   -14   -14   e12   -14    e6  
33   e1   -16    e1    e1    e1    e6    e1   -16   -16   -16   -16   -16   e12   -16    e6 


較好的地方:

這個程序分三塊:First集Follow集構造部分,項目集合生成部分,分析表構造部分

項目集合生成和分析表構造部分比較成功,多次修改文法最終生成的分析表都正確


需要改進的地方:

1、First集Follow集的構造還有待改進

2、錯誤處理還有待改進,有些錯誤處理可以合併,有些錯誤可能拆分之後更好

3、程序的結構不好,

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章