【编译原理】期末复习(例题版)

一,求表达式的逆波兰式

1,遇到字母直接写到答案中

2,遇到符号加入栈中

3,左括号优先级最低直接进栈,只有遇到成对括号才出栈;逆波兰式不需要括号

4,新加入的符号与栈中符号比较,如果前者优先级要高于原站顶等级则加入栈中,否则栈中符号先出栈(包括优先级低于和等于两种情况)

1.a+b*(c/d+g)

a #(表示栈顶)

a #+

ab #+

ab #+*

ab #+*(

abc #+*(

abc #+*(/

abcd/ #+*(+

abcd/g #+*(+

abcd/g #+*(+)

abcd/g+ #+*遇到括号直接把整个括号中的符号写入答案,注意的是()不写

abcd/g+*+ #剩余符号全部出栈

2.A+B*(C-D)+F/(C-D)^N (^表示指数)

A #

A #+

AB #+*

AB #+*(

ABC #+*(-

ABCD #+*(-

ABCD #+*(-) 、ABCD- #+*

ABCD-*+ #+

ABCD-*+F #+

ABCD-*+F #+/

ABCD-*+F #+/(

ABCD-*+FC #+/(

ABCD-*+FC #+/(-

ABCD-*+FC #+/(-)、ABCD-*+FC- #+/

ABCD-*+FC- #+/^

ABCD-*+FC-N #+/^

ABCD-*+FC-N^/+ #

二、根据文法G写出L([G])

前导知识:

在文法的每一条表达式中,大写字母是非终结符、小写字母是终结符,箭头定义为"="。语言是句子的集合,句子是特殊句型。

如果 S⇒* α,α∈(VT∪VN)*,则称α是G的一个句型。一个句型中既可以包含终结符,又可以包含非终结符,也可能是空串。

如果 S⇒* w,w ∈VT*,则称w是G的一个句子(sentence)。句子是不包含非终结符的句型。

例题1

G[N]:

N->D|ND

D->0|1|2|3|4|5|6|7|8|9

问G[N]的语言是什么?
通过观察,发现第一个表达式出现了直接左递归

N=>ND=>NDD=>NDDD......=>D...DDDD

所以N=>D的N次方(得到了一个句型)

代入第二条表达式,分别取n=1,2,3....

发现得到的是D的正闭包(从相同的地方取不一样的个数),也可以写成G[N]=D^n(n>=1)

例题2

G[N]:

Z->aZb

Z->ab

问L(G[N])的全部元素
通过观察,发现第一个表达式出现了递归

Z=>aZb=>aaZbb=>aaaZbbb......=>a...aaabbb...b

所以Z=>a^n b^n(句子)

L(G[N])={a^n b^n | n>=1},(句子的集合就是语言)

三、分析句型构造语法树、写出短语、直接短语和句柄

例题1:

令文法G[E]为:

E->E+T | T

T-> T*F | F

F->(E)|v|d

(1)分析说明v*v+d是它的一个句型

(2)指出这个句型的所有短语、直接短语和句柄
(1)

证明是否是一文法的句型,最简单的证明方法是画出语法树

第二种方法是使用最左推导或者最右推导或者混合使用

E=>E+T =>T+T=>T*F+T=>F*F+T=>v*F+T=>v*v+F=>v*v+d

按照上面的推导可以从上到下画一颗语法树

(2)

技巧:只看所有非叶子节点,从最后一层往上看,把根的叶子进行组合;只看所有非叶子节点,在同一层,从左往右看

解答如下:

先圈出所有非叶子节点

最后一层是F,所以短语有v

倒数第二层是T和F;因为T的叶子节点跟最后一层的重复了,所以不写;然后看F,F底下有个叶子节点v,所以现在短语是v,v

倒数第三层也是T和F;这个T的叶子结点则是v*v;F的叶子节点则是d;所以现在短语是v,v,v*v,d

倒数第四层是E和T;E的叶子结点和T是一样的,都是v*v,所以不重复写了;T的叶子结点和F一样都是d ,也不重复写;所以现在短语是v,v,v*v,d

最后一层也是根节点;它的叶子结点是v*v+d;所以现在短语是v,v,v*v,d,v*v+d

综上:所有短语是v,v,v*v,d,v*v+d

直接短语就是高度为一的短语,比如F-v,F-v,F-d;最左边的那个T的叶子节点虽然也是v,但是是经过两层的,所以不是直接短语。

综上:直接短语是v,v,d(按顺序写上)

句柄就是写好的直接短语中最左边的那个也就是第一个

例题2:

令文法G[S]为:

S->aAcBe

A->b|Ab

B->d

(1)分析说明aAbcde是它的一个句型

(2)指出这个句型的所有短语,直接短语和句柄
(1)

S=>aAcBe=>aAbcBe=>aAbcde

(2)

先圈出所有非叶子节点:

倒数第一层有A,B;A的叶子有Ab;B的叶子是d;所以现在短语有Ab,d;

根节点有S;S的叶子是aAbcde;所以短语有Ab,d,aAbcde

综上,短语有Ab,d,aAbcde,直接短语有Ab,d,

例题3:

令文法G[S]为:

S->SS*

S->SS+

S->a

(1)分析说明aa+a*是它的一个句型

(2)指出这个句型的所有短语,直接短语和句柄

(1)

S=>SS*=>SS+S*=>aS+S*=>aa+S*=>aa+a*

(2)

圈出所有非终结符之后开始解题:

共三层,倒数第一层是S和S;第一个S的短语和第二个短语均是a;所以短语是a,a

倒数第二层是S和S;第一个S的短语是aa+;第二个S的短语是a

最后一层短语是aa+a*

综上:短语有a,a,aa+,a,aa+a*;直接短语有a,a,a;句柄是最左边的a

四、正规式转正规文法

将正规式 r 转换为正规文法 G,核心是将正规式拆分为正规文法的多个产生式,这是一个由一到多 的过程。正规文法最终必须有一个开始符号,于是我们选定 S 作为开始符号,令 S → r,然后逐步对 r 进行拆分,生成多个产生式。

拆分规则如下:

  • A → xy 可拆分为 A → xBB → y
  • A → x*y 可拆分为 A → xAA → y
  • A → x|y 可拆分为 A → xA → y

对于规则二,实际我们知道 x*y 是形如 xxxxxxy 的,所以需要进行循环替换,必须有 A → xA;符号串最后有个 y,所以必须有 A → y

例题:

将正规式r=a(a|d)*转为相应的正规文法G[s]:

1.设开始符号为S,则S->a(a|d)*

2.使用规则1:S->aA A->(a|d)*

3.对第2步的第2个式子使用规则2展开:A->(a|d)A A->ε

4.对第三步的第一个式子可以换成A->aA|dA,使用规则3 可得:A->aA,A->dA

5.综上:

G[S]:

S->aA,A->aA,A->d,AA->ε

五、正规文法转正规式

基本为上一题型反过来罢了:

  • (1)A->xB, B->y对应A->xy(产生式有非终结符且该非终结符不等于产生式的左边)
  • (2)A->xA, A->y对应A->x*y(产生式有非终结符且该非终结符等于产生式的左边)
  • (3)A->x, A->y对应A->x|y(产生式没有非终结符)

例题:

文法G[S]:

(1)S->aA

(2)S->a

(3)A->aA

(4)A->dA

(5)A->a

(6)A->d

转换为正规式:

六、正规式转NFA

规则:

① 对ε,构造NFA如图(a)所示。其中,s0为初态,f为终态,该NFA接受ε;

② 对∑上的每一个字符a,构造NFA如图(b)所示。其中,s0为初态,f为终态,该NFA接受{a};

③ 若N(p)和N(q)是正规式p和q的NFA,则:

(a) 对正规式p|q,构造NFA如图(c)所示。其中,s0为初态,f为终态,该NFA接受L(p)∪L(q);

(b) 对正规式pq,构造NFA如图(d)所示。其中,s0为初态,f为终态,该NFA接受L(p)L(q);

(c) 对正规式p*,构造NFA如图(e)所示。其中,s0为初态,f为终态,该NFA接受L(p*)。

例题1:

将正规式r=(a|b)*abb构造成NFA:

例题2:

识别由正规式(a|b)*abb说明的记号的NFA定义如下:

S={0,1,2,3}, Σ={a,b}, s0 = 0, F={3}

move = { move(0,a)=0, move(0,a)=1, move(0,b)=0, move(1,b)=2, move(2,b)=3}

所得状态转换图和状态转换矩阵NFA如下:

上图为识别(a|b)*abb的NFA

用上图的NFA识别输入序列abb和abab

七、NFA转DFA

子集法例题:

将正规式r=(a|b)*abb构造成NFA转为DFA

解答:

状态集中如果包含NFA中的终态,该状态集也为DFA的终态

综合例题

语言Σ={0,1}上所有满足如下条件的字符串:

每个1都有0直接跟在右边

(1)构造正规式

正规式:(0|10)*

(2)用Thompson算法将其转换为NFA

(3)使用子集构造法将NFA转换为DFA (关键在求闭包)

状态转移矩阵例题

(a|b)*b

1、转换成状态转移矩阵

2.消除空转移

综合例题1

r=(0|1)*011(0|1)*

1、正规式→NFA

2、NFA→DFA(状态转移图)

综合例题2:

((ε|a)b*)*

1、正规式→NFA

2、NFA→DFA(状态转移图)

八、最小化DFA

它们接受相同的正规集,说明两个DFA是等价的,但是有可能他们的状态数不同。一般来说,对于若干个等价的DFA,总是希望由状态数最少的DFA构造词法分析器。将一个DFA等价变换为另一个状态数最少的DFA的过程被称为最小化DFA,相应DFA称为最小DFA。

练习判断正规式(a|b)*b和正规式((a|b)*|aa)*等价

方法:将两个正规式各自处理至最小DFA,然后比较是否一致。

九、消除左递归

什么时候需要消除左递归

在进行自上而下的分析(比如LL(1)分析时,构造预测分析器也是LL(1)分析)需要消除左递归,因为自上而下的分析方法不能用于左递归文法。任何二义文法绝不是LR文法。
直接左递归:

将A ------> Aα | β 转换为

A ------> β A'

A' ------> α A'

间接左递归:

先将其变为立即左递归(前面的式子代入后面式子)

然后按照消除直接左递归的规则进行转换即可

消除直接左递归:

将以下文法消除左递归:

E -> E+T | T

T -> T*F | F

F -> (E) | i

消除左递归:

E→TE'

E'→+TE'|ε

T→FT'

T'→*FT'|ε

F→(E)|i

消除间接左递归1

1)B→aBc

2)B→Bbc

3)B→d

先将其变为立即左递归,可化简为:B→aBc | Bbc | d

然后按照消除直接左递归的规则进行转换即可

1)B→aBcB' |dB'

2)B'→bcB' |ε

消除间接左递归2:

十、求first集合

FIRST( α )表示由α推导出的串的首个终结符或空字符组成的集合。

规则

求文法符号X的FIRST( X ) ,直到没有终结符或空字符可以加入。

① 如果X属于终结符VT,则FIRST(X) = { X } 。

② 如果X属于非终结符VN,且有产生式形如X → a...,则FIRST( X ) = { a }。

③ 如果X属于非终结符VN,且有产生式形如X → ABCdEF...(A、B、C均属于非终结符且包含 ε,d为终结符),需要把d、FIRST( A )、FIRST( B )、FIRST( C )加入到FIRST( X)中。

④ 如果X经过一步或多步推导出空字符ε,将ε加入FIRST( X )。

我们主要使用的是规则2 和规则3,理论上每次First集产生变化就要重新查看一遍所有式子,实际做题时可以按照变化一次重新求一次

例题1:

G[E]:

E→TE′

E′→+TE′∣ε

T→FT′

T′→∗FT′∣ε

F→(E)∣i

1.使用规则2,即产生式右边的第一个字母如果是终结符或者单独的ε即可写入first集合,遍历第一遍可得

First(E) = { }

First(E′ ) = {+,ε}

First(T) = { }

First(T′ ) = { *,ε }

First(F) = { (,i}

2.使用规则3进行第一次遍历,即产生式右边的第一个字母使用对应的first集合

First(E) = { }//E→TE′可知first(T)要写进first(E)但是此时T为空所以不写

First(E′ ) = {+,ε }

First(T) = { (,i }

First(T′ ) = { *,ε }

First(F) = { (,i }

3.使用规则3进行下一次遍历,即产生式右边的第一个字母使用对应的first集合,直到不再发生变化

First(E) = {(,i }

First(E′ ) = {+,ε}

First(T) = { (,i }

First(T′ ) = { *,ε }

First(F) = { (,i }

4.重点观察产生式右边从第一个字母开始的连续出现的非终结符,观察这几个大写字母的first集是否出现ε(详细看规则表述)

本题目只有下面两个式子复合要求

E→TE′

T→FT′

因为First(T) = { (,i },First(F) = { (,i }均不含ε,所以本题完成

例题2:

A→BCc | gDB

B→bCDE | ε

C→DaB | ca

D→dD | ε

E→gAf | c

1.使用规则2,即产生式右边的第一个字母如果是终结符或者单独的ε即可写入first集合,遍历第一遍可得

First(A) = { g}

First(B ) = {b,ε}

First(C) = {c }

First(D) = { d,ε }

First(E) = { g,c}

2.使用规则3进行第一次遍历,即产生式右边的第一个字母使用对应的first集合

First(A) = {g,b,ε }

First(B ) = {b,ε}

First(C) = {c ,d,ε}

First(D) = { d,ε }

First(E) = { g,c}

3.使用规则3进行下一次遍历,即产生式右边的第一个字母使用对应的first集合,直到不再发生变化,(发现第二轮就不发生变化了)

First(A) = {g,b,ε }

First(B ) = {b,ε}

First(C) = {c ,d,ε}

First(D) = { d,ε }

First(E) = { g,c}

4.重点观察产生式右边从第一个字母开始的连续出现的非终结符,观察这几个大写字母的first集是否出现ε(详细看规则表述)

本题目只有下面两个式子复合要求

A→BCc

C→DaB

第一个式子:因为First(B ) = {b,ε},所以first(A)加上first(C),First(A) = {g,b,ε,c,d },而First(C) = {c ,d,ε}含有ε,所以C后面的c也要加入first(A),First(A) = {g,b,ε,c,d }

第二个式子:因为First(D) = { d,ε },所以First(C) = {c ,d,ε,a}

从第2步开始重复

First(A)= {g,b,ε,c,d,a }

First(B ) = {b,ε}

First(C) = {c ,d,ε,a}

First(D) = { d,ε }

First(E) = { g,c}

另一种写法:

解:

FIRST( A ) = FIRST( BCc ) ∪ FIRST( gDB )

=FIRST( B )∪FIRST( C )∪{ c }∪{ g }

由规则③规则②可知

FIRST( A ) =FIRST( B )∪FIRST( D )∪{ a }∪{ c }∪{ c }∪{ g }

={ b,ε }∪{ d,ε }∪{ a }∪{ c }∪{ g }

={ a,b,c,d,g ,ε }

FIRST( B ) = { b,ε }

FIRST( C ) = FIRST( D )∪{ a }∪{ c }= { a,c,d,ε }

FIRST( D ) = { d,ε }

FIRST( E ) = { g,c }

对于A来说:有两种选择 BCc 与 gDB,BCc用规则③,gDB用规则②。

对于B来说:有两种选择 bCDE 与 ε,均用规则②。

对于C来说:有两种选择 DaB 与 ca,由于D存在空字符,所以 DaB用规则③,ca用规则②。

对于D来说:有两种选择dD 与 ε ,分别用规则②与规则④。

对于E来说:有两种选择gAf 与 c ,均用规则②。

例题3:

设有文法G[S]:

S→aBS | bAS | ε

A→bAA | a

B→aBB | b

解:

FIRST( S ) = FIRST( aBS )∪FIRST( bAS )∪{ ε }={ a,b,ε }

FIRST( A ) = { a,b }

FIRST( B ) = { a,b }

对于S来说:有三种选择 aBS与bAS、ε,分别用②与规则④。

对于A来说:有两种选择bAA与 a,均用规则②。

对于B来说:有两种选择aBB与 b,均用规则②。
写在最后:其实我喜欢用目测法,就从倒数第一个产生式开始,看见小写字母和单独的ε直接写进first,如果是大写字母,就找它的first,然后看它的 first有没有空,有空就往下个字母看

十一、follow集合

Follow集合求取的是非终结符的后继符号集合,不能出现空字符ε 。以X表示一个非终结符,FOLLOW( X )表示当X通过规约出现时,接下来的输入可能是哪些终结符。
规则

求非终结符X的FOLLOW( X ) ,直到没有终结符可以加入。

① 如果X是开始符号,则将#加入到FOLLOW(X)中 。

② 如果存在一个产生式S->αXβ,那么将集合FIRST(β)中除ε外的所有元素加入到FOLLOW(X)当中。

③如果存在一个产生式 S->αX , 或者S->αXβ且FIRST(β)中包含ε , 那么将集合FOLLOW(S)中的所有元素加入到集合FOLLOW(X)中。

例题1:

G[E]:

E→TE′

E′→+TE′∣ε

T→FT′

T′→∗FT′∣ε

F→(E)∣i

first集合如下:

First(E) = {(,i }

First(E′ ) = {+,ε}

First(T) = { (,i }

First(T′ ) = { *,ε }

First(F) = { (,i }

1.将#加入开始符号E的follow集合

Follow(E) = { # }

Follow(E′) = { }

Follow(T) = { }

Follow(T′) = { }

Follow(F) = { }

2.找到产生式右边的每一个非终结符还有它们后面的字符,并将后面的first集合去ε后加入follow集,有空还有看下一个字符

Follow(E) = { # ,)}//F→(E)

Follow(E′) = { }

Follow(T) = { +}//E→TE′且E′虽有空但后面无紧跟字母

Follow(T′) = { }

Follow(F) = {* }//T′→∗FT′且T ′虽有空但后面无紧跟字母

3.找到产生式右边的最后一个字母,如果是终结符则不用管,如果是非终结符,则将该产生式左边的follow集加入,若该字母可取空,则还要看上一个字符是否为非终结符,则将该产生式左边的follow集加入

Follow(E) = { # ,)}

Follow(E′) = { ),#}//E→TE′

Follow(T) = { +,#,)}//E→TE′

Follow(T′) = {+,# ,)}//T→FT′

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

4.重复3直至follow集合不再发生变化(本题在刚刚第3 步已经不再变化了)

例题2:

设有文法G[A]:

A→BCc | gDB

B→bCDE | ε

C→DaB | ca

D→dD | ε

E→gAf | c

First集合如下:

First(A)= {g,b,ε,c,d,a }

First(B ) = {b,ε}

First(C) = {c ,d,ε,a}

First(D) = { d,ε }

First(E) = { g,c}

第一种写法:

FOLLOW( A ) ={ f ,# }

FOLLOW( B ) = FIRST( C )∪FOLLOW( A )∪FOLLOW( C )

={ a,c,d }∪{ f ,#}∪{ c,d,g,# }

={ a,c,d,f,g,# }

FOLLOW( C ) = { c }∪FIRST( D )∪FIRST( E )

={ c }∪{ d }∪{ g,c }

={ c,d,g }

FOLLOW( D ) = FIRST( B )∪FOLLOW(A )∪FIRST( E )∪{ a }

={ b } ∪{ g,c }∪{ f ,# }∪{ a }

={ a,b,c,g,f,# }

FOLLOW( E ) = FOLLOW( B )

={ a,c,d,f,g,# }

第二种写法:

FOLLOW( A ) ={#}

FOLLOW( B ) = {}

FOLLOW( C ) ={}

FOLLOW( D ) ={}

FOLLOW( E ) = {}

FOLLOW( A ) ={#,f}

FOLLOW( B ) = {c ,d,a}

FOLLOW( C ) ={c,d,g}

FOLLOW( D ) ={b,g,c,a}

FOLLOW( E ) = {}

FOLLOW( A ) ={#,f}

FOLLOW( B ) = {c ,d,a,f,#,g}

FOLLOW( C ) ={c,d,g}

FOLLOW( D ) ={b,g,c,a,#,f}

FOLLOW( E ) = {c ,d,a,f,#}

4,重复找follow

FOLLOW( A ) ={#,f}

FOLLOW( B ) = {c ,d,a,f,#,g}

FOLLOW( C ) ={c,d,g}

FOLLOW( D ) ={b,g,c,a,#,f}

FOLLOW( E ) = {c ,d,a,f,#,g}

例题3:

设有文法G[S]:

S→aBS | bAS | ε

A→bAA | a

B→aBB | b

first集合如下:

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

FIRST( A ) = { a,b }

FIRST( B ) = { a,b }

FOLLOW( S ) ={#}

FOLLOW( A) ={}

FOLLOW( B )={}

FOLLOW( S ) ={#}

FOLLOW( A) ={a,b}

FOLLOW( B )={a,b}

FOLLOW( S ) ={#}

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

FOLLOW( B )={a,b,#}

十二、求selcet集

作用:用SELECT集判断是否为LL(1)文法的例题:

步骤:

对于产生式A →α

1)若 α≠*> ε,则SELECT(A →α)= FIRST(α)

2)若 α=*> ε,则SELECT(A →α)= FIRST(α)∪FOLLOW(A)

自我理解:直接看产生式的右边的第一个字母(不管是否是终结符),SELECT集直接取FIRST(产生式右边),如果FIRST集合里有ε,保留ε且在SELECT集里添上FOLLOW(产生式左边)

例题:

G(E):

①E → TE'

②E' → +TE'

③E' →ε

④T → F T'

⑤T' → *F T'

⑥T' →ε

⑦F → (E)

⑧F → id
实现准备好:

在这个文法中能推出ε的产生式的左部为:{ E',T' }

FIRST(E)= {(,id }

FIRST(E`)= {+,ε }

FIRST(T)={(,id }

FIRST(T')={*,ε }

FIRST(F)={(,id }

Follow(E)= { ),$ }

Follow(E)'= { ),$ }

Follow(T)={ +,),$ }

Follow(T')={ +,),$ }

Follow(F)={ *,+,),$ }

下面,我们来计算这个文法的SELECT集。

第①条产生式:①E → TE'

因为FIRST(T)中没有ε ,所以第一条产生式的SELECT计算就结束了。E → TE' { (,id }

第②条产生式:E' → +TE'

产生式的右部首符号为+,是一个终结符,我们可以得到E' → +TE' { + }

第③条产生式:E' →ε ,我们发现该产生式推出一个空,我们可以得到E' →ε { ε,),$ }

第④条产生式:T → F T',T → F T' { (,id }

第⑤条产生式:T' → *F T' ,与第②条产生式同理,T' → *F T' { * }

第⑥条产生式:T' →ε ,与第③条产生式同理,T' →ε { ε,+,),$ }

第⑦条产生式:F → (E),F → (E) { ( }

第⑧条产生式也同理:F → id { id }

∴该文法的SELECT集为:

① SELECT(E → TE' )= { (,id }

② SELECT(E' → +TE' )= { + }

③ SELECT(E' →ε )= { ε,),$ }

④ SELECT( T → F T' )= { (,id }

⑤ SELECT(T' → *F T' )= { * }

⑥ SELECT(T' →ε )= { ε,+,),$ }

⑦ SELECT(F → (E))= { ( }

⑧ SELECT(F → id )={ id }

十三、LL(1)文法

满足条件:

① 文法无左递归。

②如果A存在多个选择ai,那么任意两个不同的选择ai和aj,需满足FIRST( ai )∩FIRST( aj )= ∅ ,保证不会回溯。

③如果ε 属于A 的开始符号集合,需满足FIRST( A )∩FOLLOW( A ) = ∅ 保证只有一个选择存在。

另一种判断是否为LL(1)的方法:

求出每个表达式的SELECT集合,将产生式左端相同的表达式归为一组,若一组之间的SELECT集合之间交集为空,则该文法就是LL(1)文法,否则就不是。

十四、构造预测分析表

判断是LL(1)文法后,就可以构造预测分析表了

设有文法G[A]:

A→aB|ε

B→Ab|d

(1)判断是否为LL(1)文法

(2)构造分析表

FIRST(A)={a,ε},FIRST(B)={d,b,a}

FOLLOW(A)={#,b},FOLLOW(B)={#,b}

SELECT(A→aB)={a}

SELECT(A→ε)={#,b}

SELECT(B→Ab)={a,b}

SELECT(B→d)={d}

观察可知,同组SELECT集合交集为空,所以该文法是LL(1)文法

|---|------|------|-----|-----|
| | a | b | d | # |
| A | A→aB | A→ε | | A→ε |
| B | B→Ab | B→Ab | B→d | |

方法很简单:

先看终结符出现在哪个产生式的SELECT集中,就把那个产生式填到与产生式左部一样的那一行。比如对于a,在SELECT(A→aB)和SELECT(B→Ab)中出现,那就把对应产生式填进去

十五、构造文法的LR(0)

解释:右部某位置标有圆点的产生式称为相应文法的一个LR(0)项目(简称为项目),

  • 产生式A→ε 只生成一个项目A→ ·
  • 移进项目: 形如 A -> α• aβ,对应移进状态,圆点后面是终结符。
    待约项目: 形如 A -> α • Bβ,对应待约状态,圆点后面是非终结符
    归约项目: 形如 A -> α •,句柄已形成(圆点在最后面),可以归约。
    接受项目: 形如 S' -> S •(S是初始符号,S'是增广之后的初始符号)。
    初始项目: 形如 S' -> • SS是初始符号,S'是增广之后的初始符号)。
    其中a∈VT , α,β∈(VN∪VT)*, A,B∈VT
    后继项目: 表示同属于一个产生式的项目,但是圆点的位置仅相差一个文法符号,则称后者为前者的后继项目。

举例说明:S-->bBB则可以推导出4个项目

例题:

给定文法G[E]:

(1) E -> E+T

(2) E -> T

(3) T -> ( E )

(4) T -> d

构造LR(0)

① G[E]的拓广文法,得到G' [E']:

(0) E' -> E

(1) E -> E+T

(2) E -> T

(3) T -> ( E )

(4) T -> d

②构造G'[E'] 的 LR(0)


上面的LR(0)项目簇规范族:I0={E'->.E,E->.E+T,E->.T,T->.(E),T->.d};I1={E'->E. ,E->E.+Td}........I8={E->E+T.}
接下来找含有规约的项目,判断是否存在移进(小黑点在终结符的前面)/规约(小黑点在最后面)冲突,看I1就是典型的冲突(如果写到LR(0)分析表上,就会出现一个格子两个不同的动作),所以该文法不是LR(0)文法
如果LR(0)分析表中没有语法分析动作冲突 ,那么给定的文法就称为**LR(0)文法,**不是所有CFG【上下文无关文法】都能用LR(0)方法进行分析,也就是说,CFG不总是LR(0)文法

例题2:

**技巧:**当下一个读入的符号是非终结符的时候,我们填写GOTO表,只需要填写I将要取到的那个项目集的数字(I旁边的数字)即可。当下一个读入字符是终结符的时候,我们就需要判断是移进(小黑点后面是终结符)还是归约(小黑点在最后面),规约的话要判断是不是ACC

十六、 SLR

上一题型简要的说明了一下LR(0)分析在构建分析表时候会发生的一些冲突。为了解决LR(0)分析产生冲突,故学习SLR(1),意思是在解决LR(0)冲突的时候,我们需要向后多看一个字符(又因为k=1的时候,可以省略不写,所以可以简写为SLR)。如果给定文法的SLR分析表中不存在有冲突的动作,那么该文法称为SLR文法

对于一个LR(0)分析存在冲突,就多往后面多看一个字符。具体解题步骤是,对产生冲突的产生式的左边那个非终结符求FOLLOW集,然后判断下一个输入字符是否在其式子左边那个字符中的FOLLOW集中,如果在,对于输入该字符就采用该项目对应的操作,要是都不在就报错。

当我们采用SLR分析时发现,SLR依然是可能存在语法冲突的,因为原因:SLR只是简单地考察下一个输入符号b是否属于与归约项目A→α相关联的FOLLOW(A),但是b∈FOLLOW(A)只是归约α的一个必要条件,而非充分条件,即如果输入下一个字符是b,我们采用了归约操作,那么就一定可以说明b属于A的FOLLOW集,但是我们不能说:如果b属于A的FOLLOW集,那么就一定可以对A采用归约操作。

为解决冲突那么就可以引入了LR(1)分析。

十七、LR(1)文法

搜索符的两种传播方式:

1.项目[A->α.Bβ,a],当β能导出空串时,该项目的

搜索符a传播到项目[B->...,a],称为纵向传播

2.项目[A->α.B β,a],搜索符a传播到项目[A->αB .β,a]

称为横向传播
步骤:

1、拓广文法并编号

2、项目集规范族(带向前搜索符)

3、LR(1)分析表

例题1:

G[S]:

S->BB

B->bB|a

解答如下

1、拓广文法并编号

S'->S(0)

S->BB(1)

B->bB(2)

B->a(3)

2、项目集规范族(带向前搜索符)

3、LR(1)分析表

例题2

十八、写出表达式的四元式

三条规则:

1.格式:(运算符,运算对象,运算对象,临时变量)

2.先处理优先级高的一部分,然后左遍历

3.每一次运算结果用一个临时变量储存,以便后续使用

例题1:a+b*(c/d+g)

(/,c,d,t1)

(+,t1,g,t2)

(*,b,t2,t3)

(+,a,t3,t4)

例题2:a+b*(c-d)+f/(c-d)^n

(-,c,d,t1)

(*,b,t1,t2)

(+,a,t2,t3)

(-,c,d,t4)

(^,t4,n,t5)

(/,f,t5,t6)

(+,t3,t6,t7)

十九、文法

属性文法

综合属性

继承属性

相关推荐
芊寻(嵌入式)7 分钟前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
准橙考典35 分钟前
怎么能更好的通过驾考呢?
人工智能·笔记·自动驾驶·汽车·学习方法
密码小丑2 小时前
11月4日(内网横向移动(一))
笔记
鸭鸭梨吖3 小时前
产品经理笔记
笔记·产品经理
齐 飞3 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
丫头,冲鸭!!!4 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
听忆.4 小时前
手机屏幕上进行OCR识别方案
笔记
Selina K5 小时前
shell脚本知识点记录
笔记·shell
5 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习
霍格沃兹测试开发学社测试人社区6 小时前
软件测试学习笔记丨Flask操作数据库-数据库和表的管理
软件测试·笔记·测试开发·学习·flask