有错误处理功能的递归下降语法分析器
这是编译原理的一次练习代码,自己写完之后放到这篇文章里供大家参考讨论。
题目要求如下
第3次上机—语法分析1 –递归下降
目的:熟练掌握自上而下的语法分析方法,并能用程序实现。
要求:
1. 使用的文法如下:
2. 对于任意给定的输入串(词法记号流)进行语法分析,递归下降方法实现。
3. 要有一定的错误处理功能。即对错误能提示,并且能在一定程度上忽略尽量 少的记号来进行接下来的分析。可以参考书上(《编译原理》 陈意云 张昱著 第三版)介绍的同步记号集合来处理。
可能的出错情况:idid*id, id**id, (id+id, +id*+id ……
4. 输入串以#结尾,输出推导过程中使用到的产生式。例如:
本人使用的python3
整体的思想是运用递归下降的方法,其中对于错误处理则采用了同步记号集合的方法
以上表格为加入了同步记号的分析表,我根据该表建立了字典chart,其中空的格子用-1代替,推导出空串的格子用0代替
#Analysis chart with synchronization mark
#-1 represents empty cell in the Analysis chart
#0 represents ξ in the Analysis chart
chart={"E id":"T E1","E1 id":-1,"T id":"F T1","T1 id":-1,"F id":"id",
"E +":-1,"E1 +":"+ T E1","T +":"synch","T1 +":0,"F +":"synch",
"E *":-1,"E1 *":-1,"T *":-1,"T1 *":"* F T1","F *":"synch",
"E (":"T E1","E1 (":-1,"T (":"F T1","T1 (":-1,"F (":"( E )",
"E )":"synch","E1 )":0,"T )":"synch","T1 )":0,"F )":"synch",
"E #":"synch","E1 #":0,"T #":"synch","T1 #":0,"F #":"synch"
}
声明一个i 并初始化为0,用来记录输入符号串的下标,在后续代码中将其用作全局变量
声明一个叫做stack的list,利用stack.pop(-1),stack.append()两个方法将其作为栈使用,初始化时,加入标志输入串结束的符号#
i=0
stack=[] #stack
stack.append("#")
定义函数nextToken,用来在输入串中移动到以一个符号
def nextToken(originStr):
global i
if (originStr[i] == 'i'):
i=i+2
else:
i=i+1
if (originStr[i] == 'i'):
current="id"
else:
current=originStr[i]
return current
根据产生式,E为开始符号,这里我定义了一个start( )函数,起到类似于启动器的作用
def start(originStr):
global i
while (i < (len(originStr) - 1) and originStr[i] != '#'):
E(originStr)
接下来的部分就是根据产生式以及有同步记号的分析表来进行输入符号的匹配
def E(originStr):
global i
stack.append("E")
print("E→TE1")
if(originStr[i]=='i'):
current="id"
else:
current=originStr[i]
#(E,originStr[i]) is empty in chart
while(chart["E "+current]==-1):
print("ERROR: ",current," is ignored")
current=nextToken(originStr)
# (E,originStr[i]) is synch in chart
if(chart["E " + current] =="synch"):
temp_str=stack.pop(-1)
print("ERROR: ",temp_str, " is poped")
print("E stack ",stack)
#stack pop and append
end = stack.pop(-1)
if (end == "#"):
return 0
if (chart["E " + current] != 0):
temp_list=chart["E "+current].split()
num=len(temp_list)-1
while(num>-1):
stack.append(temp_list[num])
num=num-1
print("E stack ", stack)
T(originStr)
E1(originStr)
def T(originStr):
global i
print("T→FT1")
if (originStr[i] == 'i'):
current = "id"
else:
current = originStr[i]
# (T,originStr[i]) is empty in chart
while (chart["T " + current] == -1):
print("ERROR: ", current, " is ignored")
current = nextToken(originStr)
# (T,originStr[i]) is synch in chart
if(chart["T " + current] == "synch"):
temp_str = stack.pop(-1)
print("ERROR: ", temp_str, " is poped")
print("T stack ",stack)
# stack pop and append
end=stack.pop(-1)
if (end == "#"):
return 0
if (chart["T " + current] != 0):
temp_list = chart["T " + current].split()
num = len(temp_list) - 1
while (num > -1):
stack.append(temp_list[num])
num = num - 1
print("T stack ", stack)
F(originStr)
T1(originStr)
def E1(originStr):
global i
if (originStr[i] == 'i'):
current = "id"
else:
current = originStr[i]
# (E1,originStr[i]) is empty in chart
while (chart["E1 " + current] == -1):
print("ERROR: ", current, " is ignored")
current = nextToken(originStr)
# (E1,originStr[i]) is synch in chart
if (chart["E1 " + current] == "synch"):
temp_str = stack.pop(-1)
print("ERROR: ", temp_str, " is poped")
print("E1 stack ", stack)
# stack pop and append
end=stack.pop(-1)
if (end == "#"):
return 0
if (chart["E1 " + current] != 0):
temp_list = chart["E1 " + current].split()
num = len(temp_list) - 1
while (num > -1):
stack.append(temp_list[num])
num = num - 1
print("E1 stack ", stack)
#Matched
if(stack[-1]==current):
current = nextToken(originStr)
print("E1→+TE1")
stack.pop(-1)
T(originStr)
E1(originStr)
elif(chart["E1 " + current] ==0):
print("E1→ξ")
stack.pop(-1)
print("E1 stack ", stack)
def T1(originStr):
global i
if (originStr[i] == 'i'):
current = "id"
else:
current = originStr[i]
# (T1,originStr[i]) is empty in chart
while (chart["T1 " + current] == -1):
print("ERROR: ", current, " is ignored")
current = nextToken(originStr)
# (E1,originStr[i]) is synch in chart
if(chart["T1 " + current] == "synch"):
temp_str = stack.pop(-1)
print("ERROR: ", temp_str, " is poped")
print("T1 stack",stack)
# stack pop and append
end=stack.pop(-1)
if (end == "#"):
return 0
if(chart["T1 " + current]!=0):
temp_list = chart["T1 " + current].split()
num = len(temp_list) - 1
while (num > -1):
stack.append(temp_list[num])
num = num - 1
print("T1 stack", stack)
# Matched
if (stack[-1] == current):
current = nextToken(originStr)
print("T1→*FT1")
stack.pop(-1)
F(originStr)
T1(originStr)
elif (chart["E1 " + current] == 0):
print("T1→ξ")
stack.pop(-1)
print("T1 stack", stack)
def F(originStr):
global i
if (originStr[i] == 'i'):
current = "id"
else:
current = originStr[i]
# (T1,originStr[i]) is empty in chart
while (chart["F " + current] == -1):
print("ERROR: ", current, " is ignored")
current = nextToken(originStr)
# (E1,originStr[i]) is synch in chart
if(chart["F " + current] == "synch"):
print("F " + current)
temp_str = stack.pop(-1)
print("ERROR: ", temp_str, " is poped")
print("F stack", stack)
# stack pop and append
end=stack.pop(-1)
if (end == "#"):
return 0
if (chart["F " + current] != 0):
temp_list = chart["F " + current].split()
num = len(temp_list) - 1
while (num > -1):
stack.append(temp_list[num])
num = num - 1
print("F stack", stack)
# Matched
if (stack[-1] == current):
if(current=="id"):
print("F→id")
current = nextToken(originStr)
print("stack in F ",stack)
stack.pop(-1)
elif(current=="("):
print("(")
current = nextToken(originStr)
stack.pop(-1)
E(originStr)
if(originStr[i]==")"):
current = nextToken(originStr)
stack.pop(-1)
else:print("ERROR ')' missed")
print("F stack", stack)
我在代码中多次输出栈stack的内容,其内容大家可以对照下面的表,栈的变化就可以反应出具体的匹配过程