各非终结符FIRST集和FOLLOW集共72页

合集下载

编译原理-第4章 语法分析--习题答案

编译原理-第4章 语法分析--习题答案

第4章语法分析习题答案1.判断(1)由于递归下降分析法比较简单,因此它要求文法不必是LL(1)文法。

(× )LL(1)文法。

(× )(3)任何LL(1)文法都是无二义性的。

(√)(4)存在一种算法,能判定任何上下文无关文法是否是LL(1) 文法。

(√)(× )(6)每一个SLR(1)文法都是LR(1)文法。

(√)(7)任何一个LR(1)文法,反之亦然。

(× )(8)由于LALR是在LR(1)基础上的改进方法,所以LALR(× )(9)所有LR分析器的总控程序都是一样的,只是分析表各有不同。

(√)(10)算符优先分析法很难完全避免将错误的句子得到正确的归约。

(√)2.文法G[E]:E→E+T|TT→T*F|FF→(E)|i试给出句型(E+F)*i的短语、简单短语、句柄和最左素短语。

答案:画出语法树,得到:短语: (E+F)*i ,(E+F) ,E+F ,F ,i简单短语: F ,i句柄: F最左素短语: E+F3.文法G[S]:S→SdT | TT→T<G | GG→(S) | a试给出句型(SdG)<a的短语、简单短语、句柄和最左素短语。

答案:画出语法树,得到:短语:(SdG)<a 、(SdG) 、SdG 、G 、a简单(直接)短语:G 、a句柄:G最左素短语:SdG4.对文法G[S]提取公共左因子进行改写,判断改写后的文法是否为LL(1)文法。

S→if E then S else SS→if E then SS→otherE→b答案:提取公共左因子;文法改写为:S→if E then S S'|otherS'→else S|E→bLL(1)文法判定:① 文法无左递归② First(S)={if,other}, First(S')={else, }First(E)={b}Follow(S)= Follow(S')={else,#}Follow(E)={then}First(if E then S S')∩First(other)=First(else S)∩First( )=③First(S')∩Follow(S')={else}不为空集故此文法不是LL(1)文法。

转First集合和Follow集合的求法(修改含例子)

转First集合和Follow集合的求法(修改含例子)

转First集合和Follow集合的求法(修改含例⼦)对于终结符和⾮终结符的理解:终结符:通俗的说就是不能单独出现在推导式左边的符号,也就是说终结符不能再进⾏推导。

⾮终结符:不是终结符的都是⾮终结符。

如:A->B,则A是⾮终结符;A->id,则id是终结符。

(⼀般书上终结符⽤⼩写,⾮终结符⽤⼤写。

)⽂法产⽣语⾔句⼦的基本思想:从识别符号(开始符)开始,把当前产⽣的符号串中的⾮终结符替换为相应规则右部的符号串,直到全部由终结符组成。

所以⽂法产⽣句⼦的基本思想就是基于产⽣式(例如A->num)的替换,当所有的⾮终结符都被终结符替换时,推导结束。

FIRST集求法:我对First集的理解:first集应该就是求⼀个表⽰⽂法的字串(⼀般指⾮终结符,终结符的first集就是它⾃⾝)开头的所有可能出现的字符的集合。

例如A->aC | bB | cD,根据这个产⽣式,就可以知道,⾮终结符A,被替换后,它开头可能出现字符有a、b 、c, 所以 {a,b,c}是First(A)的⼀个⼦集。

求First集的步骤:1. 若X->a..,则将终结符a加⼊FIRST(X)中;(注意⾮终结符的情况)2. 若X->e ,则将终结符e加⼊FIRST(X)中(e表⽰空集);3. 若 X->BC..D,则将First(B)所有元素(除了空集)加⼊First(A),然后检测First(B),若First(B)中不存在空集, 即e,则停⽌,若存在则向B的后⾯查看,将First(C)中所有元素(除了空集)加⼊First(A),然后再检测First(C)中是否有e...直到最后,若D之前的所有⾮终结符的First集中都含有e,则检测到D时,将First(D)也加⼊First(A),若First(D)中含有e,则将 e加⼊First(A)。

对于第三条,其实也很好理解,就是说当X推导出⼀个字串时,D前⾯的⾮终结符都可能推出空串,这个时候,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个以空格分隔的字符串为产⽣式体。

编译技术复习题答案

编译技术复习题答案

第一章:编译系统概述一.单项选择题1.编译程序前三个阶段完成的工作是〔C〕。

A.词法分析, 语法分析和代码优化B.代码生成, 代码优化和词法分析C.词法分析, 语法分析, 语义分析和中间代码生成D.词法分析, 语法分析和代码优化2.编译程序绝大多数时间花在〔D〕上。

A.出错处理 B.词法分析 C.目标代码生成D.表格管理3.编译程序是对〔C〕。

A.汇编程序的翻译 B.高级语言程序的说明执行C.高级语言的翻译 D.机器语言的执行4.在运用高级语言编程时,首先可通过编译程序发觉源程序的全部〔A〕错误。

A.语法 B.语义 C.语用 D.运行二.填空题1.编译程序首先要识别出源程序中每个(单词),然后再分析每个(句子)并翻译其意义。

2.通常把编译过程分为分析前端及后端两大阶段。

词法, 语法和语义分析是对源程序的(分析),中间代码生成, 代码优化及目标代码的生成那么是对源程序的(综合)。

3.对编译程序而言,输入数据是(源程序),输出结果是(目标程序)。

4.对以下错误信息,请指出可能是编译的哪个阶段〔词法分析, 语法分析, 语义分析,代码生成〕报告的。

〔1〕 else 没有匹配的if 〔语法分析〕〔2〕数组下标越界〔语义分析〕〔3〕运用的函数没有定义〔语法分析〕〔4〕在数中出现非数字字符〔词法分析〕5.假如编译程序生成的目标程序是机器代码程序,那么源程序的执行分为两大阶段:〔编译阶段〕和〔运行阶段〕。

假如编译程序生成的目标程序是汇编语言程序,那么源程序的执行方式分成三个阶段:〔编译阶段〕〔汇编阶段〕和〔运行阶段〕。

6.编译程序在其工作过程运用最多的数据构造是〔表〕,它记录着源程序中各种信息,以便查询或修改,在这些〔表〕中,尤以〔符号表〕最重要,它的生存期最长,运用也最频繁。

三.简述题:1.编译程序的工作分为那几个阶段答:词法分析, 语法分析和语义分析是对源程序进展的分析(称为编译程序的前端),而中间代码生成, 代码优化和代码生成三个阶段合称为对源程序进展综合(称为编译程序的后端),它们从源程序的中间表示建立起和源程序等价的目标程序。

编译原理教程课后习题答案——第三章

编译原理教程课后习题答案——第三章

第三章语法分析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]为二义文法。

《编译原理》课后习题答案第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)的。

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集合的求法: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集合的求法是:紧跟随其后面的终结符号或#。

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

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

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