LL(1)文法中FIRST集和FOLLOW集的计算方法

深入理解

         在哈工大的陈老师讲这个的时候(也就是21集),我觉得她已经将

  1. 为什么要有预测分析
  2. FIRST集合和FOLLOW集合的实际意义
  3. LL(1)文法的定义形成过程
    都讲的十分清楚了。所以大家可以先去看看老师的视频,然后再来看我的文章。

FIRST集的定义

         可从α推导得到的串的首符号的集合,其中α是任意的文法符号串。在这里插入图片描述

FIRST集的实际意义

         因为我们采用自顶向下的分析方法的时候,可能会遇到回溯。这个时候可能程序就会因为做出了一个错误的选择导致分析器的效率变慢。如果我们在每一步我们都能够预测出正确的选择的话,我们就不需要回溯。我们称这样的分析为预测分析。当然也不是所有的文法都可以采用预测分析的技术,LL(1)是可以采用预测分析技术的。

         那么如何可以每次都能正确预测出下一步所要用到产生式呢?只要每一个产生式直接或者间接开头的非终结符各不相同就可以了。举个例子:在这里插入图片描述
你自己可以尝试推导一遍,发现可以顺利进行。那是因为S->aBc,此时B是第一个非终结符,而B的产生式中也仅仅只有一个产生式是有d所开头。所以就可以迅速的采用B->dB这个产生式。这个也就是FIRST集合的实际意义。想像这个一个场景:在这里插入图片描述
从文法开始符号开始推导,输入指针到d字符的时候,就是aBC。此时第一个非终结符就是B,然后我们查找B的产生式却有两个产生式都是都可以退出d,所以可以替换为adcC(采用B->dC推导出来)或者adB(采用B->dB推导)。所以,分析器就无法100%做出一个正确的判断。所以就引出了FIRST集合,所以能够使用预测分析的程序就得受到一些限制(这里就是要求文法中每一个非终结符A的各个产生式的FIRST集合两两不相交)

FIRST集的计算方法

         方法就是教材上的方法,不过我在这里说几点要注意的:

  1. X->ABC的时候,如果FIRST(A)里面有ε的话,FIRST(X)也要包含FIRST(B)的所有非ε符号
  2. ε会不会出现在FIRST(X)中,取决于X->ABC这个产生式可不可以推导出ε,而不是依赖别人的FIRST集中的ε。

FOLLOW集的定义

         FOLLOW(A)集合是所有紧跟A之后的终结符或#所组成的集合(#是句尾的标志)在这里插入图片描述

FOLLOW集的实际意义

         是不是只要有FIRST集合就可以完成预测分析的任务了呢?在视频中,老师举了一个例子(具体见视频,后面我也讲到了这个例子),在一个非终结符的FIRST集合中包含ε的时候,就仅仅使用FIRST就不行了。这点在《编译原理》蒋宗礼老师这本书中P128中也举例了。所以我们引入了FOLLOW集合

         当产生式中有ε的时候,可以如果当前的最左非终结符的所有非ε产生式都与当前的输入符号不匹配,那么就可以选择ε产生式来处理。这样是当前的最左非终结符就会往后移动,可以寻找别的来匹配了。

         为什么FOLLOW集合会有这样的效果捏?还是举例说明在这里插入图片描述
我们这里测试ada这个输入串。在推导出adBC的时候,此时输入指针指向a,第一个非终结符B的FIRST集合中没有与对应的,所以我们采用B->ε来让第一个非终结符移到C上。你可以想像为这里的B->ε是斗地主中的癞子,它可以和任何东西匹配。然后现在第一个非终结符C的FIRST集合中包含a,所以最后推导成功。但是输入串ade就不能在你使用B->ε之后,匹配成功。具体我就不分析了,大家可以自行分析。

         在分析ada的时候,我们使用空产生式可以奏效,但是分析ade的时候却不能。就是因为在S->aBC的时候,C在B的后面。所以,如果一旦使用了S->aBC这个产生式的时候,就隐含着C的FIRST集合的终结符一定是在B后面出现的。也就是说,如果采用B->ε之后,就相当于采用C的FIRST集合来匹配现在的输入串。其实本质上就是然后多看的了一个字符,只不过这里不是在输入串的这里多看一个字符,而是在匹配串这里多看一个字符。当然,不引入FOLLOW集合,在输入符号串多看一个字符也是可以解决这个问题,至于为什么没有这么做,我觉得应该也有原因。但是也有LL(2)这样的文法。

FOLLOW集的计算方法

         我平时在写这样的题目的时候,就是

  1. 从后往前扫描每一个表达式
  2. 找到每一个表达式中非终结符
  3. 然后根据规则来做

就是可能这样的规则不太好理解:

如果存在一个产生式A→αB,或存在产生式A→αBβ且first(β)包含ε,那么follow(A)中的所有符号都在follow(B)中。

就是为什么FOLLOW(A)中的元素赋值給FOLLOW(B)。因为A出现的地方都可转化为aB。例如,C->Aa;此时A的FOLLOW(A)中有a。此时将A->cB转化,就是C->cBa,那么不就是说,FOLLOW(B)中有a吗。这一点和算符优先中LASTVT集合有点区别。

预测分析表的实质

         在哈工大老师的讲课视频中,他提出了一个龙书上面没有的概念,也就是SELECT集。其实预测分析表就是一个SELECT。我们为什么需要预测分析表,希望根据当前的最左非终结符A和当前的输入符号a,来选择一个正确的A-产生式。因为如果A-的产生式有多个的话,我们就不得不去“试探的”选择一个A-产生式,然后来判断这个选择是否正确,如果正确的,那自然就好。但是如果不是正确的,就必须到之前的分叉点来重新做出选择。其实可以理解为一个dfs的过程。但是dfs的效率不高,这个也就是为什么人们在dfs种有一个重大的优化就是“剪枝”。我们要做的就是“剪枝”就绝了,直接将每一个分叉路口的选择减少为一个,那么我们每一次就不用选择了,因为仅仅只有一条路径可以选择了。这样做的前提就是文法属于LL文法,我们采用提前读取一个字符的操作来达到预测的效果。这个又依赖与每一个具有相同左部的产生式的右部的FIRST的集合交集为空集。因为如果有了交集之后,你提前预读的一个字符可能还是无法确定唯一的一个产生式。

LL(1)文法的判断

暂时没有写,之后会补充!

  • 6
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: LL(1)文法First集是指对于每个非终结符,它所能推导出的所有字符串的首字符的集合。例如,对于文法S->aB|bC,B->c,C->d,S的First集为{a,b},B的First集为{c},C的First集为{d}。 LL(1)文法Follow集是指对于每个非终结符,它所在产生式右侧的所有符号的Follow集的并集。例如,对于文法S->aB|bC,B->c,C->d,S的Follow集为{$},B的Follow集为{$},C的Follow集为{$}。其,$表示输入串的结束符号。 ### 回答2: LL(1)文法是一种上下文无关文法,它具有一个特殊的性质,即在输入符号、栈和向前看符号(特定的字符序列)给定时,可以唯一确定要采取的产生式。这种文法对于语法分析非常重要,因为它是可以实现自顶向下解析的。在LL(1)文法first集和follow集是两个重要的集合,它们被用来构造LL(1)分析表。 First集是一个集合,它包含所有的终结符串,也可以是空串,它可以首先出现在生成式的非终结符的集合。换句话说,First集可以表示由某个符号开始的所有终止符号串的集合。具体的说,对于一个非终结符A,它的first集包含A的一个直接导出终止符T的集合,即First(A) = {T1,T2,T3,...}。如果一个非终结符可以推导出一个或多个规则,那么它的first集是所有规则的first集的并集。如果一个非终结符可以推导出空集,那么空集也被认为是first的一部分。 Follow集是一个非终结符的集合,它表示在任何可能的情况下,这个非终结符可能出现的终止符号集合。在语法分析器,它用于识别符号串结束非终结符后的终止符号。具体的说,对于一个非终结符A,它的follow集合是以A的右侧的非终结符为起点,或者在其他位置以A开始的所有规则的first集的并集。如果A是输入符号串的第一个符号,则它的follow集也包括输入符号串的结束符号。如果A可以推导出一个或多个规则,那么它的follow集是所有规则的follow集的并集。如果一个非终结符可以推导出空集,那么它的follow集不会受到任何影响。一般来说,在LL(1)分析,我们必须计算follow集,因为它被用来区分在一个产生式使用的非终结符。 在LL(1)分析器first集和follow集非常重要,因为它们可以用来构造一个分析表。这个分析表可以根据输入符号的第一个符号和向前看符号,来决定采取哪个产生式。然后,我们可以在参数栈上推入符号串,直到我们获得输入符号串。当我们获得一个输入符号串时,我们将删除该符号串,并取出新符号串,继续处理直到结束。总之,first集和follow集是LL(1)文法非常重要的工具,它们被用来构造LL(1)分析器,这是一种很有用的技术用于语法分析和编译器的开发。 ### 回答3: LL(1)文法是一种文法范式,它对于识别LL(1)语法的字符串具有重要作用,最常见的用于编译器的前端分析,如语法检查、语法分析、语法规则等。其最重要的两个集合就是First集合和Follow集合。 First集是指一个产生式(规则)的首个终结符号,它可被统称为该规则的FIRST集合。对于一个LL(1)文法G,G的每个非终结符号A的FIRST(A)集合由以下规则构成: 1.如果 X 是一个终结符号,则 First(X) = {X} 2.如果 X 是一个非终结符号,则 First(规则首个符号)∈First(X) 3.假设 X => ε*,则 First(X)∈First(A) 其,第2条规则是First集合的最关键的规则,它描述了非终结符号的FIRST集合能够从规则的右边第一个符号集合获得。这个规则告诉我们,在生成语法树过程,第一个符号就是最重要的,它能够决定如何生成树。 另外,Follow集是一个非终结符的后继符号集合,它与First集合紧密相关。对于LL(1)文法的每个非终结符号A,它的Follow(A)集合创建的规则如下: 1. S(起始符号)∈Follow(S) 2. 如果有A -> BC,那么FIRST(C)∈Follow(B) 3. 如果有A -> B,或者 A -> Bx,其FIRST(x)包含ε,则Follow(A)∈Follow(B) 其,规则2告诉我们,在一个非终结符符号(B)后面输入C之前,需要知道C的FIRST集合,这样就可以进行分析计算,方便从而生成语法树,并进行分析检测。 综上所述,First集和Follow集是LL(1)文法非常重要的两个集合,它们决定了该模型的生成语法树过程,因此,在进行编译器的错误检测、修正等操作的过程,需要熟悉这些集合的相关规则。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值