给定类C语言中简单算术表达式文法G[E]:
E→E+T | E-T | T
T→T*F | T/F | F
F→(E) | id
根据该文法,编写算符优先分析器。
1)输入:任意字符串。(文法中id即对应词法分析中识别出的标识符,+-*/分别对应词法分析得到的运算符);
2)输出:判定输入串是否为该文法定义的合法算术表达式;
实验步骤
1)对上述文法补充新的开始符号E’和新的产生式(E’→ #E#),并判定给定的文法是否是OPG文法;
2)构造Firstvt和Lastvt集合算法,针对文法中所有的非终结符求解;
3)按照算符优先分析法的思路,构造所有终结符的优先关系表;
4)利用栈,对输入的测试用例进行分析识别,并给出相应的结果;
5)对程序进行分析研究,画出相应的流程图。
七. 实验结果(画出流程图、给出运行结果截图、错误发现的方法描述)
一、手动分析过程
1)对上述文法补充新的开始符号E’和新的产生式(E’→ #E#),并判定给定的文法是否是OPG文法;
补充完整后,该文法为:
S→#E#
E→E+T
E→E-T
E→T
T→T*F
T→T/F
T→F
F→(E)
F→i该文法没有E→FT的形式,没有空产生式,而且两俩终结符间至多含有一种优先关系,所以该文法为算符优先文法。
2)构造Firstvt和Lastvt集合算法,针对文法中所有的非终结符求解;
求出该文法每个终结符的FIRSTVT和LASTVT集:
FIRSTVT(E’)={#}
FIRSTVT(E)={+,-,*,/,(,i}
FIRSTVT(T)={*,/,(,i }
FIRSTVT(F)={(,i }
LASTVT(E’)={#}
LASTVT(E)={+,-,*,/,) ,i}
LASTVT(T)={*,/,) ,i }
LASTVT(F)={) ,i }
3)按照算符优先分析法的思路,构造所有终结符的优先关系表;
1.求<关系
#E有# < FIRSTVT(E)
+T有+ < FIRSTVT(T)
-T有- < FIRSTVT(T)
*F有* < FIRSTVT(F)
/F有/ < FIRSTVT(F)
(E有(< FIRSTVT(E)
2.求>关系
E#有# > LASTVT(E)
E+有+ > LASTVT(E)
E-有- > LASTVT(E)
T*有* > LASTVT(T)
T/有/ > LASTVT(T)
E)有) > LASTVT(E)
3.求=关系
E’→ #E#得到 # = #
F→(E)得到 ( = )
根据以上分析得到优先关系表如下:
表一 优先关系表
+ | - | * | / | ( | ) | i | # | |
+ | > | > | < | < | < | > | < | > |
- | > | > | < | < | < | > | < | > |
* | > | > | > | > | < | > | < | > |
/ | > | > | > | > | < | > | < | > |
( | < | < | < | < | < | = | < | |
) | > | > | > | > | > | > | ||
i | > | > | > | > | > | > | ||
# | < | < | < | < | < | < | = |
rule.txt输入如下:
S→#E#
E→E+T
E→E-T
E→T
T→T*F
T→T/F
T→F
F→(E)
F→i
stop
保存
在程序内输入对应的算式可以看到规约栈和结果
代码如下:
from collections import deque
first=[[] for i in range(10)]
last=[[] for i in range(10)]
dfirst = {}
dvt={}
stack = deque()
satck_int = deque()
mode=1
def findfirst(l,r):
for i in range(time+1):
if left[i] == r:
for x in range(len(right[i])):
if right[i][x] in vt:
if right[i][x] not in first[dfirst[l]]:
first[dfirst[l]].append(right[i][x])
break
elif right[i][x] in vn and right[i][x] != left[i]and x==0:
findfirst(l, right[i][x])
continue
def findlast(l,r):
for i in range(time+1):
if left[i] == r:
for x in range(len(right[i])):
if right[i][x] in vt:
if right[i][x] not in last[dfirst[l]]:
last[dfirst[l]].append(right[i][x])
break
if right[i][x] in vn and right[i][x] != left[i]and x==0:
findlast(l, right[i][x])
continue
def getfirstvt(mode):
for i in range(time+1):
if left[i] in vn:
for x in range(len(right[i])):
if mode==1:
if right[i][x] in vt :#非终结符
if right[i][x] not in first[dfirst[left[i]]]:
first[dfirst[left[i]]].append(right[i][x])
break
elif right[i][x] in vn and right[i][x] != left[i] and x==0:#终结符
findfirst(left[i],right[i][x])
continue
elif mode==2:
if right[i][x] in vt :#非终结符
if right[i][x] not in last[dfirst[left[i]]]:
last[dfirst[left[i]]].append(right[i][x])
break
if right[i][x] in vn and right[i][x] != left[i] and x==0:#终结符
findlast(left[i],right[i][x])
continue
def getchar():
input("scan your rules(change id to i and end with stop)")
global vt, vn, left, right, time
vt = set()
vn = set()
k = 1
time = -1
left = []
right = [[0 for i in range(10)] for i in range(10)]
f = open("D:\\桌面\\rule.txt",encoding='utf-8')
while True:
rule = f.readline().strip('\n')
if rule == 'stop':
break
case = 0
time += 1
y = 0
for index in range(len(rule)):
if case == 0 and rule[index] != '→' and rule[index] != '’':
left.append(rule[index])
if case == 1:
right[time][y] = rule[index]
y += 1
if rule[index] > "A" and rule[index] < "Z":
vn.add(rule[index])
elif not (rule[index] == "→" or rule[index] == "’"):
vt.add(rule[index])
if rule[index] == '→':
case = 1
index += 1
def creat_flvt():
l_vn=list(vn)
for i in range(len(l_vn)):
dfirst[l_vn[i]] = i
l_vt=list(vt)
for i in range(len(l_vt)):
dvt[l_vt[i]] = i
global lenth_vt
lenth_vt=len(l_vt)
for x in range(len(right)):
while 0 in right[x]:
right[x].remove(0)
def printvnvt():#对需要查看的内容取消标注
print('VT and VN:')
print(vt)
print(vn)
print('left and right:')
print(right)
print(left)
#print(time + 1)
print('VN')
print(dfirst.keys())
print('firstvt and lastvt')
print(first)
print(last)
print('VT')
print(dvt.keys())
print('TABLE')
for i in range(len(table)):
print(table[i])
def gettable():
global table
table = [[0 for i in range(lenth_vt)] for i in range(lenth_vt)]
for i in range(time+1):
for x in range(len(right[i])-1):
rig = right[i][x]
riger = right[i][x+1]
if rig in vt and riger in vn:
for s in first[dfirst[riger]]:
table[dvt[rig]][dvt[s]] = '<'
if rig in vn and riger in vt:
for f in last[dfirst[rig]]:
table[dvt[f]][dvt[riger]] = '>'
if rig in vt and riger in vt:
table[dvt[rig]][dvt[riger]] = '='
for x in range(len(right[i])-2):
if right[i][x] in vt and right[i][x+1] in vn and right[i][x+2] in vt:
if right[i][x]== right[i][x+2]:
table[dvt[right[i][x]]][dvt[right[i][x+2]]] = '='
table[dvt[right[i][x+2]]][dvt[right[i][x]]] = '='
else:
table[dvt[right[i][x]]][dvt[right[i][x + 2]]] = '='
def turndown():
for i in range(time + 1):
right[i].reverse() # 反转右侧二维数组
def simplify():
sentence=input("input your sentence:")
sentence=list(sentence)
sentence.append('#')
stack.append('#')
x=0
y=0
while(len(stack)):
print()
print(satck_int)
print(stack)
if(sentence[y]>'0'and sentence[y]<'9'):
num=int(ord(sentence[y])-ord('0'))
y+=1
while(sentence[y]>'0'and sentence[y]<'9'):
num=num*10+int(ord(sentence[y])-ord('0'))
y+=1
satck_int.append(num)
if sentence[y] in {'+','-','*','/','#','(',')'}:
t1=stack[len(stack)-1]
t2=sentence[y]
z1=dvt[t1]
z2=dvt[t2]
if table[z1][z2]=="0":
print("Error!")
return
if table[z1][z2]=="<":
stack.append(t2)
x+=1
y+=1
continue
elif table[z1][z2] == "=":
stack.pop()
x-=1
y+=1
else:#if table[z1][z2]==">"
calculate(t1)
continue
else:
print("Error!")
return
out=satck_int.pop()
print(out)
def count(a,b,c):
if c=='+':
return a+b
elif c=='-':
return a-b
elif c=='*':
return a*b
elif c=='/':
return b/a
def calculate(t1):
d1=satck_int[len(satck_int)-1]
satck_int.pop()
d2=satck_int[len(satck_int)-1]
satck_int.pop()
satck_int.append(count(d1,d2,t1))
stack.pop()
def main():
getchar()
creat_flvt()
getfirstvt(1)#mode1下的,正序寻找
turndown()
getfirstvt(2)#mode2下的,逆序寻找
turndown()
gettable()
#printvnvt()
simplify()
return
main()
'''rule.txt的内容
S→#E#
E→E+T
E→E-T
E→T
T→T*F
T→T/F
T→F
F→(E)
F→i
stop
'''
期末作业太多了,实际上还有很大的优化空间,等寒假再补吧。