Python實現算符優先分析


編譯原理實驗:實現算符優先分析程序,依舊使用python實現,由於注釋很詳細就不單獨寫編程思路啦


功能如下:

求出文法中每一個非終結符的FIRSTVT集和LASTVT集

打印算符優先關系表

進行算符優先分析並打印分析結果


源代碼:

import sys
import operator
import copy

#終結符
terSymbol = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
             '+','-','*','/','(',')','^','#']
#非終結符
non_ter = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']

firstVT = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
lastVT = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]

#求firstVT集
def first(gra_line):
    #開頭的非終結符,所以求的是x的firstVT
    x = gra_line[0]
    ind = non_ter.index(x)
    indexSET = []
    # 找到所有產生式右部的第一個字符,下標值返回列表indexSET
    i = 0
    while i < len(gra_line):
        if gra_line[i] == '>' or gra_line[i] == '|':
            indexSET.append(i + 1)
        i += 1
    #判斷符合P->a...或P->Qa...,以及P->Q...那個情況,注意gra_line[i]是當前遍歷的字符
    for i in indexSET:
        if gra_line[i] in terSymbol and gra_line[i] not in firstVT[ind]:
            firstVT[ind].append(gra_line[i])
        elif gra_line[i] in non_ter:
            for f in firstVT[non_ter.index(gra_line[i])]:
                if f not in firstVT[ind]:
                    firstVT[ind].append(f)
            if gra_line[i + 1] in terSymbol and gra_line[i + 1] not in firstVT[ind]:
                firstVT[ind].append(gra_line[i + 1])
    return firstVT


#求lastVT集
def last(gra_line):
    # 開頭的非終結符,所以求的是x的lastVT
    x = gra_line[0]
    ind = non_ter.index(x)
    indexSET = []
    # 找到所有產生式右部的最后一個字符,下標值返回列表indexSET
    i = 0
    while i < len(gra_line):
        if gra_line[i] == '|' or gra_line[i] == '\n':
            indexSET.append(i - 1)
        i += 1
    # 判斷符合P->...a或P->...aQ,以及P->...Q那個情況,注意gra_line[i]是當前遍歷的字符
    for i in indexSET:
        if gra_line[i] in terSymbol and gra_line[i] not in lastVT[ind]:
            lastVT[ind].append(gra_line[i])
        elif gra_line[i] in non_ter:
            for f in lastVT[non_ter.index(gra_line[i])]:
                if f not in lastVT[ind]:
                    lastVT[ind].append(f)
            if gra_line[i - 1] in terSymbol and gra_line[i - 1] not in lastVT[ind]:
                lastVT[ind].append(gra_line[i - 1])
    return lastVT


#求每一個產生式的右部單獨的產生式
def prostr(grammer):
    pro_str = []
    for gra_line in grammer:
        #先看每一行有幾個產生式,把每一個產生式的開始索引加入pro_index
        pro_index = []
        i = 0
        while i < len(gra_line):
            if gra_line[i] == '>' or gra_line[i] == '|':
                pro_index.append(i + 1)
            i += 1
        for p in pro_index:
            str = ''
            for s in gra_line[p:]:
                if s == '|' or s == '\n':
                    break
                else:
                    str = str + s
            pro_str.append(str)
    return pro_str


#構造優先關系表
def table(grammer, num):
    #表頭
    n = len(num) + 1
    #創建一個n行n列的空表
    gra = [[' ' for col in range(n)] for row in range(n)]
    #填充表頭
    i = 1
    for c in num:
        gra[0][i] = c
        i += 1
    j = 1
    for r in num:
        gra[j][0] = r
        j += 1
    #填充表體
    pro_str = prostr(grammer)
    for str in pro_str:
        if str == '@':
            continue
        else:
            j = -1
            for i in str[:-1]:
                #i是當前元素,j是當前索引
                j += 1
                if i in terSymbol and str[j + 1] in terSymbol:
                    r = num.index(i) + 1
                    c = num.index(str[j + 1]) + 1
                    if gra[r][c] == '·>' or gra[r][c] == '<·':
                        print("該文法不是算符優先文法,請檢查輸入")
                        return False
                    else:
                        gra[r][c] = '=·'
                if j < (len(str) - 2) and i in terSymbol and str[j + 2] in terSymbol and str[j + 1] in non_ter:
                    r = num.index(i) + 1
                    c = num.index(str[j + 2]) + 1
                    if gra[r][c] == '·>' or gra[r][c] == '<·':
                        print("該文法不是算符優先文法,請檢查輸入")
                        return False
                    else:
                        gra[r][c] = '=·'
                if i in terSymbol and str[j + 1] in non_ter:
                    for a in firstVT[non_ter.index(str[j + 1])]:
                        r = num.index(i) + 1
                        c = num.index(a) + 1
                        if gra[r][c] == '·>' or gra[r][c] == '=·':
                            print("該文法不是算符優先文法,請檢查輸入")
                            return False
                        else:
                            gra[r][c] = '<·'
                if i in non_ter and str[j + 1] in terSymbol:
                    for a in lastVT[non_ter.index(i)]:
                        r = num.index(a) + 1
                        c = num.index(str[j + 1]) + 1
                        if gra[r][c] == '=·' or gra[r][c] == '<·':
                            print("該文法不是算符優先文法,請檢查輸入")
                            return False
                        else:
                            gra[r][c] = '·>'
    #添加#的行和列元素
    for a in firstVT[non_ter.index(grammer[0][0])]:
        r = num.index('#') + 1
        c = num.index(a) + 1
        gra[r][c] = '<·'
    for a in lastVT[non_ter.index(grammer[0][0])]:
        r = num.index(a) + 1
        c = num.index('#') + 1
        gra[r][c] = '·>'
    r = num.index('#') + 1
    c = num.index('#') + 1
    gra[r][c] = '=·'
    return gra


#歸約函數
def reduce(str):
    #str是傳進來的最左素短語
    p_s = prostr(grammer)
    for s in p_s:
        if len(s) != len(str):
            continue
        else:
            j = 0
            for i in s:
                #如果是最后一個字符相比較了
                if j + 1 == len(str):
                    if i in terSymbol and str[j] in terSymbol and i == str[j]:
                        return True
                    elif i in non_ter and str[j] in non_ter:
                        return True
                else:
                    if i in terSymbol and str[j] in terSymbol and i == str[j]:
                        j += 1
                    elif i in non_ter and str[j] in non_ter:
                        j += 1
                    else:
                        break
    return False


#總控程序
def master(ana_str, num):
    stack = ['#']
    ana_str += '#'
    print("當前棧中元素為:")
    print(stack)
    print("當前字符串為:")
    print(ana_str)
    while stack != ['#','N','#']:
        if ana_str == '#':
            stack.append('#')
            print("移進#")
            print()
            print("當前棧中元素為:")
            print(stack)
            continue
        #字符串第一個字符是非終結符,則加入棧
        if ana_str[0] in non_ter:
            stack.append(ana_str[0])
            print("移進" + ana_str[0])
            print()
            print("當前棧中元素為:")
            print(stack)
            ana_str = ana_str[1:]
            print("當前字符串為:")
            print(ana_str)
        #j是stack中最上面終結符的下標
        if stack[-1] in terSymbol:
            j = len(stack) - 1
        else:
            j = len(stack) - 2
        #stack[j]是棧最上面的終結符,a是當前輸入串的第一個字符(終結符
        a = ana_str[0]
        if stack[j] not in num or a not in num:
            print("ERROR")
            return False
        else:
            #棧頂終結符優先級低於等於字符串第一個終結符
            if gra[num.index(stack[j]) + 1][num.index(a) + 1] == '<·' or gra[num.index(stack[j]) + 1][num.index(a) + 1] == '=·':
                stack.append(a)
                print("移進" + a)
                print()
                print("當前棧中元素為:")
                print(stack)
                ana_str = ana_str[1:]
                print("當前字符串為:")
                print(ana_str)
                if ana_str[0] in non_ter:
                    stack.append(ana_str[0])
                    print("移進" + ana_str[0])
                    print()
                    print("當前棧中元素為:")
                    print(stack)
                    ana_str = ana_str[1:]
                    print("當前字符串為:")
                    print(ana_str)
                j += 1
                if stack[j] in non_ter:
                    j += 1
                a = ana_str[0]
            if stack[j] not in num or a not in num:
                print("ERROR")
                return False
            else:
                #如果棧頂終結符優先級高於字符串第一個終結符
                while gra[num.index(stack[j]) + 1][num.index(a) + 1] == '·>':
                    #尋找最左素短語
                    str = ''
                    if ana_str[0] in non_ter:
                        str += ana_str[0]
                        ana_str = ana_str[1:]
                    #如果棧頂是非終結符
                    if stack[-1] in non_ter:
                        str += stack[-1]
                    while j >= 1:
                        #j是往下遍歷的指針,b是減小之前的
                        #b記錄當前棧頂非終結符,並將b加入最左素短語
                        b = stack[j]
                        str += b
                        #如果當前終結符的下一個是終結符,指向下一個,否則指向下下一個
                        if stack[j - 1] in terSymbol:
                            j -= 1
                        else:
                            str += stack[j - 1]
                            j -= 2
                        #如果下一個終結符優先級小於當前終結符
                        if gra[num.index(stack[j]) + 1][num.index(b) + 1] == '<·':
                            break
                    str = str[::-1]
                    #歸約,str是最左素短語
                    if reduce(str) == True:
                        print("將" + str + "歸約為N")
                        print()
                        del stack[len(stack) - len(str):]
                        stack.append('N')    #反正模糊歸約,這個非終結符隨便寫個就行了8
                        print("當前棧中元素為:")
                        print(stack)
                        print("當前字符串為:")
                        print(ana_str)
                    else:
                        print("歸約失敗")
                        break
                if gra[num.index(stack[j]) + 1][num.index(a) + 1] != '·>'\
                    and gra[num.index(stack[j]) + 1][num.index(a) + 1] != '=·'\
                    and gra[num.index(stack[j]) + 1][num.index(a) + 1] != '<·':
                    print("ERROR")
                    return False
                #j已經指向棧頂第一個終結符
    return True


#比較兩個嵌套列表是否相等
def cmp(SET1, SET2):
    i = 0
    while i < 26:
        if (operator.eq(SET1[i], SET2[i])) == False:
            return False
        else:
            i += 1
    return True


if __name__ == '__main__':
    ana_str = input("請輸入一個待分析的串:")
    print("請輸入一個文法:")
    grammer = sys.stdin.readlines()

    #循環求最終firstVT集
    first1 = copy.deepcopy(firstVT)
    for gr in grammer:
        first(gr)
    first2 = copy.deepcopy(firstVT)

    while not cmp(first1, first2):
        first1 = copy.deepcopy(firstVT)
        for gr in grammer:
            first(gr)
        first2 = copy.deepcopy(firstVT)

    print("該文法的非終結符的firstVT集為:")
    i = 0
    for f in firstVT:
        if len(f) != 0:
            print('firstVT(' + non_ter[i] + '):', f)
        i += 1
    print()

    # 循環求最終lastVT集
    last1 = copy.deepcopy(lastVT)
    for gr in grammer:
        last(gr)
    last2 = copy.deepcopy(lastVT)

    while not cmp(last1, last2):
        last1 = copy.deepcopy(lastVT)
        for gr in grammer:
            last(gr)
        last2 = copy.deepcopy(lastVT)

    print("該文法的非終結符的lastVT集為:")
    j = 0
    for f in lastVT:
        if len(f) != 0:
            print('lastVT(' + non_ter[j] + '):', f)
        j += 1
    print()

    num = []
    for gra_line in grammer:
        for gr in gra_line:
            if gr == '-' and gra_line.index(gr) == 1:
                continue
            elif gr in terSymbol and gr not in num:
                num.append(gr)
    num.append('#')

    if table(grammer,num) != False:
        print("該文法的優先關系表為:")
        gra = table(grammer, num)
        for i in range(len(gra)):  # 控制行
            for j in range(len(gra[i])):  # 控制列
                print(gra[i][j], end='\t')
            print()
        print()

        print("分析過程如下:")
        print()
        if master(ana_str, num) == True:
            print("接受")


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM