first集和follow集生成算法模拟

合集下载

【编译原理】语法分析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分,共20分)1.“ 用高级语言书写的源程序都必须通过编译,产生目标代码后才能投入运行”这种说法。

( )2.若一个句型中出现了某产生式的右部,则此右部一定是该句型的句柄。

( )3.一个句型的句柄一定是文法某产生式的右部。

( )4.在程序中标识符的出现仅为使用性的。

( )5.仅考虑一个基本块,不能确定一个赋值是否真是无用的。

( )6.削减运算强度破坏了临时变量在一基本块内仅被定义一次的特性。

( )7.在中间代码优化中循环上的优化主要有不变表达式外提和削减运算强度。

( )8.算符优先关系表不一定存在对应的优先函数。

( )9.数组元素的地址计算与数组的存储方式有关。

( )10.编译程序与具体的机器有关,与具体的语言无关。

( )参考答案:1、×2、×3、√4、×5、√6、√7、×8、×9、×10、×二、选择题(请在前括号内选择最确切的一项作为答案划一个勾,多划按错论)(每个4分,共40分)1.通常一个编译程序中,不仅包含词法分析,语法分析,中间代码生成,代码优化,目标代码生成等五个部分,还应包括_____。

A.( ) 模拟执行器 B.( ) 解释器C.( ) 表格处理和出错处理 D.( ) 符号执行器2.文法 G[N]= ( {b} , {N , B} , N ,{N→b│bB ,B→bN} ),该文法所描述的语言是A.( ) L(G[N])={bi│i≥0} B.( ) L(G[N])={b2i│i≥0}C.( ) L(G[N])={b2i+1│i≥0} D.( ) L(G[N])={b2i+1│i≥1}3.一个句型中的最左_____称为该句型的句柄。

A.( ) 短语 B.( ) 简单短语C.( ) 素短语 D.( ) 终结符号4.设 G 是一个给定的文法, S 是文法的开始符号,如果 S->x( 其中x∈V*), 则称 x 是文法 G 的一个_____。

构造FIRST集和FOLLOW集的方法

构造FIRST集和FOLLOW集的方法
构造 FIRST 集和 FOLLOW 集的方法
1、构造 FIRST 集的算法 (1) 对于 G 中的每个文法符号 X,为求 FIRST(X),反复应用如下规则,直到集合不再增大: ① 若 X∈VT,则 FIRST(X)是{X} ② 若 X∈VN ,且 X→aα (a∈VT ),则{ a } FIRST(X) X→ε, 则{ε} FIRST(X) ③ 若 X->Y1Y2 … Yi-1 Yi … YK∈P,Y1∈VN ,则 FIRST(Y1)-{ε} FIRST(X)
则 FIRST(Xi) -{} FIRST() 特别是,若所有的 FIRST(Xj)均含有,1jn,则{} FIRST()。 显然,若=则 FIRST()={}。
2、构造 FOLLOW 集的算法 对于 G 中的每一 AFOLLOW 集不再增大为止: ① 对于文法的开始符号 S,令# ∈ FOLLOW(S)。 ② 对于每一 A→αBβ∈P, 令 FIRST(β) - {ε} FOLLOW(B) 。 ③ 对于每一 A→αB∈P, 或 A→αBβ∈P,且ε∈FIRST(β), 则令 FOLLOW(A) FOLLOW(B) 。

而对所有的 j(1≤j ≤i-1), Yj ∈VN,且 Yj⇒ ε,则令 FIRST(Yj)-{ε} FIRST(X) (1≤j ≤i) 特别,当ε∈FIRST(Yj) (1≤j ≤k)时,令ε∈FIRST(X)
(2) 对文法 G 的任何符号串=X1X2…Xn 构造集合 FIRST() ① 置 FIRST(X1)-{} FIRST() ② 若对任何 1ji-1,FIRST(Xj),

编译原理大题

编译原理大题

五、语法分析——自底向上分析法已知文法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集合的求法: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集合的求法是:紧跟随其后面的终结符号或#。

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

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

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)中。

编译原理(3)语法_4(自顶向下语法分析:LL(1)分析法)

编译原理(3)语法_4(自顶向下语法分析:LL(1)分析法)
2first集确定了每一个非终结符在扫描输入串时所允许遇到的输入符号及所应采用的推导产生式集确定了每一个非终结符在扫描输入串时所允许遇到的输入符号及所应采用的推导产生式该非终结符所对应的产生式中的哪一个候选式33自顶向下的语法分析式中的哪一个候选式3follow集是针对文法中形如a这样的产生式的即在使用这样的产生式的即在使用a的产生式进行推导时面临输入串中哪些输入符号时有一空字的产生式进行推导时面临输入串中哪些输入符号时有一空字即匹配而不出错
课本例题3.8 第二步:计算非终结符的FOLLOW集合
G[E]: E→TE' E'→ + TE' | ε T→FT' T'→*FT' | ε F→(E) | i ③由E→TE' 知FOLLOW(E) ⊂ FOLLOW(E' ), 即FOLLOW(E' ) = {),#}; 由E→TE ' 且E ' → ε知FOLLOW(E)FOLLOW(T),即 FOLLOW(T) = {+,),#};
特别是当Y1~Yk均含有ε产生式时,应把ε也加到FIRST(X)中。
课本例题3.8 第一步:计算非终结符的FIRST集合 例3.8 试构造表达式文法G[E]的LL(1)分析表,其中: G[E]: E→TE' E'→ + TE' | ε T→FT' T'→*FT' | ε F→(E) | i
[解答] 首先构造FIRST集,步骤如下: ① FIRST(E') = {+, ε}; FIRST(T') = {*, ε}; FIRST(F) = {(, i}; ② T→F… 和E→T…知:FIRST(F) ⊂ FIRST(T) ⊂ FIRST(E) 即有FIRST(F) = FIRST(T) = FIRST(E) = {(,i}。

C++求文法的first和follow集合

C++求文法的first和follow集合

1.#include "stdafx.h"2.#include "LR.h"3.#include "MLR1.h"4.5.#ifdef _DEBUG6.#undef THIS_FILE7.static char THIS_FILE[]=__FILE__;8.#define new DEBUG_NEW9.#endif10.//----调试部分使用的代码11.CString MLR1::GetFirst(int i){12.if(i<0||i>=GetIdentNum())return"";13.return FirstSet5(m_first[i].Fi,m_first[i].flag&2);14.}15.CString MLR1::GetFollow(int i){16.if(i<0||i>=GetIdentNum())return"";17.return FollowSet1(m_first[i].Fo,m_first[i].flag&0x08);18.}19.//----构造部分20.MLR1::MLR1(){21.}22.MLR1::~MLR1(){23.}24.void MLR1::ReSet(FILE* pf){25.//使用文件指针pf来重新驱动程序26.int i;27. p_file=pf;28. list_Express.RemoveAll();29. list_Ident.RemoveAll();30.for(i=0;i<MAP_SIZE;I++) p="(char*)m_first+sizeof(s_first)*MAX_IDENT-1;"for(char* bit_map[i]="0;">=(char*)m_first;p--)31. *p=0;32. Lex3();33. FirstSet6();34.// FollowSet3();35.}36.//----输入分析部分37.bool MLR1::Lex1(){38.//截取一个分号段到tocken中39.//功能字符取其负数40.char ch=0;41.bool end=false;42. token_len=0;43.if(feof(p_file))return false;44.while(!end&&!feof(p_file)){45.if(token_len>=LINE_LENGTH)break;46.if(fread(&ch,1,1,p_file)<=0)break;47.if(ch<=0)goto error;48.switch(ch){49.case';':50. end=true;51.case'<':52.case'>':53.case'=':54. ch=-ch;55.break;56.case'\\':57. fread(&ch,1,1,p_file);58.if(ch<=0)goto error;59.break;60. }61. token[token_len++]=ch;62. }63. token[token_len]=0;64.return true;65.error:66. fprintf(stderr,"must be 1--127");67.return false;68.}69.int MLR1::Lex2_1(char*&s,bool isUse){70.//识别非终结符并加入list_Ident71.char ident[ID_LENGTH+1];72.int t=0;73.if((int)*s++!=-'<')return 0;74.if(isalpha(*s))ident[t++]=*s++;75.else return 0;76.while(isalpha(*s)||isdigit(*s))ident[t++]=*s++;77.while(*s=='\'')ident[t++]=*s++;78.if((int)*s++!=-'>')return 0;79.if(t==0)return 0;80. ident[t]=0;81.for(t=list_Ident.GetSize()-1;t>=0;t--)82.if(list_Ident[t]==(CString)ident)break;83.if(t<0){84.if(list_Ident.GetSize()>=MAX_IDENT)return false;85. list_Ident.Add((CString)ident);86. t=list_Ident.GetSize()-1;87.if(isUse)bit_map[t/8]|=1<<(t%8);88. }89.if(!isUse)bit_map[t/8]&=~(1<<(t%8));90.return t+1;91.}92.bool MLR1::Lex2(){93.//将token中的非终结符用(-1) -- (-127)表示94.//进行语法判断<终结符>=符号表;95.register char *s,*d;96.char * end;97.int i;98. s=d=token;99. end=&token[token_len];100.if(i=Lex2_1(s))*d++=-i;101.else return false;102.if(*s++!=-'=')return false;103.while(s<END){ if(*p while(*p!="0){" *p="X+1;"char const判断表达式X能否推出LR_NULL *X){ MLR1::FirstSet1(const bool * 首先判断某非终结符能否推出LR_NULL ----First集 } true; return false; if(bit_map[i]!="0)return" i="0;i<MAP_SIZE;i++ )"for(int else list_Express.Add((CString)token); if(Lex2()) if(token_ len="=0)continue;"while(Lex1()){ 判断bit_map是否为全零,如果不是则表示有未定义的非终结符循环调用Lex1读入一句,调用Lex2进行语法分析 MLR1::Lex3(){ s<end; *d="0;" *d++="*s++;" }else if(i="Lex2_1(s,true ))*d++=-i;"if((int)*s="=-'<'){"if(*s="=-';')break;">=1){104.return false;105. }else{106.if(*p==*X)return false;107.if(!FirstSet2(*p))108.return false;109. }110. p++;111. }112.return true;113.}114.bool MLR1::FirstSet2(const char X){115.//判断非终结符X能否推出LR_NULL116. CString temp;117.if(m_first[-X-1].flag&0x40)return false;118.if(m_first[-X-1].flag&1)119.return (m_first[-X-1].flag&2)!=0;120. m_first[-X-1].flag|=0x40;121.for(int i=list_Express.GetSize();i>0;i--){122. temp=list_Express.GetAt(i-1);123.if(temp[0]==X){124.if(FirstSet1((LPCSTR)temp)){125. m_first[-X-1].flag|=3;126.return true;127. }128. }129. }130. m_first[-X-1].flag|=1;131. m_first[-X-1].flag^=0x40;132.return false;133.}134.bool MLR1::FirstSet3(const char *X,char*Fi){135.//求产生式X的First集放在F中,如果LR_NULL在First集中则返回true 136.//如果要求符号串的First集,就将X[0]设为0137.//假设X中不出现LR_NULL,LR_EOF和LR_EOS138.//假设F的长度为MAP_SIZE,有128b139.const char *p=X;140. X++;141.while(*X!=0){142.if(*X>=1){143. Fi[(*X)/8]|=1<<(*X)%8;144.return false;145. }else{146.if(*X==*p){147.if(!FirstSet2(*X))148.return false;149. }else if(!FirstSet4(*X,Fi)){150.return false;151. }152. }153. X++;154. }155.return true;156.}157.bool MLR1::FirstSet4(char const X,char*Fi){158.//求非终结符X的First集放在F中159.//如果LR_NULL在其中则返回true160. CString temp;161.if(m_first[-X-1].flag&0x40)return false;162.if((m_first[-X-1].flag&4)==0){163. m_first[-X-1].flag|=0x40;164.for(int i=list_Express.GetSize();i>0;i--){165. temp=list_Express.GetAt(i-1);166.if(temp[0]==X)167. FirstSet3((LPCSTR)temp,m_first[-X-1].Fi);168. }169. m_first[-X-1].flag|=4;170. m_first[-X-1].flag^=0x40;171. }172.if(Fi!=m_first[-X-1].Fi){173.for(int i=0;i<MAP_SIZE;I++) *p="t;"char } return for(i="0;i< MAP_SIZE;i++){" i; int为每个非终结符求First集 MLR1::FirstSet6(){ void (CString)t; if(has_null)*p++="LR_NULL;" *p+ +="i*8+j;"if(Fi[i]&(1<<j)) if(Fi[i])for(j="0;j<8;j++)" i,j; t[128];将集合表示的First变为字符串式 has_null){ char*Fi,bool MLR1::FirstSet5(const CString (m_first[-X-1 ].flag&2); Fi[i]|="m_first[-X-1].Fi[i];">0;i--){174.if((m_first[i-1].flag&1)==0)175. FirstSet2(-i);176. }177.for(i=list_Ident.GetSize();i>0;i--){178.if((m_first[i-1].flag&4)==0)179. FirstSet4(-i,m_first[i-1].Fi);180. }181.}182.CString MLR1::FollowSet1(const char*Fo,bool has_eof){183.//将集合表示的Follow变为字符串式184.char t[128];185.char *p=t;186.int i,j;187.for(i=0;i<MAP_SIZE;I++){ *p="0;"char bool * } return int (CString)t; *p++="i*8+j;" i,j; if(X 如果是非法符号则退出 *p; temp[LINE_LENGTH]; flag,rc="true;" flag.b5该符号的Follow集正在被计算 flag为真表示已经找到X,将找后继的第一个字符必须在执行前将LR_EOF加入识别符号的Follow集中只有在X的Follow集未被计算时才调用该函数求非终结符X的Follow集 Fo){ X,char MLR1::FollowSet2(const if(has_eof)*p++="LR_NULL;"if(Fo[i]&(1<<j)) if(Fo[i])for(j="0;j<8;j++)">=0||X<-MAX_IDENT)return true;188.//如果该符号正被计算则退出189.if(m_first[-X-1].flag&0x20)return false;190.//如果该符号为被计算则计算191.if((m_first[-X-1].flag&0x10)==0){192. m_first[-X-1].flag|=0x20;193.for(i=list_Express.GetSize();i>0;i--){194. sprintf(temp,list_Express.GetAt(i-1));195. flag=false;196. p=temp+1;197.while(*p!=0){198.if(!flag){199.if(*p==X){200.//表达式中出现了符号X201. flag=true;}202. }else{203.if(*p>0){204.//规则2:X后碰上终结符205. flag=false;206. Fo[*p/8]|=1<<(*p%8);207. }else{208.//规则2:X后碰上非终结符则并上它的First集209.for(j=0;j<MAP_SIZE;J++) } return for(i="0;i<M AP_SIZE;i++)" i; int void m_first[0].flag|="0x08;"求各非终结符的Follow 集 MLR1::FollowSet3(){ rc; Fo[i]|="m_first[-X-1].Fo[i];"if(Fo!="m_fir st[-X-1].Fo){" m_first[-X-1].flag^="0x20;"if(rc)m_first[-X-1].flag|="0x10;" m_first[-X-1].flag|="0x08;"if(m_first[-temp[0]-1].flag&0x08) F o[j]|="m_first[-*p-1].Fi[j];"for(j="0;j<MAP_SIZE;j++)" rc="false;"if (!FollowSet2(temp[0],m_first[-temp[0]-1].Fo)) 如果是自反关系则不计算规则3:将temp[0]的Follow集并到Fo上if(flag&&(X!="temp[0])){" p++; flag="false;"if((m_first[-*p-1].fla g&2)="=0)"如果X可以推出LR_NULL则继续>0;i--){210.if((m_first[i-1].flag&0x10)==0){211. FollowSet2(-i,m_first[i-1].Fo);212. }213. }214.}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(3) 输出First集;
(4)输出由文法G构造FOLLOW集的算法;
(5)输出FOLLOW集。
2.测试数据:
输入文法G[E]:
E → TE’
E’ → +TE’|ε
T → FT’
T’ → *FT’|ε
F->(E)|i
3.实现提示:
用数据库存储多行文法,用LIST控件显示算法,用GRID类依据算法进行作图。并实现算法与生成过程的关联。
{
p[i].left=strings.substr(0,j);
p[i].right=strings.substr(j+2,strings.length()-j);
}
}
}
//对每个文法符号求first集
string Letter_First(STR *p,char ch)
{
int t;
if(!(Vt.find(ch)>100))
FIRST(α)={a | α aβ,a∈VT,α,β∈V*}。
若α ε,ε∈FIRST(α)。
由定义可以看出,FIRST(α)是指符号串α能够推导出的所有符号串中处于串首的终结符号组成的集合。所以FIRST集也称为首符号集。
设α=x1x2…xn,FIRST(α)可按下列方法求得:
令FIRST(α)=Φ,i=1;
Vt +=p[i].left[j];
}
}
for(j=0;j<(int)p[i].right.length();j++)
{
if(!(p[i].right[j]>='A'&&p[i].right[j]<='Z'))
{
if(Vt.find(p[i].right[j])>100)
Vt +=p[i].right[j];
{
if(First[Vn.find(ch)].find(p[i].right[0])>100)
{
First[Vn.find(ch)]+=p[i].right[0];
}
}
if(p[i].right[0]=='*')
{
if(First[Vn.find(ch)].find('*')>100)
{
First[Vn.find(ch)]+='*';
(5)论文撰写(20分):优( )、良( )、中( )、一般( )、差( );
评阅人:职称:讲师
2015年6月19日
中文摘要
随着计算机科学的飞速发展,形式语言与自动机理论和方法研究也越来越收到人们的重视,但前者已经成为计算机科学的理论基础。此次的课程设计主要任务是研究自动机在编译方面的应用,并将重点放在求FIRST集和FOLLOW集。
课程设计(论文)任务书
软件学院学 院软件测试专 业1班
一、课程设计(论文)题目first集和follow集生成算法模拟
二、课程设计(论文)工作自2015年6月16日起至2013年6月19日止。
三、课程设计(论文)地点:软 件 学 院 实 训 中 心
四、课程设计(论文)内容要求:
1.本课程设计的目的
进一步培养学生编译器设计的思想,加深对编译原理和应用程序的理解,针对编
(3)若),其中x,y∈V*,则FOLLOW(B)∈FOLLOW(A);
3.实验内容:计算FIRST集和FOLLOW集
4.
二、需求分析
1.基本要求:
动态模拟算法的基本功能是:
(1)输入一个文法G;
(2)输出由文法G构造FIRST集的算法;
(2)输入由文法G构造First集的算法
(3)输出First集
(4)输入由文法G构造Follow集的算法
(5)输出Follow集
2.实验目的:
输入:任意的上下文无关文法。
输出:所输入的上下文无关文法一切非终结符的first集合和follow集合。
3.设文法G[S]=(VN,VT,P,S),则首字符集为:
若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);
{
first[Vt.find(ch)]="ch";
return first[Vt.find(ch)-1];
}
if(!(Vn.find(ch)>100))
{
for(int i=0;i<N;i++)
{
if(p[i].left[0]==ch)
{
if(!(Vt.find(p[i].right[0])>100))
}
else
{
if(Vn.find(p[i].right[j])>100)
Vn+=p[i].right[j];
}
}
}
}
void getlr(STR *p,int i)
{
int j;
for(j=0;j<strings.length();j++)
{
if(strings[j]=='-'&&strings[j+1]=='>')
高的问题。最后我想到了用递归方式。
下面总结此次课程设计的一些收获:
1.对程序设计理解,算法的设计,有了进一不的提高。
2.对程序调试的技巧收获不小。因为该程序主要是算法研究,所以程序分支较复杂。断点调试是必不可缺并且很实用的工作。
3.对程序到软件过程的理解。这次也是我第一次将自己做的程序制作成一个可自定义安装过程的小软件。从而将程序的运行与IDE脱离开来。
关键字:FIRST集,FOLLOW集,算法。
目录
八、附录.......................................11
一、课程设计任务及要求
1.任务:设计一个由正规文法生成First集和Follow集并进行简化的算法动态模拟。
First集和Follow集生成模拟算法的基本功能:
(1)输入一个文法G
三、设计思路
1.识别终结符集和非终结符集
Y
N
识别终结符集
识别非终结符集
2.计算所有非终结符的First集
N
Y
Y
N
3.计算所有非终结符的Follow集
N
Y N
Y

四、详细设计
2.具体设计
通过分析输入的文法,分析出文法肿的非终结符和终结符,然后计算出每个非终结符的FIRST集和FOLLOW集。
当一个文法中存在ε产生式时,例如,存在A→ε,只有知道哪些符号可以合法地出现在非终结符A之后,才能知道是否选择A→ε产生式。这些合法地出现在非终结符A之后的符号组成的集合被称为FOLLOW集合。下面我们给出文法的FOLLOW集的定义。
设文法G[S]=(VN,VT,P,S),则
FOLLOW(A)={a | S … Aa …,a∈VT}。
2)创新要求:
动态模拟算法的基本功能是:
(1)输入一个文法G
(2)输出由文法G构造的FIRST集算法
(3)输出FIRST算法
(4)输出由文法G构造的FOLLOW集算法
(5)输出FOLLOW集
3)课程设计论文编写要求
(1)课程设计任务及要求
(2)设计思路--工作原理、功能规划
(3)详细设计---数据分析、算法思路、功能实现(含程序流程图、主要代码及注
释)、界面等。
(4)运行调试与分析讨论---给出运行屏幕截图,分析运行结果,有何改进想法等。
(5)设计体会与小结---设计遇到的问题及解决办法,通过设计学到了哪些新知识,
巩固了哪些知识,有哪些提高。
(6)报告按规定排版打印,要求装订平整,否则要求返工;
(7)课设报告的装订顺序如下:封面---任务书---中文摘要---目录----正文---附录
(1)若xi∈VT,则xi∈FIRST(α);
(2)若xi∈VN;
① 若ε FIRST(xi),则FIRST(xi)∈FIRST(α);
② 若ε∈FIRST(xi),则FIRST(xi)-{ε}∈FIRST(α);
(3)i=i+1,重复(1)、(2),直到xi∈VT,(i=2,3,…,n)或xi∈VN且若ε FIRST(xi)或i>n为止。
(代码及相关图片)
(8)严禁抄袭,如有发现,按不及格处理。
4)课程设计评分标准:
(1)学习态度:20分;
(2)系统设计:20分;
(3)编程调试:20分;
(4)回答问题:20分;
(5)论文撰写:20分。
5)参考文献:
(1)张素琴,吕映芝.编译原理[M].,清华大学出版社
(2)蒋立源、康慕宁等,编译原理(第2版)[M],西安:西北工业大学出版社
}
}
if(!(Vn.find(p[i].right[0])>100))
{
if(p[i].right.length()==1)
{
string ff;
ff=Letter_First(p,p[i].right[0]);
for(int i_i=0;i_i<ff.length();i_i++)
{
for(j=0;j<(int)p[i].left.length();j++)
相关文档
最新文档