编译原理 第4章课件.docx

上传人:b****4 文档编号:5428177 上传时间:2022-12-16 格式:DOCX 页数:21 大小:155.66KB
下载 相关 举报
编译原理 第4章课件.docx_第1页
第1页 / 共21页
编译原理 第4章课件.docx_第2页
第2页 / 共21页
编译原理 第4章课件.docx_第3页
第3页 / 共21页
编译原理 第4章课件.docx_第4页
第4页 / 共21页
编译原理 第4章课件.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

编译原理 第4章课件.docx

《编译原理 第4章课件.docx》由会员分享,可在线阅读,更多相关《编译原理 第4章课件.docx(21页珍藏版)》请在冰豆网上搜索。

编译原理 第4章课件.docx

编译原理第4章课件

第四章自顶向下语法分析方法

教学要求

重点:

  ①LL

(1)文法的定义和判别

  ②非LL

(1)文法的等价变换

  ③预测分析方法

难点:

  对一个文法如何判断是否是LL

(1)文法,由于在判断LL

(1)文法时用到文

法符号串的开始符号集合(FIRST集)和非终结符后跟符号集合(FOLLOW

集)的计算,而一般学员往往因概念不清或不够细心对这两个集合的计算常

常出错,导致判断和分析结果的错误。

目录:

4.1确定的自顶向下分析思想

4.2LL

(1)文法的判别

4.3非LL

(1)文法的改造

4.4不确定的自顶向下分析思想

4.5确定的自顶向下分析方法

语法分析方法分类

自顶向下分析方法确定的自顶向下分析方法递归子程序法

预测分析方法

不确定的自顶向下

分析方法带回溯的分析方法

自底向上分析方法算符优先分析

LR类分析

4.1确定的自顶向下分析思想

确定的自顶向下分析方法,首先要解决从文法的开始符号出发,如何根据当前的输入符号唯一地确定选用哪个产生式替换相应非终结符往下推导,或构造一颗相应的语法树。

例4.1 若有文法G1[S]:

  S→pA|qB

  A→cAd|a

  B→dB|c

 识别输入串w=

pccadd是否是G1[S]的句子

试探推导过程:

  

SpApcAdpccAddpccadd

试探成功。

例4.1这个文法有以下两个特点:

  ①每个产生式的右部都由终结符号开始。

  ②如果两个产生式有相同的左部,那么它们的右部由不同的终结符开始。

  对于这样的文法显然在推导过程中完全可以根据当前的输入符号决定选择哪个产生式往下推导,因此分析过程是唯一确定的。

例4.2若有文法G2[S]:

  S→Ap|Bq

  A→a|cA

  B→b|dB

 识别输入串w=ccap是否是G2[S]的句子,那么试探推出输入串的推导过程为:

SApcApccApccap

试探推导成功。

例4.2文法的特点是:

  ①产生式的右部不

全是由终结符开始。

  ②如果两个产生式

有相同的左部,它们的右部是由不同的终结符或非终结符开始。

 ③文法中无空产生式。

  对于产生式中相同左部含有非终结符开始的产生式时,在推导过程中选用哪个产生式不像例4.1文法那样直观,对于W=ccap为输入串时,其第一个符号是c,这时从S出发选择S→Ap还是选择S→Bq,需要知道,Ap或Bq它们的开始符号集合是什么,若c是包含在Ap的开始符号集合中,且不包含在Bq的开始符号集合中,则选择S→Ap往下进行推导。

同样若c是包含在Bq的开始符号集合中,且不包含在Ap的开始符号集合中,则选择S→Bq往下推导,其它情况则为不确定推导或出错。

例4.3若有文法G3[S]:

  S→aA|d

  A→bAS|ε

  识别输入串w=abd是

否是G3[S]的句子

  试探推导出abd的推

导过程为:

SaAabASabSabd

试探推导成功。

例4.3文法的特点是:

 文法中含有空产生式。

  由此可以看出,当某一非终结符的产生式中含有空产生式时,它的非空产生式右部的首符号集两两不相交,并与在推导过程中紧跟该非终结符后边可能出现的终结符集也不相交,则仍可构造确定的自顶向下分析。

 

当我们需选用确定的自顶向下分析方法时,首先必须判别所给的文法能否是LL

(1)文法。

先研究三个定义:

开始符号FIRST、后跟符号FOLLOW和选择集合SELECT集定义和计算

例1:

S→aAA→ε

S→dA→bAS

FIRST(S)=

FIRST(A)=

开始符号FIRST集的定义:

设G=(VN,VT,P,S)是上下文无关文法

FIRST()={a|=>a,a∈VT,,∈V*}

若=>ε则规定ε∈FRIST()

例2:

S→AaA→ε

S→dA→bAS

FIRST(S)={b,a,d}

FIRST(A)={ε,b}

FIRST(S)=

FIRST(A)=

例:

S→aAA→ε

S→dA→bAS

FOLLOW(A)=

后跟符号FOLLOW集的定义:

FOLLOW(A)={aS=>A且

a∈FRIST(),∈V*,∈V+}

若S=>A,且=>ε,则#∈FOLLOW(A)

选择集合SELECT:

给定上下文无关文法的产生式A→α

A∈VN,α∈V*,若=>ε,则:

SELECT(A→α)=FIRST(α)

如果=>ε,则:

SELECT(A→α)=FIRST(α)-{ε}∪FOLLOW(A)

例:

S→aAS→dA→εA→bAS

SELECT(S→aA)=

SELECT(S→d)=

SELECT(A→ε)=

SELECT(A→bAS)=

FIRST(aA)={a}

FIRST(d)={d}

FOLLOW(A)={a,d,#}

{b}

 

LL

(1)文法:

一个上下文无关文法是LL

(1)文法的充分必要条件是,对每个非终结符A的两个不同产生式,A→α或A→满足:

SELECT(A→α)∩SELECT(A→)=其中,α、不能同时=>ε

LL

(1)文法的含义:

第一个L:

表明自顶向下分析是从左到右扫描输入串;

第二个L:

表明分析过程中将用最左推导;

1:

表明只需向右看一个字符便可决定如何推导即选择哪个产生式。

例:

文法G[S]:

S→aASA→ε

S→bA→bA是否为LL

(1)文法?

 

SELECT(S→aAS)={a}

SELECT(S→b)={b}

SELECT(A→bA)={b}

SELECT(A→ε)=First(ε)-{ε}∪FOLLOW(A)={a,b}

 

不难看出:

SELECT(S→aA)∩SELECT(S→b)=

SELECT(A→bA)∩SELECT(A→ε)=

 

由定义该文法不是LL

(1)文法,不可用确定的自顶向下分析。

例如:

w=ab

S=>aAS=>abAS=>abS(失败)

S=>aAS=>aS=>ab(成功)

 

4.2LL

(1)文法的判别

判别文法是否是LL

(1)文法,对任何文法计算需计算FIRST、FOLLOW和SELECT集合,进而判别文法是否为LL

(1)文法。

举例说明判断LL

(1)文法的步骤。

例:

若文法G[E]为:

(1)E–>TE’

(2)E’–>+TE’

(3)E’–>

(4)T–>FT’

(5)T’–>*FT’

(6)T’–>

(7)F–>(E)

(8)F–>a

判别步骤:

1.求出能推出的非终结符

计算步骤如下:

1)将数组X[]中对应每一非终结符的标志初值置为“未定”

2)扫描文法中的产生式.

(a)删除所有右部含有终结符的产生式,若这使得以某一非终结符为左部的所有产生式都被删除,则数组中对应该非终结符的标记值改为“否”.

(b)若某一非终结符的某一产生式的右部为,则则数组中对应该非终结符的标记值置为“是”,并从文法中删去该非终结符的所有产生式.

3)扫描产生式右部的每一个符号.

(a)若某非终结符在数组中的标志是“是”,则删去该非终结符,若这使得产生式右部为空,则对左部非终结符在数组中标志该为“是”,并删除该非终结符对应的所有产生式.

(b)若某非终结符在数组中的标志是“否”,则删去该产生式,若这使得产生式左部非终结符的有关产生式都被删除,则数组中对应该非终结符的标记值改为“否”.

4)重复3),直到扫描完一遍文法的产生式,数组中非终结符对应的特征再不改变为止

.

非终结符能否推出空的

 

非终结符

E

E’

T

T’

F

初值

第一次扫描

第二次扫描

未定

未定

2.计算FIRST集

各非终结符的FIRST集合如下:

{(,i}

{+,ε}

{(,i}

{*,ε}

{(,i}

 

3.计算FOLLOW集

1)对于文法的开始符号S,置#于FOLLOW(S)中;

2)若AαBβ是一个产生式,则把FIRST(β)的非空{}加至FOLLOW(B)中;

3).若AαB是一个产生式,或AαBβ是一个产生式而β=>(即FIRST(β)),则把FOLLOW(A)加至FOLLOW(B)中.

4)反复使用2)和3)直到每个非终结符的FOLLOW集不再增大为止。

各非终结符的FOLLOW集合为:

 

各非终结符的FOLLOW集合为:

FOLLOW(E)={),#}

FOLLOW(E′)=FOLLOW(E)

FOLLOW(T)={+}+FOLLOW(E)

FOLLOW(T′)=FOLLOW(T)

FOLLOW(F)={*}+FOLLOW(T)

 

4.产生式选择集合计算

SELELECT(E–>TE’)={(,a}

SELECT(E’–>+TE’)={+}

SELECT(E′–>)=FOLLOW(E′)={),#}

SELECT(T’–>)=FOLLOW(T’)={),#+}

SELECT(T’–>*FT’)={*}

SELECT(F–>(E))={(}

SELECT(F–>a)={a}

SELECT(E’–>+TE’)∩SELECT(E′–>)=

SELECT(T’–>*FT’)∩SELECT(T’–>)=

SELECT(F–>(E))∩SELECT(F–>a)=

以上相同左部的产生式的SELECT集交集为,所以G[E]是LL

(1)文法。

 

 

4.3某些非LL

(1)文法到LL

(1)文法的等价变换

有时,我们通过提取左公共因子和消除左递归等对文法进行等价变换,可以使得非LL

(1)变成LL

(1)文法。

LL

(1)文法的性质:

LL

(1)文法不含左公共因子

LL

(1)文法不含左递归

 

一、提左公因子

将产生式Aβ|变换为:

ABBβ|

提左因子S→ifCtSA

A→eS|C→b

例:

S→ifCtS|ifCtSeS

C→b

注:

1)可通过反复提取左因子,一般能把所有非终结符的所有候选首符集变为两两不相交。

2)反复提取左因子也有一定代价,因为在提取过程中会大量引入非终结符和产生式,会增加语法分析的复杂性。

3)提取左公共因子变换后,有时会使某些产生式变成无用产生式,此时必须对文法重新化简。

提取公共左因子一般形式为:

将某产生式A1|2|….|n

改写为AA`

A`1|2|….|n

 

说明:

1、文法中不含左公共因子只是LL

(1)文法的必要条件。

G1[S]

S->aSA

A->b

A->

S->

例如:

G[S]:

S->aSb变换后:

S->aS

S->

SELECT(S->aSA)={a}

SELECT(S->)=FOLLOW(S)={#,b}

SELECT(A->b)={b}

SELECT(A->)=FOLLOW(S)={#,b}

是否为LL

2、某些文法不能在有限步骤内提取完左公共因子。

(1)S->aApp|aBqq

(2)S->dp|eq

(3)A->aAp|d

(4)B->aBq|e

(1)提取左公共因子后变成:

 

(1)S->aS’(5)S’’->Appp|Bqqq

(2)S->dp|eq(6)A->aAp|d

(3)S->aS’’(7)B->aBq|e

(4)S’->dpp|eqq

(1)S->aS’

(2)S->dp|eq

(3)S’->App|Bqq

(4)A->aAp|d

(5)B->aBq|e

用(4)(5)替换(3)后提取左公共因子后变成,变为:

 

3、一个文法提取了左公共因子后,只解决了相同左部产生式右部的FIRST集不相交问题,当改后的文法不含空产生式,且无左递归时,则改写后的文法是LL

(1)文法,否则还需要用判别方式进行判别才能确定。

二、消除左递归

1)什么是左递归左递归:

文法存在产生式PPa直接左递归:

PPa

间接左递归:

PAa,APb

2)消除左递归消除直接左递归消除间接左递归消除所有左递归

1、消除直接左递归

设有文法G=(VN,VT,P,S),其中产生式P为

PP|,V+,V+且不以P开头

将它转换为等价式:

PP’P’P’|

一般地:

将PP1|P2|….|Pm|1|2|….|n

转换为:

P1P`|2p`|……|nP`P`1P`|2P`|……|mP`|

E–>TE’

E’–>+TE’|

T–>FT’

T’–>*FT’|

F→i|(E)

 

2、消除间接左递归

对于间接左递归的消除先将间接左递归变为直接左递归,再按消除直接左递归消除.例:

(1)A–>Bb

(2)B–>Ac

(3)B–>d

先将

(1)代入

(2):

B–>Bbc再消除左递归

B–>dB’

B’–>bcB’|

3、消除文法中一切左递归

要求:

文法中不含回路A+=>A的推导

1)把文法G的所有非终结符按任意顺序排列成P1,P2,…,Pn,然后按此顺序执行步骤2。

2)For(I=1,I<=n,I++)

{for(k=1,k<=I-1,k++)

{把形如PiPk的规则改写为

Pi1|2|……|,n,其中Pk1|2|……|,n}

消除Pi规则的直接左递归;}

3)删去从文法开始符号不可达的非终结符产生式。

注:

1)此算法适用于消除不含形如PP的产生式,也不含以为右部的产生式的文法

2)这里第二步所做的工作是:

a)若产生式出现直接左递归则用消除直接左递归的方法消除掉。

b)若产生式右部最左符号是非终结符且其序号大于左部的非终结符,则不处理。

c)若序号小于左部的非终结符,则将这序号小的非终结符用其右部串来取代,然后消除新的直接左递归。

 

 

解:

1)对非终结符重新排序:

R、Q、S

2)对R:

S的序号大于R的序号,不处理。

对Q:

R的序号1小于Q的序号2,所以改写

QRb|b,将RSa|a的右部取代R,得到:

QSab|ab|b,记为:

(2`)式;此时,S的序号大于Q的序号,不再处理。

对S:

Q的序号2小于S的序号3,所以改写

SQc|c,将QSab|ab|b的右部取代Q,得到

SSabc|abc|bc|c;出现直接左递归,变换为:

S(abc|bc|c)S`

S`abcS`|

3)由于RSa|a和QSab|ab|b中的R,Q对开始符号S来说都是不可达非终结符,所有删除它们。

故最后消除左递归后文法为:

S(abc|bc|c)S`

S`abcS`|

注:

1)若非终结符排列顺序不同,改写后的文法也不同,但它们是等价的。

2)开始符号不能改变。

 

4.4不确定的自上而下分析

引起回溯的原因

由于相同左部的产生式的右部FIRST集交集不为空而引起回溯

由于相同左部非终结符的右部都能,且该非终结符的FOLLOW集中含有其

右部FIRST集元素

由于文法含有左递归而引起回溯

S–>AB

A–>aA|

B–>b|bB

aaabb.

S

(1)A...S–>AB

(2)aA...A–>aA

(3)aaA...A–>aA

(4)aaaA...A–>aA(5)aaaB...A–>

(6)aaabB–>b

aaabb.

S

(1)A...S–>AB

(2)aA...A–>aA

(3)aaA...A–>aA

(4)aaaA...A–>aA

(5)aaaBA–>

(6’)aaabBB–>bB

(7)aaabbB–>b

 

4.5确定的自顶向下分析方法

特征——根据下一个输入符号为当前要处理的非终结符选择产生式

1递归子程序法

2预测分析方法

1递归子程序法

•特点:

–简单直观易于构造

–要求文法满足LL

(1)文法

•实现思想:

–对应文法中每个非终结符编写一个递归过程,每个过程的功能是识别由该非终结符推出的串,当某非终结符的产生式有多个候选时能够按LL

(1)形式可以唯一地确定选择某个候选进行推导。

•缺点:

–对文法要求高

–递归调用多,速度慢,占用空间多

递归子程序实例:

表达式的语法分析

表达式的EBNF

〈表达式〉∷=[+|-]〈项〉{(+|-)〈项〉}

〈项〉∷=〈因子〉{(*|/)〈因子〉}

〈因子〉∷=ident|number|‘(’〈表达式〉‘)’

〈表达式〉∷=[+|-]〈项〉{(+|-)〈项〉}

 

procedureexpr;

begin

ifsymin[plus,minus]then

begin

getsym;//词法分析,读取一个单词

term;//项处理

end

elseterm;

whilesymin[plus,minus]do

begin

getsym;

term;

end

end;

〈项〉∷=〈因子〉{(*|/)〈因子〉}

Procedureterm;

begin

factor;//因子处理

whilesymin[times,slash]do

begin

getsym;

factor

end

end;

〈因子〉∷=ident|number|‘(’〈表达式〉‘)’

Procedurefactor;

beginifsym=ident

thengetsym

else

ifsym=number

thengetsym

else

ifsym=‘(‘

thenbegin

getsym;

expr;

ifsym=‘)’

thengetsym

elseerror

end

elseerror

end;

2预测分析方法

一个预测分析器由三个部分组成:

预测分析程序

先进后出栈

预测分析器表

其中只有预测分析器表与文法有关

预测分析表可用一个矩阵M(或称二维数组)表示。

矩阵元素M[A,a]中的下标A表示非终结符,a为终结符或句子括号“#”,矩阵元素M[A,a]中的内容为存放着一条关于A的产生式,表明当用非终结符A向下推导时,面临输入符号a时,应采取的候选产生式,若无产生式,元素内容转向出错处理的信息。

 

预测分析程序的工作过程

图中符号说明如下:

"#"句子括号即输入串的括号

"S"文法的开始符号

"X"存放当前栈顶符号的工作单元

"a"存放当前输入符号a的工作单元

BEGIN

首先把’#‘然后把文法开始符号推入栈;把第一个输入符号读进a;FLAG:

=TRUE;

WHILEFLAGDO

BEGIN

把栈顶符号上托出去并放在X中;

IFXVtTHENIFX=aTHEN

把下一个输入符号读进aELSEERROR

 ELSEIFX=‘#’THEN

IFX=aTHENFLAG:

=FALSEELSEERROR

ELSEIF[X,a]={X–>X1X2..XK}

THEN把XK,XK-1,..,X1一一推进栈ELSE ERROR

ENDOFWHILE;

STOP/*分析成功,过程完毕*/

END

分析算法

 

 预测分析表构造算法

1.对文法G的每个产生式A,每个终结符或“#”用a表示;

若aSELECT(A),把A加至[A,a]中,

2.把所有无定义的[A,a]标上“出错标志”。

为了使表简化,其产生式左部可以不写入表中,表中空白处为出错。

可以证明,一个文法G的予测分析表不含多重入口,当且仅当该文法是LL

(1)的

例:

G[E]:

E–>E+T|T

T–>T*F|F

F–>a|(E)

解:

(1)判断文法是否为LL

(1)文法

由于文法中含有左递归,所与必须先消除左递归,使文法变为:

G[E]:

(1)E–>TE’

(2)E’–>+TE’

(3)E’–>

(4)T–>FT’

(5)T’–>*FT’

(6)T’–>

(7)F–>(E)

(8)F–>a

1.可推出的非终结符表为:

E

E`

T

T`

F

2.各非终结符的FIRST集合如下:

FIRST(E)={(,a}

FIRST(E`)={+,}

FIRST(T)={(,a}

FIRST(T`)={*,}

FIRST(F)={(,a}

3.各非终结符的集合如下:

FOLLOW(E)={(,#}

FOLLOW(E`)={),#}

FOLLOW(T)={+,),#}

FOLLOW(T`)={+,),#}

FOLLOW(F)={*,+,),#}

SELECT(E–>TE’)={(,a}SELECT(E’–>+TE’)={+}

SELECT(E’–>)={),#}SELECT(T–>FT’)={(,a}

SELECT(T’–>*FT’)={*}SELECT(T’–>)={+,),#}

SELECT(F–>(E))={(}SELECT(F–>a)={a}

a

+

*

#

E

→TE’

→TE’

E’

→+TE’

–>

–>

T

–>FT’

–>FT’

T’

–>

–>*FT

–>

–>

F

–>a

–>(E)

分析输入串#a+a#

栈内容栈顶符号当前输入余留串M[X,b]

1#EEa+a#E–>TE’

2#E’TTa+a#T–>FT’

3#E’T’FFa+a#F–>a

4#E’T’aaa+a#

5#E’T’T’+a#T’–>

6#E’E’+a#E’–>+TE

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1