【Python】代码实现LL(1),LR(1)上下文无关文法(Stack()类)

2023-11-17

任务要求

针对书上第三章中的表达式文法,采用LL(1)、LR(1)进行分析

相关文法(需要进行消除左递归等操作):
在这里插入图片描述

顺手分享一下课本资源好了(可能不是最新版,排版略有点别扭)
后文的书上内容就是指这本书:[编译原理].陈意云.文字版
提取码:e0ag

LL1介绍

LL(1):从左往右处理输入,最左推导,向前展望1个符号的,不带回溯的自上而下的算法,是上下文无关文法的子集。
在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

LL1代码实现

书上P59-60
在这里插入图片描述
在这里插入图片描述

#LL1
import pandas as pd
class Stack:
    def __init__(self):
        self.values = "$E"
    
    def push(self, product):
        while product[-1:]!='→':
            if(product[-1:]=='\'' or product[-1:]=='d'):
                self.values+=product[-2:]
                product=product[0:-2]
            else:
                self.values+=product[-1:]
                product=product[0:-1]
                
    def pop(self):
        if(self.values[-1:]=='\''or self.values[-1:]=='d'):
            self.values=self.values[:-2];
        else:
            self.values=self.values[:-1]

    def top(self):
        if(self.values[-1:]=='\''or self.values[-1:]=='d'):
            return self.values[-2:]
        else:
            return self.values[-1:]
        
    def empty(self):
        return len(self.values) == 0
    
def Next_Char():#获取下一个词法记号
    global pend_input
    if(pend_input[0:2]=="id"):
         pend_input=pend_input[2:]
         return "id"
    else:
        t=pend_input[0:1]
        pend_input=pend_input[1:]
        return t

dic={#手工构造预测分析表
'id':['E→TE\'','error','T→FT\'','error','F→id'],
'+':['error','E\'→+TE\'','error','T\'→ε','error'],
'*':['error','error','error','T\'→*FT\'','error'],
'(':['E→TE\'','error','T→FT\'','error','F→(E)'],
')':['error','E\'→ε','error','T\'→ε','error'],
'$':['error','E\'→ε','error','T\'→ε','error']}
Analysis_table=pd.DataFrame(dic,index=['E','E\'','T','T\'','F'])

if __name__ == '__main__':
    stk = Stack()           #构造自定义栈
    #pend_input=input()+'$' #记得在输入内容后加上表示终止的"$"符号
    pend_input='id*id+id$'  #可手动输入亦可提前输入'待处理的输入内容'
    pend_head=Next_Char()   #取出第一个待处理的符号
    print("预测分析器接受输入id*id+id的部分动作(与书上稍有不同)")
    print("%-15s"%"栈","%-15s"%"输入","%+10s"%"输出")
    while(stk.empty()==False):              
        if stk.top()==pend_head: 
            if pend_head!='$':
                print('----------------成功匹配符号:{}-------------------'.format(pend_head))
            pend_head=Next_Char()
            stk.pop()
        else:
            product=Analysis_table[pend_head][stk.top()]#获取产生式
            if product=='error':
                print('Error  Skip!')
                stk.pop()
            else:
                print("%-15s"%stk.values,"%-15s"%str(pend_head+pend_input),"%+15s"%product)
                stk.pop()
                if(product[-1:]!='ε'):#对于产生空串的产生式,只需弹栈,不需入栈
                    stk.push(product)

手动构造的预测分析表:
在这里插入图片描述

预测分析器接受输入id * id + id的相关动作:
在这里插入图片描述

LR1简略介绍

LR(1):从左往右处理输入,构造一个最右推导的逆过程(规范规约),向前看1个符号的,自下而上的算法,是上下文无关文法的子集。

LR文法:我们能为之构造出所有条目都唯一的LR分析表。

LR分析器特点:适用于一大类上下文无关文法,效率高。

句型的句柄是和某产生式右部匹配的子串,并且,把它归约成该产生式左部的非终结符代表了最右推导过程的逆过程的一步。

活前缀:右句型的前缀,该前缀不超过最右句柄的右端。

在这里插入图片描述

LR1代码

书上P73-74

在这里插入图片描述
r后面的数字代表按第几个产生式做归约;s代表移进,它后面的数字转移到哪个状态。产生式:
在这里插入图片描述
在这里插入图片描述

#LR1
import pandas as pd
class Stack:
    def __init__(self):
        self.values = "0"
    def push(self, s):
        self.values=self.values+s
        def __init__(self):
            self.values = "0"             
    def pop(self):
        if(self.values[-2:]=='id'or self.values[-2:]=='10'or self.values[-2:]=='11'):
            self.values=self.values[:-2]
        else:
            self.values=self.values[:-1]
    def top(self):
        if(self.values[-2:]=='10'or self.values[-2:]=='id' or self.values[-2:]=='11'):
            return self.values[-2:]
        else:
            return self.values[-1:]
class Input_Token:
    def __init__(self):
        self.values = ""
    def Get_Token(self):#获取待处理字符串pend_input中下一个词法记号
        if(self.values[0:2]=="id"):
             self.values=self.values[2:]
             return "id"
        else:
            s=self.values[0:1]
            self.values=self.values[1:]
            return s
    def Show_Token(self):#查看待处理字符串pend_input的下一个词法记号(不取出)
        if (self.values[0:2] == "id"):
            return "id"
        else:
            s = self.values[0:1]
            return s

def Len_Right(p):
    p_char=p[p.find('→')+1:]
    if p_char=='id':
        return 1
    else:
        return len(p_char)

def LR1(head,top):#分析程序
    action=SLR[head][top]
    if action=='acc':#接受
        print("%-9s"%stk.values,"%+9s"%pend_input.values,"%+6s"%"接受")
        return False
    else:
        if action[0]=='s':#移进
            print("%-9s"%stk.values,"%+9s"%pend_input.values,"%+6s"%"移进")
            stk.push(pend_input.Get_Token())
            stk.push(action[1:])
        elif action[0]=='r':#归约
            production=Production[int(action[1:])]
            print("%-9s"%stk.values,"%+9s"%pend_input.values,"%+5s"%"按",production,"归约")
            for i in range(Len_Right(production)*2): #按照产生式右边长度的2倍出栈(1字符跟1数字)
                stk.pop()
            top_num=stk.top()
            left=production[0] #获取产生式左边的字符
            stk.push(left)
            stk.push(SLR[left][top_num])
        else:
            print('Error!\n Exit!')
            return False
        return True

dic={'id':['s5',' ',' ',' ','s5',' ','s5','s5',' ',' ',' ',' '],
      '+':[' ','s6','r2','r4',' ','r6',' ',' ','s6','r1','r3','r5'],
      '*':[' ',' ','s7','r4',' ','r6',' ',' ',' ','s7','r3','r5'],
      '(':['s4',' ',' ',' ','s4',' ','s4','s4',' ',' ',' ',' ',],
      ')':[' ',' ','r2','r4',' ','r6',' ',' ','s11','r1','r3','r5'],
      '$':[' ','acc','r2','r4',' ','r6',' ',' ',' ','r1','r3','r5'],
      'E':['1',' ',' ',' ','8',' ',' ',' ',' ',' ',' ',' '],
      'T':['2',' ',' ',' ','2',' ','9',' ',' ',' ',' ',' ',],
      'F':['3',' ',' ',' ','3',' ','3','10',' ',' ',' ',' ']}
SLR=pd.DataFrame(dic,index=['0','1','2','3','4','5','6','7','8','9','10','11'])#分析表
Production=['null','E→E+T','E→T','T→T*F','T→F','F→(E)','F→id']#产生式   
if __name__=='__main__':
    stk = Stack()
    pend_input=Input_Token()
    pend_input.values='id*id+id$'
    print("———————————————LR分析器———————————————")
    print("%-7s"%"栈","%+8s"%"输入","%+6s"%"动作")
    while(True):
        if LR1(pend_input.Show_Token(),stk.top())==False:
            break
    print("——————————————————————————————————————")

分析表(action表)
描述?
实验结果:
在这里插入图片描述

LR分析方法和LL分析方法的比较

在这里插入图片描述
部分参考资料

编译原理:语法分析2-非递归的预测分析

编译原理:语法分析3-LR分析器

编译原理:LL(1),LR(0),SLR(1),LALR(1),LR(1)对比

《编译原理》LR 分析法与构造 LR(1) 分析表的步骤 - 例题解析

Python栈实现

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Python】代码实现LL(1),LR(1)上下文无关文法(Stack()类) 的相关文章

随机推荐

  • Java工程师学快速Python(3)----- 模块、包、库 输入 输出

    简单的说一个 py文件就是一个模块 多个 py文件整合成一个包 各种包的集合就是库 import 语句 想使用 Python 源文件 只需在另一个源文件里执行 import 语句 语法如下 import module1 module2 mo
  • Endnote显示cannot edit range(无法编辑range)

    1 方法1 这种问题的原因可能是选择了 Convert to Unformatted Citations 正确的方法应该是在Word中选择endnote页面 Convert Word Citations to EndNote 然后再 Upd
  • 全栈之前端

    欢迎关注 全栈工程师修炼指南 公众号 设为 星标 每天带你 基础入门 到 进阶实践 再到 放弃学习 专注 企业运维实践 网络安全 系统运维 应用开发 物联网实战 全栈文章 等知识分享 花开堪折直须折 莫待无花空折枝 作者主页 https w
  • 如何在word文档中添加两个目录

    由于需要在一个word文档中添加两个目录 第一个目录表示文章前半部分的内容 第二个目录表示后半部分的内容 对于word不太熟悉的我经过一番折腾之后终于搞定了 在此记录一下 原理 将word文本划分成两个域 而每个域里的标题可以看做是不同的书
  • echarts 关系图 参数_Echarts关系图(使用重力图)

    首先展示一下该关系图效果 很简单的关系图 不过其中经历不少波折 使用的是echarts2 现在贴出代码 1 functiondos 2 var name document getElementById name value 3 post G
  • Pandas玩转数据透视表,用它就够了~

    大家好 我是丁小杰 对于数据透视表 相信对于 Excel 比较熟悉的小伙伴都知道如何使用它 并了解它的强大之处 而在pandas中要实现数据透视就要用到pivot table了 导入示例数据 首先导入演示的数据集 import pandas
  • 【C++】STL之栈(stack)介绍

    栈 stack 栈是一种运算受限的线性表 限定仅在表尾进行插入和删除的操作 插入 push 弹出 pop 其特性就是先进后出 即先插入的元素最后才能弹出 大家可以把栈想象成一个弹夹 你只能在顶层一颗一颗装入子弹 先装的子弹在最底层 打出时也
  • 学什么副业前景好?学一个什么副业比较好?自学副业有哪些?

    很多公司不希望自己的员工做副业 主要还是担心员工做副业会影响到工作 如果员工在下班后的空闲时间搞搞副业 那公司就没法管了呀 你平时下班后的空闲时间都做些什么 学什么副业前景好 1 自学ps 现在很多影楼 摄影工作室 电商商家会把自己拍摄的照
  • JVM调优参数归纳汇总

    GC通常参数 Xss 每个线程的栈大小 Xms 初始堆大小 默认物理内存的1 64 Xmx 最大堆大小 默认物理内存的1 4 Xmn 新生代大小 XX ParallelGCThreads 指定GC工作的线程数量 XX MinHeapSize
  • 查询局域网电脑的IP,端口号,MAC地址

    网上看到很多都是使用nmap工具 这个工具我没有使用过 我自己实现nmap工具的功能 首先我们查询局域网内有哪些电脑是alive的 下面我写了一个脚本 ping sh 这样局域网内哪些电脑的ip是alive的就可以知道 下面来查看对于IP的
  • leetcode--55--跳跃游戏

    题目描述 给定一个非负整数数组 你最初位于数组的第一个位置 数组中的每个元素代表你在该位置可以跳跃的 最大长度 判断你是否能够到达最后一个位置 示例 1 输入 2 3 1 1 4 输出 true 解释 我们可以先跳 1 步 从位置 0 到达
  • 【ChatGPT】基于WSL+Docker的ChatGPT PLUS共享服务部署

    最近买了ChatGPT PLUS服务 想通过web服务将它共享给其他人使用 搜了一下目前GitHub上比较热门的服务有 ChatGPT Next Web chatgpt web share 其中chatgpt web share支持API和
  • 【uni-app】css 关于 calc()函数计算无效

    计算符 注 计算 符前后都需要空格 否则计算无效
  • 华为OD机试真题 Java 实现【最多提取子串数目】【2023Q1 100分】

    一 题目描述 给定由 a z 26 个英文小写字母组成的字符串 A和 B 其中A中可能存在重复字母 B 中不会存在重复字母 现从字符串 A 中按规则挑选一些字母 可以组成字符串 B 挑选规则如下 同一个位置的字母只能被挑选一次 被挑选字母的
  • ue4加载本地版本_【虚幻4】创建本地数据库

    简介 这里我们主要通过使用Data table实现本地数据库 Data table可以用来保存一些用户配置 或者常用变量 或者用来实时更新外部表格数据到虚幻4中 一 创建Data table 1 首先创建Structure结构 这里我已经创
  • 我用什么写Python?

    通常来说 每个程序员都有自己趁手的兵器 代码编辑器 你要是让他换个开发环境 恐怕开发效率至少下降三成 然而 每个人对编辑器的喜好各不相同 甚至引发出诸如 神的编辑器 与 编辑器之神 这种信仰之争 但也正由此可见 个性化的编辑器对于一个程序员
  • 【FICO系列】SAP FICO 凭证错误:BKPFF$PRDCLN800在FI中达到的项目最大编号

    公众号 SAP Technical 本文作者 matinal 原文出处 http www cnblogs com SAPmatinal 原文链接 FICO系列 SAP FICO 凭证错误 BKPFF PRDCLN800在FI中达到的项目最大
  • 无法访问目标主机的原因及其和请求超时的区别

    使用ping命令时经常会遇到这两种情况 就表示网络出了问题 无法访问目标主机的原因 可以看到 无法访问目标主机 是来自一个IP的回复 实际上那个IP是一个路由器 因此 无法访问目标主机 实际上数据是发出去并且收到回复的 只不过收到的回复是别
  • 数据结构和算法(递归概念、迷宫回溯问题和八皇后问题代码实现)

    递归的概念 递归能够做解决什么问题 使用递归时需要注意的问题 递归的第一个应用 迷宫回溯问题 迷宫模拟 定义一个8 7的数组模拟迷宫 1表示围墙 0表示可以走的路 图中左上红圈为起点 右下红圈为终点 利用代码找到从起点到终点的路径 使用递归
  • 【Python】代码实现LL(1),LR(1)上下文无关文法(Stack()类)

    任务要求 针对书上第三章中的表达式文法 采用LL 1 LR 1 进行分析 相关文法 需要进行消除左递归等操作 顺手分享一下课本资源好了 可能不是最新版 排版略有点别扭 后文的书上内容就是指这本书 编译原理 陈意云 文字版 提取码 e0ag