【编译原理】自顶向下语法分析方法的实现

合集下载

编译原理-四章自顶向下语法分析法

编译原理-四章自顶向下语法分析法

第四章自顶向下语法分析方法语法分析是编译过程的核心部分。

语法分析的任务是:按照文法,从源程序符号串中识别出各类语法成份,同时进行语法检查,为语义分析和代码生成作准备。

执行语法分析任务的程序称为分析程序。

也称为语法分析器,它是编译程序的主要子程序之一。

在第二章中我们已经介绍过。

通过语法分析可建立起相应的语法树。

按语法树的建立方法,我们将语法分析方法分成两大类,即自顶向下分析和自底向上分析。

下面,我们先介绍自顶向下分析。

本章重点:自顶向下分析、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-(三)

自顶向下的语法分析-编译原理-04-(三)
给定文法S→cAd
A→ab|a
S
?句子cad是该文法定义语言的句子
S c a A b d c
A a
d
候选式的确定与回溯(Backtracking)

当要进行某个语法变量的推导时,希望能 够根据当前符号确定候选式。如果有几个 候选式(右部)左端第一个符号相同,则 分析程序无法根据当前输入符号选择产生 式,只能试探 希望:寻找一类文法,我们可以方便地根 据当前输入符合确定正确的候选式
三、重要问题——虚假匹配
S xAy
x*y 输入串x**y S→xAy A→**|* S xAy x**y
匹配成功 发现不匹配,需 要回退
S x A
*
y
S x
*
A
*
y
三、重要问题——回溯
x * * y
xAy x*y
发现不匹配,需要回退
S
S x A
*
y
x * * y
S xAy x**y
A′→αA′|ε
例:表达式文法直接左递归的消除
E → E + T|T T → T * F|F F → ( E )|id E→ T E’ E’→ + T E’|ε T→ F T’ T’→* F T’|ε F→ ( E )|id
例: 间接左递归的消除
S→Ac|c
A→Bb|b B→Sa|a 将B的定义代入A产生式得:A→Sab|ab|b 将A的定义代入S产生式得: S→Sabc|abc|bc|c 消除直接左递归: S→abcS’|bcS’|cS’ S’→abcS’|ε 删除“多余的”产生式:A→Sab|ab|b和B→Sa|a 结果: S→abcS’|bcS’|cS’ S’→abcS’|ε

编译原理第6节课第二章

编译原理第6节课第二章
n n m m n m m n
为一先天二义性语言。 为一先天二义性语言。 • CFL的先天二义性也是不可判定的。 的先天二义性也是不可判定的。 的先天二义性也是不可判定的
2.3.3 短语和句柄
• 问题:在自底向上 问题: 的语法分析中, 的语法分析中,对 于每一步直接归约, 于每一步直接归约, 应如何正确地确定 当前句型中应被归 约的最左子串 约的最左子串? 最左子串 F i E T + T F i T * F i E
E(2) + T(2)
• 但是 对一句型而言,其直接短语可能不唯一。 但是,对一句型而言,其直接短语可能不唯一。 对一句型而言 为了让分析能够机械地进行,我们只考虑最左 为了让分析能够机械地进行,我们只考虑最左 归约。 归约。 E E T F i + T F i T * F i E + T F i
* +
归约时被替换子串的选择
• 从句型 η=E+T*F+i 的语法树可知 E+T 绝不是 的语法树可知, 它的一个直接短语 因为虽然 它的一个直接短语,因为虽然 E→E+T 是 G2[E] 直接短语 的一个产生式,但不存在从 的推导。 的一个产生式 但不存在从 E 到 E*F+i 的推导。 E E(1) E(2) + T(3) T(2) * F(3) + T(1) F(1) i
E + T F T * F i
i • 对一语法树而言,其构造过程不同对应了不 对一语法树而言, 同的推导(归约)过程。 同的推导(归约)过程。 推导
文法的二义性
• 存在这样的文法 ,其某个句子 w ∈ L(G) , 存在这样的文法G, 可对应结构不同的语法树, 可对应结构不同的语法树,即 w 对应了多个 不同的最左(右)推导,这类文法称为二义 不同的最左* +

编译原理-自顶向下的语法分析

编译原理-自顶向下的语法分析

编译原理-⾃顶向下的语法分析1.代替部分由公因⼦就会出现回溯。

2.LL(1)⽂法(1)FIREST集这样说从⽂法的左部找右部相关的⾮终结符号。

若 X->BC..D,则将First(B)所有元素(除了ε)加⼊First(A),然后检测First(B),若First(B)中不存在ε,则停⽌,若存在则向B的后⾯查看,将First(C)中所有元素(除了ε)加⼊First(A),然后再检测First(C)中是否有ε...直到最后,若D之前的所有⾮终结符的First集中都含有ε,则检测到D时,将First(D)也加⼊First(A),若First(D)中含有ε,则将ε加⼊First(A)。

(2)FOLLOW集:记住是从⽂法的右部去找的。

 1)S是开始符号,将#放到follow(S)中. 2)存在A→αBβ(且β!=ε),那么first(β)中除ε之外的所有符号都在follow(B)中。

3)存在A→αB或A→αBβ(且first(β)包含ε),那么follow(A)中的所有符号都在follow(B)中。

(注意都没有说α⼀定存在。

)(3)SELECT集对于产⽣式A—>α。

集合select(A—>α)定义如下:1. 若α不能推出ε,则select(A—>α) = first(α)。

2. 若α能推出ε,则select(A—>α)= first(α)∪ follow(A)。

(4)如何判断⼀个⽂法是不是LL(1)⽂法:第⼀消除左递归,先消除去直接左递归,然后看是否有相同最左公因⼦的,提取出来。

第⼆分别求出每个推导的SELECT集,同⼀左部的求SELECT集的交集,所有的这种交集为空的话就是LL(1)⽂法,否则不是。

3.递归下降分析法:只针对LL(1)⽂法的,所以没有左递归。

简单的来说就是为每个⾮终结符号编写⼀个处理程序,⽽处理程序的代码结构是由相应的⾮终结符号的规则右部所决定。

p68.4.预测分析表的构造:p74。

编译原理语法分析-自顶向下

编译原理语法分析-自顶向下

实例分析
1
子规则匹配
根据语法规则,递归地匹配输入的源代码,构建语法树。
2
构建语法树
通过逐步匹配子规则,将语法树逐渐构建起来,形象地表示复杂的程序结构。
3
解释分析结果
对语法树进行解释,执行语义分析和生成中间分析方法,通过递归嵌套和预测分析,将复杂的源代码转换成易于处理的 语法树。
自顶向下分析算法
1 概述
自顶向下分析算法从目标语言的最高级别规则开始,逐步向下查找并匹配规则,构建语 法树。
2 递归下降分析
递归下降分析是自顶向下分析的一种常见方法,它通过递归调用子规则来分析输入的源 代码。
3 LL(1)分析
LL(1)分析是一种基于预测的自顶向下分析方法,它使用一个预测分析表来确定下一步要 采取的动作。
编译原理语法分析-自顶 向下
语法分析是编译器的重要组成部分,它负责将输入的源代码转换成语法树以 进行后续分析和解释。本节将介绍自顶向下的语法分析算法及其挑战。
语法分析概述
1 什么是语法分析
语法分析是编译器的第二个阶段,负责验证 输入的源代码是否符合语言的规范语法。
2 为什么需要语法分析
语法分析可以检查和纠正源代码中的语法错 误,以确保程序的正确性和可读性。
问题和挑战
1 二义性文法
当文法存在多个解释时,会导致语法分析的 困扰和歧义。需要通过合适的方法解决二义 性。
2 左递归文法
左递归文法会导致递归下降分析算法进入无 限循环,需要通过消除左递归来解决。
改进方法
1 消除二义性文法
通过重写或修改文法规则,消除存在二义性 的产生式。
2 消除左递归文法
通过改写产生式,消除文法中的左递归问题, 使得递归下降分析算法不会陷入无限循环。

软件工程 编译原理 第五章 自顶向下的语法分析方法

软件工程 编译原理 第五章 自顶向下的语法分析方法

P→1P | 2P |… | mP |
(2)消除间接左递归
对于间接左递归的消除需先将间接左递归变为直接左 递归,然后再按a)消除直接左递归。
例:文法G为例: (1) A→aB (2) A→Bb (3) B→Ac (4) B→d 用产生式(1)、(2)的右部 代替产生式(3)中的非终 结符A得到左部为B的产 生式为: (1) B→aBc (2) BG的产生式为: (1) S→aSb (2) S→aS (3) S→ε 请提取文法中的左公因子
对产生式(1)、(2)提取左公因子后得: S→ aS(b|ε) S→ε 进一步变换为文法G′: S→aSA A→b A→ε S→ε
例2:若文法G的产生式为: (1) A→ad (2) A→Bc (3) B→aA (4) B→bB 请提取文法中的隐式左公因子。 对文法G2分别用(3)、(4)的右 部替换(2)中的B,可得: 提取产生式(1)、(2)的左 (1) A→ad 公共因子得: (2) A→aAc A→a(d|Ac) (3) A→bBc A→bBc (4) B→aA B→aA (5) B→bB B→bB
由上面所举例子可以说明以下问题:
① 不一定每个文法的左公共因子都能在有限的步骤内 替换成无左公共因子的文法,上面文法G4就是如此。 ② 一个文法提取了左公共因子后,只解决了相同左部 产生式右部的FIRST集不相交问题,当改写后的文法 不含空产生式,且无左递归时,则改写后的文法是 LL(1)文法,否则还需用LL(1)文法的判别方式进行判 断才能确定是否为LL(1)文法。
例:文法G(E):
E→TE E→+TE | T→FT T→*FT | F→(E) | i
每个非终结符有对应的子程序的定义, 首先在分析过程中,当需要从某个非终 结符出发进行展开(推导)时,就调用这 个非终结符对应的子程序。

第5部分自顶向下语法分析方法-

第5部分自顶向下语法分析方法-
2. 如果两个产生式有相同的 左部,那么它们的右部由 不同的终结符开始。
• 文法 G2[S]: S→Ap S→Bq A→a A→cA B→b B→dB
编译原理
W=ccap自顶向下的推导过程: S Ap cAp ccAp ccap
语法树:
S
S
Ap Ap cA
S Ap cA cA
S Ap cA cA
编译原理
A→b
3.化为: S→aSA' S→bc A'→d A'→c A→aS A→b
结果中A是不可达到的符号。
• 例:文法G4[S] 为:
编译原理
3.化为:
S→Ap|Bq
S→aS'
A→aAp|d B→aBq|e
1.化为: S→aApp|aBqq|dq|eq A→aAp|d B→aBq|e
S→dq|eq S'→App|Bqq A→aAp|d B→aBq|e 4.化为: S→aS' S→dq|eq
FOLLOW(A),加至FOLLOW(B)中.
S→AB S→bC A→ε A→b B→ε B→aD C→AD C→b D→aS D→c
编译原理
FOLLOW(S)={#}∪FOLLOW(D) FOLLOW(A)={a}∪{a,c}∪FOLLOW(S) FOLLOW(B)=FOLLOW(S) FOLLOW(C)=FOLLOW(S) FOLLOW(D)=FOLLOW(B)∪FOLLOW(C)
SELECT(A→ε)
={a,d,#,ε}
SELECT(S→aA) ∩ SELECT(S→d)={a}∩{d}=Φ
SELECT(A→bAS)∩SELECT(A→ε)={b}∩{a,d,#, ε}=Φ

编译原理 第四章自顶向下语法分析法

编译原理 第四章自顶向下语法分析法
若b不∈FIRST(αi),其中i=1~n,则语法错,转出错处理。这样就避免了分析过程的回溯。
若文法的任一非终结符号,其规则右部的各个选择所能推出的终结符号串的头符号集合不满足两两相交的条件时,那么,要构造一个不带回溯的自顶向下的语法分析程序,需要采取什么措施呢?一般可采取改写文法的办法来解决。
(三)改写文法当文法不满足,可改写文法
对每一文法符号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是否还有别的选择。

编译原理 自顶向下语法分析方法

编译原理 自顶向下语法分析方法

4.2 LL(1)文法的判别
要判别一个上下文无关文法是否是LL(1)文法 分为五步: 1. 求能推出ε的非终结符集 2. 计算每个产生式右部β的FIRST(β)集 3. 计算每个非终结符A的FOLLOW(A)集 4. 计算每个产生式A→β的SELECT(A→β)集 5. 按LL(1)文法的定义判别
S→d
A→bAS
A→ε
SELECT(S→aA)=FIRST(aA)={a} SELECT(S→d)=FIRST(d)={d}
SELECT(A→bAS)=FIRST(bAS)={b}
SELECT(A→ε) =(FIRST(ε)-{ε})+ FOLLOW(A)={#,a,d}
结论三
同一非终结符的不同产生式A→α与A→β,若
第四章 自顶向下语法分析方法
学习目标:
掌握:LL(1)文法的判别,预测分析法,
递归子程序的构造方法
理解:LL(1)文法 了解:不确定的自顶向下分析
语法分析的作用是识别由词法分析给出的单词序列 是否是给定文法的正确句子 分类:
确定的
自顶向下分析 语法分析 自底向上分析 LR分析(第五章) 不确定的 算法优先分析(第六章)
SectionFirst(X1…Xj…Xn)
= (First(X1) -{ε}) (First(X2)-{ε})… (First(Xj) -{ε}) First(Xj+1) Xj+1是产生式右部中第一个不能推出ε的符号

对每个产生式 A→X1…Xj…Xn 做:
First(A)=First(A) SectionFirst(X1…Xj…Xn )
回顾——后跟符号集FOLLOW(A)的定义
定义 设G=(VT, VN, P, S)是上下文无关文法, B→xAy (A,B ∈VN x,y ∈(VNVT)* ) FOLLOW(A)={a|S=>*…Aa…,a ∈VT}, 若有S=>* …A,则规定 # ∈FOLLOW(A) (注: # 输入串#,‘#’做为输入串的结束符) 直观上说,非终结符A的后跟符号集是由句型中紧跟A后的那 些终结符(包括#)组成。

自顶向下语法分析方法

自顶向下语法分析方法

7
PL/0语言文法的EBNF表示
PL/0语言文法的EBNF表示 <程序>∷=<分程序>. <分程序>∷=[<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句> <常量说明部分>∷=CONST<常量定义部分>{,<常量定义>}; <无符号整数>∷=<数字>{<数字>} <变量说明部分>∷=VAR<标识符>{,<标识符>}; <标识符>∷=<字母>{<字母>|<数字>} <过程说明部分>∷=<过程首部><分程序>{;<过程说明部分>}; <过程首部>∷=PROCEDURE <标识符>; <语句>∷=<赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>| <读语句>|<写语句>|<复合语句>|<空> <赋值语句>∷=<标识符>:=<表达式> <复合语句>∷=BEGIN <语句>{;<语句>} END <条件>∷=<表达式><关系运算符><表达式>|ODD<表达式>
例如对文法G3[S]: S→aAS|b A→bA| SELECT(S→aAS)={a} SELECT(S→b)={b} SELECT(A→bA)={b} SELECT(A→)={a,b}

编译原理系列之四自顶向下语法分析方法

编译原理系列之四自顶向下语法分析方法

编译原理系列之四⾃顶向下语法分析⽅法⾃顶向下语法分析⽅法什么叫确定:两个确定:①确定对最左的⾮终结符进⾏替换(最左推导)②对于同⼀个⾮终结符,确定⼀个产⽣式进⾏推导(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 第四章 语法分析-自顶向下分析方法

编译课件  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)

编译原理(3)语法_3(自顶向下语法分析:递归下降)33页PPT

编译原理(3)语法_3(自顶向下语法分析:递归下降)33页PPT

G[S]: S → Q c | c
Q → R b | b
R → S a | a
(3.3)
中的S、Q、R都具有间接左递归
S Qc Rbc Sabc
3.3 自顶向下的语法分析
3、消除间接左递归 如何消除一个文法的一切左递归呢?如果一个文法不含回路(
形如A=+>A的推导),且产生式的右部也不含ε的候选式,那么
(3.1)
G[E]:E → TE' E' → +TE' | ε T → FT' T' → *FT' | ε F → (E) | i
(3.2)
可以通过文法(3.2)构造递归下 降分析器:
(1)文法(3.2)无左递归 (2) E ' 、 T ' 、F的候选式首字 符无交集
3.3 自顶向下的语法分析
4、递归下降分析器
3.3 自顶向下的语法分析 4、递归下降分析器
– 子程序的调用关系:
主程序
子程序
1.简单子程序
主程序
子程序1
2.嵌套子程序
子程序2
主程序
子程序
3.直接递归子程序
主程序
子程序1
子程序2
4.间接递归子程序
递归下降分析器的设计示例
G[E]:E → E+T | T T → T*F | F
F → (E) | i
A … Aα Aαα Aααα βααα
3.3 自顶向下的语法分析
再看下面不含A的直接左递归的产生式: A → βA' A' → α A' | ε
这两个产生式所能推导的句子如下:
A βA' β A βA' βαA' βα A βA' βαA' βααA' βαα A βA' βαA' βααA' βαααA' βααα

编译原理-清华大学-第4章-自顶向下语法分析方法(3+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,#}=Φ

#编译原理第五章自顶向下语法分析方法

#编译原理第五章自顶向下语法分析方法

第五章自顶向下语法分析方法课前索引【课前思考】为了了解自顶向下<自上而下)分析的一般过程和问题,请学员首先回顾在"文法和语言"一章中介绍的有关基本概念:◇句子、句型和语言的定义是什么?◇什么叫最左推导?◇什么叫最右推导和规范推导?◇什么叫确定的自顶向下语法分析?◇自顶向下语法分析是从文法的开始符号出发,反复使用各种产生式,寻找与输入符号匹配的推导。

◇确定的自顶向下语法分析中用的是哪种推导?◇在确定的自顶向下语法分析过程中,当以同一个非终结符为左部的产生式有多个不同右部时,如何选择用哪个产生式的右部替换当前的非终结符?◇确定的自顶向下语法分析对文法有何限制?【学习目标】确定的自顶向下分析方法虽对文法有一定的限制,但因为实现方法简单、直观,便于手工构造或自动生成语法分析器,因而仍是目前常用的方法之一。

要求学员通过本章的学习后达到以下要求:◇能够对一个给定的文法判断是否是LL(1>文法;◇能构造预测分析表;◇能用预测分析方法判断给定的输入符号串是否是该文法的句子;◇能对某些非LL(1>文法做等价变换:①消除左递归②提取左公共因子可能会变成LL(1>文法。

这样可扩大自顶向下分析方法的应用。

【学习指南】确定的自顶向下分析因为实现方法简单、直观、便于手工构造,因此,仍是目前常用的语法分析方法之一,尤其对小型编译器的实现较为适合。

对初学编译技术的学员也较容易入门。

确定的自顶向下分析要求文法是LL(1>的,所以,能否用确定的自顶向下分析方法构造语法分析器,首先必须对所给文法进行判断。

由此构造LL(1> 分析器的关键问题是对文法的LL(1>判别。

而判断LL(1>文法时用到文法符号串的开始符号集合<FIRST集)和非终结符的后跟符号集合<FOLLOW集)的计算。

本章的学习要求学员对给定的文法能熟练、准确地计算出产生式右部符号串的开始符号集合和每个非终结符的后跟符号集合,只有这两个集合的元素计算准确无误,才能对LL(1>文法的判断得出正确结论,从而正确构造LL(1>分析表。

【编译原理】自顶向下语法分析方法的实现

【编译原理】自顶向下语法分析方法的实现

实验报告实验项目列表一、实验名称自顶向下语法分析方法的实现二、实验目的1.掌握自顶向下语法分析的方法;2.运用编程的手段实现自顶向下语法分析。

三、实验内容和要求四、实验环境1.硬件环境:PC机2.软件环境:Windows操作系统,VC++集成开发环境五、算法设计思想六、主要问题与解决方法七、实验结果以下是程序的用户运行界面截图:八、体会、质疑、建议九、源代码#include<fstream>#include<sstream>#include<iostream>#include<vector>#include<string>#include<windows.h>#include<iterator>#include<algorithm>#include<stdlib.h>#define M 20using namespace std;void gotoxy(int x,int y){COORD coord;coord.X=x;coord.Y=y;SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), coord );}class table{public:void read();friend class an_process;string find_str(char row,char col);private:string matrix[M][M];char start;vector<string> vec_row;vector<string> vec_col;};class sentence{public:void read_in();friend class an_process;private:string str_input;};class an_process{public:void analyse(const table LL1_table,const sentence input);void write_result();void print2(int x,int y);private:vector<int> step;vector<vector<char> > stack_note;vector<string> remain;vector<string> production;};void table::read(){string a,str;char x,y;int linenum = 0;char line[1024]={0};ifstream infile("table1.txt");if(!infile){cerr<<"错误!无法存储用户数据!\n";}while(infile.getline(line,sizeof(line))){stringstream word(line);if(linenum>1){if(word>>x&&word>>y&&word>>str){matrix[x-48][y-48]=str;/*cout<<x<<" ";cout<<y<<" ";cout<<matrix[x-48][y-48]<<" ";*/}}while(word>>a&&linenum<2){if(linenum==0){vec_col.push_back(a);/*cout<<a<<" ";*/}else if(linenum==1){vec_row.push_back(a);/* cout<<a<<" ";*/}}/*cout<<endl;*/linenum++;}start=vec_col[0][0];/* for(int icnt=0;icnt<vec_col.size();icnt++){cout<<vec_col[icnt]<<" ";}*/}string table::find_str(char row,char col){for(int x=0;x<vec_col.size();x++)for(int y=0;y<vec_row.size();y++){if(row==vec_col[x][0]&&col==vec_row[y][0]){return matrix[x+1][y+1];}}return"";}void an_process::analyse(table LL1_table,sentence input) {int icnt=0,jcnt=0,kcnt;string ac,prod="",re="";vector<char> stack;char Now_word=input.str_input[icnt];char NOW_state=LL1_table.start;string::const_iterator Eiter;string::const_iterator Biter;stack.push_back('#');stack.push_back(NOW_state);for(;icnt<input.str_input.size();){step.push_back(++jcnt);stack_note.push_back(stack);for(kcnt=icnt;kcnt<input.str_input.size();kcnt++){re=re+input.str_input[kcnt];}re=re+"#";remain.push_back(re);re.erase();Now_word=input.str_input[icnt];NOW_state=stack.back();if(NOW_state==Now_word){stack.erase(stack.end()-1);icnt++;production.push_back("(匹配)");}else{ac=LL1_table.find_str(NOW_state,Now_word);Biter=ac.begin();Biter--;Eiter=ac.end();Eiter--;if(ac=="ε"){prod=prod+NOW_state;prod=prod+"→";prod=prod+"ε";stack.erase(stack.end()-1);production.push_back(prod);prod.erase();}else if(ac!=""){stack.erase(stack.end()-1);prod.empty();prod=prod+NOW_state;prod=prod+"→"+ac;production.push_back(prod);prod.erase();for(;Eiter!=Biter;Eiter--){stack.push_back(*Eiter);}}else{cout<<"分析失败\n";exit(0);}}}if(stack.size()!=1||stack.back()!='#'){cout<<"分析失败\n";exit(0);}}void an_process::write_result(){step.push_back(step.back()+1);vector<char> a;a.push_back('#');stack_note.push_back(a);remain.push_back("#");production.push_back("接受");gotoxy(27,1);cout<<"输入串"<<'"'<<remain[0];cout<<"\b"<<'"'<<"的分析过程"<<endl<<endl;print2(step.size()+1,4);vector<int>::const_iterator iter1=step.begin();vector<vector<char> >::const_iterator iter2=stack_note.begin(); vector<string>::const_iterator iter3=remain.begin();vector<string>::const_iterator iter4=production.begin(); gotoxy(8,4);cout<<"步骤";gotoxy(27,4);cout<<"分析栈";gotoxy(44,4);cout<<"剩余输入串";gotoxy(63,4);cout<<"所用产生式";for(int xy=0;iter1!=step.end();iter1++){gotoxy(9,xy+6);cout<<(*iter1);xy=xy+2;}for(xy=0;iter2!=stack_note.end();iter2++) {gotoxy(27,xy+6);for(int icnt=0;icnt<(*iter2).size();icnt++) {cout<<(*iter2)[icnt];}xy=xy+2;}for(xy=0;iter3!=remain.end();iter3++){gotoxy(44,xy+6);cout<<(*iter3);xy=xy+2;}for(xy=0;iter4!=production.end();iter4++){gotoxy(63,xy+6);cout<<(*iter4);xy=xy+2;}cout<<endl<<endl;}void an_process::print2(int x,int y)//简易画线代码,呵呵,画行直线{int i,j;for(int icnt=0;icnt<y-1;icnt++){for(i=0;i<37/y;i++)printf("─");printf("┬");}for(i=0;i<37/y;i++)printf("─");putchar(10);for(icnt=0;icnt<y-1;icnt++) {for(i=0;i<37/y;i++)printf(" ");printf("│");}putchar(10);for(j=0;j<x-1;j++)//画5行直线{for(icnt=0;icnt<y-1;icnt++){for(i=0;i<37/y;i++)printf("─");printf("┼");}for(i=0;i<37/y;i++)printf("─");putchar(10);for(icnt=0;icnt<y-1;icnt++){for(i=0;i<37/y;i++)printf(" ");printf("│");}putchar(10);}for(icnt=0;icnt<y-1;icnt++) {for(i=0;i<37/y;i++)printf("─");printf("┴");}for(i=0;i<37/y;i++)printf("─");putchar(10);}void sentence::read_in(){cout<<"请输入需要分析的句子:\n";cin>>str_input;system("cls");}void main(){table LL1_table;sentence input;an_process A;input.read_in();LL1_table.read();A.analyse(LL1_table,input);A.write_result();}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验报告实验项目列表一、实验名称自顶向下语法分析方法的实现二、实验目的1.掌握自顶向下语法分析的方法;2.运用编程的手段实现自顶向下语法分析。

三、实验内容和要求四、实验环境1.硬件环境:PC机2.软件环境:Windows操作系统,VC++集成开发环境五、算法设计思想六、主要问题与解决方法七、实验结果以下是程序的用户运行界面截图:八、体会、质疑、建议九、源代码#include<fstream>#include<sstream>#include<iostream>#include<vector>#include<string>#include<windows.h>#include<iterator>#include<algorithm>#include<stdlib.h>#define M 20using namespace std;void gotoxy(int x,int y){COORD coord;coord.X=x;coord.Y=y;SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), coord );}class table{public:void read();friend class an_process;string find_str(char row,char col);private:string matrix[M][M];char start;vector<string> vec_row;vector<string> vec_col;};class sentence{public:void read_in();friend class an_process;private:string str_input;};class an_process{public:void analyse(const table LL1_table,const sentence input);void write_result();void print2(int x,int y);private:vector<int> step;vector<vector<char> > stack_note;vector<string> remain;vector<string> production;};void table::read(){string a,str;char x,y;int linenum = 0;char line[1024]={0};ifstream infile("table1.txt");if(!infile){cerr<<"错误!无法存储用户数据!\n";}while(infile.getline(line,sizeof(line))){stringstream word(line);if(linenum>1){if(word>>x&&word>>y&&word>>str){matrix[x-48][y-48]=str;/*cout<<x<<" ";cout<<y<<" ";cout<<matrix[x-48][y-48]<<" ";*/}}while(word>>a&&linenum<2){if(linenum==0){vec_col.push_back(a);/*cout<<a<<" ";*/}else if(linenum==1){vec_row.push_back(a);/* cout<<a<<" ";*/}}/*cout<<endl;*/linenum++;}start=vec_col[0][0];/* for(int icnt=0;icnt<vec_col.size();icnt++){cout<<vec_col[icnt]<<" ";}*/}string table::find_str(char row,char col){for(int x=0;x<vec_col.size();x++)for(int y=0;y<vec_row.size();y++){if(row==vec_col[x][0]&&col==vec_row[y][0]){return matrix[x+1][y+1];}}return"";}void an_process::analyse(table LL1_table,sentence input) {int icnt=0,jcnt=0,kcnt;string ac,prod="",re="";vector<char> stack;char Now_word=input.str_input[icnt];char NOW_state=LL1_table.start;string::const_iterator Eiter;string::const_iterator Biter;stack.push_back('#');stack.push_back(NOW_state);for(;icnt<input.str_input.size();){step.push_back(++jcnt);stack_note.push_back(stack);for(kcnt=icnt;kcnt<input.str_input.size();kcnt++){re=re+input.str_input[kcnt];}re=re+"#";remain.push_back(re);re.erase();Now_word=input.str_input[icnt];NOW_state=stack.back();if(NOW_state==Now_word){stack.erase(stack.end()-1);icnt++;production.push_back("(匹配)");}else{ac=LL1_table.find_str(NOW_state,Now_word);Biter=ac.begin();Biter--;Eiter=ac.end();Eiter--;if(ac=="ε"){prod=prod+NOW_state;prod=prod+"→";prod=prod+"ε";stack.erase(stack.end()-1);production.push_back(prod);prod.erase();}else if(ac!=""){stack.erase(stack.end()-1);prod.empty();prod=prod+NOW_state;prod=prod+"→"+ac;production.push_back(prod);prod.erase();for(;Eiter!=Biter;Eiter--){stack.push_back(*Eiter);}}else{cout<<"分析失败\n";exit(0);}}}if(stack.size()!=1||stack.back()!='#'){cout<<"分析失败\n";exit(0);}}void an_process::write_result(){step.push_back(step.back()+1);vector<char> a;a.push_back('#');stack_note.push_back(a);remain.push_back("#");production.push_back("接受");gotoxy(27,1);cout<<"输入串"<<'"'<<remain[0];cout<<"\b"<<'"'<<"的分析过程"<<endl<<endl;print2(step.size()+1,4);vector<int>::const_iterator iter1=step.begin();vector<vector<char> >::const_iterator iter2=stack_note.begin(); vector<string>::const_iterator iter3=remain.begin();vector<string>::const_iterator iter4=production.begin(); gotoxy(8,4);cout<<"步骤";gotoxy(27,4);cout<<"分析栈";gotoxy(44,4);cout<<"剩余输入串";gotoxy(63,4);cout<<"所用产生式";for(int xy=0;iter1!=step.end();iter1++){gotoxy(9,xy+6);cout<<(*iter1);xy=xy+2;}for(xy=0;iter2!=stack_note.end();iter2++) {gotoxy(27,xy+6);for(int icnt=0;icnt<(*iter2).size();icnt++) {cout<<(*iter2)[icnt];}xy=xy+2;}for(xy=0;iter3!=remain.end();iter3++){gotoxy(44,xy+6);cout<<(*iter3);xy=xy+2;}for(xy=0;iter4!=production.end();iter4++){gotoxy(63,xy+6);cout<<(*iter4);xy=xy+2;}cout<<endl<<endl;}void an_process::print2(int x,int y)//简易画线代码,呵呵,画行直线{int i,j;for(int icnt=0;icnt<y-1;icnt++){for(i=0;i<37/y;i++)printf("─");printf("┬");}for(i=0;i<37/y;i++)printf("─");putchar(10);for(icnt=0;icnt<y-1;icnt++) {for(i=0;i<37/y;i++)printf(" ");printf("│");}putchar(10);for(j=0;j<x-1;j++)//画5行直线{for(icnt=0;icnt<y-1;icnt++){for(i=0;i<37/y;i++)printf("─");printf("┼");}for(i=0;i<37/y;i++)printf("─");putchar(10);for(icnt=0;icnt<y-1;icnt++){for(i=0;i<37/y;i++)printf(" ");printf("│");}putchar(10);}for(icnt=0;icnt<y-1;icnt++) {for(i=0;i<37/y;i++)printf("─");printf("┴");}for(i=0;i<37/y;i++)printf("─");putchar(10);}void sentence::read_in(){cout<<"请输入需要分析的句子:\n";cin>>str_input;system("cls");}void main(){table LL1_table;sentence input;an_process A;input.read_in();LL1_table.read();A.analyse(LL1_table,input);A.write_result();}。

相关文档
最新文档