本學期編譯原理的一個大做業,個人選題是算術表達式的詞法語法語義分析,當時因爲學得比較渣,只用了遞歸降低的方法進行了分析。python
首先,用戶輸入算術表達式,其中算術表達式能夠包含基本運算符,括號,數字,以及用戶自定義變量。git
詞法分析,檢查單詞變量是否正確;語法分析,檢查算術表達式語法是否正確並輸出生成語法樹;語義分析,輸出四元表達式。數據結構
最終效果圖:app
例如輸入:spa
詞法分析結果:設計
語法分析結果:3d
語義分析結果:指針
算術表達式的組成語法以下:blog
無符號整數 = 〈數字〉{〈數字〉} 遞歸
〈標識符〉= 〈字母〉{〈字母〉|〈數字〉}
表達式〉= [+|-]〈項〉{〈加減運算符〉〈項〉}
〈項〉= 〈因子〉{〈乘除運算符〉〈因子〉}
〈因子〉= 〈標識符〉|〈無符號整數〉|‘(’〈表達式〉‘)’
〈加減運算符〉= +|-
〈乘除運算符〉= *|/
注意:
#標識符以字母開頭,僅包含字母和數字
#字母包含大寫和小寫字母
符號文法表示:
Indentifer: 標識符 digit:數字 M:表達式
項:T 因子:F
M -> +E|-E|E
E -> E+T|E-T|T
T -> T*F|T/F|F
F -> (E)|indentifer|digit
消除左遞歸,改進文法:
1. M -> +E|-E|E
2. E -> TE~
3. E~ -> +TE~|-TE~|&
4. T -> FT~
5. T~ -> *FT~|/FT~|&
6. F -> (E)|indentifer|digit
運算符:( , ) , + , - , * , / 類別碼:3
標識符:〈字母〉{〈字母〉|〈數字〉} 類別碼:1
無符號整數:〈數字〉{〈數字〉} 類別碼:2
依次接受所輸入的字符串,根據DFA進行判斷單詞類型,將單詞及符號內碼存入符號表字典,將單詞存入單詞棧
1.如若接收到字母說明爲標識符,接着一直接受字母和數字,直到出現非數字和非字母符號
2.如若在運算符後接收到數字,則說明爲無符號整數,一直接受直到出現非數字符號
3.如若接受到運算符,則繼續處理
簡單繪製的DFA:
符號表:dic={}
單詞棧:table=[]輸入數據
2.語法分析
爲文法中的每個非終結符號設計對應的處理程序,處理程序按照具體的文法接受順序設計,每當程序選擇其中一個文法時,將其保存並打印出來,若單詞棧中的全部單詞都被接受,則說明語法正確,其餘狀況,則說明語法錯誤
dic={} #符號表
table=[] #單詞棧
wenfa=[] #字符串文法
3.語義分析與中間代碼生成
這裏我運用的依舊是遞歸降低的思想,我並無利用語法分析的結果,而是利用詞法分析的結果爲每個非終結符號設計相應的程序, 當結果足夠生成四元式時,將其輸出。將結果賦給給臨時變量,傳遞給父項。
table=[] #單詞棧
siyuan=[] #四元式
源碼:
#-*- coding=utf-8 -*- letter='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' number='0123456789' operater='+-*/()' dic={} #符號表 table=[] #單詞棧 wenfa=[] #字符串文法 siyuan=[] #四元式 ##################################### 詞法分析 ###################################### def cifa(string): #詞法分析 print '' m=0 state=0 #1:爲標識符 2:爲數字串 3:爲運算符 for i in range(len(string)): if string[i] in operater : #若是是運算符 if state==1: #state=1代表其前面的爲標識符 print string[m:i],'是標識符,類型碼:1' dic[string[m:i]]=1 table.append(string[m:i]) elif state==2: #state=2代表其前面的爲數字 print string[m:i],'是數字,類型碼:2' dic[string[m:i]]=2 table.append(string[m:i]) m=i+1 state=3 print string[i],'是運算符,類型碼:3' dic[string[i]]=3 table.append(string[i]) elif string[i] in number: #若是是數字 if i==m: #判斷此時的數字是否爲整數的第一個數字,如果則改變狀態爲無符號整數 state=2 elif string[i] in letter: #若是是字母 if state==2: #判斷此時的狀態,若state=2代表狀態爲無符號整數,而整數內不能包含字母,故報錯 print '詞法分析檢測到錯誤,數字串中不能包含字母' exit(0) if i==m: #判斷此時的字母是否爲標識符的第一個字母,如果則改變狀態爲標識符 state=1 else: #當輸入的字符均不符合以上判斷,則說明爲非法字符,故報錯 print '詞法分析檢測到非法字符' exit(0) if state==1: #當字符串檢查完後,若字符串最後部分爲標識符,應將其print出來 print string[m:],'是標識符,類型碼:3' dic[string[m:]]=1 table.append(string[m:]) elif state==2: #若字符串最後部分爲無符號整數,應將其print出來 print string[m:],'是無符號整數,類型碼:2' dic[string[m:]]=2 table.append(string[m:]) table.append('#') print '字符棧:',table,'\n詞法正確' ################################### 語法分析 ##################################### ''' 基本文法: M -> +E|-E|E E -> TE~ E~ -> +TE~|-TE~|& T -> FT~ T~ -> *FT~|/FT~|& F -> (E)|indentifer|digit ''' class yufa(): #語法分析程序 def __init__(self): self.i=0 #棧指針 try: #用異常處理程序捕獲程序的錯誤,出現異常則報錯 self.m() except: print '\n語法分析程序檢查到錯誤' exit(0) def m(self): #PM程序 if(table[self.i]=='+'): self.i+=1 wenfa.append('M -> +E') self.e() elif(table[self.i]=='-'): self.i+=1 wenfa.append('M -> -E') self.e() else: wenfa.append('M -> E') self.e() if(self.i is not len(table)-1): #語法分析結束時,若單詞棧指針與單詞表長度不相等,報錯 print "\n語法分析程序檢查到錯誤,'('前應該有運算符" exit(0) else: print '\n字符串語法是:' #若一切正確,則輸出語法樹文法 for i in wenfa: print i print '語法正確' def e(self): #PE程序 wenfa.append('E -> TE1') self.t() self.e1() def e1(self): #PE1程序 if(table[self.i]=='+'): self.i+=1 wenfa.append('E1 -> +TE1') self.t() self.e1() elif(table[self.i]=='-'): self.i+=1 wenfa.append('E1 -> -TE1') self.t() self.e1() else: wenfa.append('E1 -> &') def t(self): #PT程序 wenfa.append('T -> FT1') self.f() self.t1() def t1(self): #PT1程序 if(table[self.i]=='*'): self.i+=1 wenfa.append('T1 -> *FT1') self.f() self.t1() elif(table[self.i]=='/'): self.i+=1 wenfa.append('T1 -> /FT1') self.f() self.t1() else: wenfa.append('T1 -> &') def f(self): #PF程序 if(table[self.i]=='('): wenfa.append('F -> (E)') self.i+=1 self.e() if(table[self.i]!=')'): raise Exception self.i+=1 elif(dic[table[self.i]]==1): wenfa.append('F -> Indentifer '+str(table[self.i])) self.i+=1 elif(dic[table[self.i]]==2): wenfa.append('F -> Digit '+str(table[self.i])) self.i+=1 else: raise Exception #若均不符合,則引出異常 ####################################### 語義分析 ####################################### class yuyi: def __init__(self): print '\n語義分析結果(四元式):' self.i=0 #棧指針 self.flag=0 #記錄臨時變量T數目 self.m() for i in siyuan: #輸出四元式結果 print i def m(self): #PM程序 if(table[self.i]=='+'): self.i+=1 ret1=self.e() siyuan.append('(+,0,'+ret1+',out)') self.flag+=1 elif(table[self.i]=='-'): self.i+=1 ret2=self.e() siyuan.append('(-,0,'+ret2+',out)') self.flag+=1 else: ret3=self.e() siyuan.append('(=,'+ret3+',0,out)') def e(self): #PE程序 ret1=self.t() ret2,ret3=self.e1() if(ret2!='&'): #若ret2不爲&,則能夠產生四元式,不然將變量傳遞給父項 self.flag+=1 siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')') return 'T'+str(self.flag) else: return ret1 def e1(self): #PE1程序 if(table[self.i]=='+'): self.i+=1 ret1=self.t() ret2,ret3=self.e1() if(ret2=='&'): return '+',ret1 else: self.flag+=1 siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')') return '+','T'+str(self.flag) elif(table[self.i]=='-'): self.i+=1 ret1=self.t() ret2,ret3=self.e1() if(ret2=='&'): return '-',ret1 else: self.flag+=1 siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')') return '-','T'+str(self.flag) else: return '&','&' def t(self): #PT程序 ret1=self.f() ret2,ret3=self.t1() if(ret2!='&'): self.flag+=1 siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')') return 'T'+str(self.flag) else: return ret1 def t1(self): #PT1程序 if(table[self.i]=='*'): self.i+=1 ret1=self.f() ret2,ret3=self.t1() if(ret2=='&'): return '*',ret1 else: self.flag+=1 siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')') return '*','T'+str(self.flag) elif(table[self.i]=='/'): self.i+=1 ret1=self.f() ret2,ret3=self.t1() if(ret2=='&'): #若ret2不爲&,則能夠產生四元式,不然將變量傳遞給父項 return '/',ret1 else: self.flag+=1 siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')') return '/','T'+str(self.flag) else: return '&','&' def f(self): #PF程序 if(table[self.i]=='('): self.i+=1 ret1=self.e() self.i+=1 return str(ret1) elif(dic[table[self.i]]==1): #當爲標識符時,傳遞給父項 temp=self.i self.i+=1 return table[temp] elif(dic[table[self.i]]==2): #當爲整數時,傳遞給父項 temp=self.i self.i+=1 return table[temp] ####################################### 主程序 ####################################### if __name__=='__main__': string=raw_input('請輸入表達式:') cifa(string) yufa() yuyi()