【Python】代碼實現LL(1),LR(1)上下文無關文法(Stack()類)

任務要求

針對書上第三章中的表達式文法,採用LL(1)、LR(1)進行分析

相關文法(需要進行消除左遞歸等操作):
在這裏插入圖片描述

順手分享一下課本資源好了(可能不是最新版,排版略有點彆扭)
後文的書上內容就是指這本書:[編譯原理].陳意雲.文字版
提取碼:e0ag

LL1介紹

LL(1):從左往右處理輸入,最左推導,向前展望1個符號的,不帶回溯的自上而下的算法,是上下文無關文法的子集。
在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

LL1代碼實現

書上P59-60
在這裏插入圖片描述
在這裏插入圖片描述

#LL1
import pandas as pd
class Stack:
    def __init__(self):
        self.values = "$E"
    
    def push(self, product):
        while product[-1:]!='→':
            if(product[-1:]=='\'' or product[-1:]=='d'):
                self.values+=product[-2:]
                product=product[0:-2]
            else:
                self.values+=product[-1:]
                product=product[0:-1]
                
    def pop(self):
        if(self.values[-1:]=='\''or self.values[-1:]=='d'):
            self.values=self.values[:-2];
        else:
            self.values=self.values[:-1]

    def top(self):
        if(self.values[-1:]=='\''or self.values[-1:]=='d'):
            return self.values[-2:]
        else:
            return self.values[-1:]
        
    def empty(self):
        return len(self.values) == 0
    
def Next_Char():#獲取下一個詞法記號
    global pend_input
    if(pend_input[0:2]=="id"):
         pend_input=pend_input[2:]
         return "id"
    else:
        t=pend_input[0:1]
        pend_input=pend_input[1:]
        return t

dic={#手工構造預測分析表
'id':['E→TE\'','error','T→FT\'','error','F→id'],
'+':['error','E\'→+TE\'','error','T\'→ε','error'],
'*':['error','error','error','T\'→*FT\'','error'],
'(':['E→TE\'','error','T→FT\'','error','F→(E)'],
')':['error','E\'→ε','error','T\'→ε','error'],
'$':['error','E\'→ε','error','T\'→ε','error']}
Analysis_table=pd.DataFrame(dic,index=['E','E\'','T','T\'','F'])

if __name__ == '__main__':
    stk = Stack()           #構造自定義棧
    #pend_input=input()+'$' #記得在輸入內容後加上表示終止的"$"符號
    pend_input='id*id+id$'  #可手動輸入亦可提前輸入'待處理的輸入內容'
    pend_head=Next_Char()   #取出第一個待處理的符號
    print("預測分析器接受輸入id*id+id的部分動作(與書上稍有不同)")
    print("%-15s"%"棧","%-15s"%"輸入","%+10s"%"輸出")
    while(stk.empty()==False):              
        if stk.top()==pend_head: 
            if pend_head!='$':
                print('----------------成功匹配符號:{}-------------------'.format(pend_head))
            pend_head=Next_Char()
            stk.pop()
        else:
            product=Analysis_table[pend_head][stk.top()]#獲取產生式
            if product=='error':
                print('Error  Skip!')
                stk.pop()
            else:
                print("%-15s"%stk.values,"%-15s"%str(pend_head+pend_input),"%+15s"%product)
                stk.pop()
                if(product[-1:]!='ε'):#對於產生空串的產生式,只需彈棧,不需入棧
                    stk.push(product)

手動構造的預測分析表:
在這裏插入圖片描述

預測分析器接受輸入id * id + id的相關動作:
在這裏插入圖片描述

LR1簡略介紹

LR(1):從左往右處理輸入,構造一個最右推導的逆過程(規範規約),向前看1個符號的,自下而上的算法,是上下文無關文法的子集。

LR文法:我們能爲之構造出所有條目都唯一的LR分析表。

LR分析器特點:適用於一大類上下文無關文法,效率高。

句型的句柄是和某產生式右部匹配的子串,並且,把它歸約成該產生式左部的非終結符代表了最右推導過程的逆過程的一步。

活前綴:右句型的前綴,該前綴不超過最右句柄的右端。

在這裏插入圖片描述

LR1代碼

書上P73-74

在這裏插入圖片描述
r後面的數字代表按第幾個產生式做歸約;s代表移進,它後面的數字轉移到哪個狀態。產生式:
在這裏插入圖片描述
在這裏插入圖片描述

#LR1
import pandas as pd
class Stack:
    def __init__(self):
        self.values = "0"
    def push(self, s):
        self.values=self.values+s
        def __init__(self):
            self.values = "0"             
    def pop(self):
        if(self.values[-2:]=='id'or self.values[-2:]=='10'or self.values[-2:]=='11'):
            self.values=self.values[:-2]
        else:
            self.values=self.values[:-1]
    def top(self):
        if(self.values[-2:]=='10'or self.values[-2:]=='id' or self.values[-2:]=='11'):
            return self.values[-2:]
        else:
            return self.values[-1:]
class Input_Token:
    def __init__(self):
        self.values = ""
    def Get_Token(self):#獲取待處理字符串pend_input中下一個詞法記號
        if(self.values[0:2]=="id"):
             self.values=self.values[2:]
             return "id"
        else:
            s=self.values[0:1]
            self.values=self.values[1:]
            return s
    def Show_Token(self):#查看待處理字符串pend_input的下一個詞法記號(不取出)
        if (self.values[0:2] == "id"):
            return "id"
        else:
            s = self.values[0:1]
            return s

def Len_Right(p):
    p_char=p[p.find('→')+1:]
    if p_char=='id':
        return 1
    else:
        return len(p_char)

def LR1(head,top):#分析程序
    action=SLR[head][top]
    if action=='acc':#接受
        print("%-9s"%stk.values,"%+9s"%pend_input.values,"%+6s"%"接受")
        return False
    else:
        if action[0]=='s':#移進
            print("%-9s"%stk.values,"%+9s"%pend_input.values,"%+6s"%"移進")
            stk.push(pend_input.Get_Token())
            stk.push(action[1:])
        elif action[0]=='r':#歸約
            production=Production[int(action[1:])]
            print("%-9s"%stk.values,"%+9s"%pend_input.values,"%+5s"%"按",production,"歸約")
            for i in range(Len_Right(production)*2): #按照產生式右邊長度的2倍出棧(1字符跟1數字)
                stk.pop()
            top_num=stk.top()
            left=production[0] #獲取產生式左邊的字符
            stk.push(left)
            stk.push(SLR[left][top_num])
        else:
            print('Error!\n Exit!')
            return False
        return True

dic={'id':['s5',' ',' ',' ','s5',' ','s5','s5',' ',' ',' ',' '],
      '+':[' ','s6','r2','r4',' ','r6',' ',' ','s6','r1','r3','r5'],
      '*':[' ',' ','s7','r4',' ','r6',' ',' ',' ','s7','r3','r5'],
      '(':['s4',' ',' ',' ','s4',' ','s4','s4',' ',' ',' ',' ',],
      ')':[' ',' ','r2','r4',' ','r6',' ',' ','s11','r1','r3','r5'],
      '$':[' ','acc','r2','r4',' ','r6',' ',' ',' ','r1','r3','r5'],
      'E':['1',' ',' ',' ','8',' ',' ',' ',' ',' ',' ',' '],
      'T':['2',' ',' ',' ','2',' ','9',' ',' ',' ',' ',' ',],
      'F':['3',' ',' ',' ','3',' ','3','10',' ',' ',' ',' ']}
SLR=pd.DataFrame(dic,index=['0','1','2','3','4','5','6','7','8','9','10','11'])#分析表
Production=['null','E→E+T','E→T','T→T*F','T→F','F→(E)','F→id']#產生式   
if __name__=='__main__':
    stk = Stack()
    pend_input=Input_Token()
    pend_input.values='id*id+id$'
    print("———————————————LR分析器———————————————")
    print("%-7s"%"棧","%+8s"%"輸入","%+6s"%"動作")
    while(True):
        if LR1(pend_input.Show_Token(),stk.top())==False:
            break
    print("——————————————————————————————————————")

分析表(action表)
描述?
實驗結果:
在這裏插入圖片描述

LR分析方法和LL分析方法的比較

在這裏插入圖片描述

部分參考資料

編譯原理:語法分析2-非遞歸的預測分析

編譯原理:語法分析3-LR分析器

編譯原理:LL(1),LR(0),SLR(1),LALR(1),LR(1)對比

《編譯原理》LR 分析法與構造 LR(1) 分析表的步驟 - 例題解析

Python棧實現

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