编译原理 第四章自顶向下语法分析法
编译原理-四章自顶向下语法分析法
第四章自顶向下语法分析方法语法分析是编译过程的核心部分。
语法分析的任务是:按照文法,从源程序符号串中识别出各类语法成份,同时进行语法检查,为语义分析和代码生成作准备。
执行语法分析任务的程序称为分析程序。
也称为语法分析器,它是编译程序的主要子程序之一。
在第二章中我们已经介绍过。
通过语法分析可建立起相应的语法树。
按语法树的建立方法,我们将语法分析方法分成两大类,即自顶向下分析和自底向上分析。
下面,我们先介绍自顶向下分析。
本章重点:自顶向下分析、LL(1)分析第一节自顶向下分析方法一、带回溯的自顶向下分析算法这是自顶向下分析的一般方法,即对任一输入符号串,试图用一切可能的方法,从识别符号出发,根据文法自上而下地为输入串建立一棵语法树。
下面用一个简单例子来说明这种过程:假定有文法G[S]:S→cAdA→ab|a 以及输入串w=cad为了自上而下地构造w的语法树,我们首先按文法的识别符号产生根结点S,并让指示器IP指c的规则(此处左部为S的规则仅有一条)( a)(b)(c)图3-1-1图3-1-1a。
我们希望用S的子结从左至右匹配整个输入串w。
首先,此树的最左子结是终结符c为标志的子结,它和输入串的第一个符号相匹配。
于是,我们就把IP调整为指向下一输入符号a,并让第二个子结A去进行匹配,非终结符A有二个选择,我们试着用它的第一个选择去匹配输入串,于是把语法树发展为图3-1-1b。
子树A的最左子结和IP所指的符号相符,然后我们再把IP调为指向下一符号d并让A的第二个子结进入工作。
但A 的第二个子结为终结符号b,与IP当前指的符号d不一致。
因此,A宣告失败。
这意味着A的第一个选择此刻不适用于构造w的语法树。
这时,我们应该回头(回溯)看A是否还有别的选择。
为了实现回溯,我们一方面应把A的第一个选择所生长的子树注销掉;另一方面,应把IP恢复为进入A时的原值,也就是让它重新指向第二输入符号a。
现在我们试探用A的第二个选择,即考虑生成图3-1-1c的语法树。
语法分析-自顶向而下分析-编译原理-04-(二)
FIRST(α) ∩ FIRST(β) = φ
如果 β==*>ε,则 FISRT(α) ∩ FOLLOW(A) = φ
表达式文法是 LL(1) 文法
E → E'→ T → T'→ F → 考察 E’: T’: F :
T + F * (
E' T E'|ε T' F T'|ε E )|id
优缺点分析
1) 采用回朔算法
过于复杂
2)改写文法
将非
LL(1) 文法改写为等价的 LL(1) 文法
无法改写时:
文法过于复杂,无法用自顶向下方法处理
4.3
文法的编写
为描述语法,编写文法;
可能不存在分析方法;
大都可以改写为可分析的文法
LL文法、LR文法、算符优先文法
例:自顶而下分析的使用要求
1. 2. 3.
将 LL(1) 文法改写为扩充的 BNF 范式 按照 EBNF 范式编制语法图,并化简 按照语法图编制递归子程序
EBNF 范式
{ a } 表示 0 次或若干次出现 [ a ] 表示 0 次或 1 次出现
E E' T T' F
→ T E' → { + T } → F T' → { * F } → ( E )|id
+ 不在 FOLLOW( E’ ) = { ), # } * 不在 FOLLOW( T’ ) = { +, ), # } ( 和 id 不同
例 4-5: S → c A → a 输入 w =
对文法 A d b |a cad 的分析
第4章+自顶向下语法分析方法
j=1,2,…,K)均含有,则把加到FRIST(X)中.
用关系图法求文法符号的FIRST集(自学)
3.计算FOLLOW集
根据定义计算 1.对于文法的开始符号S,置#于FOLLOW(S) 中; 2.若A→αBβ是一个产生式,则把 FIRST(β)-{}加至FOLLOW(B)中; 3.若A→αB是一个产生式,或A→αBβ是一个产
A→aAp|d
B→aBq|e
结论
不一定每个文法的左公共因子都能在有限的步 骤内替换成无左公共因子的文法。
一个文法提取了左公共因子后,只解决了相同 左部产生式右部的FIRST集不相交问题,当改 写后的文法不含空产生式,且无左递归时,则 改写后的文法是LL(1)文法,否则还需用LL(1) 文法的判别方式进行判断才能确定是否为LL(1) 文法。
B→d
B→d
考虑对输入串adbcbcbc#的分析
消除直接左递归
A→Aα1| Aα2|…| Aαm|β1|β2|…|βn 其中: αi 不等于ε , βj不以A开头。 改为: A→ β1A'| β2A' |…| βnA' A'→ α1A' | α2A' |…| αmA' |ε
消除间接左递归
将间接左递归变为直接左递归,然后消除直接 左递归。
如果两个产生式有相同的左部,它们的右部是由不 同的终结符或非终结符开始。
文法中无空产生式
定义4.1 设G=(VT,VN,P,S)是上下文无关文法
FIRST()={a|
*
a,a∈VT,
,∈V*}
编译原理第4章 语法分析——自上而下分析
17
例3.4.1 假定有文法G(S): (1) S→xAy (2) A→**|*
分析输入串x*y(记为)。
x*y
S
IP x A y **
18
例3.4.1 假定有文法G(S): (1) S→xAy (2) A→**|*
分析输入串x*y(记为)。
x*y
S
IP x A y **
19
例3.4.1 假定有文法G(S): (1) S→xAy (2) A→**|*
(4.3)
虽没有直接左递归,但S、Q、R都是左递归的
SQcRbcSabc
一个文法消除左递归的条件
丌含以为右部的产生式
丌含回路
PP
30
例 文法G(S): S→Qc|c Q→Rb|b R→Sa|a
(4.3)
虽没有直接左递归,但S、Q、R都是左递归的
SQcRbcSabc
Q
Q
ⅹ
S
R
S→Qc|c Q→Rb|b R→Sa|a
35
例 考虑文法G(S)
S→Qc|c Q→Rb|b R→Sa|a
消除S的直接左递归后: S→abcS | bcS | cS S→abcS | Q→Sab |ab | b R→Sa|a
关于Q和R的觃则已是多余的,化简为:
S→abcS | bcS | cS
S→abcS |
(4.4)
36
注意,由于对非终结符排序的丌同,最 后所得的文法在形式上可能丌一样。但 丌难证明,它们都是等价的。
分析输入串x*y(记为)。
x*y
S
IP
15
例3.4.1 假定有文法G(S): (1) S→xAy (2) A→**|*
分析输入串x*y(记为)。
编译原理语法4(自顶向下语法分析:LL分析法)
PART 01
引言
编译原理概述
01
编译原理是研究将高级语言程序转换为低级语言程序的过程、 方法和技术的学科。
02
编译过程包括词法分析、语法分析、语义分析、优化和代码生
成等多个阶段。
编译原理是计算机科学的重要分支,对于理解计算机如何执行
03
程序以及开发高效、可靠的软件具有重要意义。
语法分析在编译过程中的作用
递归下降分析法
递归下降分析法基本原理
基于文法规则
递归下降分析法是一种自顶向下 的语法分析方法,它基于文法规 则进行推导。
递归调用
对于每个非终结符,都编写一个 相应的子程序来进行识别和处理。 当遇到非终结符时,就调用相应 的子程序进行处理。
预测分析
在子程序中,根据当前输入符号 和文法规则,预测下一个可能的 输入符号,并据此选择正确的推 导路径。
WENKU DESIGN
2023-2026
END
THANKS
感谢观看
KEEP VIEW
WENKU DESIGN
WENKU DESIGN
WENKU
REPORTING
https://
01
深入学习编译原理中的其他分 析方法,如LR分析法、SLR分 析法等,以便更全面地掌握编 译原理的核心内容。
02
探索编译原理在实际应用中的 价值,如编译器设计、程序优 化等,将理论知识与实践相结 合。
03
关注编译原理领域的最新研究 动态和技术发展,不断拓宽自 己的视野和知识面。
WENKU DESIGN
递归下降分析法实现步骤
构造文法
首先,需要构造一个合适的文法,用于描述待分 析的语言。
调用子程序
编译原理 第4章 语法分析—自顶向下分析
例 S::=aABbcd|ε,A::=ASd|ε,B::=SAh|eC|ε,
C::=Sf|Cg|ε,求此文法的每一个非终结符号的
FOLLOW集。
解:FOLLOW(S)={#}∪FIRST(d) ∪(FIRST(Ah)-{ε}) ∪FIRST(f)
={#}∪{d}∪{a,d,h}∪{f} = {a,d,h,f,#}
4)若对于一切1≤i≤n,ε∈FIRST(Xi),则将ε符号加 进FIRST(α)。
例4-1(P62) 有文法: E→TE′ E′→+TE′ E′→ε T→FT′ T′→*FT′ T′→ε F→(E)|i 求文法中非 终结符号以及各 产生式右部符号 串的FIRST集。
解:该文法的非终结符号有E、E′、 T、T′和F。 FIRST(E)=FIRST(TE′) =FIRST(FT′E′)={ ( ,i } FIRST(+TE′)={ + } FIRST(ε)={ε} FIRST(E′)=FIRST(+TE′) ∪FIRST(ε)={+ ,ε} FIRST(T)=FIRST(FT′)={ ( ,i } FIRST(*FT′)={ * } FIRST(T′)=FIRST(*FT′) ∪FIRST(ε)={* ,ε} FIRST((E))={ ( } FIRST(i)={ i } FIRST(F) =FIRST((E)) ∪FIRST(i)={( ,i}
分析法算符优先分析法简单优先分析法优先分析法自底向上带回溯递归下降分析法分析法不带回溯自顶向下语法分析lr回溯示例41p61自顶向下的分析方法就是从文法的开始符号出发按最左推导方式向下推导试图推导出要分析的输开始符号输入符号串自底向上的分析方法从输入符号串开始按最左归约方式向上归约到文法的开始符号
编译原理系列之四自顶向下语法分析方法
编译原理系列之四⾃顶向下语法分析⽅法⾃顶向下语法分析⽅法什么叫确定:两个确定:①确定对最左的⾮终结符进⾏替换(最左推导)②对于同⼀个⾮终结符,确定⼀个产⽣式进⾏推导(SELECT集,⽆回溯)。
⼀个上下⽂⽆关⽂法是LL(1)⽂法的充分必要条件:关于⼀个⾮终结符的各个产⽣式的可选集互不相交。
LL(1)⽂法的判定过程:1. 检查产⽣式中是否有含有左递归或左公因⼦:含有左递归或左公因⼦的⽂法⼀定不是LL(1)⽂法;不含有左递归或左公因⼦的⽂法也不能确定是否为LL(1)⽂法;2. 标记能推导出ε的⾮终结符:先找出能直接推出ε的⾮终结符,然后再查看其他产⽣式的右部,通过这些⾮终结符检查还有没有其他⾮终结符也可推出ε,直到没有发现为⽌。
3. 计算每个产⽣式的FIRST集:①如果这个产⽣式右部第⼀个字符是终结符,那么这个终结符就属于它的FIRST集。
②如果这个产⽣式右部第⼀个字符是⾮终结符,那么这个⾮终结符的FIRST集就属于它的FIRST集。
如果这个⾮终结符的FIRST集中含ε,那么后⾯的字符如果是终结符......③如果这个产⽣式右部可以推出ε,那么ε也属于它的FIRST集。
4. 计算每个⾮终结符的FOLLOW集:⾸先向开始符号的FOLLOW集中添加#,然后对于所有⾮终结符,不断的找含有它的产⽣式右部:①该⾮终结符后⾯的字符若是终结符,那么这个终结符就属于它的FOLLOW集;②该⾮终结符后⾯的字符若是⾮终结符,那么这个⾮终结符的FIRST()集中的所有元素就属于它的FOLLOW集;如果这个⾮终结符的FIRST()集中含ε,将ε删去,同时将这个产⽣式左部FOLLOW集中的所有元素添加⾄它的FOLLOW集中;注意:不需要考虑后⾯的字符了,因为已经包含在FIRST()集中了。
5. 计算每个产⽣式的SELECT集:①如果这个产⽣式可以推出ε,那么它的SELECT集是{FIRST(该产⽣式右部)-ε}∪FOLLOW(该产⽣式左部的⾮终结符)。
编译课件 04 第四章 语法分析-自顶向下分析方法
当First()
2020/7/7
9
➢计算First(X)集
对每一文法符号X计算First(X)
若XVT,First(X)={X} 若XVN则
First(X)={a| Xa…PSet,aVT} 若XVN,且有产生式X,则 First(X) 若 VXN,V则N,有产生式XY1Y2…Yn,且Y1,Y2,…,Yi
end;
主程202序0/7/:7 Begin ReadToken; Z end
21
LL分析方法
LL(1)是LL(k)的特例,其中的k则表示向前看k 个符号。
LL(1)方法和递归下降法属于同一级别的自顶 向下分析法,但有一些区别.
▪ 递归下降法对每个非终极符产生子程序,而LL(1)方 法则产生LL分析表;
2020/7/7
16
递归下降法
递归下降法(Recursive-Descent Parsing) 对每个非终极符按其产生式结构产生相 应语法分析子程序. 终极符产生匹配命令 非终极符则产生调用命令 文法递归相应子程序也递归,所以称这 种方法为递归子程序方法或递归下降法
2020/7/7
17
例:Stm→ while Exp do Stm
处理策略:
1)紧急方式恢复;
2)短语级恢复;
3)出错产生式;
4)全局纠正;
2020/7/7
4
自顶向下分析基本思想
Z
➢ 从文法开始符出发试图推导出所给的终极符串。
➢ 例 G[z] : [1] Z aBd [2] B d
aB d
[3] B c [4] B bB 对给定的终极符串abcd,推导过程:
bB
如果First(y) 则:
Follow(B):= First(y)
第四章 自顶向下语法分析方法2
α)∩SELECT( A *ε 其中α、 β不能同时 足SELECT( A
β)=Ø
14
根据前面的讨论容易看出:能够使用自顶向下分析技术的
文法正是LL(1)文法: 第一个L表明自顶向下分析是从左向右扫描输入串
第二个L表明分析过程中将用最左推导
1表明只需向右看一个符号便可决定如何推导即选择哪个 产生式(规则)进行推导 LL(k)文法,也就是需向前查看k个符号才可确定选用 哪个产生式
11
例3:求下列表达式文法G[E]的语法变量(即非终结符)的 FOLLOW 集。 G[E]:E→TE' E'→+TE’|ε T→FT' T'→*FT’|ε F→(E)|i 解:FOLLOW(E) = FIRST( ))∪{#} = { ),# } FOLLOW(E')= FOLLOW(E) = { ),# } FOLLOW(T)={FIRST(E')-{ε}}∪FOLLOW(E) ∪ FOLLOW(E') = { +, ), #} FOLLOW(T')= FOLLOW(T) = { +, ), #} FOLLOW(F) ={FIRST(T') -{ε}}∪FOLLOW(T) ∪ FOLLOW(T') = { *, +,), #}
,或如何构造一棵相应的语法树
4
例1 根据下面文法G[E],对符号串 i + i * i进行分析,并 按照最左推导构造分析树。 E → T E‟ E‟→ + T E‟|ε T → F T‟ T‟→ * F T‟|ε F → ( E )|i
5
解:与最左推导对应的语法树:
图 4.1 确定的自顶向下语 法分析树(一)
编译原理-清华大学-第4章-自顶向下语法分析方法(3+1)
(2)一个文法提取了左公共因子后,只解决 了相同左部产生式右部的FIRST集不相交问 题,当改写后的文法不含空产生式,且无左 递归时,则改写后的文法是LL(1)文法,否 则还需用LL(1)文法的判别方式进行判断才 能确定是否为LL(1)文法。
• FIRST(Ap)={a,c} • FIRST(Bq)={b,d}
2、非终结符A后跟符号FOLLOW集的定义:
• 定义:设 G = (VT ,VN , S , P) 是上下文无关文 法,A∈VN , S是开始符号。 FOLLOW(A)={a|S * …Aa… ,a∈VT} 若S *…A,则规定 #∈FOLLOW(A)
(3)反复使用规则(2)直到每个非终结符的 FOLLOW集不再增大
S→AB S→bC A→ε A→b B→ε B→aD C→AD C→b D→aS D→c
FOLLOW(S)={#}∪FOLLOW(D) FOLLOW(A)=( FIRST(B)-{ε} )∪
FOLLOW(S) ∪ FIRST(D) FOLLOW(B)=FOLLOW(S) FOLLOW(C)=FOLLOW(S) FOLLOW(D)=FOLLOW(B)∪FOLLOW(C)
• 1表示:只需向右看1个输入符号便可决定 如何推导(即选择哪个产生式进行推导)。
• 类似也可以有LL(K)文法:需向前查看K个 输入符号才可确定选用哪个产生式。
• 文法G[S]是否是LL(1)文法: S→aA S→d A→bAS A→ε
SELECT(S→aA) ={a} SELECT(S→d)={d} SELECT(A→bAS)={b} SELECT(A→ε)={a,d,#} SELECT(S→aA)∩SELECT(S→d)={a}∩{d}=Φ SELECT(A→bAS)∩SELECT(A→ε)={b}∩{a,d,#}=Φ
第04章 语法分析-自顶向下分析
刘伟 liuwei165@
1
S.P
词法分析程序 符 号 表 管 理
语法分析程序
语义分析及生成中间代码程序 代码优化程序 代码生成程序 O.P
2
错 误 处 理
第四章 语法分析-自顶向下 分析 教学目标
1. 要求明确语法分析在编译过程所处的阶段和作 用。 2. 明确语法分析的基本分析方法。 3. 掌握FIRST和FOLLOW集合定义及构造方法。
例如对A→ab|a。 3) 右部侯选式的第一个符号是非终结符号。
29
如S→A|B时,何时使用S→A选项?何时使用S→B选项?
缺点
递归调用较多,占用内存多、速度慢 如果所采用的高级语言不允许递归,则不 能使用此方法
28
4.3.2 递归下降分析中存在的问 题及解决方法
1) 左递归问题
例如文法E→E+T|T。实际上,当文法含有直接或间接 左递归时,都会出现无穷递归。
2) 右部多个侯选式的第一个符号相同问题,即局部 二义性问题。
3.选用A的右部符号串匹配输入串 A有两个右部,选第一个
完成进一步推导Acd 检查,c-c匹配,b-d不匹配(失败) 但是还不能冒然宣布α L(G[S])
S · a A b
c
d
S ·
4.回溯 即砍掉A的子树 改选A的第二右部
Ac 检查 c-c匹配 b-b匹配 建立语法树,末端结点为acb与输入acb 相匹配, 建立了推导序列 SaAbacb ∴acbL(G[S])
F INPUTSYM =„*‟ N
INPUTSYM=下一个符号
Y
Y
INPUTSYM =„/‟ N 出口
25
例4.3,考虑文法Z::=(U)|aUb ,U::=dZ|e,为其构造 递归下降分析子程序。并对输入串aeb进行语法分析 。 Z::=(U)|aUb
《编译原理》第4章自上而下语法分析
• 需要反复试探。
•问题1:回溯(P67)
x
S A y
• 例1:设有文法 (1) S xAy (2) A **|* 现有输入串:x*y 其分析过程如右:
•消除回溯
• 方法是:反复 “提取公共左因子”,使得文法 的每个非终结符号的各个候选式的首终结符集 两两不相交,来避免回溯。 设产生式为: A→δ α1|δ α2|…|δ αn
替换为:
Aδ A' A' α1|α2|…|αn
• 例3:有如下两个产生式:
<IF语句> if E then S1 else S2; <IF语句> if E then S1;
First(A1) = {a} First(A2) = {c} First(B1) = {b} First(B2) = {d}
• 在右边给定的文法中,A 的候选式有两个,其首终 结符集为: First(A1) = {*} First(A2) = {*} 相交,就会产生回溯
(1) S xAy
(2) A **|*
结论:能够从开始符号出发推导出给定的输入串,
因此,是句子。
• 常用的语法分析方法:
根据建立语法分析树的方法来分,有两大类,分四小类:
自顶向下分析法: 从文法的开始符号出发,向下推导(使用最左推 导) ,尽可能使用各种产生式,推导出与输入串 匹配的句子,从而建立语法树。
自底向上分析法: 从输入符号串开始,逐步进行归约(最右推导的 逆过程),直至归约到文法的开始符号,从而建 立语法树。 具体分类:
4第四章 自顶向下语法分析法3
} // while
{
} // exp
case ‘(‘:
void term( )
match(‘(‘) ;
{
exp( );
factor( ) ;
match(‘)’) ;
while (token == ‘*’ )
break;
{
case number :
match (token) ;
match (number) ;
while (token == + || token == - )
{
match (token) ;
term ( synchset U { +, - } ) ;
}
checkinput ( synchset, { } ) ;
}
} // exp
void term ( synchset )
{
checkinput ( { (, number }, synchset ) ;
}
} // term
void factor ( synchset ) ; {
checkinput ( {(, number }, synchset ) if ( token in { (, number } ) {
switch( token ) {
case ( : match ( ( ) ; exp ( { ) } ) ; match( ) ) ;
factor( );
break;
} //while
default:
} // term
error( ) ;
} // switch
} // factor
如果要改写为带错误校正的递归子程序,则可以 采用前面所述的方法加上checkinput和scanto即 可。
4第四章 语法分析—自顶向下分析技术
2. 识别算法
基于自顶向下分析技术对输入符号串进行句型分析
的算法称为自顶向下识别算法。
实现识别算法的程序称为识别程序。 识别程序功能:进行句型分析(识别) 。
4.1.2 讨论的前提
• 讨论的对象(输入)是符号串(中间表示形式)
• 讨论是以上下文无关文法为基础
• 分析过程从左到右逐个符号地进行
语法分析的基础文法是上下文无关文法 输入与输出 输入:词法分析程序的输出(属性字序列)
4.2.3 问题及其解决
带回溯的自顶向下分析技术是 面向目标的、试探的,因而带回溯的。 1) 效率问题 效率低, 因为回溯、查规则效率 2) 左递归问题 左递归的存在使自顶向下分析过程永世无穷。
解决方法: · 消去回溯性 使得对于任何U∈VN, U::=x1 | x2 | … | xn, 如果xi=>* Tiv 和 xj=>* Tjw, 且Ti ,Tj∈VT, 则 Ti≠Tj , i≠j, (1≤i, j≤n) 。
编译原理
Compiler Principles
2013年9月
闫雷鸣
第四章 语法分析——自顶向下分析技术 4.1 引言 4.1.1 自顶向下分析技术及识别算法 1. 基本思想 句型分析,识别一个符号串是否是某文法的句型, 是某个推导或语法分析树的构造过程。 从语法分析树的角度看,自顶向下分析过程将以识 别符号为根结点,试图向下构造语法分析树,其末端结 点符号串正好与输入符号串相同。 自顶向下识别过程是一个不断往语法分析树中添加 分支的过程。
for (i=1; i<=n; i++)
{ for (j=1; j<=i-1; j++)
{ 把形如Ui::=Ujr的规则改写成:
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
若文法的任一非终结符号,其规则右部的各个选择所能推出的终结符号串的头符号集合不满足两两相交的条件时,那么,要构造一个不带回溯的自顶向下的语法分析程序,需要采取什么措施呢?一般可采取改写文法的办法来解决。
(三)改写文法当文法不满足,可改写文法
对每一文法符号X∈V计算FIRST(X)。
(a)若X∈VT,则FIRST(X)={x}
(b)若X∈VN,且有产生式X→a…,a∈FIRST(X)。
(c)若X∈VN,X→ε,则ε∈FIRST(X)。
(d)若X∈VN,Y1,Y2,…,Yi都∈VN,而有产生式X→Y1Y2…Yn。当Y1,Y2,…,Yi-1都 ε时,(其中1≤i≤n),则FIRST(Y1)-{ε},FIRST(Y2)-{ε},…,FIRST(Yi-1)-{ε},FIRST(Yi)都包含在FIRST(X)中。
二、存在问题及解决办法
(一)左递归问题
自顶向下分析法只有规则排列得合适时,才能正确工作。该法的一个基本缺点是不能处理具有左递归的文法。如下所示。
如:直接左递归和间接左递归
无法确定语法树的终止,
清除直接左递归的较好方法是改
为右递归
如:S→Sa|b改为
S→bS′
S′→aS′|ε
一般情况下,直接左递归的形式可为:
为了自上而下地构造w的语法树,我们首先按文法的识别符号产生根结点S,并让指示器IP指
向输入串的第一符号c。然后,用S的规则(此处左部为S的规则仅有一条)把这棵树发展为
(a)
(b)(c)
图3-1-1
图3-1-1a。我们希望用S的子结从左至右匹配整个输入串w。首先,此树的最左子结是终结符c为标志的子结,它和输入串的第一个符号相匹配。于是,我们就把IP调整为指向下一输入符号a,并让第二个子结A去进行匹配,非终结符A有二个选择,我们试着用它的第一个选择去匹配输入串,于是把语法树发展为图3-1-1b。子树A的最左子结和IP所指的符号相符,然后我们再把IP调为指向下一符号d并让A的第二个子结进入工作。但A的第二个子结为终结符号b,与IP当前指的符号d不一致。因此,A宣告失败。这意味着A的第一个选择此刻不适用于构造w的语法树。这时,我们应该回头(回溯)看A是否还有别的选择。
为什么针对某些非终结符号所编出的分析程序要编成递归子程序?因为文法具有递归性。前面已讲过,自顶向下分析不能处理左递归文法,若有左递归,则应改写文法予以消除。但是,消除了左递归不等于消除了文法的所有递归性质,此时,文法仍可以有右递归性或自嵌入性。如在文法中有规则
U→…U
或U→…U…
此仍为递归规则,故分析U的子程序要编成递归子程序。因为该子程序在用规则右部符号串去匹配输入串的过程中,又要调用U自己。即在通过该子程序正常出口返回调用程序以前,又要重新直接进入该子程序,这就是直接递归。此外,还有间接递归,如在文法中有规则:
为了避免回溯,就必须保证:对文法的任何非终结符号特别是规则右部有多个选择的非终结符号,当用它去匹配输入串时,应是确定无疑的。即:
U→α1|α2|…|αn
该规则右部有n个选择,为了实现目的,我们对文法的要求是:
FIRST(αi)∩FIRST(αj)=ф(i≠j)
定义1:设G=(VT,VN,S,P)是上下文无关文法FIRST(α)={a|αaβ,a∈VT,α,β∈V*}
A→Aα1|Aα2|…Aαm|β1|β2…βn
清除左递归后改写为:
A→β1A′|β2A′…|βnA′
A′→α1A′|α2A′…|αmA′|ε
对于间接左递归的消除,需先将间接左递归变为直接左递归,然后再接上述方法消除。
条件是文法中无A→ A的有害规则和
A→ε的空产生式
(二)回溯问题
当产生式有多个选择时,选那个输入串去匹配
(e)当(d)中所有Yi ε,(i=1,2,…n)
则FIRST(X)=FIRST(Y1)∪FIRST(Y2)∪…∪FIRST(Yn)∪{ε}。
反复使用上述(b)~(e)步直到每个符号的FIRST集合不再增大为止。
i
+
*
(
)
#
E
E→TE'
E→TE'
E'
E'→+TE'
E'→ε
E'→ε
T
T→FT'
T→FT'
T'
T'→ε
T'→*FT'
T'→ε
T'→ε
F
F→i
F→(E)
图4-2-2
(二)LL(1)分析表的构造方法上述LL(1)分析算法对于不同的LL(1)文法都是相同的。也就是说,对不同的LL(1)分析器而言,它们的总控程序都是相同的,不同的仅仅是分析表。再者总控程序十分简单,非常容易实现,所以我们只着重讨论构造分析表的问题。为了构造分析表,我们需要预先定义和构造两个与文法有关的集合FIRST和FOLLOW。
提因子
U→xv|xw U→x(v|w)
三、递归子程序法
此方法的主要做法是:对文法中每个非终结符号U,都编出一个子程序,以完成该非终结符号所对应的语法成分的分析和识别任务。某个非终结符号的语法分析子程序的功能是:用该非终结符号的规则的右部符号串去匹配输入串。分析过程是按文法规则自顶向下一级一级地分配任务,即调用有关的子程序来完成。当编译程序根据文法和当前输入符号预测到下一个语法成分为U时,即预测到待匹配的输入符号串可以为从U出发所推导出的符号串相匹配时,就确定U为目标,并调用分析和识别U的子程序。在分析和识别U的过程中,有可能还要确立其他子目标并调用相应的子程序,只有在被调用的分析和识别某语法成分的子程序匹配输入串成功并正确返回时,该语法成分才算真正的获得了识别,并确定输入串无语法错误。。
1、若Xm∈VN,则以Xm及ai组成符号对(Xm, ai)查分析表M,设M[Xm, ai]为一产生式,譬如说Xm→UVW,此时将Xm从分析栈中退出,并将UVW按反序推入栈中(即用该产生式推导一步),从而得到新的格局
但若M[Xm, ai]=“ERROR”,则调用出错处理程序进行处理;
2、若Xm=ai≠#,则表明栈顶符号已与当前正扫视的输入符号得到匹配,此时应将Xm(即ai)从栈中退出,并将输入符号指示器向前推进一个位置;
在S的第二子结A完成匹配后,接着就轮到第三个子结d进行工作。由于这个子结和最后一个输入符号相符,于是,我们完成了构造语法树的任务,证明了w是文法G[ s]的一个句子。
上述自顶向下地为输入符号w建立语法树的过程,实际上也是设法建立一个最左推导序列,以便通过一步步推导将输入串推导出来。很明显,对于输入串w可以通过如下的推导过程将其推导出来: S CAd cad
第四章自顶向下语法分析方法
语法分析是编译过程的核心部分。语法分析的任务是:按照文法,从源程序符号串中识别出各类语法成份,同时进行语法检查,为语义分析和代码生成作准备。执行语法分析任务的程序称为分析程序。也称为语法分析器,它是编译程序的主要子程序之一。
在第二章中我们已经介绍过。通过语法分析可建立起相应的语法树。按语法树的建立方法,我们将语法分析方法分成两大类,即自顶向下分析和自底向上分析。下面,我们先介绍自顶向下分析。
第一步分析开始时,首先将符号#及文法的开始符号S依次置于分析栈底部,并把各指示器调整至起始位置,即初始格局为
然后,反复执行第二步所列的工作。
第二步设在分析的某一步,分析栈及余留的输入符号串处于如下的格局
其中,X1,X2,…Xm为分析过程中所得的文法符号,此时,可视栈顶符号Xm的不同情况,分别做如下的动作:
若αε,则规定α∈FIRST(α)
即对文法中的任意一个非终符号,其规则右部有多个选择时,那么,由各个选择所推出的终结符号串的头符号集合要两两不相交。这样,就可能根据当时读进的符号是属于哪个选择的FIRST(α),来唯一地确定应该选用哪个选择来匹配输入串。如当前的输入符号为b(b∈VT),
若b∈FIRST(αi),则用第i个选择;
假定α是文法G的任一符号串,或者说α∈(VTUTN)*,我们定义:
FIRST(α)={a|α aβ, a∈VT}
特别是,若α ε,则规定ε∈FIRST(α),换句话说,FIRST(α)是从α可能推导出的所有开头终结符号或可能的ε。
假定S是文法的开始符号,对于G的任何非终结符A,我们定义:
FOLLOW(A)={a|S …Aa…,a∈VT}
为了实现回溯,我们一方面应把A的第一个选择所生长的子树注销掉;另一方面,应把IP恢复为进入A时的原值,也就是让它重新指向第二输入符号a。现在我们试探用A的第二个选择,即考虑生成图3-1-1c的语法树。
由于子树A只有一个子结a,而且,它和IP所指的符号相一致,于是,A完成了匹配任务。在A获得匹配后,指示器指向下一个未被触及的符号d。
所以用最左推导,是因为我们对输入串是自左向右扫描的,只有使用最左推导,才能保证按扫描顺序去匹配输入串。在上述推出符号串w的过程中,由于出现在符号串中的非终结符号只有一个,因此,未明显地表现出最左推导的性质。
根据以上分析,不难编出程序来实现这种分析的算法。但是,上述这种自顶向下的分析算法存在着一定的困难和缺点。困难表现在不能为左递归文法构造自顶向下的语法分析器(上述所举例子的文法G[s]是不具有在递归性的)。缺点主要表现在存在着回溯问题。当然,应用带回溯的自顶向下的分析算法还必须将文法规则存放于内存。下面将具体介绍这种分析算法所存在的问题及其解决办法。
特别是,若S …A,则规定#∈FOLLOW(A)。换句话说,FOLLOW(A)是所有句型中出现在紧接A之后的终结符或#。下面,我们将首先给出构造集合FIRST及FOLLOW的算法,然后再给出构造分析表的算法。
1、计算F1RST集
根据定义计算