编译原理之first集,follow集,select集解析

2023-11-04

为了方便自顶向下语法分析,需要求文法对应的first集,follow集,以及select集。

本文主要分为两部分,一个是求法解析,还有一个例子详解:

第一部分是求法解析

将对first集,follow集,select集分为三种讲解方法

①定义介绍及推导

②简单推导演示

③规范式推导


讲解顺序为,先用最简单的推导介绍三种不同的集,然后介绍概念,最后介绍正规的推导方法

三种方法,不同人喜欢不同的理解方法,大家都可以参考,推导方法越往后,越规范!


默认规则:

起始符S,其余大写字母为非终结符;

小写字母为终结符,#为ε; 

产生式: A->BC, 其中这个是关于A的产生式,A为左部(左边部分),BC为右部 (右边部分)

Vt是终结符

Vn是非终结符



首先文法G[S]

S-> AB|bC

A->#|b

B->aD|#

C->AD|b

D->aS|c


first集:

①简单推导

first,顾名思义就是该关于该符号的所有产生式右部第一个遇到终结符。


例如:

first(S)

用上面那句话:关于S的产生式有两个:S->AB,S->bC

先看简单的情况:S->bC,明显右部第一个终结符是b,  那关于这个产生式的终结符就是b 了,解决一个!

这个时候first(S)={b}

然后是S->AB,这时右部的第一个是A,非终结符,所以不成立。这时你就要再把A的产生式引进来(因为A有关于他的产生式)。

关于A的产生式为:A->#,A->b,分别代入S->AB的产生式得:S->B(应该是S->#B,但是#可以省略) 和S->bB.

看第二个S->bB ,马上就可以知道遇到的第一个终结符是b,

这个时候first(S)={b}
然后看第一个S->B,这个时候B不是终结符,所以不成立,这时就要把B的产生式导进来。

变成S->aD ,S->#,

然后上面两个式子,分别第一个终结符为a,和 #

则这个时候first(S)={b, a , #}


这里强调一下 。为什么S->AB ,会变成后面的S->B 而S->aD就没有S->D, 因为A的产生式是有一个A->#,就是指向空,这个时候代入S->AB不就等于 S->B了吗。而S-aD。因为已经找到第一个终结符了,所以这个产生式就结束推导了





②定义讲解:

定义:设G=(Vt,Vn,P,S)是上下文无关文法。

first(A)={a| A=*>ab, a∈Vt,b∈V*}

若a=*>ε ,则规定ε ∈first(a).成first(a)为a的开始符号集或首符号集


上面是大白话,下面是系统总结一下:

first,顾名思义就是该关于该符号的所有产生式右部第一个遇到终结符。

举例:

一、单个非终结符的first集

(1)求终结符的first集,是他本身

first(a)={a}

(2)X->a....

first(X)= a....,取右部的终结符,则a∈first(x)

(3)X->YZ...

first(X)=YZ...,  当右部第一个符号(Y)是非终结符的时候,你就要把这个符号(Y)的产生式导进来了,然后再判断右边第一个是否是终结符。若Y的产生式存在#,则继续导入Z的产生式寻找右边第一个终结符,重复以上动作。即

first(X)=first(Y),若存在Y->#,则继续first(X)=first(Z),直到非终结符不存在#结束。



二、多个非终结符

X->M...

Y->N...

first(XY)=M...N...  ,同样找右边第一个是终结符的符号,

③正规推导:

(1)对每一文法X∈V,计算first(X)

(2)

①X∈Vt,则first(X)={X}

②X∈Vn(非终结符),且有X->a , 则a∈first(X)

③X∈Vn(非终结符),且有X-># , 若#∈first(X)

④若有X,Y1,Y2,Y3...∈Vn,且有产生式X->Y1,Y2,Y3=*>#,则first(Y1)-{#},first(Y2)-{#}...first(Yi)都属于first(X)找中
重复②-④

⑤当所有Yi=*>#   则first(X)=first(Y1)-{#}∪first(Y2)-{#}.....∪first(Yi)
当有X-># ,才能说#∈first(X)


follow集

follow,顾名思义,就是该符号后面跟着的第一个终结符

PS:求follow集,都是从开始符号S开始推导


①定义介绍

设G=(Vt,Vn,P,S)是上下文无关算法,A属于Vn,S是开始符号

follow(A)={a|S=*>uAb 且a∈Vt,a∈first(b),u∈Vt,b属于V*}

也可定义为

follow(A)={a | S=*>.....Aa....,a∈Vt}.....(1)

若

S=*>...AB....,则follow(A)=first(B)....(2)

若

S=*>....A   ,因为这个时候A属于S,因此这个时候应该看得是S后面的东西也就是follow(S)∈follow(A)....(3)


若

S=*>...AB,这个时候first(B)存在空的情况,而这个时候first的空集不能出现在follow集中,因此还应该看S后面的东西,因此这个等于follow(A)=(first(B)-{#})∪follow(S)....(4)

通过上面(1)(2)(3)(4)不难得出,follow(A)就是从开始符号通过各种产生式推导,直到出现A,然后取A后面的第一个终结符


ps first产生的空集不能给follow,只有follow产生的才可以给,参考上面的(4)


②简单推导:

(1)终结符的follow没有定义,只有非终结符的follow才有定义



(2)

假设:

S->xAy

A->aBb

先求上面

follow(A):

因为要找A后面的跟着的第一个终结符,所以应该直接看谁能产生A,得

S->xAy,

此时A后面跟着的终结符是y,因此follow(A)={y} ,解决!



求FOLLOW(B)



则先找谁能产生B:

B的产生式:

A->aBb,此时,要把first(b)(因为是B后面遇到第一个终结符,也就是first(b),也就是b的first集合)





但是如果这个时候b等于#,那么B的follow集应该取得是b(假设b可能为空的情况)后面的东西,那么问题来了,b后面的东西怎么来呢?

S->xAy,先看下A的产生式,(因为永远是从S出发,因此当产生式出现B的时候一定是这样的流程)

然后代入A的产生

S->xaBby

可以看到出现B的时候是这样的,所以这个时候就应该是把b忽视,直接看y,那么这个时候是不是很熟悉?没错就是跟上面求FOLLOW(A)的一样做法,也就是follow(A)∈follow(B)

这个时候可以总结一个规律

当b为#的时候,follow(B) 就应该看谁产生生它的那个非终结符的follow(),在这里就是因为A->xBy,因此看follow(A)

③正规推导

计算follow集

①设S为起始,{#}加入follow(S)

②要求follow(B),若A->aBb是一个产生式,则把first(B)的非空元素加入follow(B)中

③若B->#,则把follow(A)加入follow(B)中

解释:因为  若D->xAy,A->aBb, 则 D->xaBby,且b=#,则first(y)或者说是 follow(A),  ∈follow(B)



就是所求符号的右边如果等于# 则不停找上一级


前排提示:

做first集的时候,应该第一个找的是左部跟所求符合相同的产生式,然后再分别找这些产生式中右部第一个终结符,然后他们组成一个集合,就是结果


做follow集的时候,应该第一个找的是右部存在所求符号的产生式(区别:first找左,follow找右,first找的符号要跟所求符号完全一样,follow只要找左部存在所有符号的即可),然后再找该符号后面跟着的第一个终结符,如果后面没有符号(即为#),则继续follow()这个产生式的左部,直到找到终结符为止。


做follow集的时候往往要不停往上面找上一级,如果有循环语句的话,不妨顺着从S开始往下找(这样也可以找到所求符号的上级),这样虽然繁杂,但是不会陷入死循环



select集

在求出first集和follow集后

select就方便多了

例:

select(X->Y),先求first(Y),如果first(Y)存在#∈first(Y)的情况,则再求follow(X),最后求两者的并集即可即可



例子:

默认规则:大写字母为非终结符,小写字母和字符(包括 '^'  '( '   ',' 等三个符号 )都是终结符


S->a

S->^

S->(T)

T->SN

N->,SN

N->#

 

 first(S)=first(a)∪first(^)∪first((T)) ={a,^,T}

first(T)=first(S)={a,^,T}

first(N)=first(,SN)∪first(#)={ ‘,’ #}



只有开始符号才有默认{#} ,其余符号的follow集不能通过first产生#,只能通过 ‘∪follow(S)‘ 产生

follow(S)={#}∪follow(N)={#}

follow(T)=first()) ={  ) }

follow(N)=follow(T)={)}


 

是否=>#

First

Follow

S

{a,^,(}

{#,  ’,’ ,  ) }

T

{a,^,(}

{ ) }

N

{‘,’ , #}

{ ) }


Select(S->a) =first(a)= {a}

Select(S->^) =first(^)={^}

Select(S->(T)) =first( (T)  )={ ( }

Select(T->SN) = first(S)={a,^,(}

Select(N->,SN)=first( , ) ={ , }

Select(N->#) =follow(N) = { ) }
select技巧。如select(N->,SN)  即求N->,SN  ,看下图,判断右部 有否必否,有终必否,  如果确定是否的,则只计算first(左部)即可。
在这里左部(,SN) 其中 ‘,‘ 是终结符,所以直接select(N->,SN)=first(,SN). 你也可以判断说:因为S有下图可知是‘否‘, 因此也是只计算first(,SN)



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

编译原理之first集,follow集,select集解析 的相关文章

  • LLVM Language Reference Manual

    摘要 该文档是LLVM汇编语言的参考指南 LLVM是基于表示的静态单赋值 SSA 该表示提供类型安全 低层级操作 灵活性 及简洁表示所有高层级语言的能力 这是贯穿各方面LLVM编译策略的通用代码表示 简介 LLVM代码表示用于三个不同形式
  • 编译原理第七章笔记 -- 中间代码生成

    本文中内容整理西安交通大学软件学院吴晓军老师的ppt中 仅供学习使用 请勿转载或他用 参考教材 程序设计语言 编译原理 第3版 陈火旺等 国防工业出版社 这一章分数在35左右 两个大题 数组的引用四元式生成 控制语句当中布尔表达式的翻译 考
  • 静态单赋值(二)—gcc中的SSA化算法

    版权声明 本文为CSDN博主 ashimida 的原创文章 遵循CC 4 0 BY SA版权协议 转载请附上原文出处链接及本声明 原文链接 https blog csdn net lidan113lidan article details
  • 编译原理实验 实验二 LL(1)分析法 Python实现

    1 实验目的 通过完成预测分析法的语法分析程序 了解预测分析法和递归子程序法的区别和联系 使学生了解语法分析的功能 掌握语法分析程序设计的原理和构造方法 训练学生掌握开发应用程序的基本方法 有利于提高学生的专业素质 为培养适应社会多方面需要
  • 电子科技大学编译原理复习笔记(五):词法分析

    目录 前言 重点一览 词法分析概述 词法分析的功能 词法分析器的输出形式 词法分析器的结构 状态转换图 状态转换图的构造 词法分析器的设计 基本结构 内容 符号表 目的 组成 在词法分析中的作用 符号表的一般形式 常用的符号表结构 总结与补
  • 【编译原理】- 递归下降的语法分析器的实现

    目录 一 实验题目 二 分析与设计 三 源代码 一 实验题目 编写识别由下列文法G E 所定义的表达式的递归下降语法分析器 E E T E T T T T F T F F F E i 输入 含有十进制数或十六进制数的表达式 如 75 1ah
  • 编译原理------词法分析器C/C++代码实现

    一 实验目的 设计 编制并调试一个词法分析程序 加深对词法分析原理的理解 二 实验内容 2 1 待分析的简单的词法 1 关键字 begin if then while do end 所有的关键字都是小写 2 运算符和界符 lt lt lt
  • 编译原理------语法分析器C/C++代码实现

    一 实验目的 编制一个递归下降分析程序 实现对词法分析程序所提供的单词序列的语法检查和结构分析 二 实验内容 利用C语言编制递归下降分析程序 并对简单语言进行语法分析 2 1 待分析的简单语言的语法 用扩充的BNF表示如下 lt 程序 gt
  • 吉首大学_编译原理实验题_基于预测方法的语法分析程序的设计【通过代码】

    一 实验要求 实验二 基于预测方法的语法分析程序的设计 一 实验目的 了解预测分析器的基本构成及用自顶向下的预测法对表达式进行语法分析的方法 掌握预测语法分析程序的手工构造方法 二 实验内容 1 了解编译程序的基于预测方法的语法分析过程 2
  • 龙书学习笔记

    目录 第一章 引论 1 1 语言处理器 1 2 一个编译器的结构 1 2 1 词法分析 1 2 2 语法分析 1 2 3 语义分析器 1 2 4 中间代码生成
  • 编译原理 实验四 LR(1)分析法程序

    源代码仓库 CompilePrincipleLearning experiment 4 yusixian CompilePrincipleLearning github com 源代码在demo文件夹中 一 实验目的 掌握LR 1 分析法的
  • 编译原理 CS-143(更新至week4)

    编译原理 CS 143 Pre Course Survey Navigation Your Course 01 01 Introduction 8m20s 01 02 Structure of a Compiler 13m53s 编译器结构
  • The Backus-Naur Form (BNF) & The Extended Backus-Naur Form (EBNF)

    The Backus Naur Form BNF The Backus Naur Form BNF is a notation used for formal description of the syntax of programming
  • OCaml 安装以及简单的加减乘除Demo(以Ubuntu16.04为例)

    安装nix 参考 https mirrors tuna tsinghua edu cn help nix 安装nix sh lt curl https mirrors tuna tsinghua edu cn nix latest inst
  • 编译原理——自顶向下分析中FOLLOW集的计算

    一 FOLLOW集的定义 对于非终结符号A FOLLOW A 被定义为 可能在某些句型中紧跟在A右边的终结符号的集合 为什么说是可能 因为在一些推导出来的文法符号串中 该非终结符号A可能在最右边 比如 A gt TA 如果存在S gt Aa
  • 编译原理LL(1)文法之提取左公因子,消除左递归

    在判断LL 1 文法是否符合的时候 需要判断LL 1 文法是否存在左公因子 和左递归的情况 以下给出相应的判断方法以及通过提取左公因子和消除左递归使非LL 1 文法转换为LL 1 法的方法 第一种情况 存在左公因子 解决方法 提取左公因子
  • 自下而上分析方法-算符优先,LR(0),SLR,LR(1),LALR大全

    文章目录 自下而上分析法 一 规范规约 相关定义 短语 直接短语 句柄 素短语 最左素短语 语法树表示 示例 规范规约 二 语法分析器 三 算符优先分析算法 算符文法 1 算符优先文法 2 FIRSTVT P 和LASTVT P 1 FIR
  • Compiler- 自增运算

    我们来看一下C语言中的前自增 i 和后自增 i 这个经典案例 大家在学习C的时候肯定学过前自增是先自增 然后将结果用于计算 后自增是先参与计算 再增加 好 看一下这段代码的结果 include
  • 编译原理13:SLR(1)分析表、LR(1)分析表

    更强的LR分析 可以根据当前单词 来选择是移进还是归约 只要所有移进项目中的点后面的那些终结符 与归约项目生成的非终结符的Follow集合的元素没有重叠 若当前单词属于上述Follow集合里则规约 SLR 1 冲突解决办法 SLR 1 分析
  • Go 程序编译过程(基于 Go1.21)

    版本说明 Go 1 21 官方文档 Go 语言官方文档详细阐述了 Go 语言编译器的具体执行过程 Go1 21 版本可以看这个 https github com golang go tree release branch go1 21 sr

随机推荐

  • ESDA in PySal (2) localjoincounts

    ESDA in PySal 2 localjoincounts 参考 https blog csdn net angel0929 article details 128433265 https blog csdn net allenlu20
  • 知乎转来的、、、Nuitka用法

    Python打包exe的王炸 Nuitka Python与模具 Python在制造领域的使用 关注 1 726 人 赞同了该文章
  • Ubuntu安装JDK1.8(手动解压JDK压缩包)

    1 官网下载JDK https www oracle com technetwork java javase downloads jdk8 downloads 2133151 html 2 解压缩 下载的版本jdk 8u211 linux
  • ubuntu18.04安装wireshark3.x与tshark3.x

    默认安装tshark会是2 x 以下是安装3 x的方法 使用命令 sudo add apt repository ppa wireshark dev stable sudo apt update 安装wireshark3 x sudo ap
  • IPv6 PMTUD 路径发现机制 工作原理

    Technorati 标签 IPv6 PMTUD PMTUD IPv6 PMTUD是IPv6的一个工作机制 其主要的目的就是 当网络源发送数据报文到目的的时候 避免分段 也可以称为分片 源节点可以使用发现整个路径上面最大的MTU与目的节点通
  • Android opengles2.0 背景透明

    在Android上开发OpenGL ES应用时 默认的背景不透明的 即使使用了glClearColor来设置了不透明度为0 且纹理图片中有透明的部分也可能被GLView的背景填充 那么首先解决GLView的透明背景问题吧 要设置透明的第一步
  • python-gitlab

    一 安装 pip install python gitlab 官方文档 http python gitlab readthedocs io en stable API https docs gitlab com ce api project
  • springboot项目层次结构_SpringBoot 项目目录结构(工程结构)

    一 代码层结构 根目录 com jianbao 启动类JianbaoApplication java推荐放在根目录 com jianbao 包下 数据实体类domain jpa项目 com jianbao domain mybatis项目
  • 江西理工大学计算机网络基础试卷,无线网络技术作业(江西理工大学期末复习)...

    无线网络技术 1 1 跳频扩频和直接序列扩频各有什么特点 我的答案 跳频扩频 1 一定扩频码序列进行选择的多频率频移键控调制 载波频率不断跳变 2 发送方看似随机的无线电频率序列广播消息 并以固定间隔从一频率跳到另一频率 3 接收方接收时也
  • java对象和类的定义 属性 方法

    类 class 对象 Object instance 实例 1 类可以看成一类对象的模板 对象可以看成该类的一个具体实例 2 类是用于描述同一类型的对象的一个抽象概念 类中定义了这一类对象所应具有的共同属性 方法 类的定义方式 每一个源文件
  • JSP数据交互(一)---内置对象》response

    JSP内置对象之response response对象用于响应客户请求并向客户端输出信息 设置响应参数等 页面重定向 void sendRedirect String location 客户端将重新发送请求到指定的URL 实现登陆验证 并验
  • vector、list、queue

    引用 windows程序员面试指南 vector vector 类似于C语言中的数组 vector 支持随机访问 访问某个元素的时间复杂度 O 1 vector 插入和删除元素效率较低 时间复杂度O n vector 是连续存储 没有内存碎
  • 重构——写在后面

    重构方法有很多 但是只要满足以下条件 怎么重构都是合理的 原则一 SRP Single responsibility principle 单一职责原则又称单一功能原则 核心 解耦和增强内聚性 高内聚 低耦合 描述 类被修改的几率很大 因此应
  • MyBatis实现Mysql数据库分库分表操作和总结(推荐)

    阅读目录 前言 MyBatis实现分表最简单步骤 分离的方式 分离的策略 分离的问题 分离的原则 实现分离的方式 总结 前言 作为一个数据库 作为数据库中的一张表 随着用户的增多随着时间的推移 总有一天 数据量会大到一个难以处理的地步 这时
  • 对于git功能的探索与研究

    读前提示 注意 本文只是面向初学者或者之前并未接触过git而想学习如何初步使用git的读者 如果您很擅长使用git 并善于维护远程仓库 那么不建议您看此篇文章 这会浪费您的时间 当然 这篇文章还是能很好地告诉初学者如何简单的运用git的 比
  • 【C++】类的隐式转换和explicit抑制类的隐式转换

    2023年8月5日 周六下午 今天在网上找了很久都没找到有精确定义了类的隐式转换条件的资料 最后是在权威书籍 C Primer 第5版 里面找到的 说真的 虽然我认为 C Primer 第5版 不适合作为新手学习C 的教材 因为内容太多了
  • [[概率论与数理统计-2]:随机函数、概率、概率函数、概率分布函数

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 123608954 目录 第1章 随机与
  • ZonedDateTime 转为字符串

    Java8新特性ZonedDateTime 这个类有很多好用的方法 但是也有很多坑 它转为字符串时间不对 一般会少几个小时 这个因为地区时间不对 我们只需要转为字符串的时间添加几小时就好 代码如下 public static String
  • c++ vector内存释放踩坑,内存泄漏

    目录 vector删除元素 智能指针 vector移动元素位置 vector条件删除
  • 编译原理之first集,follow集,select集解析

    为了方便自顶向下语法分析 需要求文法对应的first集 follow集 以及select集 本文主要分为两部分 一个是求法解析 还有一个例子详解 第一部分是求法解析 将对first集 follow集 select集分为三种讲解方法 定义介绍