語義分析較困難的根本原因在於語法的可遞歸性,深層次的遞歸使得問題的分解看起來變得相當地復雜。但是如果能將遞歸問題轉化為迭代問題,便能很大程度地簡化此問題模型。遞歸轉化為迭代的關鍵在於——找到最深層遞歸結構的全部特征,迭代化之,問題便迎刃而解。 一般情況下,人們在面對復雜的遞歸問題時時,亦是依據其語法規則,找到其遞歸深層的結構,化解之,步步迭代,如此,問題便得到解決。人類的思維很是擅長將遞歸問題轉化為迭代問題,而學習知識的過程,則可以看成是對各種各樣語法規則的理解與掌握。 一元操作符、二元操作符的遞歸問題,可以很簡單的轉化為迭代,多元操作符的情況稍復雜些。 所有的操作符及其優先級如下圖: 如typeof、取地址、指針指向等,在這裡並未實現。實現的包括有算數運算式、邏輯運算式、函數調用與括號。對於理解語義分析的過程,已足夠。 對於不包含括號與函數的簡單表達式,我們語義分析演算過程如下: 我們的數據結構: 復制代碼 1 ''' 2 ____________________________ Syntax Tree 3 Parenthesis: 4 ["(",None] 5 [")",None] 6 Operators(grouped by precedence): 7 Unary : 8 1 + - ! ~ ["+",None] ["-",None] ["!",None] ["~",None] 9 Binary : 10 2 * / % ["*",None] ["/",None] ["%",None] 11 3 + - ["+",None] ["-",None] 12 4 << >> ["<<",None] [">>",None] 13 5 > >= < <= [">",None] [">=",None] ["<",None] ["<=",None] 14 6 == != ["==",None] ["!=",None] 15 7 & ["&",None] 16 8 ^ ["^",None] 17 9 | ["|",None] 18 10 && ["&&",None] 19 11 || ["||",None] 20 Ternary : 21 12 expr ? expr : expr ["?",None] [":",None] ["@expr","?:",listPtr0,listPtr1,listPtr2] 22 13 expr , expr , expr... 23 Var,Num,Expr,Function: 24 ["@var","varName"] 25 ["@num","num_string"] 26 ["@expr","Operator",listPtr,...] 27 ["@func","funcName",listPtr1,...] 28 ["@expr_list",["@var"|"@num"|"@expr"|"@func",...],...] 29 ''' 復制代碼 這是我們最終的代碼模塊圖: 其中形如 module_x_y 的函數,x表示此運算符的優先級,y表示橫向序號,從零開始。代碼注釋已經寫得很詳細了,請看源代碼: View Code 上面的代碼雖然很大,卻是最簡單的一部分了,其實可以采取一些方法顯著地壓縮代碼量,但是時間有限。 下面給出一元運算符、二元運算符、三元運算符及逗號分隔符的語義分析過程,這是本文的核心代碼之一: 復制代碼 1 ######################################## global list 2 # construct a module dictionary 3 # module_dic_tuple[priority]['Operator'](lis,i) 4 module_dic_tuple=({}, { '+':module_1_0,'-':module_1_1,'!':module_1_2,'~':module_1_3 },\ 5 { '*':module_2_0,'/':module_2_1,'%':module_2_2 }, \ 6 { '+':module_3_0,'-':module_3_1 },\ 7 { '<<':module_4_0,'>>':module_4_1 },\ 8 { '>':module_5_0,'>=':module_5_1,'<':module_5_2,'<=':module_5_3 },\ 9 { '==':module_6_0,'!=':module_6_1 },\ 10 { '&':module_7_0 },\ 11 { '^':module_8_0 },\ 12 { '|':module_9_0 },\ 13 { '&&':module_10_0 },\ 14 { '||':module_11_0 },\ 15 { '?:':module_12_0 },\ 16 { ',':module_13_0 } ) 17 18 operator_priority_tuple=( () , ('+', '-', '!', '~') , ('*','/','%'),\ 19 ('+','-'),('<<','>>'),\ 20 ('>','>=','<','<='),('==','!='),\ 21 ('&'),('^'),('|'),('&&'),('||'),('?',':'),(',') ) 22 23 ############################# parse:unary,binary,ternary,comma expr 24 ########### return value : 25 ############# 0 parsed sucessfully 26 ############# 1 syntax error 27 def parse_simple_expr(lis): 28 if len(lis)==0: 29 return 1 30 #if lis[len(lis)-1][0][0]!='@': 31 # return 1 32 #if lis[0][0][0]!='@' and lis[0][0] not in ('+','-','!','~'): 33 # return 1 34 for pri in range(1,12): # pri 1,2,3,4,5,6,7,8,9,10,11 35 i=0 36 while 1: 37 if len(lis)==1 and lis[0][0][0]=='@': 38 return 0 39 if i>=len(lis): 40 break 41 if lis[i][0] in operator_priority_tuple[pri]: 42 if module_dic_tuple[pri][lis[i][0]](lis,i)==0: 43 i=0 44 continue 45 else: 46 i=i+1 47 continue 48 else: 49 i=i+1 50 for pri in range(12,13): # pri 12 # parse ...A?A:A... 51 i=0 52 while 1: 53 if len(lis)==1 and lis[0][0][0]=='@': 54 return 0 55 if i>=len(lis): 56 break 57 if lis[i][0]==':': 58 if module_dic_tuple[pri]['?:'](lis,i)==0: 59 i=0 60 continue 61 else: 62 i=i+1 63 continue 64 else: 65 i=i+1 66 return module_dic_tuple[13][','](lis,0) 67 return 1 復制代碼 上面代碼中,使用了函數引用的詞典鏈表來簡化此部分的代碼數量。 這一部分就不進行驗證展示了,具體過程與前面的文章《一個簡單的語義分析算法:單步算法——Python實現》中的描述類似。 實現了 parse_simple_expr 功能之後,剩下的函數與括號的語義分析變得簡單些,演算過程如下: 代碼實現: 復制代碼 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 if length==0: 12 return [2,None,None] 13 try: 14 x=lis.index([")",None]) 15 except: 16 err=1 17 lis.reverse() 18 try: 19 y=lis.index(["(",None],length-x-1) 20 except: 21 err=1 22 lis.reverse() 23 y=length-y-1 24 if err==1: 25 return [1,None,None] 26 else: 27 return [0,y,x] 28 29 30 ############################# parse:unary binary ternary prenthesis function expr 31 ########### return value : 32 ############# 0 parsed sucessfully 33 ############# 1 syntax error 34 ############################# find first ')' 35 def parse_comp_expr(lis): 36 while 1: 37 if len(lis)==0: 38 return 1 39 if len(lis)==1: 40 if lis[0][0][0]=='@': 41 return 0 42 else: 43 return 1 44 place=module_parenthesis_place(lis) 45 if place[0]==0: 46 mirror=lis[(place[1]+1):place[2]] 47 if parse_simple_expr(mirror)==0: 48 if place[1]>=1 and lis[place[1]-1][0]=='@var': 49 '''func''' 50 funcName=lis[place[1]-1][1] 51 del lis[place[1]-1:(place[2]+1)] 52 lis.insert(place[1]-1,["@func",funcName,mirror[0]]) 53 else: 54 del lis[place[1]:(place[2]+1)] 55 lis.insert(place[1],mirror[0]) 56 else: 57 return 1 58 else: 59 return parse_simple_expr(lis) 60 return 1 復制代碼 如此,代碼到此結束。 下面給出實驗結果: 復制代碼 >>> ls=[['(',None],['@var','f'],['(',None],['@num','1'],[',',None],['@num','2'],[',',None],['@num','3'],[',',None],['!',None],['-',None],['@var','x'],['?',None],['@var','y'],[':',None],['~',None],['@var','z'],[')',None],['-',None],['@num','3'],[')',None],['/',None],['@num','4']] >>> ls [['(', None], ['@var', 'f'], ['(', None], ['@num', '1'], [',', None], ['@num', '2'], [',', None], ['@num', '3'], [',', None], ['!', None], ['-', None], ['@var', 'x'], ['?', None], ['@var', 'y'], [':', None], ['~', None], ['@var', 'z'], [')', None], ['-', None], ['@num', '3'], [')', None], ['/', None], ['@num', '4']] >>> len(ls) 23 >>> parse_comp_expr(ls);ls 0 [['@expr', '/', ['@expr', '-', ['@func', 'f', ['@expr_list', ['@num', '1'], ['@num', '2'], ['@num', '3'], ['@expr', '?:', ['@expr', '!', ['@expr', '-', ['@var', 'x']]], ['@var', 'y'], ['@expr', '~', ['@var', 'z']]]]], ['@num', '3']], ['@num', '4']]] >>> len(ls) 1 >>> 復制代碼