以前 曾經有一個人教會我一件事
要學會相信一些看似不可能的事
當你真的相信的時候
或許 沒有什么事情是不可能的
——《秦時明月•與子同歸》
在編譯原理的眾多書籍中,陳述了很多生成語法樹的經典算法,它們大多是基於遞歸的方式進行工作的。在本文中,將與大家分享一種基於迭代方式的、易於理解的語法樹生成算法,由於其一次成功迭代僅生成一個語法“樹枝”的處理特點,可稱之為單步算法。
我們將通過對中綴表達式的語法樹生成實驗進行算法細節的初步闡述與驗證。
第一階段:簡單模型
我們第一階段的中綴表達式語法規定如下:
expr -> expr addop term | term addop -> + | - term -> term mulop factor | factor mulop -> * | / | % factor -> var | num | function
該語法的等價描述:
運算符優先級:(從高到低)
—————————————————————————— * / % 二元操作符 - + 二元操作符 —————————————————————————— 參與運算的可以是:
—————————————————————————— num:常數 var:變量 function:函數
expr:表達式
——————————————————————————
對於這種簡單的中綴表達式,我們的算法處理過程如下:(先大概看一遍處理過程,不要阻塞在這兒)
#例子1:
90-565*235/31+6756+45/312-321%12 90-A/31+6756+45/312-321%12 90-A+6756+45/312-321%12 A+6756+45/312-321%12 A+45/312-321%12 A+A-321%12 A-321%12 A-A A
為了接下來討論方便,我們做一些類似正則表達式的符號約定:
# ^ 行首錨定
# $ 行尾錨定
# ... 與正則的(.*)意義相同,表示任意多字符
# A 參與運算的單位 可以是num、var、function或者expr
# 下面便是我們算法的合並規則
^A-A$ ^A-A+...
^A-A-... ^A+A$ ^A+A-...
^A+A+... ...A*A... ...A/A... ...A%A...
算法處理過程:
下面我們故意給中綴表達式加入一語法錯誤,看一看處理過程:
如果語法正確,是不可能上圖情況的,所以,如果出現上圖情況,可斷定所給中綴表達式中有語法錯誤出現。
下面我們給出此算法的Python實現代碼:
1 # 數據結構 2 """ 3 list structure : 4 - + * / % ( ) @var @num @expr @func 5 6 ["-",None] 7 ["+",None] 8 ["*",None] 9 ["/",None] 10 ["%",None] 11 ["(",None] 12 [")",None] 13 ["@var","varName"] 14 ["@num","num_string"] 15 ["@expr","-"|"+"|"*"|"/"|"%",listPtr,...] 16 ["@func","funcName",listPtr1,...] 17 18 """ 19 20 ''' 31 + 8 * 9 ''' 21 listToParse=[ ['@num','31'] , ['+',None] , ['@num','8'] , ['*',None] , ['@num','9'] ]
運算符'-'規則:
1 ########### return value : 2 ############# 0 parsed some expresions 3 ############# 1 done nothing but no errors happene 4 def module_minus(lis,i): 5 6 # left i right are both indexes :) 7 left=i-1 8 right=i+1 9 10 # process: ^A-A$ 11 if i==1 and len(lis)==3: 12 if lis[left][0]=="@var" or lis[left][0]=="@num" or \ 13 lis[left][0]=="@expr" or lis[left][0]=="@func" : 14 if lis[right][0]=="@var" or lis[right][0]=="@num" or \ 15 lis[right][0]=="@expr" or lis[right][0]=="@func" : 16 leftPtr=lis[left] 17 rightPtr=lis[right] 18 del lis[left:left+3] 19 lis.insert(left,["@expr","-",leftPtr,rightPtr]) 20 return 0 21 # process: ^A-A+... | ^A-A-... 22 if i==1 and len(lis)>3: 23 if lis[left][0]=="@var" or lis[left][0]=="@num" or \ 24 lis[left][0]=="@expr" or lis[left][0]=="@func" : 25 if lis[right][0]=="@var" or lis[right][0]=="@num" or \ 26 lis[right][0]=="@expr" or lis[right][0]=="@func" : 27 if lis[right+1][0] in "-+" : 28 leftPtr=lis[left] 29 rightPtr=lis[right] 30 del lis[left:left+3] 31 lis.insert(left,["@expr","-",leftPtr,rightPtr]) 32 return 0 33 34 return 1
運算符'+'規則:
1 ########### return value : 2 ############# 0 parsed some expresions 3 ############# 1 done nothing but no errors happene 4 def module_plus(lis,i): 5 6 # left i right are both indexes :) 7 left=i-1 8 right=i+1 9 10 # process ^A+A$ 11 if i==1 and len(lis)==3: 12 if lis[left][0]=="@var" or lis[left][0]=="@num" or \ 13 lis[left][0]=="@expr" or lis[left][0]=="@func" : 14 if lis[right][0]=="@var" or lis[right][0]=="@num" or \ 15 lis[right][0]=="@expr" or lis[right][0]=="@func" : 16 leftPtr=lis[left] 17 rightPtr=lis[right] 18 del lis[left:left+3] 19 lis.insert(left,["@expr","+",leftPtr,rightPtr]) 20 return 0 21 # process ^A+A-... | ^A+A+... 22 if i==1 and len(lis)>3: 23 if lis[left][0]=="@var" or lis[left][0]=="@num" or \ 24 lis[left][0]=="@expr" or lis[left][0]=="@func" : 25 if lis[right][0]=="@var" or lis[right][0]=="@num" or \ 26 lis[right][0]=="@expr" or lis[right][0]=="@func" : 27 if lis[right+1][0] in "-+" : 28 leftPtr=lis[left] 29 rightPtr=lis[right] 30 del lis[left:left+3] 31 lis.insert(left,["@expr","+",leftPtr,rightPtr]) 32 return 0 33 34 return 1
運算符'*'規則:
1 ########### return value : 2 ############# 0 parsed some expresions 3 ############# 1 done nothing but no errors happene 4 def module_multiply(lis,i): 5 6 # left i right are both indexes :) 7 left=i-1 8 right=i+1 9 10 # i is not at head and end 11 # process ...A*A... 12 if i<len(lis)-1 and i>0 : 13 if lis[left][0]=="@var" or lis[left][0]=="@num" or \ 14 lis[left][0]=="@expr" or lis[left][0]=="@func" : 15 if lis[right][0]=="@var" or lis[right][0]=="@num" or \ 16 lis[right][0]=="@expr" or lis[right][0]=="@func" : 17 leftPtr=lis[left] 18 rightPtr=lis[right] 19 del lis[left:left+3] 20 lis.insert(left,["@expr","*",leftPtr,rightPtr]) 21 return 0 22 return 1
運算符'/'規則:
1 ########### return value : 2 ############# 0 parsed some expresions 3 ############# 1 done nothing but no errors happene 4 def module_division(lis,i): 5 6 # left i right are both indexes :) 7 left=i-1 8 right=i+1 9 10 # i is not at head and end 11 # process ...A/A... 12 if i<len(lis)-1 and i>0 : 13 if lis[left][0]=="@var" or lis[left][0]=="@num" or \ 14 lis[left][0]=="@expr" or lis[left][0]=="@func" : 15 if lis[right][0]=="@var" or lis[right][0]=="@num" or \ 16 lis[right][0]=="@expr" or lis[right][0]=="@func" : 17 leftPtr=lis[left] 18 rightPtr=lis[right] 19 del lis[left:left+3] 20 lis.insert(left,["@expr","/",leftPtr,rightPtr]) 21 return 0 22 return 1
運算符'%'規則:
1 ########### return value : 2 ############# 0 parsed some expresions 3 ############# 1 done nothing but no errors happene 4 def module_mod(lis,i): 5 6 # left i right are both indexes :) 7 left=i-1 8 right=i+1 9 10 # i is not at head and end 11 # process ...A%A... 12 if i<len(lis)-1 and i>0 : 13 if lis[left][0]=="@var" or lis[left][0]=="@num" or \ 14 lis[left][0]=="@expr" or lis[left][0]=="@func" : 15 if lis[right][0]=="@var" or lis[right][0]=="@num" or \ 16 lis[right][0]=="@expr" or lis[right][0]=="@func" : 17 leftPtr=lis[left] 18 rightPtr=lis[right] 19 del lis[left:left+3] 20 lis.insert(left,["@expr","%",leftPtr,rightPtr]) 21 return 0 22 return 1
語義分析函數:
1 ########### return value : 2 ############# 0 parsed sucessfully 3 ############# 1 syntax error 4 ############# 2 list is null :( 5 def parse_simple_expr(lis): 6 while 1: 7 if len(lis)==0 : 8 return 2 9 if len(lis)==1 : 10 if lis[0][0]=="@var" or lis[0][0]=="@num" or \ 11 lis[0][0]=="@expr" or lis[0][0]=="@func" : 12 return 0 13 else: 14 return 1 15 if len(lis)==2 : 16 return 1 17 i=0 18 while 1: 19 if i<0 or i>=len(lis): 20 return 1 21 if lis[i][0] in "-+*/%": 22 if lis[i][0]=="-": 23 if module_minus(lis,i)==0: 24 break 25 else: 26 i=i+1 27 continue 28 elif lis[i][0]=="+": 29 if module_plus(lis,i)==0: 30 break 31 else: 32 i=i+1 33 continue 34 elif lis[i][0]=="*": 35 if module_multiply(lis,i)==0: 36 break 37 else: 38 i=i+1 39 continue 40 elif lis[i][0]=="/": 41 if module_division(lis,i)==0: 42 break 43 else: 44 i=i+1 45 continue 46 elif lis[i][0]=="%": 47 if module_mod(lis,i)==0: 48 break 49 else: 50 i=i+1 51 continue 52 else : 53 return 1 54 else: 55 i=i+1 56 57 return 0
實驗結果:
第二階段:為我們的中綴表達式加入括號 :)
新的文法規則如下:
expr -> expr addop term | term addop -> + | - term -> term mulop factor | factor mulop -> * | / | % factor -> ( expr )| var | num | function
算法處理大概過程:
尋找出表達式中第一對'('')'位置的方法:
1 ########### return value :[intStatusCode,indexOf'(',indexOf')'] 2 ############# intStatusCode 3 ############# 0 sucessfully 4 ############# 1 no parenthesis matched 5 ############# 2 list is null :( 6 def module_parenthesis_place(lis): 7 length=len(lis) 8 err=0 9 x=0 10 y=0 11 12 if length==0: 13 return [2,None,None] 14 15 try: 16 x=lis.index([")",None]) 17 except: 18 err=1 19 lis.reverse() 20 try: 21 y=lis.index(["(",None],length-x-1) 22 except: 23 err=1 24 lis.reverse() 25 y=length-y-1 26 27 if err==1: 28 return [1,None,None] 29 else: 30 return [0,y,x]
處理包含有'('')'功能的中綴表達式的方法:
########### return value : ############# 0 parsed sucessfully ############# 1 syntax error ############# 2 list is null :( def parse_parenthesis_expr(lis): while 1: if len(lis)==0 : return 2 if len(lis)==1 : if lis[0][0]=="@var" or lis[0][0]=="@num" or \ lis[0][0]=="@expr" or lis[0][0]=="@func" : return 0 else: return 1 if len(lis)==2 : return 1 place=module_parenthesis_place(lis) if place[0]==0: mirror=lis[(place[1]+1):place[2]] if parse_simple_expr(mirror)==0: del lis[place[1]:(place[2]+1)] lis.insert(place[1],mirror[0]) else: return 1 else: return parse_simple_expr(lis) return 0
實驗結果:
附錄:
在接下來的文章中,將會逐步增加其他的語義分析功能,如參與表達式運算的函數、條件語句的語法樹生成等。
如有問題或者建議,歡迎留言討論 :)