编译原理实验 LL(1)文法 python实现

序言

因为课程实验需要,使用python+pyqt编写了一个简易的显示LL(1)分析表的程序
大体思路都是按照书上给的步骤来的,其中提取公共左因子这一块没有针对性测试,可能会出现一些毛病
如有错误望指正

运行截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码

首先是methods.py,里面包含除了求预测分析表的其他方法

"""
    编译原理实验6
    构造G[E]的LL(1)预测分析表

    SDUWH 章逸民         2021-6-10

    首先消除左递归
    然后使所有候选首符集两两不相交
    求出FIRST集和FOLLOW集
    最后生成预测分析表

"""
import string
# 非终结字符, 假设均为大写字母
Vn = []
for upletter in string.ascii_uppercase:
    Vn.append(upletter)
Vn_unused = Vn[:]
# Vn.extend(['α', 'β', 'γ', 'δ', 'ε', 'ζ', 'ν', 'ξ', 'ο', 'π', 'ρ', 'σ', 'η', 'θ'])

"""
    输入示例
    S -> a | ^ | (T)
    T -> T,S | S
"""
# s = 'S -> a | ^ | (T)\n'  \
#     'T -> T,S | S'
#
# s = 'E -> E+T | T\n' \
#     'T -> T*F | F\n' \
#     'F -> (E) | i'

# s = 'R -> Sa | a\n' \
#     'Q -> Rb | b\n' \
#     'S -> Qc | c'


def reset():
    global Vn
    Vn = []
    for up_letter in string.ascii_uppercase:
        Vn.append(up_letter)
    global Vn_unused
    Vn_unused = Vn[:]


# 预处理
def pre_deal(s):
    product = s.split('\n')
    t = {}
    not_end_c = []  # 非终结符集合
    end_c = []  # 终结符集合

    for p in product:
        left = p.split('->')[0].replace(' ', '')

        t[left] = []
        if left not in not_end_c:
            not_end_c.append(left)                      # 生成式左侧必为非终结符
        if Vn_unused.count(left) != 0:
            Vn_unused.remove(left)

        all_right = p.split('->')[1].split('|')
        for right in all_right:
            right = right.replace(' ', '')
            t[left].append(right)

            for r in range(len(right)):
                if right[r] in Vn:
                    # 大写字母
                    if right[r] not in not_end_c:
                        not_end_c.append(right[r])
                        Vn_unused.remove(right[r])
                elif right[r] != 'ε' and right[r] not in end_c and right[r] != ' ':
                    # 除了空串的终结字符
                    end_c.append(right[r])

    return t, not_end_c, end_c


# 消除左递归
def clear_left_loop(s):
    # 按照消除左递归方法进行操作
    t, not_end_c, end_c = pre_deal(s)
    for i in range(len(not_end_c)):
        for j in range(i):
            # 如果not_end_c[i]的产生式右端的开头字符为not_end_c[j],则用t[not_end_c[j]]替代
            for k in t[not_end_c[i]]:
                if k[0] == not_end_c[j]:
                    for m in t[not_end_c[j]]:
                        t[not_end_c[i]].append(m+k[1:])
                    t[not_end_c[i]].remove(k)
        # 消除not_end_c[i]的直接左递归
        # 先将开头为not_end_c[i]的移至前端,并设置flag为True,代表需要消除直接左递归
        flag = False
        for k in t[not_end_c[i]]:
            if k[0] == not_end_c[i]:
                t[not_end_c[i]].remove(k)
                t[not_end_c[i]].insert(0, k)
                flag = True
        if flag:
            # 需要消除直接左递归
            # 先从Vn_unused里挑选一个非终结符
            V = Vn_unused[0]
            Vn_unused.remove(V)
            not_end_c.append(V)
            t[V] = []
            temp = []
            for k in t[not_end_c[i]]:
                if k[0] == not_end_c[i]:
                    t[V].append(k[1:] + V)
                else:
                    temp.append(k + V)
            t[not_end_c[i]] = temp[:]
            t[V].append('ε')

    temp_t = {}
    for key, value in t.items():
        flag, pub, pub_len = select_pub_elem(value)
        temp = {
            key: value
        }
        while flag:
            V = Vn_unused[0]
            Vn_unused.remove(V)
            not_end_c.append(V)
            temp[key] = [pub + V]
            temp[V] = []
            for v in value:
                if v[:pub_len] != pub:
                    temp[key].append(v)
                else:
                    temp[V].append(v[pub_len:])
            value = temp[key]
            flag, pub, pub_len = select_pub_elem(temp[key])
        temp_t.update(temp)
    t = temp_t
    print(t)
    print("非终结符", not_end_c)
    print("终结符", end_c)
    return t, not_end_c, end_c


# 提取公共左因子
def select_pub_elem(L):
    temp = []
    pub = ''
    pub_len = 0
    flag = False
    for l in L:
        if l[0] not in temp:
            temp.append(l[0])
        else:
            # 需要消除公共左因子
            flag = True
            pub = l[0]
            pub_len = 1
            break
    if flag:
        temp = []
        for l in L:
            if l[0] == pub:
                temp.append(l[1:])
        _, m, n = select_pub_elem(temp)
        pub += m
        pub_len += n
    return flag, pub, pub_len


# 生成FIRST集
def first_set(key, t, not_end_c, end_c):
    result = []
    if key in end_c:
        # 如果X是终结符,那么FIRST(X) = {X}
        result.append(key)
    elif key in not_end_c:
        for value in t[key]:
            if value[0] in end_c:
                result.append(value[0])
            else:
                # 向FIRST(X)中加入FIRST(Y1)的所有非空符号
                for m in first_set(value[0], t, not_end_c, end_c):
                    if m not in result and m != 'ε':
                        result.append(m)
                # 如果ε在FIRST(Y1)中,再加入FIRST(Y2)中所有非ε符号,以此类推
                temp = 0
                while temp < len(value) - 1 and 'ε' in first_set(value[temp], t, not_end_c, end_c):
                    temp += 1
                    for m in first_set(value[temp], t, not_end_c, end_c):
                        if m not in result and m != 'ε':
                            result.append(m)
        # 如果X -> ε,则将 ε 加入FIRST(X)中
        if 'ε' in t[key]:
            result.append('ε')
    return result


def all_first_set(s):
    t, not_end_c, end_c = clear_left_loop(s)
    FIRST = {}
    for c in not_end_c + end_c:
        FIRST[c] = first_set(c, t, not_end_c, end_c)
    print("FIRST集", FIRST)
    return FIRST, t, not_end_c, end_c


# 生成FOLLOW集
def all_follow_set(s, start_c):
    FIRST, t, not_end_c, end_c = all_first_set(s)
    FOLLOW = {}
    # 初始化
    for c in not_end_c:
        FOLLOW[c] = []
    FOLLOW[start_c].append('#')

    # 循环至每个FOLLOW不再增大
    # 使用L代表长度
    L = 1
    temp = 0
    while(L != temp):
        temp = L

        # 对所有产生式操作
        for key, value in t.items():
            for v in value:
                # 此时 key -> v
                for i in range(len(v)-1):
                    if v[i] in not_end_c:
                        for m in FIRST[v[i+1]]:
                            if m not in FOLLOW[v[i]] and m != 'ε':
                                FOLLOW[v[i]].append(m)
                                L += 1
                        # 如果v[i]后的FIRST[β]包含ε
                        flag = True
                        for j in range(i+1, len(v)):
                            if 'ε' not in FIRST[v[j]]:
                                flag = False
                        if flag:
                            # 将FOLLOW(key)加至FOLLOW(v[i])中
                            for f in FOLLOW[key]:
                                if f not in FOLLOW[v[i]]:
                                    FOLLOW[v[i]].append(f)
                                    L += 1
                if v[len(v)-1] in not_end_c:
                    # 将FOLLOW(key)加至FOLLOW(v[len(v)-1])中
                    for f in FOLLOW[key]:
                        if f not in FOLLOW[v[len(v)-1]]:
                            FOLLOW[v[len(v)-1]].append(f)
                            L += 1

    print('FOLLOW集', FOLLOW)
    return FIRST, FOLLOW, t, not_end_c, end_c


下面是pyqt文件,我命名为interface.py,其中的set函数包含了将FIRST集和FOLLOW集显示以及生成预测分析表的功能

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'interface.ui'
#
# Created by: SDUWH 章逸民 2021-6-10
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
import methods

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(951, 866)
        self.tE = QtWidgets.QTextEdit(Form)
        self.tE.setGeometry(QtCore.QRect(10, 30, 401, 371))
        self.tE.setObjectName("tE")
        self.tB_first = QtWidgets.QTextBrowser(Form)
        self.tB_first.setGeometry(QtCore.QRect(480, 50, 201, 351))
        self.tB_first.setObjectName("tB_first")
        self.tB_follow = QtWidgets.QTextBrowser(Form)
        self.tB_follow.setGeometry(QtCore.QRect(740, 90, 201, 311))
        self.tB_follow.setObjectName("tB_follow")
        self.btn_table = QtWidgets.QPushButton(Form)
        self.btn_table.setGeometry(QtCore.QRect(10, 410, 931, 28))
        self.btn_table.setObjectName("btn_table")
        self.btn_table.clicked.connect(self.set)
        self.tW = QtWidgets.QTableWidget(Form)
        self.tW.setGeometry(QtCore.QRect(10, 450, 931, 401))
        self.tW.setObjectName("tW")
        self.tW.setColumnCount(0)
        self.tW.setRowCount(0)
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(10, 10, 72, 15))
        self.label.setObjectName("label")
        self.tE2 = QtWidgets.QTextEdit(Form)
        self.tE2.setGeometry(QtCore.QRect(740, 30, 201, 31))
        self.tE2.setObjectName("tE2")
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setGeometry(QtCore.QRect(740, 10, 72, 15))
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(Form)
        self.label_3.setGeometry(QtCore.QRect(480, 30, 72, 15))
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(Form)
        self.label_4.setGeometry(QtCore.QRect(740, 70, 72, 15))
        self.label_4.setObjectName("label_4")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.btn_table.setText(_translate("Form", "生成"))
        self.label.setText(_translate("Form", "输入文法:"))
        self.label_2.setText(_translate("Form", "开始符号:"))
        self.label_3.setText(_translate("Form", "FIRST集:"))
        self.label_4.setText(_translate("Form", "FOLLOW集:"))

    def set(self):
    	methods.reset()
        self.tW.clear()
        self.tB_first.clear()
        self.tB_follow.clear()
  
        s = self.tE.toPlainText().strip()
        start_c = self.tE2.toPlainText().strip()
        FIRST, FOLLOW, t, not_end_c, end_c = methods.all_follow_set(s, start_c)
        s = ""
        for key, value in FIRST.items():
            s += "FIRST( {} ) = ".format(key)
            for v in value:
                s += v + " "
            s += '\n'
        self.tB_first.setText(s)
        s = ""
        for key, value in FOLLOW.items():
            s += "FOLLOW( {} ) = ".format(key)
            for v in value:
                s += v + " "
            s += "\n"
        self.tB_follow.setText(s)

        self.tW.setRowCount(len(not_end_c))
        self.tW.setColumnCount(len(end_c)+1)
        self.tW.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
        self.tW.verticalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
        self.tW.setHorizontalHeaderLabels(end_c+['#'])
        self.tW.setVerticalHeaderLabels(not_end_c)

        end_c.append('#')
        # 对每个产生式
        for key, value in t.items():
            for v in value:
                # 此时为 key -> v
                s = '{} -> {}'.format(key, v)
                temp = s
                if v[0] != 'ε':
                    for a in FIRST[v[0]]:
                        if a in end_c:
                            if self.tW.item(not_end_c.index(key), end_c.index(a)) is not None:
                                temp = self.tW.item(not_end_c.index(key), end_c.index(a)).text() + ', ' + s
                            new_item = QtWidgets.QTableWidgetItem(temp)
                            self.tW.setItem(not_end_c.index(key), end_c.index(a), new_item)
                    # 判断ε是否属于FIRST(v)
                    flag = True
                    for p in v:
                        if 'ε' not in FIRST[p]:
                            flag = False
                            break
                    if flag:
                        for b in FOLLOW[key]:
                            if self.tW.item(not_end_c.index(key), end_c.index(b)) is not None:
                                temp = self.tW.item(not_end_c.index(key), end_c.index(b)).text() + ', ' + s
                            new_item = QtWidgets.QTableWidgetItem(temp)
                            self.tW.setItem(not_end_c.index(key), end_c.index(b), new_item)
                else:
                    # 此时为 key -> ε
                    for b in FOLLOW[key]:
                        if self.tW.item(not_end_c.index(key), end_c.index(b)) is not None:
                            temp = self.tW.item(not_end_c.index(key), end_c.index(b)).text() + ', ' + s
                        new_item = QtWidgets.QTableWidgetItem(temp)
                        self.tW.setItem(not_end_c.index(key), end_c.index(b), new_item)



if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    widget = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(widget)
    widget.show()
    sys.exit(app.exec_())

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值