自下而上语法分析-LR..

合集下载

第5章 语法分析(2)自下而上分析

第5章 语法分析(2)自下而上分析

则成功,达不到这种格局则输入串有错误。

栈中符号串+剩余输入串 = 规范句型。
26
规范归约分析算法
1. 在栈底放入# ,在输入串尾附上#; 2. 逐个移入输入符号,当栈顶形成句柄时,进行归约; 3. 重复2 直到输入串已全部进栈,仅剩#, 4. 若栈中归约为#S, 表示分析成功,输入串为合法的 句子,否则为非法句子.
2
5.1 自下而上分析的基本问题

自下而上分析法的基本思想:
从输入串出发,反复利用产生式逐步进行 ‚归约‛,如果最后能归约到文法的开始符 号,则输入串是句子,否则输入串有语法错 误。

各种不同自下而上分析法一个共同特点是:
边输入单词符号(移进栈),边归约;
3
5.1 自下而上分析的基本问题

自下而上分析的基本技术是采用归约栈,如下图所示: #

或者说从文法的开始符号产生句子。

自下而上分析采用的方法是归约,从叶子到根构造分析树。

或者说从句子开始归约出文法的开始符号。

语法树的一个子树:由该树的某个结连同它的所有子孙组成。 在自下而上分析过程中,每一步归约都可画出一棵子树。
例如,上例中的归约过程可描述为如下分析树:
9
例5.2:文法G[S], 其4条产生式如下: ① S→aABe ② A→b ③ A→Abc ④ B→d 对句子abbcde的分析 最右推导 SaABeaAdeaAbcdeabbcde 最左归约 abbcde,aAbcde ,aAde,aABe ,S S S aABe aAde aAbcde abbcde
S (2)每次归约用的句柄: , (a,(a)), , , , , , ( (L,(S)) (L,(L)) (L,S) (L) S (S,(a)) (L,(a)) L )

LLLRSLRLALR傻傻分不清

LLLRSLRLALR傻傻分不清

LLLRSLRLALR傻傻分不清⼀:LR(0),SLR(1),规范LR(1),LALR(1)的关系⾸先LL(1)分析法是⾃上⽽下的分析法。

LR(0),LR(1),SLR(1),LALR(1)是⾃下⽽上的分析法。

⾃上⽽下:从开始符号出发,根据产⽣式规则推导给定的句⼦。

⽤的是推导⾃下⽽上:从给定的句⼦规约到⽂法的开始符号。

⽤的是归约1: SLR(1)与LR(0)的关系:SLR(1)与LR(0):简单的LR语法分析技术(即SLR(1)分析技术)的中⼼思想是根据⽂法构造出LR(0)⾃动机。

LR(0):见到First集就移进,见到终态就归约SLR(1)见到First集就移进,见到终态先看Follow集,与Follow集对应的项⽬归约,其它报错。

2: LR(1)与LR(0)的关系:规范LR(1)语法分析技术的中⼼思想是根据⽂法构造出LR(1)⾃动机,⽽规范LR(1)⾃动机构造⽅法和LR(0)⾃动机的构造⽅法相同,只是多增加了向前搜索符号。

3:规范LR(1)与LALR(1)的关系:LALR(1)是对LR(1)项集族I中具有同⼼项的项集进⾏合并得到I',然后根据I’进⾏分析的⽅法。

⼆:LL(1),SLR(1),规范LR(1),LALR(1)的判别1:LL(1)判断规则判定规则:龙书上有很明确的规则,龙书上这样说,对形如 A->a|β这样的⽂法,满⾜①FIRST(α)∩ FIRST (β ) =Φ②若ε∈ FIRST( α),要满⾜ FIRST(β) ∩FOLLOW(A)=Φ这两个条件的才是 LL(1) ⽂法。

这⾥要注意⼀下条件②,α和β是可以互换的,意思就是只要其中有⼀个 FIRST 集包含ε,那么就要看另⼀个了。

2:SLR(1)判断规则⽅法⼀:画出⽂法的LR(0)⾃动机,如果没有移进--规约冲突,即shift--reduce 冲突,则该⽂法是SLR(1)⽂法3:LALR(1)和LR(1)的判断规则画出⽂法的LR(1)⾃动机,如果没有同⼼项且没有状态冲突,则该⽂法是LALR(1)⽂法;如果有同⼼项且合并同⼼项有状态冲突,则是LR(1)⽂法最后附上我们sysu编译原理作业的两个例⼦⼀,证明下列⽂法S à Aa | bAc | dc | bdaA à d是LALR(1)⽂法但不是SLR(1)⽂法.拓⼴⽂法(0) S’→S(1) S → Aa(2) S → bAc(3) S → dc(4) S → bda(5) A → d拓⼴⽂法的LR(1)项⽬集规范族及Go函数如下⼀、证明下列⽂法S à Aa | bAc | Bc | bBaA à dB à d是LR(1)⽂法但不是LALR(1)⽂法.拓⼴⽂法(0) S’→S(1) S → Aa(2) S → bAc(3) S → Bc(4) S → bBa(5) A → d(6) B → d拓⼴⽂法的LR(1)项⽬集规范族及Go函数如下。

实验5---语法分析器(自下而上):LR(1)分析法

实验5---语法分析器(自下而上):LR(1)分析法

实验5---语法分析器(自下而上):LR(1)分析法一、实验目的构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。

二、实验内容程序输入/输出示例(以下仅供参考):对下列文法,用LR(1)分析法对任意输入的符号串进行分析:(1)E->E+T(2)E->E—T(3)T->T*F(4)T->T/F(5)F-> (E)(6)F->i输出的格式如下:(1)LR(1)分析程序,编制人:姓名,学号,班级(2)输入一个以#结束的符号串(包括+—*/()i#):在此位置输入符号串(3)输出过程如下:3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。

同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照。

三、实验方法1.实验采用C++程序语言进行设计,文法写入程序中,用户可以自定义输入语句;2.实验开发工具为DEV C++。

四、实验步骤1.定义LR(1)分析法实验设计思想及算法①若ACTION[sm , ai] = s则将s移进状态栈,并把输入符号加入符号栈,则三元式变成为:(s0s1…sm s , #X1X2…Xm ai , ai+1…an#);②若ACTION[sm , ai] = rj则将第j个产生式A->β进行归约。

此时三元式变为(s0s1…sm-r s , #X1X2…Xm-rA , aiai+1…an#);③若ACTION[sm , ai]为“接收”,则三元式不再变化,变化过程终止,宣布分析成功;④若ACTION[sm , ai]为“报错”,则三元式的变化过程终止,报告错误。

2.定义语法构造的代码,与主代码分离,写为头文件LR.h。

3.编写主程序利用上文描述算法实现本实验要求。

五、实验结果1. 实验文法为程序既定的文法,写在头文件LR.h中,运行程序,用户可以自由输入测试语句。

第5章 语法分析——自下而上

第5章 语法分析——自下而上

B d
e
SaAcBeaAcdeaAbcdeabbcde SS→aAcBeB→d A→Ab A→b
每次归约的都是句型中的句柄。
22
算符优先分析法
LR分析法
23
1. LR分析法介绍
2. LR(0)分析表的构造
3. SLR分析表的构造
24
从左(Left,L)向右扫描输入串,构造一 个最右推导(Rightmost,R)的逆过程 进行规范归约(最左归约),每次归约 的都是真正的句柄; 对文法限制最少,是识别效率较强的方 法; 出错处理能力较强; 采用自动构造技术(构造LR分析表)
B
e
A
b
d
S → aAcBe A → Ab A→b B→d
b
分 析 树
输入串:abbcde
7
短语 直接短语 句柄
8
定义:设文法G的开始符号为S,是文法 *则称β是 的一个句型,若有SA且Aβ, + 相对于非终结符A的一个短语。 句型
短语是指句型中的某个部分,这部分可以由某 个非终结符推出。 可以利用语法树来找出句型中的所有短语。
查表 A[0,a]=s2,进栈 A[2,a]=s2,进栈 A[2,b]=s5,进栈 A[5,b]=r2,按第2条产生式归约 G[2,A]=3,进入状态3 A[3,b]=s4,进栈 A[4,#]=r1,归约 G[0,A]=1,进入状态1 A[1,#]=acc 31
对于一个文法,如果能够构造一张分析表, 使得它的每个入口均是唯一确定的,则我们 把这个文法称为LR文法。
33
前缀:字的任意首部。即移去符号尾
部零个或多于零个符号得到的一个符
号串。 例:abc的前缀有ε,a, ab, abc

程序设计语言与编译原理_自下而上的语法分析

程序设计语言与编译原理_自下而上的语法分析
程序设计语言与编译
第8章 自下而上的语法分析 第一节 引言
自下而上分析:从输入串出发,归约, 直至开始符 方法:采用栈,在移进的过程中,观察栈顶是否 形成某个产生式的一个候选
程序设计语言与编译
自下而上分析法(Bottom-up)
» 基本思想:
从输入串开始,逐步进行“归约”,直到文法的开 始符号。所谓归约,是指根据文法的产生式规则, 把产生式的右部替换成左部符号。
程序问设题计的语提言出与:编译
① 在构造语法树的过程中,何时归约? 当可归约串出现在栈顶时就进行归约。
② 如何知道在栈顶符号串中已经形成可归约串? 如何进行归约? 通过不同的自底向上的分析算法来解释,不同的
算法对可归约串的定义是不同的,但分析过程都有一 个共同的特点:边移进 边归约。
规范归约:使用句柄来定义可归约串。 算符优先:使用最左素短语来定义可归约串
E1
8个内部节点—— 8棵子树 句型η 有8个短语:
E2 + T3
i1*i2+i3是句型η 相对于E1的短语
T4
F5
i1*i2是句型η 相对于E2 ,T4的短语
i1是句型η 相对于T6 ,F8的短语 i2是句型η 相对于F7的短语
T6 * F7
i3
i3是句型η 相对于T3,F5的短语
步骤: 1 2 3 4 5 6 7 8 9 10 动作: 进a 进b 归(2) 进b 归(3) 进c 进d 归(4) 进e 归(1)
e
dBB
b
cccc
bAAAAAAA
aaaaaaaaaS
程序设计语言与编译
S
分析树
aA c
Be
A
bd
b
分析树和语法树不一定一致。 自下而上分析过程:边输入单词符号,边 归约。 核心问题:识别可归约串

第五章 语法分析(自上而下分析法)

第五章 语法分析(自上而下分析法)

解: 这里P=exp , α 1=+term , α 2=-term, β =term 改写: exp → term exp' , exp' → +term exp' | - term exp' | ε
(3)间接左递归的消除 例如文法G(S): S→Qc|c Q→Rb|b R→Sa|a
虽没有直接左递归,但S、Q、R都是左递归的
例:简单的表达式文法 exp → exp addop term | term 消除其左递归。 解:属于格式P → Pα | β 这里 P=exp , α =addop term , β =term 改写: exp → term exp' exp' → addop term exp' | ε
例 文法G(E): E→E+T | T T→T*F | F F→(E) | i 经消去直接左递归后变成: E→TE′ E′→+TE′ | ε T→FT′ T′→*FT′ | ε F→(E) | i 不变
例1 假定有文法G(S): (1) S→xAy (2) A→** | * 分析输入串x*y(记为α)。 ① 按文法的开始符号产生语法树的根节点S,根据规 则,S有三个子孙,于是此时的语法树如图所示; 并把指示器IP指向串α的第一个符号x x*y IP S x*y IP S x A y
把语法树的子节点从左至右对IP所指向的符号进行匹 配。第一符号匹配,于是,IP向后移动一个符号。
是递归下降分析法和预测分析法的基础
LL(1)分析法
构造不带回溯的自上而下分析算法 要消除文法的左递归性 克服回溯
1 左递归的消除
(1)简单直接左递归 直接消除见诸于产生式中的左递归:假定关于非 终结符P的规则为

第六章 语法分析-自下而上分析法

第六章 语法分析-自下而上分析法

一、自下而上语法分析的基本问题 1.归约: 如何判断栈顶符号的可归约性以及如何归约,是 自下而上分析的中心问题。 2.短语和句柄
如果S ⇒ αAβ and A ⇒γ,则称γ是句型 αγβ的相对于变量A的短语 * 如果S ⇒αAβ and A⇒γ,则称γ是句型 αγβ的相对于变量A的直接(简单)短语 最左直接短语叫做句柄
e
abbcde
一、自下而上语法分析的基本问题 (3)自下而上分析的关键问题
似乎移进-归约过程很简单,其实不然,在上面第5步,如果用 规则2(P → b)进行归约而不是用规则3(P → Pb)进行归约,结果 会怎么样呢? 上面的归约过程是从文法的句子abbcde开始,每一步都是把最 左直接短语(句柄)替换为相应产生式的左部符号(在步骤5时 栈顶为#aPb,此时是将b归约为P还是将Pb归约为P?由于此时对 于句型aPbcde(即栈内容+输入缓冲区内容)来说Pb是句柄,故 将Pb归约为P)。也就是说,自底向上分析的关键问题是在分析 中如何确定句柄(准确地说为可归约串),即如果知道何时在 栈顶符号串中已形成了某句型的句柄,那么就可以确定何时进 行归约。对此,不同的分析方法有不同的解决办法。这里主要 介绍算符优先及LR分析方法。
例: 移进—归约分析(Shift-reduce parsing)
要点:建立符号栈,用来纪录分析的历史和现状, 并根据所面临的状态,确定下一步动作是移 进还是归约。
输入串 # 符号栈 #
S.R.P
输入串 # 符号栈 #
S.R.P
分析过程:把输入符号串按自左向右顺序一一地 移进符号栈(一次移一个),检查栈中符号,当在栈 顶的若干符号形成当前句型的句柄时,就根据规则进 行归约,将句柄从符号栈中弹出,并将相应的非终结 符号压入栈内(即规则的左部符号),然后再检查栈 内符号串是否形成新的句柄,若有就再进行归约,否 则移进符号。分析一直进行到读到输入串的右界符为 止。最后,若栈中仅含有左界符号和识别符号,则表 示分析成功,否则失败

编译原理 第五章 语法分析-自下而上分析

编译原理 第五章 语法分析-自下而上分析

5.2.2 算符优先分析算法
• 素短语:
–是一个短语,它至少含有一个终结符,并且,除 它自身之外不再含任何更小的素短语。
• 最左素短语:
–最左边的素短语是最左素短语。
• 例子:
– 对文法(5.3)p*p和i是句型p*p+i的素短语,而p*p+i 本身也是素短语。
பைடு நூலகம்
• 算符优先文法:
算符优先文法,我们把句型(括在两个#之间) 的一般形式写成: #N1a1N2a2…NnanNn+1# 其中,每个ai都是终结符,Ni是可有可无的非终结 符。 文法G的任何短语是满足如下条件的最左子串 Njaj…NiaiNi+1 aj-1⋖ aj aj ≖ aj+1 , …,aj-1 ≖ ai ai ⋗ ai+1
– 对于每个终结符a(包括#)令其对应两个符号fa 和ga ,画一张以fa 和ga 所有符号为结点的方向图, 如 果 a⋗≖b, 那 么 , 就 从 fa 画 一 箭 弧 至 gb ; 如 果 a ⋖≖b,就画一条从gb到fa的箭弧。 – 对每个结点都赋予一个数,此数等于从该结点能 到达结点(包括出发结点自身在内)的个数。赋 给fa的数作为f(a),赋给gb的数作为g(b)。 –检查所构造出来的函数f和g,看它们 同原来的关 系表是否有矛盾。如果没有矛盾,则f和g就是所 要的优先函数。如果有矛盾,那么,就不存在优 先函数。
• 例子:假定文法G
S→aAcBe A→b A→Ab B→d 输入串abbcde归约到S过程。
图5.1 规约中符号栈的变迁
步骤 动作
1 进 a
2 进 b
3 归 (2)
4 进 b
5 归 (3)
6 进 c
7 进 d d

语法分析自下而上分析

语法分析自下而上分析
同理,可构造计算LASTVT的算法。 使用每个非终结符P的FIRSTVT(P)和
LASTVT(P),就能够构造文法G的优先 表。构造优先表的算法是:
.
FOR 每条产生式P→X1X2…Xn DO FOR i:=1 TO n-1 DO
BEGIN
IF Xi和Xi+1均为终结符 THEN 置Xi Xi+1
.
文法G(E) (1) E→E+T | T (2) T→T*F | F (3) F→P F | P (4) P→(E) | i
的优先函数如下表
+ *↑( ) i # F2440660 G1 3 5 5 0 5 0
.
有许多优先关系表不存在优先函数,如:
ab a b
不存在对应的优先函数f和g 假定存在f和g,则有
TN
LA ( P ) S { a |P T a , 或 V P T a ,a Q V T 而 Q V N }
.
有了这两个集合之后,就可以通过检查每
所有终结符对。
➢假定有个产生式的一个候选形为 …aP…
那么,对任何bFIRSTVT(P),有 a b。 ➢假定有个产生式的一个候选形为
…Pb… 那么,对任何aLASTVT(P),有 a b。
栈STACK,把所有初值为真的数组元素F[P, a]的符号对(P,a)全都放在STACK之中。
.
运算:
如果栈STACK不空,就将顶项逐出,记此 项为(Q,a)。对于每个形如 P→Q… 的产生式,若F[P,a]为假,则变其值为真 且将(P,a)推进STACK栈。
上述过程必须一直重复,直至栈STACK拆 空为止。
17
ELSE ERROR /*调用出错诊察程序*/

第4章语法分析3 LR分析法概述

第4章语法分析3 LR分析法概述

S2 x2
… …
Sm xm
ai…an #
5 6
7
以符号对去查表:
8 9
10
2024/8/10
LR分析表
action
ab c
S4
S5
r1 r1 r1
r2 r2 r2
rS44
r4
S5 r4
r6 r6 r6
S8 r3 r3 r3
S10 r5 r5 r5
计算机教研室
d# S6
acc r1 r1 r2 r2 S6 r4 r4 r6 r6
4 5
rS44
r4
S5 S6 r4 r4
6 r6 r6 r6 r6
7
S8
8 r3 r3 r3 r3
9
S10
10 r5 r5 r5 r5
分析成功!
计算机教研室
GoTo
#
SAB
1 23
acc r5
G [S]
0 S→S 1 S→A 2 S→B 3 A→aAb 4 A→c 5 B→aBb 6 B→d
1 S→A
并假设我们现在已经有了LR分析表,
2 S→B
则输入串#aacbb的分析过程为:
G[S] 3 A→aAb
0
a acbb #
#
由查表得action[0,a]=S4
04 #a
acb b # 再由查表得action[4,a]=S4
4 A→c 5 B→aBb 6 6 B→d
2024/8/10
计算机教研室
4-4-2 LR分析法
12
——LR(0)分析法 二、规范句型活前缀
1、前缀:字符串的任意首部。 Ex:字符串abc,前缀有:,a,ab,abc。

语法分析最常用的两类方法

语法分析最常用的两类方法

LL分析法和LR分析法。

1、自上而下语法分析方法(LL分析法)
给定文法G和源程序串r。

从G的开始符号S出发,通过反复使用产生式对句型中的非终结符进行替换(推导),逐步推导出r 。

是一种产生的方法,面向目标的方法。

分析的主旨为选择产生式的合适的侯选式进行推导,逐步使推导结果与r匹配。

2、自下而上语法分析方法(LR分析法)
从给定的输入串r开始,不断寻找子串与文法G中某个产生式P的候选式进行匹配,并用P的左部代替(归约)之,逐步归约到开始符号S。

是一种辨认的方法,基于目标的方法。

分析的主旨为寻找合适的子串与P的侯选式进行匹配,直到归约到G的S为止。

扩展资料
LALR分析器可以对上下无关文法进行语法分析。

LALR即“Look-AheadLR”。

其中,Look-Ahead为“向前看”,L代表对输入进行从左到右的检查,R代表反向构造出最右推导序列。

LALR分析器可以根据一种程序设计语言的正式语法的产生式而对一段文本程序输入进行语法分析,从而在语法层面上判断输入程序是否合法。

实际应用中的LALR分析器并不是由人手工写成的,而是由类似于yacc和GNU Bison之类的LALR语法分析器生成工具构成。

由机器自动生成的代码相比较于程序员手工的代码,拥有更好的运行效率而且减少了程序员的工作量。

自上而下语法分析方法

自上而下语法分析方法

11
根据定义计算FIRST集
1.若XV,则FIRST(X)={X}. 2.若XVN,且有产生式Xa…,aV 则
把a加入到FIRST(X)中;若X是一条产 生式,则把也加到FIRST(X)中。 3.若XY…是一个产生式且YVN,则把 FIRST(Y)中的所有非元素都加到 FIRST(X)中;
12
23
G1[S]: S →xAy A →ab | a 输入串:
xay
G2[S]: S →aAS | b A →bAS | ε 输入串:
ab
左递归
G3[S]: S →Sa | b 输入串:
baa
公因子
24
4.2.1 消除左递归
1 消除直接左递归 消除直接左递归(改写为等价的右递归)
形如:A → A α|β α非, β不以A开始 改写为: A →βB(B为新增加的非终结符)
的右部由不同的VT开始。
7
G2[S]: S →Ap S → Bq 输入串:
A → cA
A →a
W=ccap
G2文法B 特→点d:B
B→b
(1)每个产生式的右部不全由VT开始。 (2)如果两个产生式有相同的左部,那么它们
的右部由不同的VT或VN开始。 (3)文法中无空产生式
8
FIRST集定义
令G是一个上下无关文法,对G的所有非终结符 的每个候选定义它的终结首符号集FIRST() 为:
*
FIRST () = {a | a..., a VT }
特别是,若
*
,则规定FIRST()。
9
G2[S]: S →Ap S → Bq
A → cA
A →a
• 如果非终结符A的所有候B 选→首b符集两两不相交, 即A的任B何→两个dB不同候选 i和 j

自下而上语法分析

自下而上语法分析

自下而上语法分析1、规约:自下而上的语法分析过程:分为简单优先分析法,算符优先分析法,LR分析法。

2、自下而上的语法分析过程思想:自下而上的语法分析过程是一个最左规约的过程,从输入串开始,朝着文法的开始符号进行规约,直到文法的开始符号为止的过程。

输入串在这里是指词法分析器送来的单词符号组成的二元式的有限序列。

3、自下而上的PDA(下推自动机)工作方式:“移近-规约”方式注:初态时栈内仅有栈顶符“#”,读头指在最左边的单词符号上。

语法分析程序执行的动作:◆移进:读入一个单词并压入栈内,读头后移◆规约:检查栈顶若干符号能否进行规约,若能,就以产生式左部代替该符号串,同时输出产生式编号。

◆识别成功:移近-规约的结局是栈内只剩下栈底符号和文法的开始符号,读头也指向语句的结束符。

◆识别失败。

4、判读一语句是否是该文法的合法语句(可以用语法树)5、优先分析器:简单优先分析法(理论简单,实际比较麻烦)算符优先分析法6、LR分析器7、相邻文法符号之间的优先关系◆在句型中,句柄内各相邻符号之间具有相同的优先级。

◆由于句柄要先规约,所以规定句柄两端符号的优先级要比位于句柄之外的相邻符号的优先级高。

(#的优先级是最低的。

)9、简单优先文法:定义:一个文法G,如果它不含ε的产生式,也不含任何右部相同的不同产生式,并且它的任何符号(X,Y)-X,Y是非终结符或终结符—或者没有关系,或者存在优先级相同或低于、高于等关系之一,则这是一个简单优先文法。

10、简短优先分析的思想1)简单优先矩阵:根据优先关系的定义:将简单优先文法中各文法符号之间的这种关系用一个矩阵表示,称作简单优先矩阵。

2)PDA读入一个单词后,比较栈顶符号和该单词的优先级,若栈顶符号优先级低于该单词,继续读入;若栈顶符号优先级高于或者等于读入符号,则找句柄进行规约,找不到句柄继续读入11、简单优先法的优缺点:1、优点:算法比较好理解。

2、缺点:适用范围小,分析表尺寸太大。

编译原理实验三-自下而上语法分析报告及语义分析报告.docx

编译原理实验三-自下而上语法分析报告及语义分析报告.docx

上海电力学院编译原理课程实验报告实验名称:实验三自下而上语法分析及语义分析院系:计算机科学与技术学院专业年级:学生姓名:学号:指导老师:实验日期:实验三自上而下的语法分析一、实验目的:通过本实验掌握LR分析器的构造过程,并根据语法制导翻译,掌握属性文法的自下而上计算的过程。

二、实验学时:4学时。

三、实验内容根据给出的简单表达式的语法构成规则(见五),编制LR分析程序,要求能对用给定的语法规则书写的源程序进行语法分析和语义分析。

对于正确的表达式,给出表达式的值。

对于错误的表达式,给出出错位置。

四、实验方法采用LR分析法。

首先给出S-属性文法的定义(为简便起见,每个文法符号只设置一个综合属性,即该文法符号所代表的表达式的值。

属性文法的定义可参照书137页表6.1),并将其改造成用LR分析实现时的语义分析动作(可参照书145页表6.5)。

接下来给出LR分析表。

然后程序的具体实现:●LR分析表可用二维数组(或其他)实现。

●添加一个val栈作为语义分析实现的工具。

●编写总控程序,实现语法分析和语义分析的过程。

注:对于整数的识别可以借助实验1。

五、文法定义简单的表达式文法如下:(1)E->E+T(2)E->E-T(3)E->T(4)T->T*F(5)T->T/F(6)T->F(7)F->(E)(8)F->i五、处理程序例和处理结果例示例1:20133191*(20133191+3191)+ 3191#六、源代码【cifa.h】//cifa.h#include<string> using namespace std;//单词结构定义struct WordType{int code;string pro;};//函数声明WordType get_w();void getch();void getBC();bool isLetter();bool isDigit();void retract();int Reserve(string str); string concat(string str); 【Table.action.h】//table_action.hclass Table_action{int row_num,line_num;int lineName[8];string tableData[16][8]; public:Table_action(){row_num=16;line_num=8;lineName[0]=30;lineName[1]=7;lineName[2]=13;lineName[3]=8;lineName[4]=14;lineName[5]=1;lineName[6]=2;lineName[7]=15;lineName[8]=0;for(int m=0;m<row_num;m++) for(int n=0;n<line_num;n++) tableData[m][n]="";tableData[0][0]="S5";tableData[0][5]="S4";tableData[1][1]="S6";tableData[1][2]="S12";tableData[1][7]="acc";tableData[2][1]="R3";tableData[2][2]="R3";tableData[2][3]="S7";tableData[2][6]="R3"; tableData[2][7]="R3"; tableData[3][1]="R6"; tableData[3][2]="R6"; tableData[3][3]="R6"; tableData[3][4]="R6"; tableData[3][6]="R6"; tableData[3][7]="R6"; tableData[4][0]="S5"; tableData[4][5]="S4"; tableData[5][1]="R8"; tableData[5][2]="R8"; tableData[5][3]="R8"; tableData[5][4]="R8"; tableData[5][6]="R8"; tableData[5][7]="R8"; tableData[6][0]="S5"; tableData[6][5]="S4"; tableData[7][0]="S5"; tableData[7][5]="S4"; tableData[8][1]="S6";tableData[8][6]="S11"; tableData[9][1]="R1"; tableData[9][2]="R1"; tableData[9][3]="S7"; tableData[9][4]="S13"; tableData[9][6]="R1"; tableData[9][7]="R1"; tableData[10][1]="R4"; tableData[10][2]="R4"; tableData[10][3]="R4"; tableData[10][4]="R4"; tableData[10][6]="R4"; tableData[10][7]="R4"; tableData[11][1]="R7"; tableData[11][2]="R7"; tableData[11][3]="R7"; tableData[11][4]="R7"; tableData[11][6]="R7"; tableData[11][7]="R7"; tableData[12][0]="S5"; tableData[12][5]="S4";tableData[13][5]="S4";tableData[14][1]="R2";tableData[14][2]="R2";tableData[14][3]="S7";tableData[14][4]="S13";tableData[14][6]="R2";tableData[14][7]="R2";tableData[15][1]="R5";tableData[15][2]="R5";tableData[15][3]="R5";tableData[15][4]="R5";tableData[15][5]="R5";tableData[15][6]="R5";tableData[15][7]="R5";}string getCell(int rowN,int lineN){int row=rowN;int line=getLineNumber(lineN);if(row>=0&&row<row_num&&line>=0&&line<=line_num) return tableData[row][line];elsereturn"";}int getLineNumber(int lineN){for(int i=0;i<line_num;i++)if(lineName[i]==lineN)return i;return -1;}};【Table_go.h】//table_go.hclass Table_go{int row_num,line_num;//行数、列数string lineName[3];int tableData[16][3];public:Table_go(){row_num=16;line_num=3;lineName[0]="E";lineName[1]="T";lineName[2]="F";for(int m=0;m<row_num;m++) for(int n=0;n<line_num;n++)tableData[m][n]=0;tableData[0][0]=1;tableData[0][1]=2;tableData[0][2]=3;tableData[4][0]=8;tableData[4][1]=2;tableData[4][2]=3;tableData[6][1]=9;tableData[6][2]=3;tableData[7][2]=10;tableData[12][1]=14;tableData[12][2]=3;tableData[13][2]=15;}int getCell(int rowN,string lineNa){int row=rowN;int line=getLineNumber(lineNa);if(row>=0&&row<row_num&&line<=line_num) return tableData[row][line];elsereturn -1;}int getLineNumber(string lineNa){for(int i=0;i<line_num;i++)if(lineName[i]==lineNa)return i;return -1;}};【Stack_num.h】class Stack_num{int i; //栈顶标记int *data; //栈结构public:Stack_num() //构造函数{data=new int[100];i=-1;}int push(int m) //进栈操作{i++;data[i]=m;return i;}int pop() //出栈操作{i--;return data[i+1];}int getTop() //返回栈顶{return data[i];}~Stack_num() //析构函数{delete []data;}int topNumber(){return i;}void outStack(){for(int m=0;m<=i;m++)cout<<data[m];}};【Stack_str.h】class Stack_str{int i; //栈顶标记string *data; //栈结构public:Stack_str() //构造函数{data=new string[50];i=-1;}int push(string m) //进栈操作{i++;data[i]=m;return i;}int pop() //出栈操作{data[i]="";i--;return i;}string getTop() //返回栈顶{return data[i];}~Stack_str() //析构函数{delete []data;int topNumber(){return i;}void outStack(){for(int m=0;m<=i;m++)cout<<data[m];}};【cifa.cpp】//cifa.cpp#include<iostream>#include<string>#include"cifa.h"using namespace std;//关键字表和对应的编码stringcodestring[10]={"main","int","if","then","else","return","void","cout","endlint codebook[10]={26,21,22,23,24,25,27,28,29};//全局变量char ch;int flag=0;/*//主函数int main(){WordType word;cout<<"请输入源程序序列:";word=get_w();while(word.pro!="#")//#为自己设置的结束标志{cout<<"("<<word.code<<","<<"“"<<word.pro<<"”"<<")"<<endl;word=get_w();};return 0;}*/WordType get_w(){string str="";int code;WordType wordtmp;getch();//读一个字符getBC();//去掉空白符if(isLetter()){ //以字母开头while(isLetter()||isDigit()){str=concat(str);getch();}retract();code=Reserve(str);if(code==-1){wordtmp.code=0;wordtmp.pro=str;}//不是关键字else{wordtmp.code=code;wordtmp.pro=str;}//是关键字}else if(isDigit()){ //以数字开头while(isDigit()){str=concat(str);getch();}retract();wordtmp.code=30;wordtmp.pro=str;}else if(ch=='(') {wordtmp.code=1;wordtmp.pro="(";} else if(ch==')') {wordtmp.code=2;wordtmp.pro=")";} else if(ch=='{') {wordtmp.code=3;wordtmp.pro="{";} else if(ch=='}') {wordtmp.code=4;wordtmp.pro="}";} else if(ch==';') {wordtmp.code=5;wordtmp.pro=";";} else if(ch=='=') {wordtmp.code=6;wordtmp.pro="=";} else if(ch=='+') {wordtmp.code=7;wordtmp.pro="+";} else if(ch=='*') {wordtmp.code=8;wordtmp.pro="*";} else if(ch=='>') {wordtmp.code=9;wordtmp.pro=">";} else if(ch=='<') {wordtmp.code=10;wordtmp.pro="<";} else if(ch==',') {wordtmp.code=11;wordtmp.pro=",";} else if(ch=='\'') {wordtmp.code=12;wordtmp.pro="\'";} else if(ch=='-') {wordtmp.code=13;wordtmp.pro="-";} else if(ch=='/') {wordtmp.code=14;wordtmp.pro="/";} else if(ch=='#') {wordtmp.code=15;wordtmp.pro="#";} else if(ch=='|') {wordtmp.code=16;wordtmp.pro="|";}else {wordtmp.code=100;wordtmp.pro=ch;}return wordtmp;}void getch(){if(flag==0) //没有回退的字符ch=getchar();else //有回退字符,用回退字符,并设置标志flag=0;}void getBC(){while(ch==' '||ch=='\t'||ch=='\n')ch=getchar();}bool isLetter(){if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')return true;elsereturn false;}bool isDigit(){if(ch>='0'&&ch<='9')return true;elsereturn false;}string concat(string str){return str+ch;}void retract(){flag=1;}int Reserve(string str){int i;for(i=0;i<=8;i++){if(codestring[i]==str) //是某个关键字,返回对应的编码return codebook[i];}if(i==9) //不是关键字return -1;}【LR.cpp】#include<iostream>#include<string>#include<cstdlib>#include"cifa.h"#include"stack_num.h"#include"stack_str.h"#include"table_action.h"#include"table_go.h"using namespace std;void process(){int stepNum=1;int topStat;Stack_num statusSTK; //状态栈Stack_str symbolSTK; //符号栈Stack_num valueSTK; //值栈WordType word;Table_action actionTAB; //行为表Table_go goTAB; //转向表cout<<"请输入源程序,以#结束:";word=get_w();//总控程序初始化操作symbolSTK.push("#");statusSTK.push(0);valueSTK.push(0);cout<<"步骤\t状态栈\t符号栈\t值栈\t当前词\t动作\t转向"<<endl;//分析while(1){topStat=statusSTK.getTop(); //当前状态栈顶string act=actionTAB.getCell(topStat,word.code);//根据状态栈顶和当前单词查到的动作//输出cout<<stepNum++<<"\t";statusSTK.outStack(); cout<<"\t";symbolSTK.outStack(); cout<<"\t";valueSTK.outStack(); cout<<"\t";cout<<word.pro<<"\t";//行为为“acc”,且当前处理的单词为#,且状态栈里就两个状态//说明正常分析结束if(act=="acc"&&word.pro=="#"&&statusSTK.topNumber()==1){cout<<act<<endl;cout<<"分析成功!"<<endl;cout<<"结果为:"<<valueSTK.getTop()<<endl;return;}//读到act表里标记为错误的单元格else if(act==""){cout<<endl<<"不是文法的句子!"<<endl;cout<<"错误的位置为单词"<<word.pro<<"附近。

编译原理作业集-第五章-修订

编译原理作业集-第五章-修订

第五章语法分析—自下而上分析本章要点1. 自下而上语法分析法的基本概念:2. 算符优先分析法;3. LR分析法分析过程;4. 语法分析器自动产生工具Y ACC;5. LR分析过程中的出错处理。

本章目标掌握和理解自下而上分析的基本问题、算符优先分析、LR分析法及语法分析器的自动产生工具YACC等内容。

本章重点1.自下而上语法分析的基本概念:归约、句柄、最左素短语;2.算符优先分析方法:FirstVT, LastVT集的计算,算符优先表的构造,工作原理;3.LR分析器:(1)LR(0)项目集族,LR(1)项目集簇;(2)LR(0)、SLR、LR(1)和LALR(1)分析表的构造;(3)LR分析的基本原理,分析过程;4.LR方法如何用于二义文法;本章难点1. 句柄的概念;2. 算符优先分析法;3. LR分析器基本;作业题一、单项选择题:1. LR语法分析栈中存放的状态是识别________的DFA状态。

a. 前缀;b. 可归前缀;c. 项目;d. 句柄;2. 算符优先分析法每次都是对________进行归约:(a)句柄(b)最左素短语(c)素短语(d)简单短语3. 有文法G=({S},{a},{S→SaS,S→ε},S),该文法是________。

a. LL(1)文法;b.二义性文法;c.算符优先文法;d.SLR(1)文法;4. 在编译程序中,语法分析分为自顶向下分析和自底向上分析两类,和LL(1)分析法属于自顶向下分析;a. 深度分析法b. 宽度优先分析法c. 算符优先分析法d. 递归下降子程序分析法5. 自底向上语法分析采用分析法,常用的是自底向上语法分析有算符优先分析法和LR分析法。

a. 递归b. 回溯c. 枚举d. 移进-归约6. 一个LR(k)文法,无论k取多大,。

a. 都是无二义性的;b. 都是二义性的;c. 一部分是二义性的;d. 无法判定二义性;7. 在编译程序中,语法分析分为自顶向下分析和自底向上分析两类,和LR分析法属于自底向上分析。

编译原理第五章语法分析——自下而上分析

编译原理第五章语法分析——自下而上分析

第五章语法分析——自下而上分析要紧内容:[1]自下而上分析的大体问题[2]算符优先分析法[3]算符优先分析表和优先函数的构造[4]LR分析器的大体原理大体要求:[1]明白得自下而上分析法的大体思想[2]明白得有关归约、短语、句柄、标准归约等概念[3]把握算符优先分析法[4]了解算符优先表和优先函数的构造技术[5]了解LR 分析器大体原理和工作方式教学要点:本章介绍自下而上语法分析方式。

所谓自下而上分析法确实是从输入串开始,慢慢进行“归约”,直至归约到文法的开始符号;或说,从语法树的结尾开始,步步向上“归约”,直到根结。

讲义摘要:5.1 自下而上分析大体问题自下而上分析法的大体思想:从输入串开始,慢慢进行“归约”,直到文法的开始符号。

即从树结尾开始,构造语法树。

所谓归约,是指依照文法的产生式规那么,把产生式的右部替换成左部符号。

自上而下分析的核心问题是:如何判定符号串的可归约性,和如何归约。

即,识别可归约串的问题。

归约自下而上分析法事实上确实是一种“移进-归约”法,即,采纳“移进-归约”思想进行。

实现思想是:对输入符号串自左向右进行扫描,并将输入符逐个移入一个后进先出栈中,边移入边分析,一旦栈顶符号串形成某个句型的句柄时,(该句型对应某产生式的右部,即栈顶生成了某产生式的右部的文法符号串),就将栈顶的这一部份替换成 (归约为) 该产生式的左部符号,这称为归约。

重复这一进程直到归约到栈中只剩文法的开始符号时那么为分析成功,也就确认输入串是文法的句子。

现举例说明。

例1:设文法G[S]为:(1) S→aAcBe(2) A→b(3) A→Ab(4) B→d试对abbcde进行“移进-归约”分析。

步骤: 1 2 3 4 5 6 7 8 9 10解:动作: 进a 进b 归(2) 进b 归(3) 进c 进d 归(4) 进e 归(1)表1符合栈的转变进程自下而上语法分析的进程也可看成自底向上构造语法树的进程,每步归约都是构造一棵子树,最后当输入串终止时恰好构造出整个语法树,如图1所示。

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

编译原理
长春工业大学计算机科学与工程学院
LR分析表的构成
状 态 动作表ACTION a1 a2 … # 状态转换表GOTO X1 X2 … Xk
S1 S2
. . .
Sn
编译原理
长春工业大学计算机科学与工程学院
分析表的动作部分:ACTION[Si,aj]表示当
分析状态栈的栈顶为Si,输入符号为aj时应执 行的动作; 表中GOTO[Si,Xj]指出栈顶状态为Si,碰到文 法符号为Xj时应转到的下一状态; 动作有下列四种: 移进(Sn),归约(R),接受(A),报错(E)
编译原理
长春工业大学计算机科学与工程学院

后继符号有多种,据此将项目分为多种:
后继符号为终结符: Aα·aβ, 称为移进项目; 后继符号为非终结符:Aα·Bβ, 称为待约项目; 后继符号为空:即圆点在最右边Aα·, 称为归约项目; 归约项目的左边是文法的开始符号Sα· , 称为接受项目。

编译原理
长春工业大学计算机科学与工程学院
有文法G∶E→T|E+T|E-T, T→i|(E), 找规范句型E+(i-i)的活前缀和 可归前缀。 解:首先画出E+(i-i)的语法树 可找出第一个i是句柄,那么 λβ=E+(i ,t=-i) 因此活前缀为:E,E+,E+(, E+(i,其中E+(i是可归前缀。
长春工业大学计算机科学与工程学院
LR(0) 项目集规范族的说明
如果LR(0) 项目集规范族中的每个项目集看 做FA一个状态,则项目集规范族的GO函数 把这些项目集连接成一个DFA。 令I0(CLOSURE({S’→.S}))为DFA的初态,则该 DFA就是恰好识别文法所有活前缀的有限自 动机。 结论:对于任一文法G,关于该文法的LR(0) 项目集规范族的GO函数定义了一个识别文法 所有活前缀的DFA。
编译原理
长春工业大学计算机科学与工程学院
活前缀与有效项目的关系
同一项目可能对多个活前缀是有效的 对同一活前缀,可能存在多个有效项目

编译原理
长春工业大学计算机科学与工程学院
活前缀有效项目的结论
一个活前缀w的有效项目集,正是由识别文 法所有活前缀的DFA的初态出发,经由标记 为w的路径所到达的那个项目集。 语法分析过程中,栈中的活前缀的有效项目 集就是栈顶的状态所代表的那个项目集。

后继符号集:项目集中各项目的后继符号所组成的 集合称为后继符号集。 例如:项目集{ E E · +T , F ·i }的后继符 号集为{+,i}
编译原理
长春工业大学计算机科学与工程学院

可以由文法的所有LR(0)项目,构造识别文法 所有活前缀的FA。在此构造过程中,需要对 文法进行拓广,并利用CLOSURE函数和GO 函数。
编译原理
长春工业大学计算机科学与工程学院
LR(0) 项目集规范族构造算法
ITEMSETS(G’); { C={CLOSURE({S’→.S})}; 重复以下操作: 对C中每个项目I和I中每个紧接“.”的文法符号 x If GO(I,x)非空且不属于C then 将GO(I,x)加到C 直到 C不再增大; }
E
E
+

T
E )
E
T i
-
T
i
编译原理
长春工业大学计算机科学与工程学院




活前缀意味着,当前还未形成句柄,或刚刚形成句 柄。 在活前缀的右边添上一些终结符号后,总可以构成 一个规范句型。 LR识别过程中,栈里面的符号就是一个活前缀。栈 里面的符号添加上适当的终结符号串就可以得到一 个句型。 在任何时候,只要输入串已扫描过的部分能构成一 个活前缀,则意味着所扫描过的这一部分没有错误。
• 一个LR分析器由3个部分组成:
编译原理
长春工业大学计算机科学与工程学院
总控程序根据分析表的内容来决定其下一步 的处理动作,分析表是根据具体的文法按某 种规则构造出来的。 LR方法:根据具体文法的分析表对输入串进 行分析处理。 LR分析过程:在总控程序的控制下,从左到 右扫描输入符号串,根据分析栈中的状态和 当前输入符号,按分析表中的内容完成相应 的分析工作。
编译原理
长春工业大学计算机科ห้องสมุดไป่ตู้与工程学院
项目集I的闭包CLOSURE(I)

设I是文法G的任一项目集,则定义和构造 CLOSURE(I)的规则如下:
① 属于I的任何项目也属于CLOSURE(I); ② 若A → α .Bβ 属于CLOSURE(I),那么,对于 任何关于B的产生式B→γ ,项目B→ .γ 也属于 CLOSURE(I); ③ 重复执行以上两步,直到CLOSURE(I)不再增大 为止。
编译原理
长春工业大学计算机科学与工程学院
GO(I,X)函数
用于定义项目集之间的转换。 定义:设I是一个项目集,X是任一文法符,则 GO(I,X)定义为:

GO(I,X)=CLOSURE(J), 其中J={任何具有[A → αX.β]的项目| [A → α.Xβ]
∈I}
I:A→α·Xβ
X
J: A→αX·β
编译原理 文法符号: X1X2…Xm是目前 已移进并归约出的句型部分。 其实它是多余的,已经概括到 状态里。
长春工业大学计算机科学与工程学院
状态栈:(S0,#)为预先放到 栈中的初始状态和符号。
分析器实际上是一个带有先进后出栈的确定的有穷自动机。将 • LR分析程序,又称总控程序。所有的LR分析器都是相同的。 “历史”和“展望”综合成“状态”,分析栈用来存放状态, 状态概括了从分析开始直到某一归约阶段的全部历史和展望资 • 分析表(分析函数),不同的文法分析表不同,同一个文法采用的LR分 析器不同时,分析表也不同,分析表又可分为动作表 (ACTION) 和状 料,不必象算符优先分析法中要翻阅栈中的内容才能决定是否 态转换(GOTO)表两个部分,它们都可用二维数组表示。 要进行归约。只需根据栈顶状态和输入符号就可以唯一决定下 一个动作。 • 分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
2 3
02 023
#( #(a
a)# )#
S3 R2
4 5
024 0245
#(A #(A)
)# #
S5 R1
6
01
#A
# ACCEPT
编译原理
长春工业大学计算机科学与工程学院
LR文法:对一个文法,如果能够构造一个分 析表,且它的每个入口均是唯一的 如何构造LR分析表?

编译原理
长春工业大学计算机科学与工程学院
编译原理
开始
长春工业大学计算机科学与工程学院
初始状态0和#入栈 读符号 根据栈顶状态和输入符号 查分析动作表 Y 归约 ? N
按产生式i归约 根据产生式i的右部符 号的个数,符号栈和 状态栈相应元素出栈 产生式i的左部 符号入栈 查状态转换表 新状态入状态栈
移进 ?
Y
N 接受 ? Y 分析结束 N
编译原理
长春工业大学计算机科学与工程学院
项目集闭包的例子
文法: 0. E ’→E 3. T→T*F 6. F→i 1. E→E+T 4. T→F 2. E→T 5. F→(E) I={[E ’ →.E]} CLOSURE(I)还包含以下项: [E→.E+T] [E→.T] [T→.T*F] [T→.F] [F →.i] [F →.(E)]
输入符号入符号栈
状态i入状态栈
错误
读符号
LR的分析流程
编译原理
长春工业大学计算机科学与工程学院
利用分析表分析符号串 (a)
步骤 状态栈 符号栈 输入串 1 0 # (a)# ACTION S2 GOTO 说明 开始时,0入状态栈,#入符号栈,输 入符号为(,查动作表0行(列为S2,2 入状态栈,(入符号栈。 输入符号为a,查动作表2行a列为S3, 3入状态栈,a入符号栈。 4 输入符号为),查动作表3行)列为R2, 用A→a 归约,a 出符号栈、A入符号 栈,3出状态栈、2为栈顶,查GOTO 表2行A列得4,4入状态栈。 输入符号为),查动作表4行)列为S5, 5入状态栈,)入符号栈。 1 输入符号为#,查动作表5行#列为R1, 用A→(A) 归约,(A)出符号栈、A入 符号栈,245出状态栈、0为栈顶,查 GOTO表0行A列得1,1入状态栈。 输入符号为#,查动作表1行#列为 ACCEPT,接受。

编译原理
长春工业大学计算机科学与工程学院
LR(0)项目

A → xyz的LR(0)项目: A → .xyz A → x.yz A → xy.z A → xyz.

项目集:若干个项目组成的集合称为项目集。 例 如:对于上述产生式的4个项目即构成一个项目集。 后继符号:在项目中紧跟在符号“·”后面的符号称 为该项目的后继符号。 后继符号表示下一时刻读 到的符号。
编译原理
长春工业大学计算机科学与工程学院
LR(0) 项目集规范族定义

定义:构成识别一个文法活前缀的DFA的项 目集(状态)的全体称为这个文法的LR(0) 项目集规范族。
编译原理
长春工业大学计算机科学与工程学院
文法G的拓广文法

文法G[S]的拓广文法:
G’[S’]=G[S]+{S’ → S}

拓广的原因:使得语法分析有唯一的“接受” 项目:S’ → S.
编译原理
长春工业大学计算机科学与工程学院
LR分析器的关键就是构造分析表。文法G: 0)S→A,1)A→(A),2)A→a 的分析表: 状态
( 0 1 2 3 4 5 R1 S2 R2 R2 S5 R1 R1 R1 S3 R2 R2 S2 ) ACTION a S3 ACCEPT 4 # GOTO A 1
相关文档
最新文档