编辑推荐: |
本文主要分享了一种基于迭代方式的、易于理解的语法树生成算法。
本文来自于燕云,由火龙果软件Linda编辑,推荐。 |
|
以前 曾经有一个人教会我一件事
要学会相信一些看似不可能的事
当你真的相信的时候
或许 没有什么事情是不可能的
——《秦时明月•与子同归》
在编译原理的众多书籍中,陈述了很多生成语法树的经典算法,它们大多是基于递归的方式进行工作的。在本文中,将与大家分享一种基于迭代方式的、易于理解的语法树生成算法,由于其一次成功迭代仅生成一个语法“树枝”的处理特点,可称之为单步算法。
我们将通过对中缀表达式的语法树生成实验进行算法细节的初步阐述与验证。
第一阶段:简单模型
我们第一阶段的中缀表达式语法规定如下:
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 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
|
实验结果:
|