SLR分析器

本文档详细介绍了如何设计并实现一个SLR编译器,包括构造LR(0)、SLR分析表的过程。通过具体文法示例,展示了从拓广文法到LR项目集,再到项目集规范族和分析表的生成。同时,还提供了额外功能如栈分析和文法示例,以及实验的可视化结果。
摘要由CSDN通过智能技术生成

一、实验目的

设计实现一个LR编译器或一个完整的编译程序,掌握编译器的基本原理和实现技术。

二、实验内容

  1. LR(0)、SLR或LR(1)等语法分析器。 2. 基于实验一(词法分析器)和实验二(LL<1>等语法分析器)的基础上,完成一个完整的编译器。 3. 自行选题

三、实验环境

WIN10 + Python3.8

四、实验要求

1.对于内容一LR分析器的要求
(1)自行定义两种文法,可参照教材和实验指导书。
(2)LR分析表需要自动生成。
2.对于内容二编译器的要求
(1)输入源代码可参考实验一,自行定义文法。
(2)输入源代码可以根据兴趣确定,自行定义文法。如数学计算式的识别。
3.对于内容三的要求 自行选题难度不少于内容一和内容二。

五、实验原理(及其相关流程图)

构造SLR(1)分析表的步骤流程图:

在这里插入图片描述

已知有文法G[E]如下:
在这里插入图片描述
则其拓广文法G’[S’]如图:
在这里插入图片描述
应该得到的该文法G’[S’]的DFA为:
在这里插入图片描述
实验代码分析及实现流程图:

第一步:拓广文法

(1)数据结构:

kuoguangsentences = []    # 存放拓广后的语句列表 如B->BD|d  =>  ["B->BD","B->d"]
Sentences = {}      # 语句字典,方便查找 如B->BD|d  =>  {B:["BD","d"]}

(2)关键代码:

def kuoguang(sentences):
    Sentences["S'"] = sentences[0].split("->")[0]    # 文法开头增加S’-> ?
    for i, value in enumerate(sentences):   # 遍历语句,将每句语法中的|分开,并存放在语法字典中
        begin = value.split("->")[0]    # begin存放语句的开头,即 B->aA 去掉”->“拆分成 ["B", "aA"], 存放B
        Sentences[begin] = []   # 初始化语法字典存放的非终结符,即 {B:[]}
        for j in value.split("->")[1].split("|"):
            Sentences[begin].append(j)     # 语法字典增加非终结符对应的语句,即 {B:[]} =>  {B:["aA"]}
    for i in Sentences:
        for j in Sentences[i]:
            kuoguangsentences.append(i + "->" + j)      # 根据语法字典还原语句放入拓广语句列表中,方便打印,即{B:["aA"]} =>  "B->aA"

(3)流程图:
在这里插入图片描述

第二步:求LR0项目集

(1)数据结构:

itemsentences = []      # 存放所有项目语句的列表,方便打印
Item = {}   # 项目集的字典,方便查找

(2)关键代码:

# 遍历语法字典,将每个位置的情况都添加,即B->aA  =>  ["B->·aA","B->a·A","B->aA·"]
def LR0item(Sentences):
    for i in Sentences:     # 遍历语法字典中的非终结符
        Item[i] = []    # 初始化对应非终结符的项目集列表
        for j in Sentences[i]:      # 遍历对应非终结符的语句
            for n in range(len(j) + 1):     # 读取语句中的每一个符号对应的位置
                list_p = list(j)    # 将语句转化为列表方便操作
                list_p.insert(n, "·")       # 在相应的位置插入"·"
                q = "".join(list_p)      # 再将语句转化为str类型
                itemsentences.append(i + "->" + q)      # 存放列表当中
                Item[i].append(q)       # 存放字典中

(3)流程图:
在这里插入图片描述

第三步:求LR(0)项目集规范族

(1)数据结构:

StandardLR0item = {}    # 存放DFA的字典,即:{I0:["B->bD".....],I1:["D->·cB".....],....}
num = 0     # 记录项目集的下标,即:I0,I1.....In
after = []      # 记录当前项目集其中一个语句进入下一状态集的符号,即: E->a·A  =>  E->aA·  ,存放A  => ["A"]
itemfirst = []      # 存放用于求闭包集合的语句的列表
check = {}      # 存放当前集合前往另一状态集合的记录的字典, 即: I0 --A--> I1 , 存放{I0:["A","I1"]}

(2)关键代码:

def Standarditem(item, cengshu):    # item为对应的项目集In,层数为项目集的下标数字n
    global num      # 记录项目集的下标
    after = {}      # 记录当前项目集其中一个语句进入下一状态集的符号,即: E->a·A  =>  E->aA·  ,存放A  => ["A"]
    clourse = []    # 记录查询过的闭包集合
    for i in item:      # 遍历项目集中的语句
        last = i.split("·")[1]  # 获得"·"之后的符号串
        if last == '':      # 如果"·"之后没有符号串,则不进入下一状态,直接遍历下一语句
            continue
        str1 = i.replace('·', "")   # str1存放去除"·"的语句,即:B->a·D  =>  B->aD
        str1 = list(str1)   # 将str1转化为列表,方便操作
        str1.insert(i.find("·") + 1, "·")   # 在后一位符号插入"·", 即:B->a·D  =>  B->aD·
        str1 = "".join(str1)    # 将str1转化为符号串
        if last[0] not in after:    # last[0]即为原语句中"·"的后一位符号,判断是否已经根据这个符号探寻过
            for p in range(1, len(StandardLR0item) - 1):    # 判断上一次探寻的项目集是否已经包含在另一个项目集当中
                if is_subsequence(StandardLR0item[num], StandardLR0item[p]):    # 使用is_subsequence()函数来判断前一列表是否包含在另一个列表当中,如果包含,则返回真,并进行如下操作
                    StandardLR0item.pop(num)    # 若包含,则删除这一项目集合
                    num -= 1    # 项目集合下标-1
                    if cengshu in check:    # 记录这一个集合根据状态n,指向前面已经探寻过的项目集当中
                        check[cengshu].update({StandardLR0item[p][0].split("·")[0][-1]: p})
                    else:
                        check.update({cengshu: {StandardLR0item[p][0].split("·")[0][-1]: p}})
                    break
            num += 1    # 如果该状态没探寻过,则下标+1,创建新的项目集合
            num1 = num  # num1记录上一个项目集的下标
            after[last[0]] = num    # 记录来源,状态+原项目集合的下标
            clourse = []    # 初始化记录查询过的闭包集合
            if cengshu in check:    # 记录这一个集合根据状态n,指向后面已经未探寻过的项目集
                check[cengshu].update({last[0]: num})
            else:
                check.update({cengshu: {last[0]: num}})
        else:
            num1 = after[last[0]]   # 如果存在,那么返回对应状态指向的项目集的下标
        for j in itemsentences:     # 遍历项目集的语句
            if str1 == j:   # 如果遍历的语句与新的语句str1相等,那么存放对应项目集的列表当中
                if num1 not in StandardLR0item:
                    StandardLR0item[num1] = [j]
                else:
                    if j not in StandardLR0item[num1]:
                        StandardLR0item[num1].append(j)
                    else:
                        continue
        if i.index("·") + 2 < len(i):   # 判断是否增加闭包集合,假如新语句的"·"已经是最后一位,则不用判断
            v = last[1]     # v是原语句中"·"对应后两位的符号
            if v.isupper() and num in StandardLR0item and v not in clourse:   # 如果是非终结符,则在对应的项目集中增加其闭包集合
                p = Closure(v)  # 求原语句中"·"对应后两位的符号的闭包集合
                p.Create()
                StandardLR0item[num][1:1] = CLOUSRE[v]      # 在对应的项目集中增加其闭包集合
                clourse.append(v)
    for p in range(1, len(StandardLR0item) - 1):    # 最后一句语句中需要再次判断上一次探寻的项目集是否已经包含在另一个项目集当中
        if is_subsequence(StandardLR0item[num], StandardLR0item[p]): # 使用is_subsequence()函数来判断前一列表是否包含在另一个列表当中,如果包含,则返回真,并进行如下操作
            StandardLR0item.pop(num)    # 若包含,则删除这一项目集合
            num -= 1    # 项目集合下标-1
            if cengshu in check:    # 记录这一个集合根据状态n,指向前面已经探寻过的项目集当中
                check[cengshu].update({StandardLR0item[p][0].split("·")[0][-1]: p})
            else:
                check.update({cengshu: {StandardLR0item[p][0].split("·")[0][-1]: p}})
            break

(3)流程图:
在这里插入图片描述

第四步:生成SLR分析表

(1)数据结构:

VC = []     # 存放非终结符
VT = []     # 存放终结符
ACTION = {}     # 存放ACTION表
GOTO = {}      # 存放GOTO表

(2)关键代码:

def CREATETABLE():  # 根据项目集更新ACTION和GOTO表
    for v in VT:    # 初始化ACTION表
        for n in range(len(StandardLR0item)):
            if v in ACTION:
                ACTION[v].update({n: ""})
            else:
                ACTION.update({v: {n: ""}})
    for v in VC:    # 初始化GOTO表
        for n in range(len(StandardLR0item)):
            if v in GOTO:
                GOTO[v].update({n: ""})
            else:
                GOTO.update({v: {n: ""}})
    if "S'" in GOTO:    # GOTO表去除S‘
        GOTO.pop("S'")
    for i in StandardLR0item:   # 循环项目集
        for j in StandardLR0item[i]:    # 循环项目集中的语句
            if j.find("·") + 1 == len(j):   # 若·符号是结尾,判断是否执行acc操作还是归约操作
                str1 = j.split("·")[0]
                n = str1.split("->")[0]     # 存放语句对应的非终结符
                if n == "S'":       # 如果非终结符为S'则更新acc到ACTION表中
                    TABLE('#', i, "acc")
                else:
                    for p in range(len(kuoguangsentences)):
                        if str1 == kuoguangsentences[p]:
                            for m in FOLLOW[n]:     # 循环在该非终结符对应的FOLLOW集合中的终结符,更新其对应的归约操作到ACTION表中
                                TABLE(m, i, "r" + str(p))
            else:
                v = j.split("·")[1][0]      # 判断是移进操作,更新到对应的ACTION表中
                TABLE(v, i, check[i][v])

(3)流程图:
在这里插入图片描述

六、实验运行结果图

本小组在完成SLR语法分析器的同时也实现了其可视化工作,如下图:
在这里插入图片描述
实例文法为:
E->E+T|T
T->TF|F
F->(E)|i
实例输入串为:
i+i
i (归约顺序:64264631)
(i+i)*i (归约顺序:64264154632)

第一步:得到拓广文法
在这里插入图片描述
在这里插入图片描述

第二步:得到LR0项目集
在这里插入图片描述
第三步:构造LR0项目集规范族的DFA
在这里插入图片描述
(上述步骤基本与LR0相同,在SLR中,根据DFA构造SLR分析表的时候需要用到FOLLOW集)
因此第四步应该是:生成FOLLOW集

在这里插入图片描述第五步:生成分析表
在这里插入图片描述
额外功能
1.栈分析
输入串(i+i*i)进行栈分析,归约顺序:64264631
在这里插入图片描述
输入串((i+i)*i)进行栈分析,归约顺序:64264154632
在这里插入图片描述2.生成DFA构造图
在这里插入图片描述
在这里插入图片描述
3.其它文法展示

(1)
S->bAS|bA
A->aSc

在这里插入图片描述
(2)
S->BB
B->aB|b
在这里插入图片描述
(3)
S->aAcBe
A->b
A ->Ab
B->d
在这里插入图片描述
(4)
A->G=E
E->E+T|E-T|T
T->TF|T/F|F
F->(E)|i
G->i
在这里插入图片描述
(5)
E->E+E|E
E|(E)|i I7和I8的二义性未解决
在这里插入图片描述
**

要源码的留邮箱

**

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 34
    评论
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值