【编译原理复习笔记】语法分析(一)

【编译原理复习笔记】语法分析(一)

码农世界 2024-05-27 前端 72 次浏览 0个评论

分类

语法分析可以按照分析方向分为两类

自顶向下/自底向上

自顶向下的分析

从分析树的顶部向底部方向构造分析树

每一步推导需要做两个选择:

(1)需要替换哪个非终结符

(2)用哪个产生式

最左推导

在最左推导中,总是选择每个句型的最左非终结符进行替换

经过最左推导得到的句型叫做最左句型

最右推导

在自底向上的分析中,总是采用最左规约的方式,因此把最左规约称为规范规约,相对应最右推导成为规范推导

递归下降分析

由于语法分析器一般从左至右读取代码,故采用最左推导

根据输入流中的下一个终结符,选择最左非终结符的有关候选式

循环过程,每个过程对应目标句子中的非终结符

问题:可能需要回溯,导致效率低

预测分析

预测分析是递归下降分析技术的特例,通过在输入中向前看固定个数 k 个符号来选择正确的 A-产生式,称为 LL(k)文法

文法转换

含有 A → A α A \to A\alpha A→Aα的产生式的文法称为直接左递归

如果一个文法中存在非终结符 A → + A α A \to^+ A \alpha A→+Aα,那么这个文法就是左递归的

经过两步及以上产生的左递归被称为是间接左递归

左递归文法会使递归下降分析器无限循环

消除直接左递归

A → A α ∣ β , β 不以 A 开头 A\to A\alpha | \beta \\ ,\beta 不以 A 开头 A→Aα∣β,β不以A开头

可以推导出 r = β α ∗ r = \beta\alpha^* r=βα∗

故可以写成

KaTeX parse error: Undefined control sequence: \betaA at position 6: A\to \̲b̲e̲t̲a̲A̲’

A ’ → α A ’ ∣ ϵ A’ \to \alpha A’|\epsilon A’→αA’∣ϵ

就避开了直接左递归,转换成了右递归

消除间接左递归

e.g.

S → A a ∣ b S \to A a|b S→Aa∣b

A → A c ∣ S d ∣ ϵ A \to Ac|Sd|\epsilon A→Ac∣Sd∣ϵ

在实际推导时会出现:

S = > A a S => Aa S=>Aa

= > S d a => Sda =>Sda

出现了左递归

解决方法:将 S 产生式放入 A 产生式中,然后消除 A产生式的直接左递归

消除公共前缀

LL1 文法

S_文法:每个产生式的右部都以终结符开始,同一非终结符的各个候选式的首终结符都不同

产生式的后继符号集
在某个句型中紧跟在 A 后面的终结符的集合,记为 FOLLOW 集
产生式的可选集

一个产生式的可选集指的是当选用该产生式进行推导的时候,对应输入符号的集合,

e.g. S E L E C T ( A → a β ) = a SELECT(A \to a\beta) = \\{a\\} SELECT(A→aβ)=a

q_文法:每个产生式的右部为 epsilon/首字母为终结符,且具有相同左部的产生式具有不相交的可选集

串首终结符集

串首第一个符号是非终结符,简称首终结符

给定一个文法符号串 alpha,alpha 的串首终结符集 FIRST(alpha)被定义为 alpha 推导出的所有串首终结符构成的集合

对于可选集 SELECT,

如果空字符不属于 FIRST 集, S E L E C T ( A → α ) = F I R S T ( α ) SELECT(A \to \alpha) = FIRST(\alpha) SELECT(A→α)=FIRST(α)

如果空字符属于 FIRST 集, S E L E C T ( A → α ) = ( F I R S T ( a ) − ϵ ) ∪ F O L L O W ( A ) SELECT(A \to \alpha) = (FIRST(a) - \\{\epsilon\\}) \cup FOLLOW(A) SELECT(A→α)=(FIRST(a)−ϵ)∪FOLLOW(A)

LL1 文法的定义

根据上面的概念,在文法 G 中,任意两个具有相同左部的产生式 A → α ∣ β A \to\alpha|\beta A→α∣β:

(1)如果 alpha 和 beta 均不能推出空字符,则 F I R S T ( α ) ∩ F I R S T ( β ) = ∅ FIRST(\alpha)\cap FIRST(\beta) = \varnothing FIRST(α)∩FIRST(β)=∅

(2)alpha 和 beta 至多有一个能够推导出空字符

如果 β = > ϵ \beta => \epsilon β=>ϵ,则 F I R S T ( α ) ∩ F O L L O W ( A ) = ∅ FIRST(\alpha)\cap FOLLOW(A) = \varnothing FIRST(α)∩FOLLOW(A)=∅

对于 alpha 同理

(3)不可能同时推出空字符,否则会产生二义性

S → α → ϵ , S → β → ϵ S \to \alpha \to \epsilon,S \to \beta \to \epsilon S→α→ϵ,S→β→ϵ

FIRST 集细究

对于一串产生式,寻找 FIRST 集方法如下:

E → T E ’ E \to TE’ E→TE’

E ’ → + T E ∣ ϵ E’ \to +TE|\epsilon E’→+TE∣ϵ

T → F T ’ T \to FT’ T→FT’

T ’ → ∗ F T ’ ∣ ϵ T’ \to *FT’|\epsilon T’→∗FT’∣ϵ

F → ( E ) ∣ i d F \to (E)|id F→(E)∣id

(1)查看各产生式右部第一个符号是否为终结符,如果为终结符,则直接填在对应左部的 FIRST 集中

(2)寻找空串,并将空串添加到对应的 FIRST 集中

(3)对于串首是非终结符的产生式,则看该非终结符下所具有的 FIRST 集合

不断运用这三个规则,就可以得到 FIRST 集的集合

FOLLOW 集细究

(1)首先查看开始符号的位置,开始符号算作该产生式集合所构成句型的最右符号,FOLLOW 集包含$

(2)观察每个式子的右部,两个连接的非终结符,后者 FIRST 集中的终结符则在前者的 FOLLOW 集中

(3)对于每个产生式右部的最末尾,如果其右边没有终结符,则左部的 FOLLOW 集被添加到该非终结符的 FOLLOW 集中

(4)对于 FIRST包含空字符的非终结符(且在右部末尾),其前面的非终结符填入左部非终结符的 FOLLOW 集

(5)对于右部中,一个非终结符后紧跟着一个终结符,将该终结符添加到前者的 FOLLOW 集中

重复以上几步作为一个循环,直到这些 FOLLOW 集不再发生变化,此时结束循环,认为找到了所有 FOLLOW 集

该例子最终的 FOLLOW 集如下所示

SELECT 集的细究

对于原产生式,可改写为

E → T E ’ E \to TE’ E→TE’

E ’ → + T E E’ \to +TE E’→+TE

E ’ → ϵ E’ \to \epsilon E’→ϵ

T → F T ’ T \to FT’ T→FT’

T ’ → ∗ F T ’ T’ \to *FT’ T’→∗FT’

T ’ → ϵ T’ \to \epsilon T’→ϵ

F → ( E ) F \to (E) F→(E)

F → i d F \to id F→id

在拥有了 FIRST 集和 FOLLOW 集后,判断 SELECT 集只需要以下三种分类方法:

(1)如果产生式右部第一个为终结符,则该产生式 SELECT集就为该终结符

(2)如果产生式右部第一个为非终结符,则 SELECT 集为该非终结符的 FIRST 集

(3)如果产生式右部为空字符,则 SELECT 集为产生式左部非终结符的 FOLLOW 集

遵循这三个原则,我们可以得到:

此时对于相同左部的产生式,其满足之前定义的 LL1 文法的要求,或者在此处直接观察 SELECT 集,red:SELECT 集不相交则说明其为 LL1 文法

所以上述文法是 LL1 文法

同时拥有了SELECT 集之后也可以很轻松的定义预测分析表:

预测分析表

递归的预测分析法

在递归下降分析中,编写每一个非终结符对应的过程时,根据预测分析表进行产生式的选择

e.g.

非递归的预测分析法

非递归的预测分析不需要为每个非终结符编写递归下降程序,而是根据预测分析表构造一个自动机,也叫表驱动的预测分析

类似有穷自动机,但是增加了栈,用于记忆,一方面从预测分析表中使用新产生式替换,另一方面当遇到目标输入时将当前终结符出栈,同时开始考虑下一个终结符

递归与非递归之对比

递归的预测分析表规模比较大,不需要载入预测表,而且比较直观,但是在自动生成和效率上不占优势;非递归的预测方法尽管不算特别直观且需要载入预测分析表,但是对于机器自动生成的难度来说较小,而且效率也比较高

预测分析中的错误处理

两种情况可以检测到错误

(1)栈顶的终结符和当前输入符号不匹配

(2)栈顶的非终结符与当前输入符号在预测分析表中在对应项为空

恐慌模式

忽略输入中的一些符号,直到输入中出现同步词法单元集合中的某个词法单元

一般将非终结符的 FOLLOW 集认为是同步词法单元

M(A,a),其中 A 表示当前栈顶符号,a 表示输入符号,如果 M = null,则表示检测到错误,根据恐慌模式忽略 a

如果遇到 synch,则弹出栈顶的非终结符 A,尝试继续分析后面的语法符号

如果栈顶此时为终结符且与输入符号不匹配,则弹出栈顶的终结符

转载请注明来自码农世界,本文标题:《【编译原理复习笔记】语法分析(一)》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,72人围观)参与讨论

还没有评论,来说两句吧...

Top