编译原理第四章笔记 -- 自上而下的语法分析

本文中内容整理西安交通大学软件学院吴晓军老师的ppt中,仅供学习使用,请勿转载或他用
参考教材:《程序设计语言 编译原理》(第3版) 陈火旺等 国防工业出版社
有排版问题或者图片不显示问题及时留言


编译程序的结构

image-20220314082150167

中间箭头不一定是单向的,有请求和响应,更多表现的是先后划分的因果关系

表格管理和出错处理是不可缺少的构建

红色字体是输入及输出

语法分析:判断若干个单词符号串是不是一个合规的语法单元

语法分析的前提

对语法的语法结构进行描述

  • 采用正规式有限自动机描述和识别语言的单词符号
  • 上下文无关文法来描述语法规则

语法分析的任务:分析一个文法的句子的结构

语法分析器的功能:按照文法的产生式(语言的语法规则),识别输入符号串是否为一个句子(合式程序)

方法

这个的分析的方法是针对语法树的

自上而下(Top-down)

  • 从文法的开始符号出发,反复使用各种产生式,寻找匹配的推导
  • 推导:根据文法的产生式的规则,把串中出现的产生式的左部符号替换成右部
  • 从树的根开始,构造语法树
  • 主要方法:递归下降分析法、预测分析程序

自下而上(Bottom-up)

  • 从输入串开始,逐步进行到规约,直到文法的开始符号
  • 规约:根据文法的产生式规则,把串中出现的产生式的右部替换成左部符号
  • 从树叶节点开始,构造语法树
  • 主要方法:算符优先分析法、LR分析法

语法分析–自上而下分析

本章内容

  • 语法分析的任务与分类
  • 自上而下分析面临的问题
  • 递归下降分析程序构造
  • 预测分析程序
  • LL(1)文法

语法分析的任务与分类

w w w表示的是终结符串

语法分析的任务:对于任一给定 w ∈ V T ∗ w\in V_T^* wVT,判断 w ∈ L ( G ) w\in L(G) wL(G)

语法分析器是一个程序,他按照P,做识别 w w w的工作

一个单词符号可能无法得到结果,然后会请求下一个单词符号

image-20220314083522723

语法分析的分类:自下而上和自上而下

面临的问题

主旨:从文法开始符号出发,自上而下地为输入串建立一颗语法树

image-20220314083659104

在该例子中有文法G: S → c A d , A → a b , A → a S\to cAd,A\to ab, A\to a ScAd,Aab,Aa

W:输入串

input pointer:输入字符指针

S:文法的开始符号

image-20220314083948590

首先从开始字符开始生成语法树,然后判断当前输入字符(IP指向的字符)是否与当前语法树的左子节点匹配,如果匹配则进行下一步,如果不匹配就需要退回

image-20220314084106820

c匹配上了之后IP向后移动,然后再次匹配,发现不一样,这时候就需要展开A,到这里有两种展开方法,一种展开为ab,一种展开为a,先按照ab来看

image-20220314084259480

首先与第一个字符是a是匹配的,然后IP继续向后走,这时候发现不匹配了。这里发现不匹配了之后要回退回去,即撤销A展开为ab的过程。这种过程类似于超前搜索,读了之后要还回去

image-20220314084534241

再将A展开为a,就可以完成匹配了,最后语法树如下:

image-20220314084713427

上述分析方法的实现:

  • 每一个非终结符对应于一个递归子程序,在只生成两个串的文法过程中过程无需递归;但是,对于生成无数个串的文法而言,递归不可避免。
  • 递归子程序是一个布尔过程,一旦它发现自己的某个候选式与输入串匹配,它就按此式扩充语法树,返回true,指针移过已匹配的子串;否则,返回false,保持原来的语法树和指针不变

程序实现:使用两个过程:S()和A(),他们送回true or false,决定于他们是否在输入串汇总找到相应的终结符所构成的串

使用记号:

  • input_symbol:当前符号内容
  • input_pointer:输入字符指针

使用过程:ADVANCE(),把input_pointer移到下一输入符号位置,置input_symbol是当前符号内容

过程A的上半部分是去尝试匹配ab,下半部分是去尝试匹配a

image-20220314090130157

困难和问题

  • 文法的左递归
  • 回溯
  • 使用候选式的顺序会影响所接受的语言
    • 如: A → a b ∣ a 改为 A → a ∣ a b A\to ab|a改为A\to a|ab Aaba改为Aaab
  • 难以报告出错的确切位置
  • 穷举试探法----低效的分析方法

问题:进行自上而下语法分析时,下列哪些问题必须首先解决否则无法有效生成语法树?

  • 回溯问题(√)
  • 文法右递归问题
  • 文法左递归问题(√)
  • 多个候选式问题

解释:多个候选式问题和回溯问题可以看成是相关的,但是存在多个候选式不一定会发生回溯

问题的解决

  • 左递归问题
  • 回溯问题

相对而言,左递归问题危害更大,因为会使程序陷入无线迭代

区分三种类型的左递归

  • 直接左递归

    形如 N → N α N\to N\alpha NNα

  • 间接左递归

    形如 N → A α , A → B β , B → N γ N\to A\alpha,A\to B\beta,B\to N\gamma NAα,A,BNγ

  • 潜在左递归

    形如 N → α N β , 而 α ⇒ + ε N\to \alpha N \beta,而\alpha \stackrel{+}{\Rightarrow}\varepsilon Nα,α+ε

1.消除左递归

直接左递归的消除

直接左递归改造前不能有空字产生式,即右侧不能含有 ε \varepsilon ε

消除方法:

  • 如果 A → A α ∣ β A\to A\alpha|\beta AAαβ,其中 β \beta β不以A开头
  • 则修改规则为 A → β A ′ A ′ → α A ′ ∣ ε A\to \beta A'\quad A'\to \alpha A'|\varepsilon AβAAαAε

α \alpha α不能为空字,这是在开始就已经进行限制了,如果是空字了,那么通过吸收律可以得到 P → P P\to P PP,这样就没有意义了,式子可以直接转换成 A → β A\to \beta Aβ

一般规则

假定P的全部产生式是 P → P α 1 ∣ . . . ∣ P α m ∣ β 1 ∣ β 2 ∣ . . . ∣ β n P\to P\alpha_1|...|P\alpha_m|\beta_1|\beta_2|...|\beta_n PPα1∣...∣Pαmβ1β2∣...∣βn,其中每个 α \alpha α都不等于 ε \varepsilon ε,每个 β \beta β都不以P开头

那么可以将其由左递归转换为右递归:
P → β 1 P ′ ∣ β 2 P ′ ∣ . . . ∣ β n P ′ P ′ → α 1 P ′ ∣ α 2 P ′ ∣ . . . ∣ α m P ′ ∣ ε P\to \beta_1P'|\beta_2P'|...|\beta_nP'\\ P'\to \alpha_1P'|\alpha_2P'|...|\alpha_mP'|\varepsilon Pβ1Pβ2P∣...∣βnPPα1Pα2P∣...∣αmPε
例子:

新的非终结符的记号最好与原非终结符对应上,即只在其右上角加个单引号

现有文法:
E → E + T ∣ T T → T ∗ F ∣ F F → ( E ) ∣ i E\to E+T|T\\ T\to T*F|F\\ F\to (E)|i EE+TTTTFFF(E)i
消去直接左递归后:
E → T E ′ E ′ → + T E ′ ∣ ε T → F T ′ T ′ → ∗ F T ′ ∣ ε F → ( E ) ∣ i \begin{aligned} &E\to TE'\\ &E'\to +TE'|\varepsilon\\ &T\to FT'\\ &T'\to *FT'|\varepsilon\\ &F\to (E)|i \end{aligned} ETEE+TEεTFTTFTεF(E)i

间接和潜在左递归的消除

一个文法消除左递归的条件

  • 不含以 ε \varepsilon ε为右部的产生式
  • 不含回路

即不会后面的式子不会成立 P ⇒ + P P\stackrel{+}{\Rightarrow}P P+P

代入法:将一个产生式规则右部的 α \alpha α中的非终结符N替换为”N的候选式“。如果N有n个候选式,则右边的 α \alpha α重复n次,而且每一次重复都用N的不同候选式来代替N

例子

这里右部产生式有空字可以理解成是为了消除直接左递归时引入的,不然会与上面的消除左递归的条件发生冲突

N → a ∣ B c ∣ ε N\to a|Bc|\varepsilon NaBcε S → p N q S\to pNq SpNq中的代入结果: S → p a q ∣ p B c q ∣ p q S\to paq|pBcq|pq SpaqpBcqpq

间接和潜在左递归通常通过代入能转换为直接左递归

消除一个文法一切左递归的算法

一般是按照字母表的升序排序的

for循环是完成代入的

化简在课本上有例题,可以尝试着变一下排序的策略,看看做出来的文法有什么差异

例子

现有文法:
S → Q c ∣ c Q → R b ∣ b R → S a ∣ a S\to Qc|c\\ Q\to Rb|b\\ R\to Sa|a SQccQRbbRSaa
方法一:排序顺序为R、Q、S

将R带入到Q中:

Q → S a b ∣ a b ∣ b Q\to Sab|ab|b QSababb

将Q带入到S中:

S → S a b c ∣ a b c ∣ b c ∣ c S\to Sabc|abc|bc|c SSabcabcbcc

整个文法为:
S → a b c S ′ ∣ b c S ′ ∣ c S ′ S ′ → a b c S ′ ∣ ε S\to abcS'|bcS'|cS'\\ S'\to abcS'|\varepsilon SabcSbcScSSabcSε
方法二:排序顺序为S、Q、R

将Q带入到S中:

S → R b c ∣ b c ∣ c S\to Rbc|bc|c SRbcbcc

将S带入到R中:

R → R b c a ∣ b c a ∣ c a ∣ a R\to Rbca|bca|ca|a RRbcabcacaa

整个文法为:
R → b c a R ′ ∣ c a R ′ ∣ a R ′ R ′ → b c a R ′ ∣ ε R\to bcaR'|caR'|aR'\\ R'\to bcaR'|\varepsilon RbcaRcaRaRRbcaRε

  • 对文法G的所有非终结符进行排序

  • 按上述顺序对每一个非终结符 P i P_i Pi依次执行:

    • for(j = 1; j < i - 1; j++)

      P j P_j Pj代入 P i P_i Pi的产生式(若可代入的话)

    • 消除关于 P i P_i Pi的直接左递归

  • 化简上述所得的文法

2.消除回溯

回溯原因

若当前符号 = a,对A展开,而 A → α 1 ∣ α 2 ∣ . . . ∣ α m A\to \alpha_1|\alpha_2|...|\alpha_m Aα1α2∣...∣αm,那么,要知道哪一个 α i \alpha_i αi是获得以a开头的串的唯一替换式。即:选择哪一个 α i \alpha_i αi,亦即通过查看第一个(当前)符号来发现合适的替换式 α i \alpha_i αi

怎样选择 α i \alpha_i αi

  • 以a为头的 α i \alpha_i αi
  • 如有多个 α i \alpha_i αi以a为头,则这是文法的问题

例如,有产生式: 语句 → 条件 t h e n 语句 e l s e 语句 ∣ w h i l e 条件 d o 语句 ∣ b e g i n 语句表 e n d 语句\to 条件 then 语句 else语句\quad|\quad while条件do语句\quad|\quad begin语句表end 语句条件then语句else语句while条件do语句begin语句表end

若要寻找一个语句,那么关键字if,while,begin就提示我们哪一个替换式是最有可能成功的替换式

抽象地看问题:若问题不得回溯,文法G(当然G不含左递归)的必要条件是什么,也即对文法有什么要求?

若由 α i ⇒ + a ⋅ ⋅ ⋅ \alpha_i \stackrel{+}{\Rightarrow} a\cdot\cdot\cdot αi+a,选该 α \alpha α必中,但若 α j ⇒ + ⋅ ⋅ ⋅ \alpha_j\stackrel{+}{\Rightarrow}\cdot\cdot\cdot αj+,就会导致无法百发百中。解决办法是对文法本身提出要求:“不要出现以上情况”。把上述要求阐明清楚可以采用如下顶替的FIRST( α \alpha α),即 α \alpha α首符集

首符集定义

F I R S T ( α ) = { a ∣ α ⇒ ∗ a ⋅ ⋅ ⋅ , a ∈ V T } ,若 α ⇒ ∗ ε ,规定 ε ∈ F I R S T ( α ) FIRST(\alpha)=\{a|\alpha\stackrel{*}{\Rightarrow}a \cdot\cdot\cdot,a\in V_T\},若\alpha\stackrel{*}{\Rightarrow}\varepsilon,规定\varepsilon\in FIRST(\alpha) FIRST(α)={aαa,aVT},若αε,规定εFIRST(α)

F I R S T ( α ) FIRST(\alpha) FIRST(α)不可以称为首终结符集,因为有 ε ∈ F I R S T ( α ) \varepsilon\in{FIRST(\alpha)} εFIRST(α)

定理

若一个 A ∈ V N A\in V_N AVN,有许多 F I R S T ( α i ) FIRST(\alpha_i) FIRST(αi),如果A的任何两个候选式 α i 和 α j \alpha_i和\alpha_j αiαj之间均满足 F I R S T ( α i ) ∩ F I R S T ( α j ) = Φ FIRST(\alpha_i)\cap FIRST(\alpha_j)=\Phi FIRST(αi)FIRST(αj)=Φ,意味着,A的每一候选式 α \alpha α推倒后所得到的字符串第一个 V T V_T VT均不同。

于是,对输入符号a,如果 a ∈ F I R S T ( α i ) a\in FIRST(\alpha_i) aFIRST(αi),则 a   ∉ F I R S T ( α j ) , ( j ≠ i ) a\ \notin FIRST(\alpha_j),(j\neq i) a /FIRST(αj),(j=i),因此,对A的展开无疑应选择候选式 α i \alpha_i αi,否则无法命中

清除回溯的方法:使非终结符A所有候选式的首符集两两不相交

方法:提取公共左因子

例如:若 A → δ β 1 ∣ δ β 2 ∣ ⋅ ⋅ ⋅ ∣ δ β n ∣ γ 1 ∣ γ 2 ∣ ⋅ ⋅ ⋅ ∣ γ m A\to \delta \beta_1|\delta\beta_2|\cdot\cdot\cdot|\delta\beta_n|\gamma_1|\gamma_2|\cdot\cdot\cdot|\gamma_m Aδβ1δβ2δβnγ1γ2γm(其中,每个 γ \gamma γ不以 δ \delta δ开头)

那么,可以把这些规则改写成
A → δ A ′ ∣ γ 1 ∣ γ 2 ∣ ⋅ ⋅ ⋅ ∣ γ m A ′ → β 1 ∣ β 2 ∣ ⋅ ⋅ ⋅ ∣ β n A\to \delta A'|\gamma_1|\gamma_2|\cdot\cdot\cdot|\gamma_m\\ A'\to \beta_1|\beta_2|\cdot\cdot\cdot|\beta_n AδAγ1γ2γmAβ1β2βn
问题:清楚回溯问题时,可以检查多个候选式的首符集。请问,首符集被称为终结首符集是否正确?

答案:首符集不能被称为终结首符集或者首终结符集,因为其中可能会包含有 ε \varepsilon ε

递归下降分析程序构造

不含左递归每个非终结符的所有候选式的首符集都两两不相交的条件下,构造一个不带回溯的自上而下分析程序,该分析程序由一组递归过程组成,每个过程对应文法的一个非终结符。也就是说前提条件已经消除了左递归和回溯。

这样的一个的分析程序称为递归下降分析器

例子

有如下文法:
E → T E ′ E ′ → + T E ′ ∣ ε T → F T ′ T ′ → ∗ F T ′ ∣ ε F → ( E ) ∣ i \begin{aligned} &E\to TE'\\ &E'\to +TE'|\varepsilon\\ &T\to FT'\\ &T'\to *FT'|\varepsilon\\ &F\to (E)|i \end{aligned} ETEE+TEεTFTTFTεF(E)i
每个非终结符所对应的递归子程序如下所示:

image-20220318103206497

针对空串没有给出任何的处理,老师给出的说法是不管它,hhh

image-20220318103206497

image-20220318103206497

例如对于 i 1 + i 2 ∗ i 3 i_1+i_2*i_3 i1+i2i3有如下分析过程:

image-20220318213055267

注意

  • ε \varepsilon ε,自动匹配,不会失败;
  • 无成功/失败消息返回
  • 出错位置不确切

问题:构造递归下降分析程序时,它由一组递归过程组成。每个递归过程对应文法的一个什么?

回答:非终结符

预测分析程序

问题:用递归子程序描写递归下降分析器,要求实现该编译程序的语言(高级或汇编)允许递归

改进:使用一张分析表和一个同样可以实现递归下降分析。用这种方法实现的语法分析程序叫做预测分析程序

上面的那个叫做递归下降分析程序

预测分析程序的工作工程

  • 中间是预测分析程序的总控程序
  • 预测分析表事先需要建好,在过程中需要去查找这个表
  • 左边的栈最下面需要放置一个界符#,在终结符串右侧也有一个#

image-20220318104811825

预测分析程序

预测分析程序包含有四部分:

  1. 一个输入:含有要分析的终结符串,右端有#
  2. 一个栈:栈底是#,栈内是一系列的文法符号;开始时,#和S(开始符号)先进栈
  3. 分析表:二维数组M[A,a],其中 a ∈ V T ; A ∈ V N a\in V_T;A\in V_N aVT;AVN行数是文法非终结符的个数,列数是文法终结符的个数+1(有#号),这里一定不要忘了列数是终结符个数加1
  4. 输出:根据分析表内元素作规定的语法分析动作
分析程序的动作

栈顶符号X和当前输入符号a,由(X,a)决定程序动作,三种可能:

  1. X = a = # X=a=\# X=a=#,分析停止,宣告成功地完成分析
  2. X = a ≠ # X=a\neq \# X=a=# ,则X弹出栈,前移输入指针
  3. X ∈ V N X\in V_N XVN,则去查分析表M的元素M[X,a],该元素或为X的产生式,或者为一个出错元素

对于情况三,这里注意在替换的时候需要出栈之后将后面的元素反序压栈

M [ X , a ] = { X → U V W } M[X,a]=\{X\to UVW\} M[Xa]={XUVW},就用WVU(U在顶)替换栈顶的X

如果 M [ X , a ] = e r r o r M[X,a]=error M[X,a]=error,则调用error程序

下面这个表把出错处理全部隐去了,实际上所有地方都有东西

image-20220318214424912

记得开始一定要初始化栈底为一个#号,自己推的时候注意一下栈顶元素和当前输入元素分别是什么

image-20220318112037014

image-20220318112436975

到17步,左#和右#相遇,这表示分析是成功的,根据输出的顺序生成最终的语法树

结论:

  • 输出的产生式就是最左推导的产生式。栈中放右部,等待与 α \alpha α匹配
  • 分析表中出现(栈顶,a)时,指出如何扩充树,并且能马上发现错误

实质:

  • 栈:残缺规范句型
  • 表:指出 V N V_N VN按哪一条扩充,依赖于 V T V_T VT

上述分析过程生成的语法树:

image-20220318112747228

分析表的构造

行对应的是非终结符,列对应的是终结符(以及#号)

image-20220318113057753

定义首符集和后继符集

先要构造两个与G有关的集合: F I R S T ( α ) 和 F O L L O W ( A ) FIRST(\alpha)和FOLLOW(A) FIRST(α)FOLLOW(A),(首符集和后继符集)

定义:对于文法G, α ∈ V ∗ , S , A ∈ V N \alpha\in V^*,S,A\in V_N αV,S,AVN

F I R S T ( α ) = { a ∣ α ⇒ ∗ a ⋅ ⋅ ⋅ , a ∈ V T } , 若 α ⇒ ∗ ε ,规定 ε ∈ F I R S T ( α ) FIRST(\alpha)=\{a|\alpha\stackrel{*}{\Rightarrow}a\cdot\cdot\cdot,a\in V_T\},若\alpha\stackrel{*}{\Rightarrow}\varepsilon,规定\varepsilon\in FIRST(\alpha) FIRST(α)={aαa,aVT},αε,规定εFIRST(α)

F O L L O W ( A ) = { a ∣ S ⇒ ∗ α A a β , a ∈ V T , α , β ∈ V ∗ } FOLLOW(A)=\{a|S\stackrel{*}{\Rightarrow}\alpha Aa\beta,a\in V_T,\alpha,\beta \in V^*\} FOLLOW(A)={aSαAaβ,aVT,α,βV},即句型当中的跟在非终结符后面的终结符

构造首符集

这里其实可以看一下书,非常清楚

复习整理时候在这里重新做了梳理,可以参考这个规则:

  • 如果是终结符,则首符集就是自己,即 F I R S T ( X ) FIRST(X) FIRST(X) { X } \{X\} {X}
  • 如果是非终结符( X ∈ V N X\in V_N XVN),
    • 情况一:右侧第一个是终结符( X → a α X\to a\alpha Xaα),则 { a } ∪ F I R S T ( X ) \{a\}\cup FIRST(X) {a}FIRST(X)
    • 情况二:右侧是空串( X → ε X\to \varepsilon Xε),则 { ε } ∪ F I R S T ( X ) \{\varepsilon\}\cup FIRST(X) {ε}FIRST(X)
  • 如果是非终结符,并且右侧的第一个元素是另一个非终结符(这里有个前提是,文法中已经不包括左递归了,所以这里只能是其他非终结符而不能是自己),Y中的首符集的非空串全部纳入X的首符集中
    • 形式化语言描述是,若 X ∈ V N , X → Y ⋅ ⋅ ⋅ , Y ∈ V N X\in V_N,X\to Y\cdot\cdot\cdot,Y\in V_N XVN,XY,YVN,则 F I R S T ( Y ) ∖ { ε } ∪ F I R S T ( X ) FIRST(Y) \setminus \{\varepsilon\} \cup FIRST(X) FIRST(Y){ε}FIRST(X)
    • 如果Y的首符集包含空串 ε \varepsilon ε,则继续看Y后面的元素,按照这三个规则继续扩充X的首符集
  • 如果右侧所有字符的首符集都包含空串,则把空串也加入X的首符集中

先构造所有元素的首符集 F I R S T ( X ) , X ∈ V FIRST(X),X\in V FIRST(X),XV

然后使用以下规则,直至再无终结符或 ε \varepsilon ε加入任一 F I R S T FIRST FIRST集为止

  • 如果是终结符,则首符集就是自己,即 F I R S T ( X ) FIRST(X) FIRST(X) { X } \{X\} {X}
  • 如果是非终结符( X ∈ V N X\in V_N XVN),
    • 情况一:右侧第一个是终结符( X → a α X\to a\alpha Xaα),则 { a } ∪ F I R S T ( X ) \{a\}\cup FIRST(X) {a}FIRST(X)
    • 情况二:右侧是空串( X → ε X\to \varepsilon Xε),则 { ε } ∪ F I R S T ( X ) \{\varepsilon\}\cup FIRST(X) {ε}FIRST(X)
  • 如果是非终结符,并且右侧的第一个元素是另一个非终结符(这里有个前提是,文法中已经不包括左递归了,所以这里只能是其他非终结符而不能是自己),Y中的首符集的非空串全部纳入X的首符集中
    • 形式化语言描述是,若 X ∈ V N , X → Y ⋅ ⋅ ⋅ , Y ∈ V N X\in V_N,X\to Y\cdot\cdot\cdot,Y\in V_N XVN,XY,YVN,则 F I R S T ( Y ) ∖ { ε } ∪ F I R S T ( X ) FIRST(Y) \setminus \{\varepsilon\} \cup FIRST(X) FIRST(Y){ε}FIRST(X)

进而: X → Y 1 Y 2 ⋯ Y i − 1 Y i ⋯ Y k , Y j ∈ V N X\to Y_1Y_2\cdots Y_{i-1}Y_i\cdots Y_k,Y_j\in V_N XY1Y2Yi1YiYk,YjVN

如果 ε ∈ F I R S T ( Y j ) , 1 ≤ j ≤ i − 1 , 即 Y 1 Y 2 ⋯ Y i − 1 ⇒ ∗ ε \varepsilon \in FIRST(Y_j),1\le j\le i-1,即Y_1Y_2\cdots Y_{i-1}\stackrel{*}{\Rightarrow}\varepsilon εFIRST(Yj),1ji1,Y1Y2Yi1ε,则:
( ⋃ j = 1 i − 1 F I R S T ( Y j ) ∖ { ε } ) ∪ F I R S T ( X ) (\bigcup^{i-1}_{j=1}FIRST(Y_j)\setminus \{\varepsilon\})\cup FIRST(X) (j=1i1FIRST(Yj){ε})FIRST(X)
只有当
ε ∈ ⋂ j = 1 k F I R S T ( Y j ) , 则 { ε } ∪ F I R S T ( X ) \varepsilon\in \bigcap^k_{j=1}FIRST(Y_j),则\{\varepsilon\}\cup FIRST(X) εj=1kFIRST(Yj),{ε}FIRST(X)

右部前 i − 1 i-1 i1个都是非终结符

上面这个的意思是如果X推导出的所有非终结符中,如果对于 1 ≤ j ≤ i − 1 1\le j\le i-1 1ji1的所有 j j j来说有 ε ∈ F I R S T ( Y j ) \varepsilon\in FIRST(Y_j) εFIRST(Yj),那么把 F I R S T ( Y j ) FIRST(Y_j) FIRST(Yj)的所有非 ε \varepsilon ε元素都加入到 F I R S T ( X ) FIRST(X) FIRST(X)

只有 ∀ j ∈ [ 1 , k ] , ε ∈ ⋂ j = 1 k F I R S T ( Y j ) \forall j\in [1,k],\varepsilon \in \bigcap^k_{j=1}FIRST(Y_j) j[1,k],εj=1kFIRST(Yj)来说(也就是X推出的所有文法符号的首字符集都包含 ε \varepsilon ε),才可以把 { ϵ } \{\epsilon\} {ϵ}加到 F I R S T ( X ) FIRST(X) FIRST(X)

进而再构造 F I R S T ( X 1 X 2 ⋯ X n ) FIRST(X_1X_2\cdots X_n) FIRST(X1X2Xn)

  • F I R S T ( X 1 ) FIRST(X_1) FIRST(X1)的非 ε \varepsilon ε终结符加入 F I R S T ( α ) FIRST(\alpha) FIRST(α)
  • ε ∈ F I R S T ( X 1 ) \varepsilon\in FIRST(X_1) εFIRST(X1),则 F I R S T ( X 2 ) FIRST(X_2) FIRST(X2)的所有非 ε \varepsilon ε终结符加入 F I R S T ( α ) FIRST(\alpha) FIRST(α)
  • ε ∈ F I R S T ( X 1 ) , ε ∈ F I R S T ( X 2 ) \varepsilon\in FIRST(X_1),\varepsilon\in FIRST(X_2) εFIRST(X1),εFIRST(X2),则 F I R S T ( X 3 ) FIRST(X_3) FIRST(X3)的所有非 ε \varepsilon ε终结符加入 F I R S T ( α ) FIRST(\alpha) FIRST(α)

最后,若 ε ∈ F I R S T ( X i ) , i = 1 ⋯ n , 则 { ε } 加入 F I R S T ( α ) \varepsilon\in FIRST(X_i),i=1\cdots n,则\{\varepsilon\}加入FIRST(\alpha) εFIRST(Xi),i=1n,{ε}加入FIRST(α)

大概意思就是当前面的文法字符的首字符集包含空串的时候, α \alpha α的首字符集才包括后面的文法字符的所有非 α \alpha α的首字符集

只有当所有的元素的首字符集都包含空串的时候, α \alpha α的首字符集才包含空串

构造后继符集

F O L L O W ( A ) = { a ∣ S ⇒ ∗ α A a β , a ∈ V T , α , β ∈ V ∗ } FOLLOW(A)=\{a|S\stackrel{*}{\Rightarrow}\alpha Aa\beta,a\in V_T,\alpha,\beta \in V^*\} FOLLOW(A)={aSαAaβ,aVT,α,βV},即句型当中的跟在非终结符后面的终结符

后继符集只关注非终结符后面的终结符

#属于FOLLOW(S),一定不能忘了

应用下列规则,直到再没有什么加进任一 F O L L O W FOLLOW FOLLOW为止

  1. #属于 F O L L O W ( S ) FOLLOW(S) FOLLOW(S)
  2. 若存在 A → a B β A\to a B \beta Aa,则 F I R S T ( β ) ⊂ F O L L O W ( B ) , ε FIRST(\beta) \subset FOLLOW(B),\varepsilon FIRST(β)FOLLOW(B),ε除外
  3. 若有 A → a B , 或 A → a B β 且 ε ∈ F I R S T ( β ) , 则 F O L L O W ( B ) ⊃ F O L L O W ( A ) A\to aB,或A\to a B \beta 且 \varepsilon\in FIRST(\beta),则FOLLOW(B) \supset FOLLOW(A) AaB,AaεFIRST(β),FOLLOW(B)FOLLOW(A),把A的位置用 α B \alpha B αB替换之后,原来跟在A后面的现在就跟在B的后面了

image-20220318114826594

问题:构造首符集与后继符集是实现预测分析程序的必要准备。请问,下列哪些选项可以求首符集?

  • 终结符(终结符的首符集就是自己)
  • 非终结符
  • 文法符号串
  • 候选式

答案:ABCD

首符集可以针对任何文法符号,后继符集只能针对非终结符

例子

image-20220519185956394

首符集的构造

image-20220321080558608

观察产生式的两边,F的首符集中非空串的元素都是T首符集的元素,T的首符集中非空串的元素都是E首符集的元素

后继符集的构造

这里一定不要忘记了E(开始符号)的后继符集中还有#

  • 看看有没有两个非终结符挨着的,
  • 看看左右两边有没有都有非终结符的

image-20220321080841981

image-20220321081107746

image-20220321081118043

各个推导用到的都是规则三

第一个是E的后继符集都加入E‘的后继符集

image-20220321081618579

最终构造结果

求出所有非终结符的首符集就够了,然后可以根据其他规则构造串的首符集

image-20220321081703469

image-20220321081821379

构造分析表

这个输入不包含左递归以及回溯

  • 对于文法的每一个产生式,确定填入的位置
  • 这时候就要看产生式右部到底包含了什么终结符,第二条实现确定列,然后根据左部把他加入分析表中
  • 下面这个$b\in FOLLOW(A) $可能有不止一个b

image-20220321081910954

问题:构造预测分析表时,是否有必要专设 # 列?

  • 没必要
  • 有必要(√)
例子:构造分析表

image-20220321082722400

image-20220321082852104

最终得到如下分析表

image-20220321082959083

LL(1)分析法

image-20220321083201926

因为把需要看多个(回溯)的情况已经排除了

有多个候选式,但是只能有一个候选式可以成为空串,不会有多个为空串,如果有多个,则他们的首符集都会包括空串这个元素,就不满足第一个条件了

条件2中的alpha表示除beta外的任意一个。。。叫啥??

image-20220321083340786

image-20220321083659607

image-20220321083823595

A->alpha表示A可以直接推出来a,A->beta表示A后面跟着的第一个是a,这时候就不知道怎们操作了

image-20220321084036741

image-20220321084345840

image-20220321084539272

答案:ABC

如果只是判断一个文法能不能构成LL(1)文法则可以只求出首符集和后继符集,然后检查集合的关系

也可以构造分析表去查找有没有多重入口,也就是一个各自会不会有两个候选式

image-20220321084829615

image-20220321090529785

image-20220321091137988

image-20220321091232880

如果有嵌套的话,内层一定是多分支的,外层才有可能是单分支的

image-20220321091439212

期末题!!!

2021 - A卷

image-20220321091505768

一定不要忘了#!!

image-20220321091838548

image-20220321092205648

2021 - B卷

image-20220321092328741

image-20220321092432373

image-20220413173229323

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hydrion-Qlz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值