最近要交實驗報告了,不然這個LL1文法的博客可能還要好久才能想起來補全這個下篇。
前面實現了LL(1)文法的求first集和follow集,也求出來了預測分析表。現在我們的任務就是進行左右一項——利用預測分析表對文法進行預測。
《編譯原理(第3版)》(陳意雲等編著)這本書裏把用預測分析表進行預測的方法用僞代碼寫了出來,我寫在下方。
ip是一個標記輸入讀入的指針,a是ip所指的那個輸入的字符。
讓ip指向w $的第一個符號
令X等於棧頂符號
while(X != $) { /*棧非空*/
if(X是a) 把X從棧頂彈出並把ip推進到指向的下一個符號
else if(X是終結符) error()
else if(M[X,a]是出錯入口) error()
else if(M[X,a] = X -> Y1 Y2 …… Yk){
輸出產生式X -> Y1 Y2 …… Yk
從棧中彈出X
把Yk Yk-1 …… Y1 依次壓入棧,Y1在棧頂
}
令X等於棧頂符號
}
來看一下預測分析器接受輸入爲id * id + id的動作吧,這地方我只給了前面的一部分分析過程,後半部分看明白了這個結構就能直接推了。
按照上面的僞代碼我們就可以用python實現了。
這裏需要使用到棧數據結構,先手動寫一個Stack類吧。(這地方不寫註釋了,也很好看明白)
class Stack(object):
def __init__(self):
self.__list = []
def push(self,item):
self.__list.append(item)
def pop(self):
return self.__list.pop()
def top(self):
if self.__list:
return self.__list[-1]
return None
def is_empty(self):
return self.__list == []
def size(self):
return len(self.__list)
def show(self):
return ''.join(self.__list)
實現LL(1)文法
def getRes(lang):
V = lang.split(' ')
V.append('$')
l = len(V)
i = 0
# 生成初始棧
sta = Stack()
sta.push('$')
sta.push('E')
X = sta.top()
while X != '$':
print('輸入',''.join(V))
a = V[i]
if X == a:
sta.pop()
i = i+1
print('匹配',a)
elif X in vt:
raise Exception('Errof:the first sign is vt', X)
elif M[a][X] is []:
raise Exception('Errof:not found in analysis list', X)
elif M[a][X][0] in productions:
prod = M[a][X][0]
print('輸出',prod)
sta.pop()
ll = len(prod)
for ii in range(ll-1):
if prod[ll-ii-1] != 'epsilon':
sta.push(prod[ll-ii-1])
X = sta.top()
print('棧',sta.show())
print()
查看輸出結果
sentence = "id * id + id"
getRes(sentence)
輸入 id*id+id$
輸出 ['E', 'T', "E'"]
棧 $E'T
輸入 id*id+id$
輸出 ['T', 'F', "T'"]
棧 $E'T'F
輸入 id*id+id$
輸出 ['F', 'id']
棧 $E'T'id
輸入 id*id+id$
匹配 id
棧 $E'T'
輸入 id*id+id$
輸出 ["T'", '*', 'F', "T'"]
棧 $E'T'F*
輸入 id*id+id$
匹配 *
棧 $E'T'F
輸入 id*id+id$
輸出 ['F', 'id']
棧 $E'T'id
輸入 id*id+id$
匹配 id
棧 $E'T'
輸入 id*id+id$
輸出 ["T'", 'epsilon']
棧 $E'
輸入 id*id+id$
輸出 ["E'", '+', 'T', "E'"]
棧 $E'T+
輸入 id*id+id$
匹配 +
棧 $E'T
輸入 id*id+id$
輸出 ['T', 'F', "T'"]
棧 $E'T'F
輸入 id*id+id$
輸出 ['F', 'id']
棧 $E'T'id
輸入 id*id+id$
匹配 id
棧 $E'T'
輸入 id*id+id$
輸出 ["T'", 'epsilon']
棧 $E'
輸入 id*id+id$
輸出 ["E'", 'epsilon']
棧 $
結果和上面的表格展示的一樣,就完成了整個LL(1)文法。