c实现消除文法左递归
编译原理题——简答题
编译原理A1.简要说明语义分析的基本功能。
2. 考虑文法 G[S]:S → (T) | a+S | aT → T,S | S消除文法的左递归及提取公共左因子。
3试为表达式 w+(a+b)*(c+d/(e-10)+8) 写出相应的逆波兰表示。
4. 按照三种基本控制结构文法将下面的语句翻译成四元式序列:while (A<C ∧ B<D){if (A ≥ 1) C=C+1;else while (A ≤ D)A=A+2;}。
5. 已知文法 G[S] 为S → aSb|Sb|b,试证明文法 G[S] 为二义文法。
A答案1答:语义分析的基本功能包括: 确定类型、类型检查、语义处理和某些静态语义检查。
2解:消除文法G[S]的左递归:S→(T) | a+S | aT→ST′T′→,ST′| ε提取公共左因子:S→(T) | aS′S′→+S | εT→ST′T′→,ST′| ε3答:w a b + c d e 10 - / + 8 + * +4答:该语句的四元式序列如下(其中E1、E2和E3分别对应A<C∧B<D、A≥1和A≤D,并且关系运算符优先级高):100 (j<,A,C,102)101 (j,_,_,113)102 (j<,B,D,104)103 (j,_,_,113)104 (j=,A,1,106)105 (j,_,_,108)106 (+, C, 1, C)107 (j,_,_,112)108 (j≤,A,D,110) 109 (j,_,_,112)110 (+, A, 2, A)111 (j,_,_,108)112 (j,_,_,100)1135答:证明:由文法G[S]:S→aSb|Sb|b,对句子aabbbb对应的两棵语法树为:因此,文法G[S]为二义文法。
编译原理B1.什么是句子?什么是语言 ?2. 写一文法,使其语言是偶正整数的集合,要求:(1)允许0打头;(2) 不允许0打头。
c语言的递归
c语言的递归递归,作为一种编程技巧和思维方式,是计算机科学中一个重要的概念。
在C语言中,递归可以被广泛应用于各种算法和问题的解决过程中。
本文将介绍C语言中递归的基本原理、优缺点以及一些常见的递归应用场景。
一、递归的基本原理递归是指在一个函数的定义中调用函数本身的过程。
在C语言中,递归函数的定义通常包括两个部分:基准情况(base case)和递归情况(recursive case)。
基准情况是指满足特定条件时递归停止,递归情况则是通过不断调用函数本身来实现问题的拆解和解决。
下面是一个简单的例子,演示了如何使用递归来实现计算n的阶乘:```cint factorial(int n) {// 基准情况if (n == 0 || n == 1) {return 1;}// 递归情况return n * factorial(n - 1);}int main() {int n = 5;int result = factorial(n);printf("%d的阶乘是:%d\n", n, result);return 0;}```在上面的代码中,当n等于0或者1时,递归停止,返回结果1。
否则,函数将n与factorial(n-1)相乘,并返回结果。
通过逐步拆解n的值,直到满足基准情况,递归函数可以完成阶乘的计算。
二、递归的优缺点递归在解决某些问题时可以提供简洁、优雅的解决方案,但同时也存在一些缺点。
1. 优点:简洁清晰:递归能够将问题分解为更小的子问题,代码结构更加清晰易懂。
解决复杂问题:某些问题如果采用迭代的方式来解决会非常复杂,而递归提供了一种更加直观的解决思路。
2. 缺点:性能开销:递归往往需要调用函数本身多次,会产生额外的函数调用开销,导致性能下降。
内存占用:递归的过程中需要保存每一次函数调用的上下文,可能会导致内存占用较大。
三、递归的应用场景递归可以用于解决一些常见的问题和算法,比如树的遍历、图的搜索、排列组合等。
编译原理实验二:消除文法的左递归.doc
编译原理实验报告实验名称消除文法的左递归实验时间2013年11月12日院系计算机科学与电子技术系班级11计算机软件学号JV114001 JV114095 JP114065 姓名唐茹韩强强徐思维1.试验目的:输入:任意的上下文无关文法。
输出:消除了左递归的等价文法。
2.实验原理:1.直接左递归的消除消除产生式中的直接左递归是比较容易的。
例如假设非终结符P 的规则为:P →P α / β其中,β是不以P 开头的符号串。
那么,我们可以把P 的规则改写为如下的非直接左递归形式: P →βP ’P ’→αP ’ / ε这两条规则和原来的规则是等价的,即两种形式从P 推出的符号串是相同的。
设有简单表达式文法G[E]: E →E+T/ T T →T*F/ F F →(E )/ I经消除直接左递归后得到如下文法: E →TE ’E ’ →+TE ’/ ε T →FT ’T ’ →*FT ’/ εF →(E )/ I考虑更一般的情况,假定关于非终结符P 的规则为P →P α1 / P α2 /…/ P αn / β1 / β2 /…/βm其中,αi (I =1,2,…,n )都不为ε,而每个βj (j =1,2,…,m )都不以P 开头,将上述规则改写为如下形式即可消除P 的直接左递归:P →β1 P ’ / β2 P ’ /…/βm P ’P ’ →α1P ’ / α2 P ’ /…/ αn P ’ /ε 2.间接左递归的消除直接左递归见诸于表面,利用以上的方法可以很容易将其消除,即把直接左递归改写成直接右递归。
然而文法表面上不存在左递归并不意味着该文法就不存在左递归了。
有些文法虽然表面上不存在左递归,但却隐藏着左递归。
例如,设有文法G[S]:S →Qc/ c Q →Rb/ b R →Sa/ a虽不具有左递归,但S 、Q 、R 都是左递归的,因为经过若干次推导有 S ⇒Qc ⇒Rbc ⇒SabcQ ⇒Rb ⇒Sab ⇒Qcab R ⇒Sa ⇒Qca ⇒Rbca就显现出其左递归性了,这就是间接左递归文法。
第三章习题解答
第三章 语法分析
对产生式V′→ε |[E] 有:FIRST(ε)∩FIRST(‘[’]= Φ; FIRST(‘[’)∩FOLLOW(V′)={[}∩{#,+,]}=Φ;
对E′→ε | +E 有:FIRST(ε)∩FIRST(‘+’)= Φ; FIRST(‘+’)∩FOLLOW(E′)={+}∩{ ] }=Φ。 故文法G[V′]为LL(1)文法。
第三章 语法分析 表3-12 习题3.24的SLR(1)分析表
状态
ACTION
GOTO
b
d
i
#
T
E
H
0
r3
s3
1
2
1
acc
2
s4
3
r2
4
r6
s6
r6
5
5
s7
r1
6
r4
r4
7
s8
8
r5
r5
第三章 语法分析
序号 状态栈 符号栈 产生式 输入串
10
#
E→ε bibi# 归约 r3
2 02
#E
bibi# 移进
第三章 语法分析
表3-8 优先关系表
a
b
c
a
⋖⋗
⋖≡
⋗
b
⋖
⋖⋗
≡
c
⋗
⋗
由于表中的优先关系不唯一,故文法G[S]不是算符优 先文法。
第三章 语法分析 (4) 消除文法G[S]的左递归: S→aSb | P P→bPc | bQc Q→aQ′ Q′→aQ′| ε 提取公共左因子后得到文法G′[S]: S→aSb | P P→bP′ P′→Pc | Qc Q→aQ′ Q′→aQ′| ε
编译原理教程课后习题答案——第三章
第三章语法分析3.1 完成下列选择题:(1) 文法G:S→xSx|y所识别的语言是。
a. xyxb. (xyx)*c. xnyxn(n≥0)d. x*yx*(2) 如果文法G是无二义的,则它的任何句子α。
a. 最左推导和最右推导对应的语法树必定相同b. 最左推导和最右推导对应的语法树可能不同c. 最左推导和最右推导必定相同d. 可能存在两个不同的最左推导,但它们对应的语法树相同(3) 采用自上而下分析,必须。
a. 消除左递 a. 必有ac归b. 消除右递归c. 消除回溯d. 提取公共左因子(4) 设a、b、c是文法的终结符,且满足优先关系ab和bc,则。
b. 必有cac. 必有bad. a~c都不一定成立(5) 在规范归约中,用来刻画可归约串。
a. 直接短语b. 句柄c. 最左素短语d. 素短语(6) 若a为终结符,则A→α·aβ为项目。
a. 归约b. 移进c. 接受d. 待约(7) 若项目集Ik含有A→α· ,则在状态k时,仅当面临的输入符号a∈FOLLOW(A)时,才采取“A→α· ”动作的一定是。
a. LALR文法b. LR(0)文法c. LR(1)文法d. SLR(1)文法(8) 同心集合并有可能产生新的冲突。
a. 归约b. “移进”/“移进”c.“移进”/“归约”d. “归约”/“归约”【解答】(1) c (2) a (3) c (4) d (5) b (6) b (7) d (8) d3.2 令文法G[N]为G[N]: N→D|NDD→0|1|2|3|4|5|6|7|8|9(1) G[N]的语言L(G[N])是什么?(2) 给出句子0127、34和568的最左推导和最右推导。
【解答】(1) G[N]的语言L(G[N])是非负整数。
(2) 最左推导:NNDNDDNDDDDDDD0DDD01DD012D0127NNDDD3D34NNDNDDDDD5DD56D568最右推导:NNDN7ND7N27ND27N127D1270127NNDN4D434NNDN8ND8N68D685683.3 已知文法G[S]为S→aSb|Sb|b,试证明文法G[S]为二义文法。
消除左递归
直接消除左递归方法:
回溯:分析工作要部分地或全部地退回去重做。
条件:在文法中,对于某个非终结符地规则是其右部有多个选择,并且根据所面临地输入符号不能准确地确定所要地选择时,就可能出现回溯.
回溯带来地问题:
严重地影响了效率,只有在理论地层面上地意义而没有实际地意义。
影响效率地原因:1)语法分析需要重做;2)语义处理工作要倒退重新来做;3)当一个非终结符用某一后选式匹配成功是,这种成功可能仅仅是暂时的;4)当最终报告分析不成功时,难以知道输入串出错地准确位置;5)穷尽试探法,效率低下,代价之高。
假定P关于的全部产生式是
P→Pα1| Pα2|…| Pαm| β 1| β 2 |… | βn
其中,每个α都不等于ε,而每个β都不以P开头,
那么消除P地直接左递归就是把这个规则改写成:
P→ | β 1 P’| β 2 P’|…| β n P’
P’ →α1P’| α2P’| …| αmP’| ε
例4.2消去以下文法的直接左递归。
E→E+T|T
T→T*F|F
F→(E)|i
解:
E →TE´
E ´→+TE´|ε
T →FT´
T´→*FT´|ε
F→(E)|i
练习1]:
已知G[E]:
E→T*F | T/F | F
T →F | T*F | T/F
请消除该文法的左递归。
c语言递归算法
c语言递归算法C语言递归算法递归算法是一种基于函数调用的编程方法,即一个函数在执行过程中调用自身,以此实现循环的效果。
C语言中递归函数的应用范围很广,可以帮助我们简化代码结构,提高代码复用率和可读性。
在接下来的文章中,将会详细介绍C语言中递归算法的原理和应用。
1.递归算法的基本原理递归算法的原理非常简单,即一个函数在执行过程中,调用自身直到达到某个结束条件。
换句话说,递归算法就是把一个大问题不断地分成小问题,直到小问题可以轻松解决的时候,再逐层返回最终结果。
2.递归算法的应用2.1.阶乘问题递归算法最经典的应用场景之一就是求阶乘。
阶乘的定义是从1乘到给定的数字n,所以我们可以使用递归函数来求解阶乘问题。
即,如果n等于1,则阶乘就是1;否则阶乘为n乘以n-1的阶乘。
代码如下:```cint factorial(int n){if (n == 1)return 1;elsereturn n * factorial(n-1);}```2.2.斐波那契数列斐波那契数列是另一个非常经典的递归算法实现问题。
斐波那契数列的定义是,前两个数都是1,之后的每一个数都是前两个数的和。
以下是斐波那契数列的递归函数的实现:```cint fibonacci(int n){if (n <= 1)return n;elsereturn fibonacci(n-1) + fibonacci(n-2);}```2.3.越界问题递归函数存在一个重要的问题就是越界问题。
如果递归函数的调用层数过多,会容易就会导致栈内存溢出,从而导致程序崩溃。
为了防止这种情况的发生,我们可以使用迭代方法来提高程序的效率和稳定性。
```cint fibonacci(int n){int result[100];result[0] = 1;result[1] = 1;for(int i=2; i<=n; i++)result[i] = result[i-1] + result[i-2];return result[n-1];}```3.总结本文详细介绍了C语言中递归算法的实现原理和应用场景,从阶乘问题到斐波那契数列,每一个问题都展示了递归算法的优点和缺点,以及如何提高程序的效率和稳定性。
编译原理实验二:消除文法的左递归说课讲解
编译原理实验报告实验名称消除文法的左递归实验时间2013年11月12日院系计算机科学与电子技术系班级11计算机软件学号JV114001 JV114095 JP114065 姓名唐茹韩强强徐思维1.试验目的:输入:任意的上下文无关文法。
输出:消除了左递归的等价文法。
2.实验原理:1.直接左递归的消除消除产生式中的直接左递归是比较容易的。
例如假设非终结符P 的规则为:P →P α / β其中,β是不以P 开头的符号串。
那么,我们可以把P 的规则改写为如下的非直接左递归形式: P →βP ’P ’→αP ’ / ε这两条规则和原来的规则是等价的,即两种形式从P 推出的符号串是相同的。
设有简单表达式文法G[E]: E →E+T/ T T →T*F/ F F →(E )/ I经消除直接左递归后得到如下文法: E →TE ’E ’ →+TE ’/ ε T →FT ’T ’ →*FT ’/ εF →(E )/ I考虑更一般的情况,假定关于非终结符P 的规则为P →P α1 / P α2 /…/ P αn / β1 / β2 /…/βm其中,αi (I =1,2,…,n )都不为ε,而每个βj (j =1,2,…,m )都不以P 开头,将上述规则改写为如下形式即可消除P 的直接左递归:P →β1 P ’ / β2 P ’ /…/βm P ’P ’ →α1P ’ / α2 P ’ /…/ αn P ’ /ε 2.间接左递归的消除直接左递归见诸于表面,利用以上的方法可以很容易将其消除,即把直接左递归改写成直接右递归。
然而文法表面上不存在左递归并不意味着该文法就不存在左递归了。
有些文法虽然表面上不存在左递归,但却隐藏着左递归。
例如,设有文法G[S]:S →Qc/ c Q →Rb/ b R →Sa/ a虽不具有左递归,但S 、Q 、R 都是左递归的,因为经过若干次推导有 S ⇒Qc ⇒Rbc ⇒SabcQ ⇒Rb ⇒Sab ⇒Qcab R ⇒Sa ⇒Qca ⇒Rbca就显现出其左递归性了,这就是间接左递归文法。
编译原理 第5章习题解答
第五章习题解答5.1 设一NDPDA识别由下述CFG定义的语言,试给出这个NDPDA的完整形式描述。
S→SASCS→εA→AaA→bC→DcDD→d5.2 消除下列文法的左递归:① G[A]:A→BX∣CZ∣WB→Ab∣BcC→Ax∣By∣Cp② G[E]:E→ET+∣ET–∣TT→TF*∣TF/FF→(E)∣i③ G[X]:X→Ya∣Zb∣cY→ Zd∣Xe∣fZ→X e∣Yf∣a④ G[A]:A→Ba|Aa|cB→Bb|Ab|d5.3 设文法G[<语句>]:<语句>→<变量>: = <表达式>|if<表达式>then<语句>|if<表达式>then<语句>else<语句> <变量>→i<表达式>→<项>|<表达式>+<项><项>→<因子>|<项>*<因子><因子>→<变量>|′(′<表达式>′)′试构造该文法的递归下降子程序。
5.4 设文法G[E]:E→ TE'E'→ + E∣εT→ FT'T'→ T∣εF→ PF'F'→ *F∣εP→ (E)∣ a∣^①构造该文法的递归下降分析程序;②求该文法的每一个非终结符的FIRST集合和FOLLOW集合;③构造该文法的LL(1)分析表,并判断此文法是否为LL(1)文法。
5.5 设文法G[S]:S→ SbA∣aAB→ SbA→ Bc①将此文法改写为LL(1)文法;②求文法的每一个非终结符的FIRST集合和FOLLOW集合;③构造相应的LL(1)分析表。
5.6 设文法G[S]:S→ aABbcd∣εA→ ASd∣εB→ SAh∣eC∣εC→ Sf∣Cg∣εD→ aBD∣ε①求每一个非终结符的FOLLOW集合;②对每一个非终结符的产生式选择,构造FIRST集合;③该文法是LL(1)文法。
文法类型-消除左递归.doc
Chomsky文法类型判断消除文法的左递归年级___________专业___________学号___________姓名___________1. 实验目的要求:输入:一组任意的规则。
输出:相应的Chomsky 文法的类型。
2.实验原理1.0型文法(短语文法)如果对于某文法G,P中的每个规则具有下列形式:u:: = v其中u∈V+,v∈V*,则称该文法G为0型文法或短语文法,简写为PSG。
0型文法或短语结构文法的相应语言称为0型语言或短语结构语言L0。
这种文法由于没有其他任何限制,因此0型文法也称为无限制文法,其相应的语言称为无限制性语言。
任何0型语言都是递归可枚举的,故0型语言又称递归可枚举集。
这种语言可由图灵机(Turning)来识别。
2.1型文法(上下文有关文法)如果对于某文法G,P中的每个规则具有下列形式:xUy:: = xuy其中U∈V N;u∈V+;x,y∈V*,则称该文法G为1型文法或上下文有关文法,也称上下文敏感文法,简写为CSG。
1型文法的规则左部的U和右部的u具有相同的上文x和下文y,利用该规则进行推导时,要用u替换U,必须在前面有x和后面有y的情况下才能进行,显示了上下文有关的特性。
1型文法所确定的语言为1型语言L1,1型语言可由线性有界自动机来识别。
3.2型文法(上下文无关文法)如果对于某文法G,P中的每个规则具有下列形式:U :: = u其中U∈V N;u∈V+,则称该文法G为2型文法或上下文无关文法,简写为CFG。
按照这条规则,对于上下文无关文法,利用该规则进行推导时,无需考虑非终结符U所在的上下文,总能用u替换U,或者将u归约为U,显示了上下文无关的特点。
2型文法所确定的语言为2型语言L2,2型语言可由非确定的下推自动机来识别。
一般定义程序设计语言的文法是上下文无关的。
如C语言便是如此。
因此,上下文无关文法及相应语言引起了人们较大的兴趣与重视。
4.3型文法(正则文法,线性文法)如果对于某文法G,P中的每个规则具有下列形式:U :: = T 或 U :: = WT其中T∈V T;U,W∈V N,则称该文法G为左线性文法。
消除左递归的算法
消除左递归的算法
在编译原理中,左递归是一种常见的文法问题。
左递归指的是产生式规则中,右侧的符号可以通过一个或多个相同的非终结符号推导出自身。
例如,下面的产生式规则就存在左递归:
A -> A
B | C
为了消除左递归,需要进行一定的转换。
具体来说,可以采用以下步骤:
1. 将所有的左递归规则拆分为非左递归规则。
对于上述例子,可以得到以下规则:
A -> C A'
A' -> B A' | ε
2. 将新的规则加入到文法中。
需要注意的是,新规则的非终结符号应该是原规则的非终结符号加上一个后缀。
在上述例子中,加上的后缀是A'。
3. 消除原规则中的左递归。
具体来说,需要将原规则中的左递归部分替换成新规则。
在上述例子中,需要将A -> A B替换成A ->
C A'。
4. 最后,需要在新规则中添加一个ε产生式作为结尾。
在上述例子中,需要在A' -> B A'后添加一个A' -> ε。
通过上述步骤,可以消除文法中的左递归,使得编译器能够更好地处理该文法。
- 1 -。
上下文无关文法规约技巧
上下文无关文法规约技巧1. 使用左递归消除左递归问题:如果某个产生式的右部以同一个非终结符开头,并且它的右部不能推导出一个空串,则可以使用左递归消除技巧来转换该产生式。
例如,假设有一个文法规则 A -> Aα | β,其中α和β是任意的终结符和非终结符序列。
为了消除左递归,可以将该规则修改为 A -> βA',A' -> αA' | ε,其中A'是一个新的非终结符。
2. 提取公因子:如果某个非终结符的多个产生式的右部具有相同的前缀,可以使用公因子提取技巧来将这个前缀提取出来,并创建一个新的非终结符来表示这个公因子。
例如,假设有一个文法规则 A -> αβ | αγ,其中α是一个非终结符或终结符,而β和γ是任意的终结符和非终结符序列。
为了提取公因子,可以将该规则修改为 A -> αA',A' -> β | γ。
3. 消除无用的产生式和非终结符:如果某个产生式或非终结符无法通过其他产生式推导出来,或者某个非终结符无法由起始符号推导出来,则可以将其视为无用的,可以通过删除这些无用的产生式和非终结符来简化文法。
4. 消除多余的终结符:如果某个终结符在文法的其他部分没有出现过,则可以认为它是多余的,可以通过删除这个多余的终结符来简化文法。
5. 利用语义动作将一些语义信息引入到文法中:语义动作可以在语法分析过程中执行一些特定的操作,例如计算表达式的值或生成中间代码。
通过引入适当的语义动作,可以将语义信息引入到文法中,从而使文法更加强大和灵活。
这些技巧可以应用于上下文无关文法的规约过程,以使文法更加简洁、可读性更强,并消除一些潜在的歧义。
然而,对于复杂的文法,可能需要多种技巧的组合来进行规约。
消除左递归例题
消除左递归例题
左递归是编译原理中语法分析部分的一个概念,它指的是某个非终结符A通过自身直接或间接的左递归定义产生式的规则。
消除左递归是为了简化语法分析,提高解析效率。
下面以一个简单的算术表达式为例来说明如何消除左递归:
原始的带有左递归的文法:
E -> E + T | T
T -> T * F | F
F -> (E) | id
这个文法中,E到自身的转换就构成了左递归。
消除左递归后的文法:
E -> TE'
E' -> + TE' | ε
T -> FT'
T' -> * FT' | ε
F -> (E) | id
解释一下这个变换过程:
1. 对于E,我们引入一个新的非终结符E',并将原产生式转换为`E -> TE'`和`E' -> + TE' | ε`,这里的ε表示空串,即加号后面可以没有E。
2. 同理,对于T也引入T',并将原产生式转换为`T -> FT'`和`T' -> * FT' | ε`。
这样,新的文法就没有了左递归,同时保持了原语义不变,能够描述同样的算术表达式结构。
python实现文法左递归的消除方法
python实现⽂法左递归的消除⽅法前⾔继词法分析后,⼜来到语法分析范畴。
完成语法分析需要解决⼏个⼦问题,今天就完成⽂法左递归的消除。
没借鉴任何博客,完全⾃⼰造轮⼦。
开始之前⽂法左递归消除程序的核⼼是对字符串的处理,输⼊的产⽣式作为字符串,对它的拆分、替换与合并操作贯穿始终,处理过程的逻辑和思路稍有错漏便会漏洞百出。
采⽤直接改写法,不理解左递归消除⽅法很难读懂代码。
要求CFG⽂法判断左递归的类型消除直接左递归和间接左递归界⾯源码import osimport tkinter as tkimport tkinter.messageboximport tkinter.font as tfzhuizhong = ""wenfa = {"⾮左递归⽂法"}xi_ = ""huo = ""window = ()window.title('消除左递归')window.minsize(500,500)#转换坐标显⽰形式为元组def getIndex(text, pos):return tuple(map(int, str.split(text.index(pos), ".")))def zhijie(x,y):if not len(y):passelse:if x == y[0]:wenfa.discard("⾮左递归⽂法")#处理直接左递归zuobian = y.split('|')feizhongjie = []zhongjie = []for item in zuobian:if x in item:item = item[1:]textt = str(item) + str(x) + "'"feizhongjie.append(textt)else:text = str(item) + str(x) + "'"zhongjie.append(text)if not zhongjie:#处理A -> Ax的情况zhongjie.append(str(x + "'"))cheng = str(x) + " -> " + "|".join(zhongjie)zi = str(x) + "'" + " -> " + "|".join(feizhongjie) + "|є"text_output.insert('insert','直接左递归⽂法','tag1')text_output.insert('insert','\n')text_output.insert('insert',cheng,'tag2')text_output.insert('insert','\n')text_output.insert('insert',zi,'tag2')'''加上会判断输出⾮递归产⽣式,但会导致间接左递归不能删除多余产⽣式else:h ="不变: " + x + " -> " + ytext_output.insert('insert','⾮左递归⽂法','tag1')text_output.insert('insert','\n')text_output.insert('insert',h,'tag2')'''text_output.insert('insert','\n')def zhijie2(x,y):if not len(y):passelse:if x == y[0]:wenfa.discard("⾮左递归⽂法")#处理直接左递归zuobian = y.split('|')feizhongjie = []zhongjie = []for item in zuobian:if x in item:item = item[1:]textt = str(item) + str(x) + "'"feizhongjie.append(textt)else:text = str(item) + str(x) + "'"zhongjie.append(text)cheng = str(x) + " -> " + "|".join(zhongjie)zi = str(x) + "'" + " -> " + "|".join(feizhongjie) + "|є"text_output.insert('insert',"间接左递归⽂法",'tag1')text_output.insert('insert','\n')text_output.insert('insert',cheng,'tag2')text_output.insert('insert','\n')text_output.insert('insert',zi,'tag2')text_output.insert('insert','\n')def tihuan(xk,yi,yk):yi_you = []yi_wu =[]yi_he = ""yi_wuhe = ""yi_zhong = ""yi_feizhong = []if xk in yi:yk_replace = yk.split('|')yi_fenjie = yi.split('|')#将含⾮终结与不含分开for ba in yi_fenjie:if xk in ba:yi_you.append(ba)else:yi_wu.append(ba)yi_he = "|".join(yi_you)for item in yk_replace:yi_zhong = yi_he.replace(xk,item)#替换yi_feizhong.append(yi_zhong)yi_wuhe = "|".join(yi_wu)#再合并global zhuizhongzhuizhong = "|".join(yi_feizhong) + "|" + yi_wuhe#点击按钮后执⾏的函数def changeString():text_output.delete('1.0','end')text = text_input.get('1.0','end')text_list = list(text.split('\n'))#⼀⾏⼀⾏的拿⽂法text_list.pop()if not text_list[0]:print(tkinter.messagebox.showerror(title = '出错了!',message='输⼊不能为空')) else:for cfg in text_list:x,y = cfg.split('->')#将⽂法左右分开x = ''.join(x.split())#消除空格y = ''.join(y.split())if not (len(x) == 1 and x >= 'A' and x <= 'Z'):pos = text_input.search(x, '1.0', stopindex="end")result = tkinter.messagebox.showerror(title = '出错了!',message='⾮上下⽂⽆关⽂法!坐标%s'%(getIndex(text_input, pos),))# 返回值为:okprint(result)return 0else:zhijie(x,y)for i in range(len(text_list)):for k in range(i):xi,yi = text_list[i].split('->')xi = ''.join(xi.split())#消除空格yi = ''.join(yi.split())xk,yk = text_list[k].split('->')xk = ''.join(xk.split())#消除空格yk = ''.join(yk.split())tihuan(xk,yi,yk)tihuan(xk,zhuizhong,yk)global xi_xi_ = xizhijie2(xi_,zhuizhong)for item in wenfa:text_output.insert('insert',item,'tag1')#创建⽂本输⼊框和按钮text_input = tk.Text(window, width=80, height=16)text_output = tk.Text(window, width=80, height=20)#简单样式ft = tf.Font(family='微软雅⿊',size=12)text_output.tag_config("tag1",background="yellow",foreground="red",font=ft)text_output.tag_config('tag2',font = ft)#按钮button = tk.Button(window,text="消除左递归",command=changeString,padx=32,pady=4,bd=4) text_input.pack()text_output.pack()button.pack()window.mainloop()是不是很难懂,看看半吊⼦流程图主要流程直接左递归间接左递归合并运⾏截图总结(1)确定⽅向做⼀件事并不难,最难的是没有⽅向,不知道要做什么;只是感觉时光流逝⾃⼰却⼀点东西都没产出。
编译原理4.3.1-左递归的消除
c) 消除文法中一切左递归
将非终结符排序为P1,P2,…,Pn FOR i=1 TO n DO { FOR j= 1 TO i-1 DO { 若Pj的所有产生式为: Pj→δ1|δ2|…|δk 把形如Pi → Pjγ的规则改写为: Pi → δ1γ | δ2 γ |…| δk γ } 消除Pi中的一切直接左递归 } 要求: 文法不 + 化简文法, 删除无用产生式 含回路P P , 不含以ε为右 部的产生式
例4.3: 消除一切左递归
G: (1) S→Qc|c (2) Q→Rb|b (3) R→Sa|a
补充例
排序: R、Q、S G2: S→(abc|bc|c)S′ G1和G2等价 S'→abcS′|ε Q→Sab|ab|b 无用产生式,应删除 R→Sa|a
排序: S、Q、R G1: S→Qc|c Q→Rb|b R→(bca|ca|a)R' R'→bcaR'|ε
4.3.1 左递归的消除
• 直接左递归 : P→Pβ + • 间接左递பைடு நூலகம் : PP
a) 消除直接左递归
P→ Pα|β P→βP' P'→αP'|ε
P→Pα1| Pα2 |…| Pαm | β1 | β2 |…| βn P →β1 P'|β2 P'|…|βn P' P'→α1 P'|α2 P'|…|αm P' | ε
补充例: 消除直接左递归
G: S→Sa|b
可改写为:
G' : S→bS' S'→aS'|ε
b) 消除间接左递归
补充例
G: (1) A→aB (2) A→Bb (3) B→Ac (4) B→d
(a)消除习题3文法的左递归
(a)消除习题3⽂法的左递归3.8 (a)消除习题3.⽂法的左递归(b)为(a)的⽂法构造预测分析器答案:(a)S —> (L) | aL —>S L′L′—> ,S L′|∈(b) FIRST(S)={(,a}FIRST(L)={(,a,}FIRST(L′)={‘,’, ∈}FOLLOW(S)={ ‘,’,﹩}FOLLOW(L)={ ),﹩,‘,’}FOLLW(L′)={ ) ,﹩,‘,’}预测分析表如下:⾮终结符输⼊符号() a , ﹩S S —> (L)S —> aL L —>S L′ L —>S L′L′ L′—> ∈ L′—> ,S L′ L′—> ∈【典型错误】:消除左递归请参考书上介绍的⽅法,有些⼈引⼊了两个⾮终结符,但不是最简的情况。
另外很多⼈没有构造FIRST和FOLLOW表,本题需要注意的是当FIRST 集合中有∈预测分析表的构造⽅法。
3.15(a)⽤习题3.1的⽂法构造(a,(a,a))的最右推导,说出每个右句型的句柄。
(b)给出对应(a)的最右推导的移进-归约分析器的步骤。
(c)对照(b)的移进-规约,给出⾃下⽽上构造分析树的步骤。
答案:(a) S => (L) => (L,S) =>(L,(L)) => (L,(L,S)) => (L,(L,a)) =>(L,(S,a)) =>(L,(a,a)) =>(S,(a,a)) =>(a,(a,a))(b)栈输⼊动作﹩(a,(a,a))﹩移进﹩( a,(a,a))﹩移进﹩(a ,(a,a))﹩ S->a归约﹩(S ,(a,a))﹩ L->S归约﹩(L ,(a,a))﹩移进﹩(L,(a,a))﹩移进﹩(L,( a,a))﹩移进﹩(L,(a ,a))﹩ S->a归约﹩(L,(S ,a))﹩ L->S归约﹩(L,(L ,a))﹩移进﹩(L,(L, a))﹩移进﹩(L,(L,a ))﹩ S->a归约﹩(L,(L,S ))﹩ L->L,S归约﹩(L,(L ))﹩移进﹩(L,(L))﹩ S—>(L)归约﹩(L,S )﹩ L->L,S归约﹩(L )﹩移进﹩(L)﹩ S—>(L)归约﹩ S ﹩ Acc(c)图见下页【典型错误】:(a)中要求的是最右推导,很多⼈没有注意到(b)⼀般没有错误,但注意a归约到S后要继续归约到L(c)这题的错误主要是没有给出构造的步骤,另外题⽬要求的是⾃下⽽上构造分析表。
消除左递归的方法
消除左递归的方法一、什么是左递归?在语法分析中,左递归是指产生式中左部直接或间接递归调用了自身的情况。
简单来说,就是一个非终结符的产生式中,左侧第一个符号又是该非终结符本身的情况。
在以下产生式中,非终结符A存在左递归:A -> Ab | cA的第一个符号是A本身。
左递归可能会导致递归下降解析器进入无限递归,导致程序崩溃或死循环。
在编写解析器时,需要消除所有的左递归。
二、消除左递归的方法1. 直接左递归消除方法对于直接左递归的产生式A -> Aα | β,可以通过以下步骤消除左递归:1)将产生式改写为A -> βA',A' -> αA' | ε。
2)将产生式进行分割,得到以下两个产生式:A -> βA'A' -> αA' | εε表示空产生式。
对于以下产生式:A -> Aa | b可以通过直接左递归消除方法得到以下产生式:A -> bA'A' -> aA' | ε2. 间接左递归消除方法对于间接左递归的产生式,可以通过以下步骤消除左递归:1)将所有非直接左递归的产生式移至左边,所有直接左递归的产生式移至右边。
2)将每个非终结符的所有产生式按照首符号分成两个集合,一个集合为直接或间接以该非终结符开始的产生式,另一个集合为不以该非终结符开始的产生式。
3)对于每个集合,递归地消除左递归。
4)将消除左递归后的产生式合并到一起。
对于以下文法:A -> BcB -> Ad | e可以通过间接左递归消除方法得到以下产生式:B -> eB'B' -> dB' | εA -> eB'c | dcB'是在消除左递归后新增加的符号。
三、消除左递归的示例以下为一个简单的文法:S -> S + S | S * S | id该文法存在直接左递归S -> S + S和S -> S * S,因此需要进行消除。
编译原理消除左递归
编译原理消除左递归一、前言编译原理是计算机科学中的重要分支之一,它研究如何将高级语言转化成机器语言,使计算机能够理解并执行程序。
编译器是完成这一过程的关键工具之一。
编译器的核心任务是将源代码转换为目标代码,其中一个重要的步骤就是消除左递归。
二、概述在文法中,如果一个非终结符可以推导出以自身为左部的产生式,则称该文法具有左递归。
例如,对于以下文法:```A -> Aa | b```可以发现非终结符 A 可以推导出 Aa 这个产生式,而 Aa 中又包含了非终结符 A,因此该文法具有左递归。
左递归会导致递归下降分析法和 LL(1) 分析法无法正确处理该文法。
因此,在进行语法分析时需要先将文法中的左递归消除。
三、消除直接左递归直接左递归指的是形如 A -> Ab | c 的产生式中以 A 为左部且右部以A 开头的情况。
消除直接左递归需要进行以下步骤:1. 将所有以 A 开头的产生式提取出来,并将它们的右部中的 A 去掉,得到新的产生式:```A -> cA'A' -> bA' | ε```2. 将新产生式中的 A' 替换为原来的非终结符 A,得到最终结果:```A -> cA'A' -> bA' | ε```四、消除间接左递归间接左递归指的是存在一系列非终结符 A1, A2, ..., An,使得文法中存在产生式 A1 -> A2B,A2 -> A3C,..., An-1 -> AnD,An -> A1E 的情况。
消除间接左递归需要进行以下步骤:1. 将文法中所有非终结符按照拓扑排序的方式排列,并将它们编号为1, 2, ..., n。
2. 对于每个非终结符 Ai,将其可以推导出的所有非终结符按照编号从小到大排序,并将它们存储在一个集合 Bi 中。
3. 对于每个集合 Bi 中的非终结符 Bj,将其可以推导出的所有非终结符按照编号从小到大排序,并将它们存储在一个集合 Ci 中。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
编译原理实验报告实验名称消除文法的左递归实验时间 2010.11.1 院系计算机科学与技术班级 2008 学号 JB084193姓名潘亚飞1.试验目的输入:任意的上下文无关文法。
输出:消除了左递归的等价文法。
2.实验原理1.直接左递归的消除消除产生式中的直接左递归是比较容易的。
例如假设非终结符P 的规则为P →P α / β其中,β是不以P 开头的符号串。
那么,我们可以把P 的规则改写为如下的非直接左递归形式: P →βP ’ P ’→αP ’ / ε这两条规则和原来的规则是等价的,即两种形式从P 推出的符号串是相同的。
设有简单表达式文法G[E]: E →E+T/ T T →T*F/ F F →(E )/ I经消除直接左递归后得到如下文法: E →TE ’E ’ →+TE ’/ ε T →FT ’T ’ →*FT ’/ εF →(E )/ I考虑更一般的情况,假定关于非终结符P 的规则为P →P α1 / P α2 /…/ P αn / β1 / β2 /…/βm其中,αi (I =1,2,…,n )都不为ε,而每个βj (j =1,2,…,m )都不以P 开头,将上述规则改写为如下形式即可消除P 的直接左递归:P →β1 P ’ / β2 P ’ /…/βm P ’P ’ →α1P ’ / α2 P ’ /…/ αn P ’ /ε 2.间接左递归的消除直接左递归见诸于表面,利用以上的方法可以很容易将其消除,即把直接左递归改写成直接右递归。
然而文法表面上不存在左递归并不意味着该文法就不存在左递归了。
有些文法虽然表面上不存在左递归,但却隐藏着左递归。
例如,设有文法G[S]:S →Qc/ c Q →Rb/ b R →Sa/ a虽不具有左递归,但S 、Q 、R 都是左递归的,因为经过若干次推导有 S ⇒Qc ⇒Rbc ⇒SabcQ ⇒Rb ⇒Sab ⇒Qcab R ⇒Sa ⇒Qca ⇒Rbca就显现出其左递归性了,这就是间接左递归文法。
消除间接左递归的方法是,把间接左递归文法改写为直接左递归文法,然后用消除直接左递归的方法改写文法。
如果一个文法不含有回路,即形如P ⇒+P 的推导,也不含有以ε为右部的产生式,那么就可以采用下述算法消除文法的所有左递归。
消除左递归算法:(1) 把文法G 的所有非终结符按任一顺序排列,例如,A 1,A 2,…,A n 。
(2) for (i =1;i<=n ;i++)for (j =1;j<=i -1;j++){ 把形如A i →A j γ的产生式改写成A i →δ1γ /δ2γ /…/δk γ 其中A j →δ1 /δ2 /…/δk 是关于的A j 全部规则; 消除A i 规则中的直接左递归; }(3) 化简由(2)所得到的文法,即去掉多余的规则。
利用此算法可以将上述文法进行改写,来消除左递归。
首先,令非终结符的排序为R 、Q 、S 。
对于R ,不存在直接左递归。
把R 代入到Q 中的相关规则中,则Q 的规则变为Q →Sab/ ab/ b 。
代换后的Q 不含有直接左递归,将其代入S ,S 的规则变为S →Sabc/ abc/ bc/ c 。
此时,S 存在直接左递归。
在消除了S 的直接左递归后,得到整个文法为: S →abcS ’/ bcS'/ cS' S ’ →abcS'/ ε Q →Sab/ ab/ b R →Sa/ a可以看到从文法开始符号S 出发,永远无法达到Q 和R ,所以关于Q 和R 的规则是多余的,将其删除并化简,最后得到文法G[S]为:S →abcS'/ bcS ’/ cS' S' →abcS'/ ε当然如果对文法非终结符排序的不同,最后得到的文法在形式上可能不一样,但它们都是等价的。
例如,如果对上述非终结符排序选为S 、Q 、R ,那么最后得到的文法G[R]为: R →bcaR'/ caR'/ aR ’R' →bcaR'/ ε容易证明上述两个文法是等价的。
3..实验内容消除左递归算法:(1)把文法G的所有非终结符按任一顺序排列,例如,A1,A2,…,An。
(2)for (i=1;i<=n;i++)for (j=1;j<=i-1;j++){ 把形如Ai →Ajγ的产生式改写成Ai→δ1γ/δ2γ/…/δkγ其中Aj →δ1/δ2/…/δk是关于的Aj全部规则;消除Ai规则中的直接左递归;}(3)化简由(2)所得到的文法,即去掉多余的规则。
利用此算法可以将上述文法进行改写,来消除左递归。
4.实验代码//#include "stdafx.h"#include<iostream>#include<string>using namespace std;struct WF //定义一个产生式结构体{string left; //定义产生式的左部string right; //定义产生式的右部};void Removing(WF *p,char *q,int n,int count){int count1=n;int flag=0;for(int i=0;i < n;i++)//判断第一个非终结符是否存在直接左递归 if(p[i].left[0]==q[0])if(p[i].left[0]==p[i].right[0])flag++;if(flag!=0)//如果存在直接左递归则消除直接左递归{for(int i=0;i < n;i++)if(p[i].left[0]==q[0])if(p[i].left[0]==p[i].right[0]){string str;str=p[i].right.substr(1,int (p[i].right.length()));string temp=p[i].left;string temp1="'";p[i].left=temp+temp1;p[i].right=str+p[i].left;}else{string temp=p[i].left;string temp1="'";temp=temp+temp1;p[i].right=p[i].right+temp;}string str="'";p[count1].left=p[0].left[0]+str;p[count1].right="ε";}for( i=0;i <= count;i++){for(int j=0;j < i;j++){for(int g=0;g < n;g++)if(q[i]==p[g].left[0])if(p[g].right[0]==q[j]){for(int h=0;h < n*n;h++)if(p[h].left[0]==q[j]&&int (p[h].left.length())==1) {string str;str=p[g].right.substr(1,int (p[g].right.length())); p[++count1].left=p[g].left;p[count1].right=p[h].right+str;}p[g].left="";p[g].right="";}}}for( i=0;i <= count;i++){flag=0;for(int j=0;j < n*n;j++)if(p[j].left[0]==q[i])if(p[j].left[0]==p[j].right[0])flag++;if(flag!=0){for(int j=0;j <= n*n;j++)if(p[j].left[0]==q[i])if(p[j].left[0]==p[j].right[0]){string str;str=p[j].right.substr(1,int (p[j].right.length())); string temp=p[j].left;string temp1="'";p[j].left=temp+temp1;p[j].right=str+p[j].left;}else{string temp=p[j].left;string temp1="'";temp=temp+temp1;p[j].right=p[j].right+temp;}string str="'";p[++count1].left=q[i]+str;p[count1].right="ε";}}}int Delete(WF *p,int n){return 0;}int main(){int i,j,flag=0,count=1,n;cout<<"请输入文法产生式个数n:"<<endl;cin>>n;WF *p=new WF[50];cout<<"请输入文法的个产生式:"<<endl;for(i=0;i<n;i++)//输入产生式{cin>>p[i].left;cout<<"->"<<endl;cin>>p[i].right;cout<<endl;}cout<<endl;cout<<"即输入的文法产生式为:"<<endl;for(i=0;i < n;i++)cout<<p[i].left<<"-->"<<p[i].right<<endl;cout<<"*********************"<<endl;char q[20];//对产生式的非终结符排序并存取在字符数组qq[0]=p[0].left[0];//把产生式的第一个非终结符存入q中for(i=1;i<n;i++)//对非终结符排序并存取{flag=0;for(j=0;j<i;j++)if(p[i].left==p[j].left)flag++;if(flag==0)q[count++]=p[i].left[0];}count--;Removing(p,q,n,count);//调用消除递归子函数Delete(p,n);//删除无用产生式cout<<"消除递归后的文法产生式为:"<<endl;for(i=0;i <= count;i++){for(int j=0;j <= n*n;j++)if( (p[j].left[0]==q[i]) && int (p[j].left.length())==1 ) cout<<p[j].left<<"-->"<<p[j].right<<endl;else continue;for( j=0;j <= n*n;j++)if( (p[j].left[0]==q[i]) && int (p[j].left.length())==2 ) cout<<p[j].left<<"-->"<<p[j].right<<endl;else continue;}return 0;}5.实验结果消除直接左递归:消除间接左递归:6.实验心得一个文法是含有左递归的,如果存在非终结符P ,P ⇒+P α含有左递归的文法将使上述的自上而下的分析过程陷入无限循环,即当试图用P 去匹配输入串时,就会出现在没有吃进任何输入符号的情况下,又得重新要求P 去进行新的匹配。