【编译原理】LL(1)预测分析法

一、实验目的

LL(1)的含义:第一个L表明自顶向下分析是从左向右扫描输入串,第2个L表明分析过程中将使用最左推导,1表明只需向右看一个符号便可决定如何推导,即选择哪个产生式进行推导。

LL(1) 预测分析方法是确定的自顶向下的语法分析技术。本次实验的主要目的就是要加深对LL(1)预测分析法的理论和预测分析程序工作过程的理解。

二、实验要求

实现LL(1)预测分析法需要:

(1)判别文法是否为LL(1)文法。为此需要依次计算FIRST集、FOLLOW集和SELLECT集,根据SELLECT集可判断文法否为LL(1)文法。

(2)构造出分析表。根据SELLECT集和文法产生式构造出LL(1)分析表。

(3)进行句子分析。依据分析表判断出某句子是否为给定文法的句子。

为了降低实现的难度,本实验只要求实现步骤(3)的部分,即手动实现步骤(1)和(2),然后依据步骤(2)建立的分析表编写一个总控程序,实现的句子的分析。

程序应满足下列要求:

  1. 输入一个分析表,则输出预测分析的步骤。要求从输入文件(input.txt)和键盘中输入预测分析表,把结果输出到结果文件(result.txt)和显示器。

输出格式,如:

步骤         符号栈        输入串       所用产生式

0        #E          i1*i2+i3#               

1      #ET          i1*i2+i3#         T-->FT

…       ………        …………        …………

2、程序应能判断出某句子是否为该文法的句子。(结论)

3、准备多组测试数据存放于input.txt文件中,测试数据中应覆盖是文法的句子和不是文法的句子两种情况,测试结果要求以原数据与结果对照的形式输出并保存在result.txt中,同时要把结果输出到屏幕。

4、对于上面步骤(1)和(2)虽不需要通过程序来实现,但要求和测试数据一起在实验报告中写明。

5、提前准备

① 实验前,先编制好程序,上机时输入并调试程序。

  • 准备好多组测试数据(存放于文件input.txt中)。

三、实验过程:

  • 算法分析:
  • 初始化文法和预测分析表:
  • 首先,定义了文法的终结符集合 v1 和非终结符集合 v2。
  • 接着,创建了几个产生式对象,并将它们赋值给预测分析表 C 的不同位置。
  • 读取文件内容:
  • 从指定的文件中读取文本内容,并存储在变量 exps 中,每行表示一个要分析的文法。
  • 预测分析:
  • 对于每个读取的文法,先检查是否只包含终结符,然后开始进行预测分析。
  • 预测分析过程通过遍历输入字符并根据预测分析表中的产生式进行推导和匹配。
  • 复杂度分析:
  • 初始化阶段的时间复杂度取决于产生式数量和预测分析表的大小,通常为 O(n)。
  • 读取文件内容和预测分析的时间复杂度主要取决于文法的长度和输入长度,通常为 O(m), 其中 m 为文法或输入的长度。
  • 空间复杂度主要取决于预测分析表的大小和其他数据结构的空间占用,通常为 O(n^2)。
  • 优点:
  • 预测分析器具有较好的可读性和易于实现的特点。
  • 可以快速识别输入串是否符合给定文法规则。
  • 局限性:
  • 预测分析器需要提前构建预测分析表,对于大型文法或复杂语言可能会变得复杂。
  • 对于某些文法,可能需要使用其他类型的解析器来处理。
  • 程序流程图:

  • 程序代码:

class Type:

    def __init__(self):

        self.origin = 'N'  # 产生式左侧字符 大写字符

        self.array = ""  # 产生式右边字符

        self.length = 0  # 字符个数



    def init(self, a, b):

        self.origin = a

        self.array = b

        self.length = len(self.array)





# 预测分析表

C = [[Type() for _ in range(10)] for _ in range(10)]





def is_terminator(c):

    # 判断是否是终结符

    v1 = "i+*()#"

    return c in v1





def read_file(file_name):

    # 读文件

    res = []

    try:

        with open(file_name, 'r') as file:

            for line in file:

                res.append(line.strip())

    except Exception as e:

        print(e)

    return res





def init(exp):

    global ridx, len_exp, rest_stack, top

    top = ridx = 0

    len_exp = len(exp)  # 分析串长度

    rest_stack = list(exp)





def print_stack():

    # 输出分析栈和剩余栈

    global top, ridx, len_exp, analye_stack, rest_stack

    print(''.join(analye_stack[:top + 1]), end=' '*(20-top))



    for i in range(ridx):

        print(' ', end='')

    for i in range(ridx, len_exp):

        print(rest_stack[i], end='')

    print('\t\t\t', end='')





def analyze(exp):

    # 分析一个文法

    global ridx, len_exp, analye_stack, rest_stack, C, top

    init(exp)

    k = 0

    analye_stack[top] = '#'

    top += 1

    analye_stack[top] = 'E'  # '#','E'进栈

    print("步骤\t\t分析栈 \t\t\t\t\t剩余字符 \t\t\t\t所用产生式 ")

    while True:

        ch = rest_stack[ridx]

        x = analye_stack[top]

        top -= 1  # x为当前栈顶字符

        print(str(k + 1).ljust(8), end='')

        if x == '#':

            print("分析成功!AC!\n")  # 接受

            return

        if is_terminator(x):

            if x == ch:  # 匹配上了

                print_stack()

                print(ch, "匹配")

                ridx += 1  # 下一个输入字符

            else:  # 出错处理

                print_stack()

                print("分析出错,错误终结符为", ch)  # 输出出错终结符

                return

        else:  # 非终结符处理

            m = v2.find(x) if x in v2 else -1  # 非终结符下标

            n = v1.find(ch) if ch in v1 else -1  # 终结符下标

            if m == -1 or n == -1:  # 出错处理

                print_stack()

                print("分析出错,错误非终结符为", x)

                return

            elif C[m][n].origin == 'N':  # 无产生式

                print_stack()

                print("分析出错,无法找到对应的产生式")  # 输出无产生式错误

                return

            else:  # 有产生式

                length = C[m][n].length

                temp = C[m][n].array

                print_stack()

                print(x, "->", temp)  # 输出所用产生式

                for i in range(length - 1, -1, -1):

                    if temp[i] != '^':

                        top += 1

                        analye_stack[top] = temp[i]  # 将右端字符逆序进栈

        k += 1





ExpFileName = "./input.txt"

v1 = "i+*()#"  # 终结符

v2 = "EGTSF"  # 非终结符



e = Type()

t = Type()

g = Type()

g1 = Type()

s = Type()

s1 = Type()

f = Type()

f1 = Type()



e.init('E', "TG")

t.init('T', "FS")

g.init('G', "+TG")

g1.init('G', "^")

s.init('S', "*FS")

s1.init('S', "^")

f.init('F', "(E)")

f1.init('F', "i")



C[0][0] = C[0][3] = e

C[1][1] = g

C[1][4] = C[1][5] = g1

C[2][0] = C[2][3] = t

C[3][2] = s

C[3][4] = C[3][5] = C[3][1] = s1

C[4][0] = f1

C[4][3] = f

exps = read_file(ExpFileName)



analye_stack = [' ' for _ in range(20)]



for exp in exps:

    flag = True

    for ch in exp:

        if not is_terminator(ch):

            flag = False

            break



    if flag:

        analyze(exp)

  • 程序运行结果截图:

四、思考题:

请描述确定的自顶向下分析思想。

确定的自顶向下分析思想是指自顶向下地对输入串进行分析,在每一步都根据当前的符号栈顶符号和输入串的当前符号,在分析表中查找所用产生式,然后将产生式右部的符号依次推入符号栈中,直到符号栈中只剩下底符号和输入串中所有符号都被读入为止。如果在分析过程中遇到了分析表中没有对应的产生式,则分析失败。

五、实验小结: 

通过本次实验,我初步了解了LL(1)预测分析法的基本原理和实现方法,掌握了自顶向下分析思想。在实验过程中,我手动计算了文法的FIRST集、FOLLOW集和SELECT集,构造出了LL(1)分析表,并编写了一个总控程序,实现了句子的分析。在测试过程中,我准备了多组测试数据,覆盖了是文法的句子和不是文法的句子两种情况,测试结果以原数据与结果对照的形式输出并保存在result.txt中,同时输出到屏幕。通过本次实验,我深刻理解了LL(1)预测分析法的工作原理,并掌握了其实现方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/644180.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode-189. 旋转数组 原地递归算法(非官方的三种方法)

Problem: 189. 轮转数组 思路 首先&#xff0c;很明显&#xff0c;题目要求的操作等同于将数组的后k%n个元素移动到前面来。 然后我们思考原地操作的方法&#xff1a; &#xff08;为了方便讲解&#xff0c;我们先假设k<n/2&#xff09; 1.我们将数组划分为 [A&#xff0c;B…

电能抄表是什么?

1.电能抄表的概念和功能 电能抄表&#xff0c;说白了&#xff0c;是一种用于数据记录载入电力工程使用量的机器。它主要职能精确测量做好记录客户在一定时间内的耗电量&#xff0c;为供电公司提供准确的收费根据。电能抄表的应用&#xff0c;不仅方便了电费的清算&#xff0c;…

智源与HuggingFace联合推出开放中文大语言模型榜单 - 旗鉴榜

近日&#xff0c;智源研究院与 Hugging Face 开发者社区合作&#xff0c;发布 Open Chinese LLM Leaderboard&#xff0c;旨在跟踪、排名和评估开放式中文大语言模型&#xff0c;通过开源社区共建、用户自主贡献的方式&#xff0c;持续推动和完善中文语言大模型的科学、客观排名…

SW 弯曲找方向

当旋转弯曲轴的时候,半径和角度 越和理论的接近,越接近(只要输入角度,然后旋转弯曲轴,看半径跟随的变化值)

结合时间复杂度浅谈二分法的好处(将持续更新,绝对值你一个收藏)

前言 笔者虽然刷的算法题不多,但是笔者也敢说,二分法真的是一种很优越的算法,使用上限极高的那种,正因如此,笔者才想浅谈一下二分法. 封面是我很喜欢的一个游戏角色,不知道有没有老gal玩家知道! 什么是二分法? 枚举查找即顺序查找&#xff0c;实现原理是逐个比较数组 a[0:…

【DZ模板】价值288克米设计APP手机版DZ模板 数据本地化+完美使用

模版介绍 【DZ模板】价值288克米设计APP手机版DZ模板 数据本地化完美使用 腾讯官方出品discuz论坛DIY的后台设置&#xff0c;功能齐全&#xff0c;论坛功能不亚于葫芦侠&#xff0c;自定义马甲&#xff0c;自定义认证&#xff0c;自定义广告&#xff0c;完全可以打造出自己想…

微信小程序预览图片和H5使用canvas实现图片+蒙层+文字

1、效果 2.H5实现 <!--* Author: limingfang* Date: 2024-05-20 10:26:51* LastEditors: limingfang* LastEditTime: 2024-05-21 16:31:11* Description: --> <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8&q…

sysbench压测mysql性能测试命令和报告

sysbench压测mysql性能测试命令和报告 一、安装sysbench工具二、创建测试数据库三、基于sysbench构造测试表和测试数据四、数据库性能测试1、数据库读写性能测试2、数据库读性能测试3、数据库删除性能测试4、数据库更新索引字段性能测5、数据库更新非索引字段性能测试6、数据库…

Redis内存回收-内存淘汰策略

LFU的访问次数之所以叫做逻辑访问次数&#xff0c;是因为并不是每次key被访问都计数&#xff0c;而是通过运算&#xff1a; 生成0~1之间的随机数R计算 (旧次数 * lfu_log_factor 1)&#xff0c;记录为P如果 R < P &#xff0c;则计数器 1&#xff0c;且最大不超过255访问…

ASP+ACCESS多功能论坛程序设计

摘 要 随着计算机的广泛应用&#xff0c;人们已经对网络不再感到陌生。在科技飞速发展的今天&#xff0c;电脑信息技术与各行各业进行了有效的结合。人们在网上可以进行网上购物&#xff0c;网上交友&#xff0c;电子商务&#xff0c;网络营效等等。面对强大的网络功能&#x…

@Async详解,为什么生产环境不推荐直接使用@Async?

一、Async 注解介绍&#xff1a; Async 注解用于声明一个方法是异步的。当在方法上加上这个注解时&#xff0c;Spring 将会在一个新的线程中执行该方法&#xff0c;而不会阻塞原始线程。这对于需要进行一些异步操作的场景非常有用&#xff0c;比如在后台执行一些耗时的任务而不…

Vue3实战笔记(45)—VUE3封装一些echarts常用的组件,附源码

文章目录 前言一、柱状图框选二、折线图堆叠总结 前言 日前使用hooks的方式封装组件&#xff0c;在我使用复杂的图标时候遇到了些问题&#xff0c;预想在onMounted中初始化echarts&#xff0c;在使用hooks的时候&#xff0c;组件没有渲染完&#xff0c;使用实例会出现各种各样…

ArcGIS中分割与按属性分割的区别

1、分割ArcGIS批量导出各个市的县级行政边界 视频教学&#xff1a; ArcGIS批量导出各个市的县级行政边界002 2、ArcGIS批量导出全国各省的边界 视频教学&#xff1a; ArcGIS导出全国各省的边界003 推荐学习&#xff1a; ArcGIS全系列实战视频教程——9个单一课程组合系列直播回…

文章解读与仿真程序复现思路——电力系统保护与控制EI\CSCD\北大核心《计及温控厌氧发酵和阶梯碳交易的农村综合能源低碳经济调度》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Vite + Vue3 部署 GitHub

因为静态资源是可以部署到 GitHub 上&#xff0c;自己顺便学习部署网站 因为我使用的是 Vite 工具&#xff0c;官方有提供相应 Demo 部署静态站点 | Vite 官方中文文档 新建文件夹 .github 然后再建一个文件夹 workflows 新建文件 main.yml 文件 直接使用官方文档 demo #…

ps进程查看命令详解

1、PS 命令是什么 查看它的man手册可以看到&#xff0c;ps命令能够给出当前系统中进程的快照。它能捕获系统在某一事件的进程状态。如果你想不断更新查看的这个状态&#xff0c;可以使用top命令。 2、ps命令支持三种使用的语法格式 UNIX 风格&#xff0c;选项可以组合在一起…

「云渲染课堂」3dmax地砖材质参数怎么让画面更加真实?

在3DMAX中&#xff0c;地砖材质的渲染需要细致的调整&#xff0c;因为不同材质的地砖在反射和折射参数上各不相同。为了使地砖材质更加逼真&#xff0c;以下简要说明了一些设置方法&#xff0c;希望对大家有所帮助&#xff01; 3dmax地砖材质参数如何设置 1、打开材质编辑器&a…

Git提交和配置命令

一、提交代码到仓库 在软件开发中&#xff0c;版本控制是一个至关重要的环节。而Git作为目前最流行的版本控制系统之一&#xff0c;为我们提供了便捷高效的代码管理和协作工具。在日常开发中&#xff0c;我们经常需要将本地代码提交到远程仓库&#xff0c;以便于团队协作和版本…

C++ | Leetcode C++题解之第112题路径总和

题目&#xff1a; 题解&#xff1a; class Solution { public:bool hasPathSum(TreeNode *root, int sum) {if (root nullptr) {return false;}if (root->left nullptr && root->right nullptr) {return sum root->val;}return hasPathSum(root->left…

电磁仿真--CST网格介绍

1. 简介 网格会影响仿真的准确性和速度&#xff0c;花时间理解网格化过程是很重要的。 CST 中可用的数值方法包括FIT、TLM、FEM、MoM&#xff0c;使用不同类型的网格&#xff1a; FIT和TLM&#xff1a;六面体 FEM&#xff1a;四面体、平面 MoM&#xff1a;表面 CFD&#…