编译原理 FIRST集和FOLLOW集的求法

合集下载

求first集和follow集

求first集和follow集
for(i=0;i<s1.size();i++)
{
cout<<s1[i]<<" "<<follow(s1[i])<<endl;
}
return 0;
}
四.实验截图
}
}
}
}
}
return s;
}
//******************************
int main()
{
int i;
string s1,s2;
char b;
cout<<"\t************求First集和Follow集**************"<<endl;
cout<<"请输入产生式的数目:";
}
else
{
rights=p[pos.front()].right;
for(i=0;i<rights.size();i++)
{
if(find(rights[i]))
{
s+=first(rights[i]);
index= s.find_last_of('@');
s=s.erase(index,1);
}
编译原理实验
实验名称:求first集和follow集
姓名:
学号:
教师签字:
成绩:
一.实验目的:
.掌握和了解first集和follow集的求解过程。
二.实验原理:
1.first集的求解:(1)若X∈Vt,则FIRST(X)={X};
(2)若X∈Vn,且有产生式X->a……,a∈Vt,则a∈FIRST(X);

【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集 近来复习编译原理,语法分析中的⾃上⽽下LL(1)分析法,需要构造求出⼀个⽂法的FIRST和FOLLOW集,然后构造分析表,利⽤分析表+⼀个栈来做⾃上⽽下的语法分析(递归下降/预测分析),可是这个FIRST集合FOLLOW集看得我头⼤。

教课书上的规则如下,⽤我理解的语⾔描述的:任意符号α的FIRST集求法:1. α为终结符,则把它⾃⾝加⼊FIRSRT(α)2. α为⾮终结符,则:(1)若存在产⽣式α->a...,则把a加⼊FIRST(α),其中a可以为ε(2)若存在⼀串⾮终结符Y1,Y2, ..., Yk-1,且它们的FIRST集都含空串,且有产⽣式α->Y1Y2...Yk...,那么把FIRST(Yk)-{ε}加⼊FIRST(α)。

如果k-1抵达产⽣式末尾,那么把ε加⼊FIRST(α) 注意(2)要连续进⾏,通俗地描述就是:沿途的Yi都能推出空串,则把这⼀路遇到的Yi的FIRST集都加进来,直到遇到第⼀个不能推出空串的Yk为⽌。

重复1,2步骤直⾄每个FIRST集都不再增⼤为⽌。

任意⾮终结符A的FOLLOW集求法:1. A为开始符号,则把#加⼊FOLLOW(A)2. 对于产⽣式A-->αBβ: (1)把FIRST(β)-{ε}加到FOLLOW(B) (2)若β为ε或者ε属于FIRST(β),则把FOLLOW(A)加到FOLLOW(B)重复1,2步骤直⾄每个FOLLOW集都不再增⼤为⽌。

⽼师和同学能很敏锐地求出来,⽽我只能按照规则,像程序⼀样⼀条条执⾏。

于是我把这个过程写成了程序,如下:数据元素的定义:1const int MAX_N = 20;//产⽣式体的最⼤长度2const char nullStr = '$';//空串的字⾯值3 typedef int Type;//符号类型45const Type NON = -1;//⾮法类型6const Type T = 0;//终结符7const Type N = 1;//⾮终结符8const Type NUL = 2;//空串910struct Production//产⽣式11 {12char head;13char* body;14 Production(){}15 Production(char h, char b[]){16 head = h;17 body = (char*)malloc(strlen(b)*sizeof(char));18 strcpy(body, b);19 }20bool operator<(const Production& p)const{//内部const则外部也为const21if(head == p.head) return body[0] < p.body[0];//注意此处只适⽤于LL(1)⽂法,即同⼀VN各候选的⾸符不能有相同的,否则这⾥的⼩于符号还要向前多看⼏个字符,就不是LL(1)⽂法了22return head < p.head;23 }24void print() const{//要加const25 printf("%c -- > %s\n", head, body);26 }27 };2829//以下⼏个集合可以再封装为⼀个⼤结构体--⽂法30set<Production> P;//产⽣式集31set<char> VN, VT;//⾮终结符号集,终结符号集32char S;//开始符号33 map<char, set<char> > FIRST;//FIRST集34 map<char, set<char> > FOLLOW;//FOLLOW集3536set<char>::iterator first;//全局共享的迭代器,其实觉得应该⽤局部变量37set<char>::iterator follow;38set<char>::iterator vn;39set<char>::iterator vt;40set<Production>::iterator p;4142 Type get_type(char alpha){//判读符号类型43if(alpha == '$') return NUL;//空串44else if(VT.find(alpha) != VT.end()) return T;//终结符45else if(VN.find(alpha) != VN.end()) return N;//⾮终结符46else return NON;//⾮法字符47 }主函数的流程很简单,从⽂件读⼊指定格式的⽂法,然后依次求⽂法的FIRST集、FOLLOW集1int main()2 {3 FREAD("grammar2.txt");//从⽂件读取⽂法4int numN = 0;5int numT = 0;6char c = '';7 S = getchar();//开始符号8 printf("%c", S);9 VN.insert(S);10 numN++;11while((c=getchar()) != '\n'){//读⼊⾮终结符12 printf("%c", c);13 VN.insert(c);14 numN++;15 }16 pn();17while((c=getchar()) != '\n'){//读⼊终结符18 printf("%c", c);19 VT.insert(c);20 numT++;21 }22 pn();23 REP(numN){//读⼊产⽣式24 c = getchar();25int n; RINT(n);26while(n--){27char body[MAX_N];28 scanf("%s", body);29 printf("%c --> %s\n", c, body);30 P.insert(Production(c, body));31 }32 getchar();33 }3435 get_first();//⽣成FIRST集36for(vn = VN.begin(); vn != VN.end(); vn++){//打印⾮终结符的FIRST集37 printf("FIRST(%c) = { ", *vn);38for(first = FIRST[*vn].begin(); first != FIRST[*vn].end(); first++){39 printf("%c, ", *first);40 }41 printf("}\n");42 }4344 get_follow();//⽣成⾮终结符的FOLLOW集45for(vn = VN.begin(); vn != VN.end(); vn++){//打印⾮终结符的FOLLOW集46 printf("FOLLOW(%c) = { ", *vn);47for(follow = FOLLOW[*vn].begin(); follow != FOLLOW[*vn].end(); follow++){48 printf("%c, ", *follow);49 }50 printf("}\n");51 }52return0;53 }主函数其中⽂法⽂件的数据格式为(按照平时做题的输⼊格式设计的):第⼀⾏:所有⾮终结符,⽆空格,第⼀个为开始符号;第⼆⾏:所有终结符,⽆空格;剩余⾏:每⾏描述了⼀个⾮终结符的所有产⽣式,第⼀个字符为产⽣式头(⾮终结符),后跟⼀个整数位候选式的个数n,之后是n个以空格分隔的字符串为产⽣式体。

编译原理一些习题答案

编译原理一些习题答案

第2章形式语言基础2.2 设有文法G[N]: N -> D | NDD -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9(1)G[N]定义的语言是什么?(2)给出句子0123和268的最左推导和最右推导。

解答:(1)L(G[N])={(0|1|2|3|4|5|6|7|8|9)+} 或L(G[N])={α| α为可带前导0的正整数}(2)0123的最左推导:N ⇒ ND ⇒ NDD ⇒ NDDD ⇒ DDDD ⇒ 0DDD ⇒ 01DD ⇒ 012D ⇒ 0123 0123的最右推导:N ⇒ ND ⇒ N3 ⇒ ND3 ⇒ N23 ⇒ ND23 ⇒ N123 ⇒ D123 ⇒ 0123268的最左推导:N ⇒ ND ⇒ NDD ⇒ DDD ⇒ 2DDD ⇒ 26D ⇒ 268268的最右推导:N ⇒ ND ⇒ N8 ⇒ ND8 ⇒ N68 ⇒ D68 ⇒ 2682.4 写一个文法,使其语言是奇数的集合,且每个奇数不以0开头。

解答:首先分析题意,本题是希望构造一个文法,由它产生的句子是奇数,并且不以0开头,也就是说它的每个句子都是以1、3、5、7、9中的某个数结尾。

如果数字只有一位,则1、3、5、7、9就满足要求,如果有多位,则要求第1位不能是0,而中间有多少位,每位是什么数字(必须是数字)则没什么要求,因此,我们可以把这个文法分3部分来完成。

分别用3个非终结符来产生句子的第1位、中间部分和最后一位。

引入几个非终结符,其中,一个用作产生句子的开头,可以是1-9之间的数,不包括0,一个用来产生句子的结尾,为奇数,另一个则用来产生以非0整数开头后面跟任意多个数字的数字串,进行分解之后,这个文法就很好写了。

N -> 1 | 3 | 5 | 7 | 9 | BNB -> 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | B02.7 下面文法生成的语言是什么?G1:S->ABA->aA| εB->bc|bBc G2:S->aA|a A->aS解答:B ⇒ bcB ⇒ bBc⇒ bbccB ⇒ bBc⇒ bbBcc ⇒ bbbccc……A ⇒εA ⇒ aA ⇒ aA ⇒ aA ⇒ aaA ⇒ aa……∴S ⇒ AB ⇒ a m b n c n , 其中m≥0,n≥1即L(G1)={ a m b n c n | m≥0,n≥1} S ⇒ aS ⇒ aA ⇒ aaS ⇒ aaaS ⇒ aA ⇒ aaS ⇒ aaaA ⇒aaaaS ⇒ aaaaa ……∴S ⇒ a2n+1 , 其中n≥0即L(G2)={ a2n+1 | n≥0}2.11 已知文法G[S]: S->(AS)|(b)A->(SaA)|(a)请找出符号串(a)和(A((SaA)(b)))的短语、简单短语和句柄。

求解FOLLOW集的方法

求解FOLLOW集的方法

求解FOLLOW集的方法刚刚学习FOLLOW集时总是容易忽略一些条件而造成错误,学会FOLLOW集的求解对于编译原理的学习很重要,一旦求错就容易造成分析SLR(1)分析表时出现错误。

1、对文法中的每个A属于V n,计算FOLLOW(A):(1)、对文法的开始符号S,将“$”加到FOLLOW(S)中;(2)、若A->aBb是一条规则,则把FIRST(b)中的非ε元素加到FOLLOW(B)中;(3)、若A->aB或A->aBb是一条规则且b=>ε,则把FOLLOW(A)加到FOLLOW(B)中;(4)、反复使用(2)、(3),直到每个非终结符的FOLLOW集不再增大为止。

看完规则,难免觉得有些许枯燥,下面我将列举一个较复杂的例子,可以使用到上述的全部规则。

eg: 设有文法G[A]:A→BCc | gDB B→bCDE |ε C→DaB | ca D→dD |ε E→gAf | c计算该文法的每一个非终结符的FIRST集和FOLLOW集。

解:(1)、FIRST集的求解:FIRST(A) = FIRST(BCc) ∪ FIRST(gDB)= FIRST(B) ∪ FIRST(C) ∪ {c} ∪ {g}= {b} ∪ FIRST(D) ∪ {a} ∪ {c,,g}= {a,b,c,d,g}同理:FIRST(B) = {b,ε} FIRST(C) = {a,c,d}FIRST(D) = {d,ε} FIRST(E) = {g,c}(2)、接下来求解FOLLOW集:a、由于A是文法的开始符号,所以$属于FOLLOW(A),由E→gAf | c l利用规则(2)可知f属于FOLLOW(A),所以FOLLOW(A)={f,$}b、由A→BCc利用规则(2)把FIRST(C)中的非ε元素加到FOLLOW(B)中,利用规则(3)把FOLLOW(A)加到FOLLOW(B)中;所以a,c,d,f,$属于FOLLOW(B).此外,由A→gDB ,C→DaB利用规则(3)把FOLLOW(A),FOLLOW(C)加到FOLLOW(B)中,由于还没求FOLLOW(C),暂不求FOLLOW(B).c、由A→BCc利用规则(2)把FIRST(c)加入FOLLOW(C),则c属于FOLLOW(C), 由B→bCDE利用规则(2)将FIRST(D)中的非ε元素加入FOLLOW(C),则d属于FOLLOW(C),当FIRST(D)的元素为ε时,紧跟随在C后面的是E,所以FIRST(E)的非ε元素也应计入FOLLOW(C)中,则g也属于FOLLOW(C),所以FOLLOW(C)={c,d,g}由此可求得FOLLOW(B)={a,c,d,f,g,$}d、由A→gDB 利用规则(2)把FIRST(B)中的非ε元素加到FOLLOW(D)中,则b属于FOLLOW(D)。

《编译原理》课后习题答案第5章

《编译原理》课后习题答案第5章

《编译原理》课后习题答案第5章《编译原理》课后习题答案第5章.pdf《编译原理》课后习题答案第5章.pdf第5章自顶向下语法分析方法第1题对文法G[S] S→a|∧|(T) T→T,S|S(1) 给出(a,(a,a))和(((a,a),∧,(a)),a)的最左推导。

(2) 对文法G,进行改写,然后对每个非终结符写出不带回溯的递归子程序。

(3) 经改写后的文法是否是LL(1)的?给出它的预测分析表。

(4) 给出输入串(a,a)#的分析过程,并说明该串是否为G的句子。

答案:(1) 对(a,(a,a)的最左推导为:S(T) (T,S) (S,S) (a,S) (a,(T)) (a,(T,S)) (a,(S,S)) (a,(a,S)) (a,(a,a))对(((a,a),∧,(a)),a) 的最左推导为:S(T) (T,S) (S,S) ((T),S) ((T,S),S) ((T,S,S),S) ((S,S,S),S) (((T),S,S),S) (((T,S),S,S),S) (((S,S),S,S),S) (((a,S),S,S),S) (((a,a),S,S),S) (((a,a),∧,S),S) (((a,a),∧,(T)),S)(((a,a),∧,(S)),S)《编译原理》课后习题答案第5章.pdf《编译原理》课后习题答案第5章.pdf(((a,a),∧,(a)),S) (((a,a),∧,(a)),a)(2) 改写文法为:0) S→a 1) S→∧ 2) S→( T ) 3) T→S N 4) N→, S N 5) N→ε非终结符FIRST集FOLLOW集S {a,∧,(} {#,,,)} T {a,∧,(} {)} N {,,ε} {)}对左部为N的产生式可知:FIRST (→, S N)={,} FIRST (→ε)={ε} FOLLOW (N)={)}由于SELECT(N →, S N)∩SELECT(N →ε) ={,}∩ { )}= 所以文法是LL(1)的。

编译原理大题

编译原理大题

五、语法分析——自底向上分析法已知文法G:EE+TE TTT*FTFF(E)Fi(1)求文法G中每个非终结符的First集和Follow集。

(2)构造文法G的SLR(1)预测分析表。

(20分)首先构造增广文法:SEEE+TE TTT*FTFF(E)FiFirst(S)=First(E)=First(T)=First(F)={(,I)Follow(S)={#} Follow(E)={+,#,}}Follow(T)={+,},#,*} Follow(F)={+,},#,*}状态Action Gotoi + * ( ) # E T F0 S5 S4 1 2 31 S6 Acc2 r 2 S7 r 2 r 23 r4 r 4 r 4 r44 S5 S4 8 2 35 r6 r 66 S5 9 37 S5 108 S6 S119 r 1 S7 r 1 r 110 r 3 r 3 r 3 r 311 r 5 r 5 r 5 r 5注:识别可归前缀的DFA共12项。

词法分析——确定性有穷自动机为以下字符集编写正规表达式,并构造与之等价的最简DFA(写出详细的具体过程):在字母表{a,b}上的包含偶数个a且含有任意数目b的所有字符串。

(15分)(b*ab*ab*)*b a b1a状态Action GOTOa b d e f $ S R T0 S3 11 acc2 r2 S3 r2 r2 53 S6 S4 24 r4 r4 r4 r45 S10 96 77 S88 r3 r3 r3 r39 r1 r1 r110 r6 S6 S4 r6 r6 1111 S1212 r5 r5 r5五、语法分析——自底向上分析法已知文法G:S’SS bRSTS bRRdSaR eTfRaTf(1)求文法G中每个非终结符的First集和Follow集。

(2)构造文法G的SLR(1)预测分析表。

(20分)frist(s’)={b} follow(s’)={$}frist(s)={b} follow(s)={f,a, $}frist(R) ={d,e} follow( R )={a,b,f, $}frist(T)={t} follow (T)={a,f,#}五、对下面的文法(15分)S->UTa|TbT->S|Sc|dU->US|e判断是否为LR(0),SLR(1),说明理由,并构造相应的分析表。

first集合和follow集合的求法

first集合和follow集合的求法

first集合和follow集合的求法
FIRST集合和FOLLOW集合的求法如下:
1、FIRST集合的求法:
直接收取:如果X是终结符或为空,则First(X) = {X}。

反复传送:如果X是非终结符,则First集合一直传送下去,直到遇到终结符。

第一个状态减去ε(即空字符串)后加入到First集合中。

注意传送时非终结符是否可以为空,如果可以为空,则看下一个字符。

对于形如“…UP…”(P是非终结符)的组合,把First(P)直接收入到First集合中。

遇到形如E →TE’这样的产生式时,先把First(T)放入First(E),然后查看T是否能推导出ε(即空字符串)。

如果能,则把First(E’)放入First(E),以此类推。

若T不能推出ε,则First(E)求完。

2、FOLLOW集合的求法:
对于文法的开始符号S,将识别符号“#”置于FOLLOW(S)中。

若存在产生式A →αBβ,则将First(β) - {ε}加至FOLLOW(B)中。

这里,First(β)表示β能推导出的第一个终结符或非终结符的集合,但要去掉ε。

如果β可以推导出ε,则将FOLLOW(A)加至FOLLOW(B)中。

这意味着,如果B有可能是最后一个符号,那么A的FOLLOW集合应该加入到B的FOLLOW集合中。

反复使用上述规则,直到所求FOLLOW集合不再增大为止。

以上是对FIRST集合和FOLLOW集合求法的简要概述。

在实际应用中,需要根据具体的文法和产生式进行具体的分析和计算。

编译原理实验+求first集和follow集+代码

编译原理实验+求first集和follow集+代码

编译原理实验+求first集和follow集+代码/*说明:输入格式:每行输入一个产生式,左部右部中间的→用空格代替。

非终结符等价于大写字母^ 表示空输入到文件结束,或用 0 0 结尾。

Sample Input:(习题5·3):S MHS aH LSoH ^K dMLK ^L eHfM KM bLM0 0*/#include#include#include#include#includeusing namespace std;char l;string r;multimap sentence; //存储产生式multimap senRever; //产生式逆转set ter; //非终结符集合map toEmpty; //非终结符能否推出空bool flag;set fir; // 保存单个元素的first集set follow; //保存单个元素的follow集vector rightSide; //右部char Begin;bool capL(char c) //字母是否大写{if(c<='Z' && c>='A')return true;return false;}/*bool lowerL(char c) //小写字母{if(c<='z' && c>='a')return true;return false;}*/bool CapLString(string s) // 大写字符串{for(int i=0; iif(!capL(s[i])) {return false;}}return true;}bool isToEmpty(char ch) // 判断终结符能否推出空{bool flag;// for(set::iterator sIter = ter.begin(); sIter!=ter.end(); ++sIter) {flag = false;multimap::iterator mIter = sentence.find(ch);int cnt = sentence.count(ch);for(int i=0; iif(mIter->second=="^") {return true;// toEmpty[ch] = true;}else if(CapLString(mIter->second)){string s(mIter->second);bool flag2 = true;for(int j=0; jif(!isToEmpty(s[j]) || s[j]==ch) {flag2 = false;break;}}if(flag2) { // 右部全为终结符,全能推出空return true;}}}// }return false;}void getFirst(char ch, set &First) //求单个元素的 FIRST集{// if(flag)// return;multimap::iterator imul = sentence.find(ch);if(imul==sentence.end())return;int sum = sentence.count(imul->first);// cout<first<<endl;for(int i=0; i// cout<second<<endl;string s(imul->second);for(int j=0; jif(!capL(s[j])) {// cout<<" "<<s[j]<<endl;First.insert(s[j]);// flag = true;break;}else if(capL(s[j])) {if(s[j]==ch) { //有左递归,跳出循环break;;}getFirst(s[j], First);if(toEmpty[s[j] ]==false) {break;}}}}flag = true;}bool isLast(string s, char ch) //ch 是否是 s 的直接或间接的最后一个非终结符{if(!capL(ch))return false;for(int i=s.size()-1; i>=0; i--) {if(ch==s[i])return true;if(!capL(s[i]) || toEmpty[s[i] ]==false) {return false;}}return false;}void getFollow(char ch, set<cha</cha</s[j]<<endl;</endl;</endl;r> &follow) //求单个元素的 FOLLOW集{if(!capL(ch))return;for(vector::iterator iter=rightSide.begin(); iter!=rightSide.end(); ++iter) {for(int i=0; i<(*iter).size(); i++) {if(ch==(*iter)[i] && i!=(*iter).size()-1) {if(!capL((*iter)[i+1])) {follow.insert((*iter)[i+1]);}else {getFirst((*iter)[i+1], follow);}}if(ch==(*iter)[i] && i==(*iter).size()-1) { //判断是否是右部的最后一个非终结符 follow +#follow.insert('#');}else if(ch==(*iter)[i] && i<(*iter).size()-1){ //不是最后一个但之后全是非终结符且都能推出空 follow +#bool flag1=true;for(int j=i+1;j<(*iter).size(); j++) {if(!capL((*iter)[j]) || toEmpty[(*iter)[j]]==false) {flag1 = false;if(!capL((*iter)[j])) {follow.insert((*iter)[j]);}break;}}if(flag1 == true) {follow.insert('#');}}}if(isLast(*iter, ch)) { //ch是*iter的最后一个符号(直接或间接)int n = senRever.count(*iter);multimap::iterator mIter = senRever.find(*iter);for(int i=0 ;iif(mIter->second!=ch )getFollow(mIter->second, follow);}}}}int main(){int cnt=0;while(cin>>l>>r) {if(cnt==0) {Begin = l;cnt++;}if(l=='0')break;sentence.insert(make_pair(l, r)); //产生式senRever.insert(make_pair(r,l));ter.insert(l); //非终结符集合(左部)rightSide.push_back(r); //右部的集合/* if(r=="^") { // 判断是否有非终结符->^toEmpty[l] = true;}else {if(toEmpty.find(l)==toEmpty.end()) {toEmpty[l] = false;}} */}for(set::iterator sIter = ter.begin(); sIter!=ter.end(); ++sIter) { // 判断是否有非终结符->^if(isToEmpty(*sIter) ) {toEmpty[*sIter] = true;}else {toEmpty[*sIter] = false;}}for(set::iterator iter=ter.begin(); iter!=ter.end(); iter++) {flag = false;cout<<*iter<<" FIRST集 :";fir.clear();getFirst(*iter, fir);for(set::iterator iterF=fir.begin(); iterF!=fir.end(); iterF++) {cout<<" "<<*iterF;}cout<<endl;follow.clear();getFollow(*iter, follow);cout<<" FOLLOW集:";if(*iter==Begin) {cout<<" #";}for(set::iterator iterF=follow.begin(); iterF!=follow.end(); ++iterF) {if(*iterF!='^')cout<<" "<<*iterF;}cout<<endl<<endl;}system("pause");return 0;}</endl<<endl; </endl;。

FIRST集和FOLLOW集求法

FIRST集和FOLLOW集求法

FIRST集和FOLLOW集求法龙书算法:First:(1)、如果X是终结符,那么First(X) = X;(2)、如果X是⾮终结符,且XàY1Y2......Yk是⼀个产⽣式,其中k>=1;那么如果对于某个I, a在First(Yi)中,且#(空串)在所有的First(Y1)…..First(Yi-1)中,就吧a加⼊到First(X)中。

(3)、如果Xà#(空串)是⼀个产⽣式,那么将#加⼊到First(X)中。

Follow:(1)、将$放⼊到Follow(S)中,其中S是开始符号,⽽$是输⼊右端结束的标记。

(2)、如果存在⼀个产⽣式AàaBb,那么First(b)中除#(空串)外地所有符号都在Follow(B)中。

(3)、如果存在⼀个产⽣式AàaB, 或存在AàaBb且First(b)包含#(空串),那么Follow(A)中的所有符号都在Follow(B)中。

⾃⼰理解:First:(看X的产⽣式)(1)、如果X是终结符,那么First(X)= X;(2)、如果X是⾮终结符,且XàY1Y2......Yk,i=1;1)、将First(Yi)加⼊到First(X)中,2)、如果#包含着First(Yi)中,i++,重复1);3)、如果#不包含在First(Yi)中,First(X)计算完成;(3)、如果Xà#(空串)是⼀个产⽣式,那么将#加⼊到First(X)中。

Follow:(看在右边有B的产⽣式)(1)、将$放⼊到Follow(S)中,其中S是开始符号,⽽$是输⼊右端结束的标记。

(2)、如果存在⼀个产⽣式AàaBb,那么First(b)中除#(空串)外地所有符号都在Follow(B)中。

(3)、如果存在⼀个产⽣式AàaB, 或存在AàaBb且First(b)包含#(空串),那么Follow(A)中的所有符号都在Follow(B)中。

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

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

例 S::=aABbcd|ε,A::=ASd|ε,B::=SAh|eC|ε,
C::=Sf|Cg|ε,求此文法的每一个非终结符号的
FOLLOW集。
解:FOLLOW(S)={#}∪FIRST(d) ∪(FIRST(Ah)-{ε}) ∪FIRST(f)
={#}∪{d}∪{a,d,h}∪{f} = {a,d,h,f,#}
4)若对于一切1≤i≤n,ε∈FIRST(Xi),则将ε符号加 进FIRST(α)。
例4-1(P62) 有文法: E→TE′ E′→+TE′ E′→ε T→FT′ T′→*FT′ T′→ε F→(E)|i 求文法中非 终结符号以及各 产生式右部符号 串的FIRST集。
解:该文法的非终结符号有E、E′、 T、T′和F。 FIRST(E)=FIRST(TE′) =FIRST(FT′E′)={ ( ,i } FIRST(+TE′)={ + } FIRST(ε)={ε} FIRST(E′)=FIRST(+TE′) ∪FIRST(ε)={+ ,ε} FIRST(T)=FIRST(FT′)={ ( ,i } FIRST(*FT′)={ * } FIRST(T′)=FIRST(*FT′) ∪FIRST(ε)={* ,ε} FIRST((E))={ ( } FIRST(i)={ i } FIRST(F) =FIRST((E)) ∪FIRST(i)={( ,i}
分析法算符优先分析法简单优先分析法优先分析法自底向上带回溯递归下降分析法分析法不带回溯自顶向下语法分析lr回溯示例41p61自顶向下的分析方法就是从文法的开始符号出发按最左推导方式向下推导试图推导出要分析的输开始符号输入符号串自底向上的分析方法从输入符号串开始按最左归约方式向上归约到文法的开始符号

编译原理及实践教程(黄贤英 王柯柯 编著) 习题答案

编译原理及实践教程(黄贤英 王柯柯 编著) 习题答案

第2章参考答案:1,2,3:解答:略!4. 解答:A:① B:③ C:① D:②5. 解答:用E表示<表达式>,T表示<项>,F表示<因子>,上述文法可以写为:E → T | E+TT → F | T*FF → (E) | i最左推导:E=>E+T=>E+T+T=>T+T+T=>F+T+T=>i+T+T=>i+F+T=>i+i+T=>i+i+F=>i+i+iE=>E+T=>T+T=>F+T=>i+T=>i+T*F=>i+F*F=>i+i*F=>i+i*i 最右推导:E=>E+T=>E+F=>E+i=>E+T+i=>E+F+i=>E+i+i=>T+i+i=>F+i+i=>i+i+iE=>E+T=>E+T*F=>E+T*i=>E+F*i=>E+i*i=>T+i*i=>F+i*i =>i+i*ii+i+i和i+i*i的语法树如下图所示。

i+i+i、i+i*i的语法树6. 解答:(1) 终结符号为:{or,and,not,(,),true,false}非终结符号为:{bexpr,bterm,bfactor}开始符号为:bexpr(2) 句子not(true or false)的语法树为:7. 解答:(1) 把a n b n c i分成a n b n和c i两部分,分别由两个非终结符号生成,因此,生成此文法的产生式为:S → ABA → aAb|abB → cB|ε(2) 令S为开始符号,产生的w中a的个数恰好比b多一个,令E为一个非终结符号,产生含相同个数的a和b的所有串,则产生式如下:S → aE|Ea|bSS|SbS|SSbE → aEbE|bEaE|ε(3) 设文法开始符号为S,产生的w中满足|a|≤|b|≤2|a|。

求first和follow集合c++

求first和follow集合c++
};
struct biaoji//第三步扫描式子的右部标记号
{
int r[100];
};
struct first//初步求first集合时用
{ char fjihe[200];
};
struct first2//保存最终的first集合
{ char fjihe2[200];
};
{ fji[u].fjihe[0]='\0';
}
for(a3=0;a3<=n;a3++)
{if(shizi[a3].right[0]>='a' && shizi[a3].right[0]<='z')
{
linshi2[0]=shizi[a3].right[0];
if(kongshi[a5].kongzuo!=1)
{strcat(fji[a5].fjihe,fji[a8].fjihe);
}
else{strcat(fji[a5].fjihe,fji[a8].fjihe);
for(b1=0;b1<n;b1++)
{ fw[b1].fow[0]='\0';
}
fw[0].fow[0]='#';
fw[0].fow[1]='\0';
for(b8=0;b8<n;b8++)
{ if(shizi[b8].left==shizi[0].left)
fw[b8].fow[0]='#';
{if(shizi[b2].right[b3]==shizi[b9].left)

【编译原理】FIRST集、FOLLOW集算法原理和实现

【编译原理】FIRST集、FOLLOW集算法原理和实现

【编译原理】FIRST集、FOLLOW集算法原理和实现书中⼀些话,不知是翻译的原因。

还是我个⼈理解的原因感觉不是⾮常好理解。

个⼈重新整理了⼀下。

不过相对于消除左递归和提取左公因,FIRST集和FOLLOW集的算法相对来说⽐较简单。

书中的重点给出:FIRST:⼀个⽂法符号的FIRST集就是这个符号能推导出的第⼀个终结符号的集合, 包括空串。

例: A -> abc | def | ε那么FIRST(A) 等于 { a, d, ε }。

FOLLOW:蓝线画的部分很重要。

特别是这句话:请注意,在这个推导的某个阶段,A和a之间可能存在⼀些⽂法符号。

单如果这样,这些符号会推导得到ε并消失。

这句话的意思就是好⽐说: S->ABa B->c | ε 这个⽂法 FOLLOW(A)的值应该是FIRST(B)所有的终结符的集合(不包含ε),但是FIRST(B)是包含ε的,说明B是可空的,既然B是可空的S->ABa 也可以看成 S->Aa。

那么a就可以跟在A的后⾯.所以在这种情况下,FOLLOW(A)的值是包含a的。

换句话说就是。

⼀个⽂法符号A的FOLLOW集合就是它的下⼀个⽂法符号B的FIRST集合。

如果下⼀个⽂法符号B的FIRST集合包含ε,那么我们就要获取下⼀个⽂法符号B的FOLLOW集添加到FOLLOW(A)中代码中的注释已经很详细// 提取First集合func First(cfg []*Production, sym *Symbolic) map[string] *Symbolic {result := make(map[string] *Symbolic)// 规则⼀如果符号是⼀个终结符号,那么他的FIRST集合就是它⾃⾝if sym.SymType() == SYM_TYPE_TERMINAL || sym.SymType() == SYM_TYPE_NIL {result[sym.Sym()] = symreturn result}// 规则⼆如果⼀个符号是⼀个⾮终结符号// (1) A -> XYZ 如果 X 可以推导出nil 那么就去查看Y是否可以推导出nil// 如果 Y 推导不出nil,那么把Y的First集合加⼊到A的First集合// 如果 Y 不能推导出nil,那么继续推导 Z 是否可以推导出nil,依次类推// (2) A -> XYZ 如果XYZ 都可以推导出 nil, 那么说明A这个产⽣式有可能就是nil,这个时候我们就把nil加⼊到FIRST(A)中for _, production := range cfg {if production.header == sym.Sym() {nilCount := 0for _, rightSymbolic := range production.body { // 对于⼀个产⽣式ret := First(cfg, rightSymbolic) // 获取这个产⽣式体的First集合hasNil := falsefor k, v := range ret {if v.SymType() == SYM_TYPE_NIL { // 如果推导出nil, 标识当前产⽣式体的符号可以推导出nilhasNil = true} else {result[k] = v}}if false == hasNil { // 当前符号不能推导出nil, 那么这个产⽣式的FIRST就计算结束了,开始计算下⼀个产⽣式break}// 当前符号可以推导出nil,那么开始推导下⼀个符号nilCount++if nilCount == len(production.body) { // 如果产⽣式体都可以推导出nil,那么这个产⽣式就可以推导出nilresult["@"] = &Symbolic{sym: "@", sym_type: SYM_TYPE_NIL}}}}}return result}// 提取FOLLOW集合func Follow(cfg []*Production, sym string) [] *Symbolic {fmt.Printf("Follow ------> %s\n", sym)result := make([] *Symbolic, 0)// ⼀个⽂法符号的FOLLOW集就是可能出现在这个⽂法符号后⾯的终结符// ⽐如 S->ABaD, 那么FOLLOW(B)的值就是a。

first集合和follow集合的求法

first集合和follow集合的求法

first集合和follow集合的求法编译原理是计算机专业中的重要学科,其中语法分析是编译原理的基础。

而语法分析器(Parser)的核心就是构建语法分析表格。

而在构建语法分析表格的过程中,first集合和follow集合的求法是一个非常重要的问题,本文就将详细介绍first集合和follow集合的求法。

一、first集合first集合指的是文法中每个非终结符号的经过一次推导得到的所有终结符号的集合,也就是最小前缀(First)的集合。

例如对于一个简单的文法表达式E→E+T|T,其中E和T是非终结符号,+是终极符号。

那么开始寻找E的first集合时,我们应该先判断E能够推导出哪些符号,根据文法表达式,E可以推导出E+T和T。

接着我们可以判断E+T和T 所能推导出的所有终结符号,并将这些终结符号加入到E的first集合中。

具体步骤可以参考下面的推导过程:E → E + TE → TT → a那么最终E的first集合就是{a,+}。

二、follow集合follow集合指的是文法中每个非终结符号在所有推导过程中后跟的符号的集合。

例如对于一个简单的文法表达式E→E+T|T,其中E和T是非终结符号,+是终极符号。

求解E的follow集合时,首先要考虑的是E出现在了哪些地方。

通过分析E在文法表达式中的位置,我们可以发现E出现在了三种不同的情况下:1. E是文法的起始符号,此时E的follow集合中必须包含结束符$。

2. E出现在某些规则的右侧,此时E的follow集合中必须包含右侧的符号的first集合,但是需要注意的是,如果推导出空串,则应该将右侧的非终结符号所在位置的follow集合添加进来。

3. E的右侧是其所在规则的最末尾,此时需要将E所在规则的左侧符号所在位置的follow集合添加到E的follow集合中。

根据以上三种情况,我们可以结合上面的文法表达式来推导出E的follow集合。

具体步骤可以参考下面的推导过程:S → EE → E + TE → TT → a1. $ ∈ follow(E)2. follow(T) = {+, $}follow(E) = first(T) ∪ {+, $}follow(E) = {+, a, $}3. follow(E) = {+, $}那么最终E的follow集合就是{+, a, $}。

求文法的集first 和follow集

求文法的集first 和follow集

#include<iostream>#include"string.h"#define MAX 100using namespace std;//产生式结构体struct product{int rl;char l,r[20];}p[100];//first 和follow 集struct set{int n;//元素数量char elm[100];}first[MAX],follow[MAX];int table[MAX][MAX];//预测分析表char v[100],t[100];//变量和终结符int n,vnum,tnum;//产生式数量,变量数量和终结符数量//判断是否为终结符inline bool isterminal(char x){if(x>='A'&&x<='Z')return false;return true;}//判断符号x是否从未出现过bool ex(char x){int i;if(isterminal(x)){for(i=1;i<=tnum;i++)if(t[i]==x) return true;return false;}for(i=1;i<=vnum;i++)if(v[i]==x) return true;return false;}//读入文法void load(){int i,j,k;char tmp[25];//printf("输入产生式的数量:"); scanf("%d",&n);for(vnum=tnum=0,i=1;i<=n;i++) {scanf("%s",tmp);p[i].l=tmp[0];if(!ex(tmp[0])) v[++vnum]=tmp[0]; for(k=0,j=3;tmp[j];j++){p[i].r[k++]=tmp[j];if(isterminal(tmp[j])){if(!ex(tmp[j]))t[++tnum]=tmp[j];}else if(!ex(tmp[j]))v[++vnum]=tmp[j];}p[i].r[k]=0,p[i].rl=k-1;}t[++tnum]=v[++vnum]='#';}//输出用户输入的文法void show(){int i;for(i=1;i<=n;i++)printf("%c->%s\n",p[i].l,p[i].r);}//把符号x变为对应的编号int cid(char x){int i;if(!isterminal(x)){for(i=1;i<=vnum;i++)if(v[i]==x) return i;}for(i=1;i<=tnum;i++)if(t[i]==x) return i+1000;return -1;}//判断集合st里面是否包含符号idtbool inclu(struct set &st,char idt){int i;for(i=1;i<=st.n;i++)if(st.elm[i]==idt)return true;return false;}//把符号e添加到集合st里面inline void add(struct set &st,char e){st.n++;st.elm[st.n]=e;}//求first集void makefirst(){int i,j,k,idl,idr;bool inc;inc=true;while(inc){inc=false;for(i=1;i<=n;i++) //遍历所有产生式{idl=cid(p[i].l);for(j=0;p[i].r[j];j++){idr=cid(p[i].r[j]);//如果当前为终结符//并且first[idl]中不包含这个终结符就把这个终结符加入first[idl] if(idr>1000){if(!inclu(first[idl],p[i].r[j])){add(first[idl],p[i].r[j]);inc=true;}break;}//否则把该变量的first集里面的元素加入first[idl]else{for(k=1;k<=first[idr].n;k++)if(!inclu(first[idl],first[idr].elm[k])){add(first[idl],first[idr].elm[k]);inc=true;}}//.....if(!inclu(first[idl],'~')) break;}}// 若idl可以转换为空,则‘~’应属于first[idl]if(p[i].r[j]==0&&!inclu(first[idl],'~')){add(first[idl],'~');inc=true;}}}}//输出集合,flag用于表示是first还是followvoid print(struct set *st,int flag){int i,j;char *s;puts("\n");flag==0? s="FIRST":s="FOLLOW";for(i=1;i<=vnum;i++){printf("%s(%c): ",s,v[i]);for(j=1;j<=st[i].n;j++)printf("%c ",st[i].elm[j]);puts("");}}//求follow集void makefollow(){int i,j,k,idl,idr,idf;bool flag,inc=true;add(follow[1],'#');//把结束标志"#"加入起始符的follow集while(inc){inc=false;for(i=1;i<=n;i++)idl=cid(p[i].l);for(flag=true,j=p[i].rl;j>=0;j--){idr=cid(p[i].r[j]);if(idr>1000){flag=false; continue;}if(flag){for(k=1;k<=follow[idl].n;k++){if(!inclu(follow[idr],follow[idl].elm[k])){add(follow[idr],follow[idl].elm[k]);inc=true;}}}if(j<p[i].rl) idf=cid(p[i].r[j+1]);else continue;if(idf>1000){if(!inclu(follow[idr],p[i].r[j+1]))add(follow[idr],p[i].r[j+1]);continue;}for(k=1;k<=first[idf].n;k++){if(!inclu(follow[idr],first[idf].elm[k])&&first[idf].elm[k]!='~') {add(follow[idr],first[idf].elm[k]);inc=true;}}}}}}void maketable(){int i,j,k,idl,idr,idt;char ch;bool flag;memset(table,0,sizeof(table));table[vnum][tnum]=-1;for(i=1;i<=n;i++){idl=cid(p[i].l);for(j=0;j<=p[i].rl;j++){ch=p[i].r[j];idr=cid(ch);if(idr>1000){idr-=1000;if(ch!='~'){if(table[idl][idr]) goto end;table[idl][idr]=i;}else{for(k=1;k<=follow[idl].n;k++){idt=cid(follow[idl].elm[k])-1000;if(table[idl][idt]) goto end;table[idl][idt]=i;}}break;}for(flag=false,k=1;k<=first[idr].n;k++) {idt=cid(first[idr].elm[k])-1000;if(first[idr].elm[k]=='~') flag=true; if(table[idl][idt]) goto end;table[idl][idt]=i;}if(!flag) break;}if(j>p[i].rl){for(k=1;k<=follow[idl].n;k++){idt=cid(follow[idl].elm[k])-1000;if(table[idl][idt]) goto end;table[idl][idt]=i;}}}return;end: printf("It's not a LL(1) language,and if you want to use this program to compile you may get a wrong answer!\n");return;}void compile(char *exp){int i,j,top,idl,idr,t,step[MAX],c=0;char stack[MAX];top=1;t=strlen(exp);stack[0]='#',stack[1]=v[1];exp[t]='#',exp[t+1]=0;for(i=0;;){idl=cid(stack[top]);idr=cid(exp[i])-1000;if(idl>1000) goto fail;t=table[idl][idr];if(t==0) goto fail;step[++c]=t;for(top--,j=p[t].rl;j>=0;j--){if(p[t].r[j]!='~')stack[++top]=p[t].r[j];}while(top>=0&&exp[i]&&stack[top]==exp[i]){if(stack[top]=='#') goto pass;top--,i++;}}pass: printf("Accept!\n");for(i=1;i<=c;i++)printf("%c->%s\n",p[step[i]].l,p[step[i]].r);return;fail: printf("Compile Error!\n");return;}int main(){char exp[MAX];freopen("LL(1).txt","r",stdin); load();show();makefirst();print(first,0);makefollow();print(follow,1);maketable();while(scanf("%s\n",exp)!=EOF) compile(exp);return 0;}。

编译原理实验报告FIRST集和FOLLOW集

编译原理实验报告FIRST集和FOLLOW集

编译原理实验报告实验名称计算first集合和follow集合实验时间院系计算机科学和技术班级软件工程1班学号姓名输入:任意的上下文无关文法。

输出:所输入的上下文无关文法一切非终结符的first 集合和follow 集合。

2. 实验原理设文法G[S]=(V N ,V T ,P ,S ),则首字符集为: FIRST (α)={a | α⇒*a β,a ∈V T ,α,β∈V *}。

若α⇒*ε,ε∈FIRST (α)。

由定义可以看出,FIRST (α)是指符号串α能够推导出的所有符号串中处于串首的终结符号组成的集合。

所以FIRST 集也称为首符号集。

设α=x 1x 2…x n ,FIRST (α)可按下列方法求得:令FIRST (α)=Φ,i =1;(1) 若x i ∈V T ,则x i ∈FIRST (α);(2) 若x i ∈V N ;① 若ε∉FIRST (x i ),则FIRST (x i )∈FIRST (α);② 若ε∈FIRST (x i ),则FIRST (x i )-{ε}∈FIRST (α);(3) i =i+1,重复(1)、(2),直到x i ∈V T ,(i =2,3,…,n )或x i∈V N 且若ε∉FIRST (x i )或i>n 为止。

当一个文法中存在ε产生式时,例如,存在A →ε,只有知道哪些符号可以合法地出现在非终结符A 之后,才能知道是否选择A →ε产生式。

这些合法地出现在非终结符A 之后的符号组成的集合被称为FOLLOW 集合。

下面我们给出文法的FOLLOW 集的定义。

设文法G[S]=(V N ,V T ,P ,S ),则FOLLOW (A )={a | S ⇒… Aa …,a ∈V T }。

若S ⇒*…A ,#∈FOLLOW (A )。

由定义可以看出,FOLLOW (A )是指在文法G[S]的所有句型中,紧跟在非终结符A 后的终结符号的集合。

FOLLOW 集可按下列方法求得:(1) 对于文法G[S]的开始符号S ,有#∈FOLLOW (S );(2) 若文法G[S]中有形如B →xAy 的规则,其中x ,y ∈V *,则FIRST(y )-{ε}∈FOLLOW (A );(3) 若文法G[S]中有形如B →xA 的规则,或形如B →xAy 的规则且ε∈FIRST (y ),其中x ,y ∈V *,则FOLLOW (B )∈FOLLOW (A );计算first集合和follow集合4.实验心得通过上机实验我对文法符号的FIRST集和FOLLOW集有了更深刻的理解,已经熟练的掌握了求解的思想和方法,同时也锻炼了自己的动手解决问题的能力,对编程能力也有所提高。

FIRST FOLLOW SELECT 的求法

FIRST FOLLOW SELECT 的求法

FIRST FOLLOW SELECT 的求法(一)求FIRST(α)的算法(α=x1x2…xn):根据定义计算①根据定义计算由定义4.1 FIRST(α)={a|αaβ,a∈VT,α,β∈V*},若αε,则规定ε∈FIRST(α)对每一文法符号X∈V 计算FIRST(X):(a) 若X∈VT,则FIRST(X)={X}。

(b) 若X∈VN,且有产生式X→a…,a∈VT,则a∈FIRST(X)。

(c) 若X∈VN,X→ε,则ε∈FIRST(X)。

(d) 若X∈VN;Y1,Y2,…,Yi∈VN,且有产生式X→Y1 Y2 … Yn;当Y1 Y2 … Yi-1都ε时,(其中1≤i≤n),则FIRST(Y1)、FIRST(Y2)、…、FIRST(Yi-1)的所有非{ε}元素和FIRST(Yi)都包含在FIRST(X)中。

(e) 当(d)中所有Yiε,(i=1,2,… n),则FIRST(X)=FIRST(Y1)∪FIRST(Y2)∪…∪FIRST(Yn)∪{ε}反复使用上述(b)~(e)步直到每个符号的FIRST集合不再增大为止。

求出每个文法符号的FIRST集合后也就不难求出一个符号串的FIRST集合。

若符号串α∈V*,α=X1 X2 … Xn,当X1不能ε,则置FIRST(α)= FIRST(X1)。

若对任何j(1≤j≤i-1,2≤i≤n), ε∈FIRST(Xj), 则FIRST(α)=(FIRST(Xj)\{ε})∪FIRST(Xi)当所有FIRST(Xj)(1≤j≤n)都含有{ε}时,则FIRST(α)=(FIRST(Xj))∪{ε}例4.7:文法G7[S]为:S→ABS→bCA→εA→bB→εB→aDC→ADC→bD→aSD→c解:FIRST(S)={FIRST(A)\{ε}}∪{FIRST(B)\{ε}}∪{ε}∪{b}={b,a,ε} FIRST(A)={b}∪{ε}={ b,ε}FIRST(B)={ε}∪{a}={a,ε}FIRST(C)={FIRST(A) \{ε}}∪FIRST(D)∪FIRST(b)={b,a,c}FIRST(D)={a}∪{c}={a,c}所以最终求得:FIRST(S)={a,b,ε}FIRST(A)={b,ε}FIRST(B)={a,ε}FIRST(C)={a,b,c}FIRST(D)={a,c}每个产生式的右部符号串的开始符号集合为:FIRST(AB)={a,b,ε}FIRST(bC)={b}FIRST(ε)={ε}FIRST(b)={b}FIRST(aD)={a}FIRST(AD)={a,b,c}FIRST(b)={b}FIRST(aS)={a}FIRST(c)={c}或:1.若n=0,即α=ε,则令FIRST(α)={ε};2.否则,对1≤i≤n,求FIRST(xi)3.若n=1,则令FIRST(α)=FIRST(x1);4.若n≥2且对一切j=1,2,…,i-1都有ε∈FIRST(xj),则令FIRST(xi )-{ε} FIRST(α),其中2≤i≤n;若对一切j=1,2,…,n都有ε∈FIRST(xj),则令ε∈FIRST(α)。

XXX-编译原理-命题作业-LL(1)文法的判断(完整答案)

XXX-编译原理-命题作业-LL(1)文法的判断(完整答案)

XXX-编译原理-命题作业-LL(1)文法的判断(完整答案)LL(1)文法的判断LL(1)文法本质含义是第一个L表明自顶向下分析是从左向右扫描输入串,第2个L表明分析过程中将使用最左推导,1表明只需向右看一个符号便可决定如何推导,即选择哪个产生式进行推导。

给定文法G:E ->TE'E'->+E|εT ->FT'T' ->T|εF-。

PF'F'-。

*F'|εP->(E)|a|b|^1) 计算该文法每个非终结符的FIRST集和FOLLOW集。

首先计算FIRST集合:FIRST(E) = FIRST(T) = FIRST(F) = FIRST(P) = {(。

a。

b。

^)}FIRST(E') = {+。

ε}FIRST(T') = FIRST(T) + {ε} = {(。

a。

b。

^。

ε)}FIRST(F') = {*。

ε}FIRST(P) = {(。

a。

b。

^)}然后计算FOLLOW集合:FOLLOW(E) = {)。

#}FOLLOW(E') = FOLLOW(E) = {)。

#}FOLLOW(T) = FIRST(E') ∪ FOLLOW(E) = {+。

)。

#}FOLLOW(T') = FOLLOW(T) = FIRST(E') ∪ FOLLOW(E) = {+。

)。

#}FOLLOW(F) = FIRST(T') ∪ FOLLOW(T) = {(。

a。

b。

^。

+。

)。

#}FOLLOW(F') = FOLLOW(F) = FIRST(T') ∪ FOLLOW(T) = {(。

a。

b。

^。

+。

)。

#}FOLLOW(P) = FIRST(F') ∪ FOLLOW(F) = {*。

(。

a。

b。

^。

+。

)。

#}2) 证明该方法是LL(1)的。

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

First集合的求法:
First集合最终是对产生式右部的字符串而言的,但其关键是求出非终结符的First集合,由于终结符的First集合就是它自己,所以求出非终结符的First集合后,就可很直观地得到每个字符串的First集合。

1. 直接收取:对形如U-a…的产生式(其中a是终结符),把a收入到First(U)中
2. 反复传送:对形入U-P…的产生式(其中P是非终结符),应把First(P)中的全部内容传送到First(U)中。

Follow集合的求法:
Follow集合是针对非终结符而言的,Follow(U)所表达的是句型中非终结符U所有可能的后随终结符号的集合,特别地,“#”是识别符号的后随符。

1. 直接收取:注意产生式右部的每一个形如“…Ua…”的组合,把a直接收入到Follow(U)中。

2.直接收取:对形如“…UP…”(P是非终结符)的组合,把First(P)除ε直接收入到Follow(U)中。

3.反复传送:对形如P-…U的产生式(其中U是非终结符),应把Follow(P)中的全部内容传送到Follow(U)中。

(或 P-…UB且First(B)包含ε,则把First(B)除ε直接收入到Follow(U)中,并把Follow(P)中的全部内容传送到Follow(U)中)
例1:判断该文法是不是LL(1)文法,说明理由 S→ABc A→a|ε B→b|ε?
First集合求法就是:能由非终结符号推出的所有的开头符号或可能的ε,但要求这个开头符号是终结符号。

如此题A可以推导出a和ε,所以FIRST(A)={a,ε};同理FIRST (B)={b,ε};S可以推导出aBc,还可以推导出bc,还可以推导出c,所以FIRST(S)={a,b,c}。

Follow集合的求法是:紧跟随其后面的终结符号或#。

但文法的识别符号包含#,在求的时候还要考虑到ε。

具体做法是把所有包含你要求的符号的产生式都找出来,再看哪个有用。

Follow(S)={#}如求A的,产生式:S→ABc A→a|ε,但只有S→ABc 有用。

跟随在A后年的终结符号是FIRST(B)={b,ε},当FIRST(B)的元素为ε时,跟随在A 后的符号就是c,所以 Follow(A)={b,c}同理Follow(B)={c}。

相关文档
最新文档