編譯原理-python實現LL(1)分析器(GUI界面tkinter,自動分析文法)

原理

  • 本次實驗是設計一個LL(1)分析器,給定任意文法,自動消除一切左遞歸(前提是文法中不含迴路,且產生式右部不含有空字),自動回溯(提取最左公因子),自動生成FIRST集,自動生成FOLLOW集,自動生成LL(1)分析表,給定一個輸入串,輸出該輸入串的分析過程。

  • 本次實驗需要的原理知識在此不過多闡述,可以參考《編譯原理教程》第四版(胡元義主編)

  • 需要注意的是,書本上自動消除一切左遞歸的算法中,我認爲會出現第一個產生式的直接左遞歸沒有消除(不知道對不對,看兩層循環中中第一個產生式沒有消除直接左遞歸),所以消除完所有產生式的左遞歸後,在進行處理,判斷是否含有直接左遞歸,有則消除;其他算法都是根據書上的原理進行實現的。

  • 設計一個類LL1,初始化傳入參數:終結符(Tset),非終結符(NTset),文法開始符(S)(需要注意的是,本次實驗必須要求文法開始符是字符S), 產生式(Production), FIRST集(firstset),FOLLOW集(followset), LL(1)分析表(Table)

    class LL1:
        def __init__(self, Tset, NTset, S, Production, firstset, followset, Table):
            self.Tset = Tset
            self.NTset = NTset
            self.S = S
            self.Production = Production
            self.firstset = firstset
            self.followset = followset
            self.Table = Table
    
    各個參數的數據存放形式:
    Tset:[]列表
    NTset:[]列表
    S: 'S' 字符串
    Production:{},例如:A->aA|b, 就是表示爲{'A': ["aA","b"]}
    firstset: {}, 例如:fisrt(A):(a,b),就是表示爲{‘A’:["a","b"]}
    followset:{},同firstset一樣
    Table:{}嵌套字典,例如:M[A,a] = (A->a),那麼就是表示爲{'A':{'a':['A->a']}}
    
  • LL1類的各個方法:

    • removeLeftRecursion(self):消除一切左遞歸
    • removeLeftCommonFactor(self):消除最左公因子
    • createFirst(self),createFirstSet(self): 生成FIRST集
    • createFollow(self),createFollowSet(self):生成FOLLOW集
    • createTable(self):生成LL1分析表
  • 其他函數是跟界面各個按鈕綁定的函數,跟實驗主旨沒啥大的關係,就不闡述了

  • 本次實驗GUI是用Python tkinter

實驗效果

LL(1)分析器界面:

圖片.png

點擊打開文件,選擇文法的txt文件,就是把文件的內容讀到文本框中

在這裏插入圖片描述

在這裏插入圖片描述

點擊消除左遞歸,消除左因子,生成first集,生成follow集按鈕,就是生成對應的結果。

在這裏插入圖片描述

點擊生成Table表,就會生成一個新窗口,顯示結果

在這裏插入圖片描述

然後在輸入框輸入判定的字符串

在這裏插入圖片描述

點擊判斷棧情況,輸入該字符串的分析過程

在這裏插入圖片描述

源代碼(main.py)

import tkinter
import tkinter.filedialog   #對話框
import tkinter.ttk      # 表格

"""
Production產生式存放:
    A->a | b
    {A:['a','b']}

firstset集存在,follow集同理
first(A) = (a,b),則{'A':[a,b]}

table表(M表)例如:M[A,(] = "A->(abc"
{'A':{'(':["A->(abc"]}}
"""

class LL1:
    def __init__(self, Tset, NTset, S, Production, firstset, followset, Table):
        self.Tset = Tset
        self.NTset = NTset
        self.S = S
        self.Production = Production
        self.firstset = firstset
        self.followset = followset
        self.Table = Table

    # 消除一切左遞歸
    def removeLeftRecursion(self):
        i = 1
        while i <= len(self.NTset):
            j = 1
            while j <= i-1:
                # set轉換爲list,才能進行下標取值操作
                Ai = self.NTset[i-1]  # Ai非終結符
                Aj = self.NTset[j-1]  # Aj非終結符

                rmList = [x for x in self.Production[Ai] if x.startswith(Aj)]
                if rmList:
                    addList = [y+x.replace(Aj, "", 1) if y != 'ε' else x.replace(Aj, "", 1)
                               for x in rmList for y in self.Production[Aj]]
                    # 本來不需要替換的,保留
                    self.Production[Ai] = list(
                        filter((lambda x: x not in rmList), self.Production[Ai]))
                    # 追加新替換的式子進來
                    # extend,append函數沒有返回值的,所以不能list().extend(),否則返回None
                    self.Production[Ai].extend(addList)
                # print("去除間接左遞歸", self.Production)

                # 消除直接左遞歸
                LeftRecursionProduction = [
                    x for x in self.Production[Ai] if x.startswith(Ai)]    # 左遞歸的產生式

                notLeftRecursionProduction = [
                    x for x in self.Production[Ai] if not x.startswith(Ai)]  # 不是左遞歸的產生式
                if LeftRecursionProduction:     # 含有左遞歸的產生式
                    newNT = Ai+"'"              # 新終結符,如 A,A'
                    if newNT not in self.NTset:
                        self.NTset.append(newNT)
                    if notLeftRecursionProduction:
                        self.Production[Ai] = [
                            x+newNT for x in notLeftRecursionProduction]
                    else:
                        self.Production[Ai] = [newNT]
                    newList = [
                        x.replace(x[0], '', 1)+newNT for x in LeftRecursionProduction]
                    newList.append('ε')         # 追加空字,啞f西no
                    self.Production[newNT] = newList    # 加進產生式的字典中
                j = j+1

            i = i+1
        """
        特殊判斷,第一個非終結符對應的產生式本身是直接左遞歸,
        注意是第一個非終結符,因爲上面的兩層循環判斷了除第一個非終結符的情況了
        """
        LeftRecursionProduction = [
            x for x in self.Production[self.NTset[0]] if x.startswith(self.NTset[0])]
        notLeftRecursionProduction = [
            x for x in self.Production[self.NTset[0]] if not x.startswith(self.NTset[0])]
        if LeftRecursionProduction:
            newNT = 'S'+"'"
            if newNT not in self.NTset:         # 新的終結符判斷是否存在,不存在插入
                self.NTset.append(newNT)
            if notLeftRecursionProduction:
                self.Production['S'] = [
                    x+newNT for x in notLeftRecursionProduction]
            else:
                self.Production['S'] = [newNT]
            newList = [x.replace(x[0], '', 1) +
                       newNT for x in LeftRecursionProduction]
            newList.append('ε')         # 追加空字,啞f西no
            self.Production[newNT] = newList    # 加進產生式的字典中

        # 去除多餘的生成式,dfs
        """
        fromkeys方法注意:
        如果每個key的value都爲同一個對象,
        則操作該key的value時,所有的key的value都會改變
        """
        judge = dict.fromkeys(self.NTset, 0)        # 字典,非終結符做key,0做valu
        stack = []
        stack.append(self.S)
        judge[self.S] = 1       # 標誌爲已訪問
        while(len(stack) > 0 and (0 in judge.values())):
            top = stack.pop()
            rightPro = self.Production[top]  # 產生式右部
            for item in rightPro:
                i = 0
                while i < len(item):
                    ch = ""
                    if item[i] in self.NTset:
                        ch += item[i]
                        if i != len(item)-1:
                            if item[i+1] == "'":
                                ch += "'"
                        if judge[ch] == 0:
                            stack.append(ch)
                        judge[ch] = 1       # 標誌爲訪問過
                    i = i+1
        for key, values in judge.items():
            if values == 0:
                self.Production.pop(key)        # 去除產生式
                self.NTset.remove(key)          # 去除非終結符

    # 消除最左公因子
    """
    算法思想:將每個非終結符的產生式右部,也就是多個字符串,按照首個字符分類,
    然後進行轉換,新轉換生成的新非終結符的產生式更新到self實例中,進行轉換。
    """

    def removeLeftCommonFactor(self):
        for item in self.NTset:                 # 遍歷每個非終結符的產生式
            diff = {}                           # 將相同首字符的分爲一類
            for i in self.Production[item]:     # 遍歷該非終結符的每個產生式
                if i[0] not in diff.keys():
                    diff[i[0]] = [i]
                else:
                    diff[i[0]].append(i)
            oldList = []                        # 原來非終結符產生式的右部
            newNt = item                        # 新產生的非終結符
            for key, value in diff.items():
                newList = []                    # 新產生的非終結符產生式的右部
                if len(value) > 1:              # 可以提取公因子
                    newNt += "'"                # 新的終結符
                    oldList.append(key+newNt)
                    for v in value:
                        if len(v) == 1:         # 提取公因子後爲ε
                            newList.append('ε')
                        else:
                            # 提取非公因子的部分,replace函數需要指定替換的次數,bug error
                            newList.append(v.replace(v[0], '', 1))
                    if len(newList) != 0:
                        self.Production[newNt] = newList            # 添加新的產生式右部
                        self.NTset.append(newNt)                    # 添加新的非終結符
                else:
                    # 注意這裏value爲列表,所以value[0]爲所求
                    oldList.append(value[0])

            self.Production[item] = oldList

    def createFirst(self):
        for nt in self.NTset:
            if nt not in self.firstset.keys():
                self.firstset[nt] = []
            for eachPro in self.Production[nt]:
                if eachPro[0] in self.Tset or eachPro[0] == 'ε':                          # A->a
                    self.firstset[nt].append(eachPro[0])
                    self.firstset[nt] = list(set(self.firstset[nt]))
                else:                                                # A->B...
                    if eachPro[0] in self.firstset.keys():
                        # 將Y1集除空字追加到X
                        R_addto_L = [
                            x for x in self.firstset[eachPro[0]] if x != 'ε']

                        self.firstset[nt].extend(R_addto_L)
                        self.firstset[nt] = list(
                            set(self.firstset[nt]))    # 去重

                        if 'ε' in self.Production[eachPro[0]]:  # 第一個Y1存在ε
                            after_Y1_str = eachPro[1:]
                            if not after_Y1_str:    # 爲空,即是A->B 這種情況,且B含有空字,需要追加空字
                                self.firstset[nt].append('ε')
                                self.firstset[nt] = list(
                                    set(self.firstset[nt]))
                            else:
                                index = 0
                                for ch in after_Y1_str:
                                    if 'ε' in self.Production[ch]:
                                        index = index+1
                                    else:
                                        break
                                existNULL_Y = after_Y1_str[0:index]
                                if len(existNULL_Y) == len(after_Y1_str):       # Y1後面的Y都有空字,加
                                    self.firstset[nt].append('ε')
                                    self.firstset[nt] = list(
                                        set(self.firstset[nt]))
                                for each_Y in existNULL_Y:
                                    Y_addto_X = [
                                        x for x in self.firstset[each_Y] if x != 'ε']
                                    self.firstset[nt].extend(Y_addto_X)
                                    self.firstset[nt] = list(
                                        set(self.firstset[nt]))

    def createFirstSet(self):
        while True:
            size1 = 0
            for item in self.firstset.values():
                size1 += len(item)
            # print(size1)
            self.createFirst()
            size2 = 0
            for item in self.firstset.values():
                size2 += len(item)
            if size1 == size2:
                break
        

    def createFollow(self):
        for nt in self.NTset:
            for key, values in self.Production.items():
                for item in values:
                    index = item.find(nt)
                    flag = 1
                    newnt = nt+"'"
                    if newnt in item:
                        flag = 0

                    if flag and index >= 0:
                        newindex = index + len(nt)-1
                        if newindex == len(item)-1:  # 非終結符剛剛好在末尾,規則3
                            self.followset[nt].extend(self.followset[key])
                            self.followset[nt] = list(set(self.followset[nt]))

                        # 非終結符後面有字符,item[newindex+1]表示所求follow集的非終結符後面的第一個字符
                        else:
                            nextNT = item[newindex+1]  # 後面的符號

                            if nextNT in self.Tset:  # 終結符
                                self.followset[nt].append(nextNT)
                                self.followset[nt] = list(
                                    set(self.followset[nt]))
                            else:
                                i = newindex + 2
                                while i < len(item):
                                    if item[i] == "'":
                                        nextNT += "'"
                                    else:
                                        break
                                    i = i+1
                                # 後面是非終結符
                                # first集去除空字加到follow

                                add_list = [
                                    x for x in self.firstset[nextNT] if x != 'ε']
                                self.followset[nt].extend(add_list)
                                self.followset[nt] = list(
                                    set(self.followset[nt]))
                                if 'ε' in self.firstset[nextNT]:
                                    self.followset[nt].extend(
                                        self.followset[key])
                                    self.followset[nt] = list(
                                        set(self.followset[nt]))
                    # print("{}->{},非終結符爲:{}".format(key,item,nt))
                    # print("規則爲:",self.followset)
        # print("==========", self.followset['S'])

    def createFollowSet(self):
        for nt in self.NTset:
            self.followset[nt] = []
        self.followset["S"].append('#')
        while True:
            """            
            # 判斷坑了我5小時。。。
            # 不能f1 = self.followset 執行函數  f2 = self.followset,
            # 然後判斷f1 == f2?
            # f1隨着self.followset變化而變化??未解決!
            """
            size1 = 0
            for item in self.followset.values():
                size1 += len(item)
            # print(size1)
            self.createFollow()
            size2 = 0
            for item in self.followset.values():
                size2 += len(item)
            if size1 == size2:
                break

    def createTable(self):
        ckey = self.Tset
        ckey.append("#")

        value = list()
        for k in self.NTset:            # 初始化一個嵌套字典
            for ck in ckey:
                if k in self.Table:
                    self.Table[k].update({ck: value})
                else:
                    self.Table.update({k: {ck: value}})

        """
        ERROR fromkeys少用!!
        # cdict = dict.fromkeys(ckey, [])             # 初始化子字典 一維
        # self.Table = dict.fromkeys(self.NTset, cdict)    # Table表     二維
        """
        for key, values in self.firstset.items():
            for value in values:
                if value != "ε":
                    if len(self.Production[key]) == 1:           # 該非終結符只有一個產生式
                        str_pro = "{}->{}".format(key, self.Production[key][0])
                        if len(self.Table[key][value]) == 0:
                            self.Table[key][value] = [str_pro]
                        else:
                            self.Table[key][value].append(str_pro)
                    else:
                        for i in self.Production[key]:          # 看首字符
                            if value[0] == i[0]:                # 產生式首字符和first集的每個元素首字符
                                str_pro = "{}->{}".format(key, i)
                                if len(self.Table[key][value]) == 0:
                                    self.Table[key][value] = [str_pro]
                                else:
                                    self.Table[key][value].append(str_pro)
                                break
                # first集存在空字(產生式中有空字)
                else:
                    for k in self.followset[key]:
                        str_pro = "{}->{}".format(key, 'ε')
                        if len(self.Table[key][k]) == 0:
                            self.Table[key][k] = [str_pro]
                        else:
                            self.Table[key][k].append(str_pro)


def readFile(filename):
    Tset = set()                # 終結符集
    NTset = set()               # 非終結符集
    S = 'S'                     # 文法開始符
    Production = dict()         # 產生式
    with open(filename, encoding='utf-8', mode='r') as f:
        lines = [x.strip() for x in f.readlines() if not x.isspace()]
        for line in lines:
            line = line.split('->', 1)              # 分割
            line = [x.strip() for x in line]        # 去除空白符
            line[1] = line[1].split('|')            # 分割
            line[1] = [x.strip() for x in line[1]]
            if line[0] not in Production.keys():    # 判斷非終結符是否存在
                addDict = {line[0]: line[1]}
                Production.update(addDict)
            else:
                Production[line[0]].extend(line[1])  # 存在,追加
            # 11 -> 11|221 產生式
            # {'11': ['11', '221']}
    NTset = list(set(Production.keys()))            # 字典的key作爲非終結符
    NTset.remove('S')
    NTset.append('S')                               # 保證文法開始符在最後,消除左遞歸方便點
    # 遍歷字典的values,判斷每個字符如果不是非終結符,那麼就是終結符,使用集合推導式,
    Tset = list(set([c for item in Production.values()
                     for ch in item for c in ch if c not in NTset and c != 'ε' and c != "'"]))
    return Tset, NTset, S, Production


# “打開文件”按鍵函數
def btn1(LB_txt1, x):
    LB_txt1.delete(1, tkinter.END)        # 清空列表框
    filename = tkinter.filedialog.askopenfilename()
    x.Tset, x.NTset, x.S, x.Production = readFile(filename)
    with open(filename, 'r', encoding='utf-8') as f:
        lines = f.readlines()
        for line in lines:
            LB_txt1.insert(tkinter.END, line)

# “消除左遞歸”按鍵函數
def btn2(LB_txt2, x):
    LB_txt2.delete(1, tkinter.END)
    x.removeLeftRecursion()
    for key, value in x.Production.items():
        for v in value:
            str_pro = "{}->{}".format(key, v)
            LB_txt2.insert(tkinter.END, str_pro)

# "消除左公因子"按鍵函數
def btn3(LB_txt3, x):
    LB_txt3.delete(1, tkinter.END)
    x.removeLeftCommonFactor()
    for key, value in x.Production.items():
        for v in value:
            str_pro = "{}->{}".format(key, v)
            LB_txt3.insert(tkinter.END, str_pro)

# "生成first集"的按鍵函數
def btn4(LB_first,x):
    LB_first.delete(1,tkinter.END)
    x.createFirstSet()
    for key,values in x.firstset.items():
        if key in x.NTset:          # 防止用戶沒進行消除左遞歸操作就生成first集
            str_firstset_right = ""
            for v in values:
                str_firstset_right = str_firstset_right + v + ", "
            str_first = "first({}) : ( {} )".format(key,str_firstset_right)
            LB_first.insert(tkinter.END,str_first)

# "生成follow集"的按鍵函數
def btn5(LB_follow,x):
    LB_follow.delete(1,tkinter.END)
    x.createFollowSet()
    for key,values in x.followset.items():
        if key in x.NTset:          # 防止用戶沒進行消除左遞歸,消除左因子操作就生成follow集
            str_followset_right = ""
            for v in values:
                str_followset_right =  str_followset_right + v + ", "
            str_follow = "follow({}) : ( {} )".format(key,str_followset_right)
            LB_follow.insert(tkinter.END,str_follow)

# 給定輸入串,輸出該輸入串的分析過程
def is_legal(input_text,x):
    input_str = input_text.get()  # input_text爲輸入框對象
    table_root = tkinter.Tk()
    table_root.title("輸入串的判斷情況")
    table_root.geometry('1200x500')

    # 創建表格
    table_table = tkinter.ttk.Treeview(table_root,height=200)

    # 定義列
    table_table["columns"] = ["符號棧", "當前輸入符號", "輸入串","說明"]
    table_table.pack()
    table_table.column("#0",width=0,anchor='center')
    # 設置列寬度  
    table_table.column("符號棧", width=200,anchor='center')
    table_table.column("當前輸入符號", width=200,anchor='center')
    table_table.column("輸入串", width=200,anchor='center')
    table_table.column("說明", width=600,anchor='center')
    # 設置列名
    table_table.heading("符號棧",text="符號棧")
    table_table.heading("當前輸入符號",text="當前輸入符號")
    table_table.heading("輸入串",text="輸入串")
    table_table.heading("說明",text="說明")

    stack = []
    stack.append("#")
    stack.append("S")
    input_str += "#"
    i = 0
    colindex = 0   # gui 表格的行數
    a = input_str[i]        # 當前輸入符號
    top = stack[len(stack)-1]
    """
    str1,str2都是相同的,但是懶得改了...
    """
    while stack[len(stack)-1] != "#":
        top = stack[len(stack)-1]
        cur_stack_str = "".join(stack)
        stack.pop()     # 彈出棧頂
        a = input_str[i]
        if a not in x.NTset and a not in x.Tset:
            str1 = cur_stack_str
            str2 = a
            str3 = input_str[i+1:]
            str4 = "ERROR"
            insert_tablelist = [str1,str2,str3,str4]
            table_table.insert('',colindex,values=insert_tablelist)
            print("Error!!")
            return False
        if top in x.Tset:
            if top == a:
                if a != "#":
                    i = i+1
                    insert_tablelist = []
                    str1 = cur_stack_str
                    str2 = a
                    str3 = input_str[i:]    # 注意這裏是i,不是i+1
                    str4 = "匹配,彈出棧頂符號{}並讀出輸入串的下一個輸入符號{}".format(top,input_str[i])
                    insert_tablelist = [str1,str2,str3,str4]
                    table_table.insert('',colindex,values=insert_tablelist)
                    colindex = colindex+1
                    continue
                # else:
                #     print("succeed")
                #     return True
        else:
            table_item = x.Table[top][a]
            # print("查表爲",table_item)
            if table_item:              # []或者['A->i']
                table_item = x.Table[top][a][0]
                table_item = table_item.split('->')[1]
                if table_item != 'ε':       # T'S 分離成 T' S
                    j = 0
                    table_item += '#'
                    insert_stack = []
                    while j < len(table_item)-1:
                        ch = table_item[j]             # 表示單個字符
                        if ch in x.Tset:
                            insert_stack.append(ch)
                            j = j+1
                        else:
                            while table_item[j+1] == "'" and j < len(table_item):
                                ch += "'"
                                j = j+1
                            j = j+1
                            insert_stack.append(ch)
                    insert_stack.reverse()          # 翻轉,逆序入棧
                    stack.extend(insert_stack)
                    # gui 打印
                    str1 = cur_stack_str
                    str2 = a
                    str3 = input_str[i+1:]
                    str4 = "彈出棧頂符號{},將M[{},{}]中{}的{}壓入棧中".format(top,top,a,x.Table[top][a][0],"".join(insert_stack))
                    insert_tablelist = [str1,str2,str3,str4]
                    table_table.insert('',colindex,values=insert_tablelist)
                    # ######
                else:       # 空字不壓入
                    str1 = cur_stack_str
                    str2 = a
                    str3 = input_str[i+1:]
                    str4 = "彈出棧頂符號{},因爲M[{},{}]中爲{}->'ε',故不壓入棧中".format(top,top,a,top)
                    insert_tablelist = [str1,str2,str3,str4]
                    table_table.insert('',colindex,values=insert_tablelist)

            else:   # 表中無此項
                return False
        colindex = colindex+1
    str1 = cur_stack_str
    str2 = a
    str3 = input_str[i+1:]
    str4 = "匹配,分析成功!"
    insert_tablelist = [str1,str2,str3,str4]
    table_table.insert('',colindex,values=insert_tablelist)
    print("成功!!!")

# "生成table表"的按鍵函數
def btn6(x):
    x.createTable()
    table_root = tkinter.Tk()
    table_root.title("table表")
    table_root.geometry('710x170')

    # 創建表格
    table_table = tkinter.ttk.Treeview(table_root)

    # 定義列
    column_list = x.Tset
    # print("非終結符:",column_list)
    table_table["columns"] = column_list
    table_table.pack()
    table_table.column("#0",width=100,anchor='center')
    # 設置列寬度,列名
    for i in column_list:
        table_table.column(i, width=100,anchor='center')
        table_table.heading(i, text=i)
    
    # 給表格添加數據
    i = 0
    for key,values in x.Table.items():
        column_tup = list()
        for v in values.values():
            if v:
                column_tup.append(v)
            else:
                column_tup.append("")
        table_table.insert('',i,text=key,values=column_tup)
        i = i+1
           

# gui界面
def main():
    Tset = []
    NTset = []
    S = "S"
    Production = dict()
    firstset = {}
    followset = {}
    Table = {}
    x = LL1(Tset, NTset, S, Production, firstset,
            followset, Table)   # 一個窗體,對應一個LL1類

    root = tkinter.Tk()
    root.title("LL(1)分析器")
    root.geometry('600x500')
    root.resizable(0, 0)  # 防止用戶調整尺寸

    # 詞法文件框
    LB_txt1 = tkinter.Listbox(root, height=19, width=23, bd=2.5)
    LB_txt1.insert(0, "文法產生式:")
    
    # 消除左遞歸框
    LB_txt2 = tkinter.Listbox(root, bd=2.5, height=12, width=28)
    LB_txt2.insert(0, "消除左遞歸後的文法產生式:")

    # 消除左因子框
    LB_txt3 = tkinter.Listbox(root, bd=2.5, height=12, width=28)
    LB_txt3.insert(0, "消除左因子後的文法產生式:")

    # first集合框
    LB_first = tkinter.Listbox(root, bd=2.5, height=12, width=28)
    LB_first.insert(0, "FIRST集:")

    # follow集合框
    LB_follow = tkinter.Listbox(root, bd=2.5, height=12, width=28)
    LB_follow.insert(0, "FOLLOW集:")
    # LB_follow.insert(1,"FOLLOW集:")
    # LB_follow.delete(1, tkinter.END)           # 刪除列表的內容

    # 輸入框
    input_text = tkinter.Entry(root, bd=2, width=50,fg='red')

    # btn width 85, height 35
    
    Btn_1 = tkinter.Button(root, command=lambda: btn1(
        LB_txt1, x), text="打開文件", activebackground="green", activeforeground="white", bd=4, width=10)
    Btn_2 = tkinter.Button(root, command=lambda: btn2(
        LB_txt2, x), text="消除左遞歸", activebackground="green", activeforeground="white", bd=4, width=10)
    Btn_3 = tkinter.Button(root, command=lambda: btn3(
        LB_txt3, x), text="消除左因子", activebackground="green",activeforeground="white", bd=4, width=10)
    Btn_4 = tkinter.Button(root, command=lambda: btn4(
        LB_first,x),text="生成first集", activebackground="green",activeforeground="white", bd=4, width=10)
    Btn_5 = tkinter.Button(root, command=lambda: btn5(
        LB_follow,x),text="生成follow集", activebackground="green",
                           activeforeground="white", bd=4, width=10)
    Btn_6 = tkinter.Button(root, text="生成Table表", activebackground="green",
            command=lambda:btn6(x),activeforeground="white", bd=4, width=10)
    
    Btn_7 = tkinter.Button(root, command=lambda: is_legal(
        input_text,x),text="判定棧情況", activebackground="green",activeforeground="white", bd=4, width=10)

    # 定位
    input_text.place(x=200, y=460,height=30)
    LB_txt1.place(x=5, y=0)
    LB_txt2.place(x=172, y=0)
    LB_txt3.place(x=377, y=0)
    LB_first.place(x=172, y=230)
    LB_follow.place(x=377, y=230)
    Btn_1.place(x=5, y=350)
    Btn_2.place(x=5, y=385)
    Btn_3.place(x=90, y=385)
    Btn_4.place(x=5, y=420)
    Btn_5.place(x=90, y=420)
    Btn_6.place(x=5, y=455)
    Btn_7.place(x=90, y=455)

    root.mainloop()
    print(x.Table)


if __name__ == "__main__":
    main()
    

    # dict不支持下標索引

    """    
    測試樣例
    S->Qc|c
    Q->Rb|b
    R->Sa|a

    S->S+S|S-S|S*S|S/S| (S) | I

    S->TS'
    S'->+TS'|ε
    T->FT'
    T'->*FT'|ε
    F->(S)|i

    A->ab1 | ab2 | Dc | Ac |Acc  ==>消除左遞歸新生成的生成式,還有可能存在最左公因子
    D->ad                             #消除所以消除左遞歸新的終結符爲A',最左公因子用A''
    

    A->aB|abD|abDE ==》這種情況公因子怎麼提取。。

    S->ac|abd|cc|cce

    S->LA
    L->i:|ε
    A->i=e
    

    注意!!!:
    文法開始符一定要以S開頭!!!!!!

    """

測試文件(.txt)

注意,一定文法開始符一定是要S,不能是其他字符忘記優化了

S->TS'
S'->+TS'|ε
T->FT'
T'->*FT'|ε
F->(S)|i

總結

實驗原理還易理解,但是後期突然加上界面化,就導致設計的函數不太合理,存在冗餘,所以還是要好好思考項目的架構,各個函數模塊的功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章