编译原理 实验三 算符优先分析算法的设计与实现(python)

本文章根据一篇文章修改而成,原文章链接: http://t.csdnimg.cn/OzRhM

一、 实验目的

根据算符优先分析法,对表达式进行语法分析,使其能够判断一个表达式是否正确。通过算符优先分析方法的实现,加深对自下而上语法分析方法的理解。

二、 实验要求

1、输入文法。可以是如下算术表达式的文法(你可以根据需要适当改变):

            E→E+T|E-T|T

T→T*F|T/F|F

F→(E)|i

2、对给定表达式进行分析,输出表达式正确与否的判断。

程序输入/输出示例:

输入:1+2;

输出:正确

输入:(1+2)/3+4-(5+6/7);

输出:正确

输入:((1-2)/3+4

输出:错误

输入:1+2-3+(*4/5)

输出:错误

三、实验步骤

1、参考数据结构

char *VN=0,*VT=0;//非终结符和终结符数组

char firstvt[N][N],lastvt[N][N],table[N][N];

typedef struct   //符号对(P,a)

{

char Vn;

char Vt;

} VN_VT;

typedef struct  //栈

{

    VN_VT *top;

     VN_VT *bollow;

     int  size;

}stack;

2、根据文法求FIRSTVT集和LASTVT集

给定一个上下文无关文法,根据算法设计一个程序,求文法中每个非终结符的FirstVT 集和LastVT 集。

算符描述如下:

/*求 FirstVT 集的算法*/

PROCEDURE insert(P,a);

IF not F[P,a] then   

begin  

        F[P,a] = true; //(P,a)进栈  

end;  

Procedure FirstVT;

Begin

for 对每个非终结符 P和终结符 a do

   F[P,a] = false

for 对每个形如 P a…或 P→Qa…的产生式 do

Insert(P,a)

while stack  非空

begin

栈顶项出栈,记为(Q,a)

for  对每条形如 P→Q…的产生式 do

         insert(P,a)

end;

end.

同理,可构造计算LASTVT的算法。

3、构造算符优先分析表

依据文法和求出的相应FirstVT和 LastVT 集生成算符优先分析表。

算法描述如下:

for  每个形如 P->X1X2…Xn的产生式  do

  for i =1 to n-1 do

  begin

        if Xi和Xi+1都是终结符 then  

           Xi   =   Xi+1

        if i<= n-2, Xi和Xi+2 是终结符, 但Xi+1 为非终结符 then

           Xi  = Xi+2

        if Xi为终结符, Xi+1为非终结符 then   

             for FirstVT 中的每个元素 a do

                  Xi  <  a ;

        if Xi为非终结符, Xi+1为终结符 then

             for LastVT 中的每个元素 a do

                  a  >  Xi+1 ;

  end

4、构造总控程序

 算法描述如下:

   stack S;

   k = 1;  //符号栈S的使用深度

   S[k] = ‘#’

   REPEAT

       把下一个输入符号读进a中;

       If S[k]

 VT   then  j = k  else  j = k-1;

       While S[j] > a  do

           Begin

           Repeat

               Q = S[j];

               if  S[j-1]

 VT  then  j = j-1  else   j = j-2

           until  S[j] < Q;

           把S[j+1]…S[k]归约为某个N,并输出归约为哪个符号;

           K = j+1;

           S[k] = N;

           end of while

       if S[j] < a  or  S[j] = a  then

           begin  k = k+1; S[k] = a      end

        else  error //调用出错诊察程序

    until a = ‘#’

5、对给定的表达式,给出准确与否的分析过程

6、给出表达式的计算结果。(本步骤可选作)

总代码:

grammarElement = {}
terSymblo = ['#']  #终结符列表
non_ter = [] #非终结符
Start = 'E'   #开始符号
allSymbol = []  # 所有符号
firstVT = {}  # FIRSTVT集
lastVT = {}  # lastVT集
formules = []

def data_input():  # 读取文法
    with open("3.txt", 'r+', encoding="utf-8") as f:
        temp = f.readlines()
    for i in temp:
        line = str(i.strip("\n"))  #获取当前行的字符串内容,并移除其尾部的换行符
        formules.append(line)      #将当前文法规则添加到一个名为formules的列表中
        if line[0] not in non_ter:  #检查当前规则的首字符是否已经在non_ter(非终结符号)列表中
            non_ter.append(line[0])
            #在grammarElement字典中设置一个键值对。键是当前规则的首字符,值是该规则的右侧部分(从第五个字符开始)。
            #如果这个键已经存在于字典中,那么它的值将被更新为当前规则的右侧部分。
            grammarElement.setdefault(line[0], line[5:])
        else:
            grammarElement[line[0]] += "|" + line[5:]
    for i in temp:
        line = str(i.strip("\n")).replace(" -> ", "")
        for j in line:
            if j not in non_ter and j not in terSymblo:
                terSymblo.append(j)
    if 'ε' in terSymblo: terSymblo.remove('ε')  #如果ε存在终结符列表中,则从列表中移除它


def get_fistVT(formule):
    x = formule[0]  #获取文法规则的首字符,并将其赋值给变量x
    ind = non_ter.index(x)  #查找x在non_ter列表中的索引
    index = []
    i = 5
    if formule[i] in terSymblo and formule[i] not in firstVT[x]:  # 首位为终结符 P->a...
        firstVT[x] += formule[i]
    elif formule[i] in non_ter:  # 首位为非终结符  P->Q...
        for f in firstVT[formule[i]]:  #如果a属于FIRSTVT(Q)
            if f not in firstVT[x]:
                firstVT[x] += f
        if i + 1 < len(formule):  #非终结符后面一个字符
            if formule[i + 1] in terSymblo and formule[i + 1] not in firstVT[x]:  # P->Qa...
                firstVT[x] += formule[i + 1]

def get_lastVT(formule):
    x = formule[0]
    i = len(formule) - 1
    if formule[i] in terSymblo and formule[i] not in lastVT[x]:  #P->...a
        lastVT[x] += formule[i]
    elif formule[i] in non_ter:   #P->...Q
        for f in lastVT[formule[i]]:    #遍历LastVT(Q)
            if f not in lastVT[x]:     #若a属于LastVT(Q)
                lastVT[x] += f
        if formule[i - 1] in terSymblo and formule[i - 1] not in lastVT[x]:  #P->...aQ
            lastVT[x] += formule[i - 1]

def addtodict2(thedict, key_a, key_b, val):  # 设置二维字典的函数
    if key_a in thedict.keys():
        thedict[key_a].update({key_b: val})
    else:
        thedict.update({key_a: {key_b: val}})

def analy(formule): #算符优先分析表
    start = 5
    end = len(formule) - 2
    if start == end: return
    for i in range(start, end):  #每个形如 P->X1X2…Xn的产生式
        if formule[i] in terSymblo and formule[i + 1] in terSymblo:  #Xi和Xi+1都是终结符
            addtodict2(data, formule[i], formule[i + 1], "=")
        #Xi和Xi+2 是终结符, 但Xi+1 为非终结符
        if formule[i] in terSymblo and formule[i + 1] in non_ter and formule[i + 2] in terSymblo:
            addtodict2(data, formule[i], formule[i + 2], "=")
        #Xi为终结符, Xi+1为非终结符 ...aP...
        if formule[i] in terSymblo and formule[i + 1] in non_ter:
            for j in firstVT[formule[i + 1]]:  #FirstVT 中的每个元素 b
                addtodict2(data, formule[i], j, "<")  #a<b
        #Xi为非终结符, Xi+1为终结符...Pb...
        if formule[i] in non_ter and formule[i + 1] in terSymblo:
            for j in lastVT[formule[i]]:   #LastVT 中的每个元素 a
                addtodict2(data, j, formule[i + 1], ">")    #a>b
        if formule[i + 1] in terSymblo and formule[i + 2] in non_ter:
            for j in firstVT[formule[i + 2]]:
                addtodict2(data, formule[i + 1], j, "<")
        if formule[i + 1] in non_ter and formule[i + 2] in terSymblo:
            for j in lastVT[formule[i + 1]]:
                addtodict2(data, j, formule[i + 2], ">")

def reverseString(string):
    return string[::-1]     #选择了从末尾到开头的所有字符,从而得到了一个反向的字符串

# 初始化两个栈
def initStack(string):
    # 分析栈,入栈#
    analysisStack = "#"
    # 当前输入串入栈,即string逆序入栈
    currentStack = reverseString(string)
    # 调用分析函数
    toAnalyze(analysisStack, currentStack)


# 寻找分析栈最顶终结符元素,返回该元素及其下标
def findVTele(string):
    ele = '\0'
    ele_index = 0

    for i in range(len(string)):
        if (string[i] in terSymblo):
            ele = string[i]
            ele_index = i
    return ele, ele_index

# 根据栈中内容进行分析,构造算符优先分析表
def toAnalyze(analysisStack, currentStack):
    global analyzeResult
    global analyzeStep
    analyzeStep += 1
    analysisStack_top, analysisStack_index = findVTele(analysisStack)  # 分析栈最顶终结符元素及下标
    currentStack_top = currentStack[-1]  # 当前输入串栈顶
    #relation = data[analysisStack_top][currentStack_top]
    #根据分析栈顶和当前输入串栈顶,从data中获取对应的关系。
    relation = data.get(analysisStack_top, {}).get(currentStack_top, None)

    if relation == '<':
        print(" {:^5} {:^15} {:^9} {:^15} {:^12} ".format(analyzeStep, analysisStack, relation,
                                                          reverseString(currentStack), '移进'))
        #将当前输入串栈顶的元素添加到分析栈,并从当前输入串中移除栈顶元素。
        analysisStack += currentStack_top
        currentStack = currentStack[:-1]
        toAnalyze(analysisStack, currentStack)
    elif relation == '>':
        print(" {:^5} {:^15} {:^9} {:^15} {:^12} ".format(analyzeStep, analysisStack, relation,
                                                          reverseString(currentStack), '归约'))
        currenChar = analysisStack_top     #初始化变量currenChar为分析栈顶的元素
        temp_string = ""
        for i in range(len(analysisStack) - 1, -1, -1):   #从分析栈的最后一个元素开始往前循环(倒序)
            if (analysisStack[i] >= 'A' and analysisStack[i] <= 'Z'):
                temp_string = analysisStack[i] + temp_string   #将当前元素加到temp_string的开头
                continue
            elif (data[analysisStack[i]][currenChar] == '<'):
                break;      #最左素短语,跳出
            temp_string = analysisStack[i] + temp_string
            currenChar = analysisStack[i]
        if (temp_string in sentencePattern):
            analysisStack = analysisStack[0:i + 1]  #截取分析栈,使其只包含归约后的部分
            analysisStack += 'N'
            toAnalyze(analysisStack, currentStack)
        else:
            print("归约出错!待归约串为:", temp_string, "--->产生式右部无此句型!")
            analyzeResult = False
            return
    elif (relation == '='):
        if (analysisStack_top == '#' and currentStack_top == '#'):
            print(" {:^5} {:^15} {:^9} {:^15} {:^12} ".format(analyzeStep, analysisStack, relation,
                                                              reverseString(currentStack), '完成'))
            analyzeResult = True
            return
        else:
            print(" {:^5} {:^15} {:^9} {:^15} {:^12} ".format(analyzeStep, analysisStack, relation,
                                                              reverseString(currentStack), '移进'))
            #将当前输入串栈顶的元素添加到分析栈,并从当前输入串中移除栈顶元素
            analysisStack += currentStack_top
            currentStack = currentStack[:-1]
            toAnalyze(analysisStack, currentStack)
    elif (relation == None):
        print(" {:^5} {:^15} {:^9} {:^15} {:^12} ".format(analyzeStep, analysisStack, 'None',
                                                          reverseString(currentStack), '报错'))
        analyzeResult = False
        return

data_input()
data = dict()   #准备工作,创造字典
for i in non_ter:
    firstVT.setdefault(i, "")
    lastVT.setdefault(i, "")
for i in terSymblo:
    for j in terSymblo:
        addtodict2(data, i, j, '')
#print(data)
sym = non_ter + terSymblo    #创建一个新的列表sym,它是将non_ter和terSymblo两个列表连接在一起的结果

#输出firstVT集合、lastVT集合:
for n in range(10):
    for i in formules:
        get_fistVT(i)
        get_lastVT(i)
print("firstVT集合:")
for i in non_ter:
    print(i+" : "+firstVT[i])
print("lastVT集合:")
for i in non_ter:
    print(i+" : "+lastVT[i])

temp2 = Start +" -> #" +Start+"#"
formules.append(temp2)    #在前后加上井号
for i in formules:
    analy(i)
print("算符优先分析表")
for i in terSymblo:
    print("\t" + i.ljust(4), end="")
print()
for i in terSymblo:
    print(i.ljust(4), end="")   #i.ljust(4):如果i的长度小于4,那么它将在i的左侧添加空格,使其总宽度为4。
    for j in terSymblo:
        if j in data[i]:
            print(data[i][j].ljust(8), end="")
        else:
            print("\t\t", end="")
    print()

sentencePattern = ["N+N", "N*N", "N/N", "(N)", "i","N^N","N,N","N-N","a"]
analyzeResult = False
analyzeStep = 0
print("请输入待分析的字符串:")
string = input()
string = string.replace(" ", "")
#将数字转化成字符i
string = string.replace('0', 'i').replace('1', 'i').replace('2', 'i').replace('3', 'i').replace('4', 'i').replace(
        '5', 'i').replace('6', 'i').replace('7', 'i').replace('8', 'i').replace('9', 'i')

string+="#"

print(" {:^4} {:^13} {:^6} {:^12} {:^10} ".format('步骤', '分析栈', '优先关系', '当前输入串', '移进或归约'))
initStack(string)
if (analyzeResult):
    print("该字符串是文法的合法句子。\n")
else:
    print("该字符串不是文法的合法句子。\n")

 测试用例:

E -> E+T
E -> E-T
E -> T
T -> T*F
T -> T/F
T -> F
F -> (E)
F -> i

测试结果:

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值