《编译原理-实验3-LL(1)分析文法构造.doc》由会员分享,可在线阅读,更多相关《编译原理-实验3-LL(1)分析文法构造.doc(38页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Four short words sum up what has lifted most successful individuals above the crowd: a little bit more.-author-date编译原理-实验3-LL(1)分析文法构造华东师范大学计算机科学技术系学生上机报告集美大学计算机工程学院实验报告课程名称:编译原理指导教师:付永钢实验成绩:实验编号: 实验三实验名称:LL(1)语法分析器的构造班级:计算14姓名:学号上机实践日期:2017.6上机实践时间: 6学时一、实验目的1、掌握LL(1)分析法的基本原理;2、掌握LL(1)分析表的构造方法;3、掌
2、握LL(1)驱动程序的构造方法。二、实验环境Ubuntu三、实验原理1、对文法要求LL(1)分析法属于自顶向下分析方法,因此需要预测匹配的产生式。即在LL(1)分析法中,每当在符号栈的栈顶出现非终结符时,要预测用哪个产生式的右部去替换该非终结符。LL(1)分析方法要求文法满足如下条件:对于任一非终结符A,其任意两个产生式Aa,Ab,都要满足下面条件:First(Aa)First(Ab)=2、分析表构造LL(1)分析表的作用是对当前非终结符和输入符号确定应该选择用哪个产生式进行推导。它的行对应文法的非终结符,列对应终结符,表中的值有两种:一是产生式的编号,一是错误编号。若用T表示LL(1)分析表
3、,则T可表示如下:T: VNVTPErrorT(A, t) = A,当tFirst(A)T(A, t) = Error,否则其中P表示所有产生式的集合。显然,一个文法G是LL(1)文法,当且仅当T的元素包含唯一的一个产生式或Error。3、驱动程序构造LL(1)分析主要包括以下四个动作,其中X为符号栈栈顶元素,a为输入流当前字符。l 替换:当XVN时选相应产生式的右部b去替换X。l 匹配:当XVT时它与a进行匹配,其结果可能成功,也可能失败,如果成功则符号栈中将X退栈并将输入流指针向前移动一位,否则报错。l 成功:当格局为(空,空)时报告分析成功。l 报错:出错后,停止分析。四、实验内容已知文
4、法GE: EE+T|T TT*F|F F(E)|i 说明:终结符号i为用户定义的简单变量, 即标识符的定义。1、消除文法的左递归,构造对应文法的预测分析表;2、根据构造的预测分析表,实现LL(1)分析中控制程序(表驱动程序),并完成整个的LL(1)分析程序的界面设计、运行;3、P104中,3.36写一个Yacc程序,把输入的算术表达式翻译成对应的后缀表达式输出。要求转换正确,同时对于简单错误能够识别。4、P104中,3.37,写一个Yacc“台式计算器”程序,它计算布尔表达式,其中的词法分析器用Lex写。要求转换正确,同时对于简单错误能够识别。五、实验要求1、输入串应是词法分析的输出二元式序列
5、,即某算术表达式“实验项目一”的输出结果。输出为输入串是否为该文法定义的算术表达式的判断结果。2、LL(1)分析过程应能发现输入串中的错误。3、设计至少两个测试用例(尽可能完备,正确和出错),并给出测试结果。六、实验步骤、1、分析文法(1)E=E+T=E+T*F=E+T*(E)即有E=E+T*(E)存在左递归。用直接改写法消除左递归,得到如下文法:GE:ETEE+TE|TFTT*FT|F(E)|i(2)对于以上改进的文法,可以得到:FIRST(E)=FIRST(+TE)FIRST(-TE)=+,FIRST(T)=FIRST(*FT)FIRST(/FT)=*,FIRST(E)= FIRST( T
6、 ) = FIRST( F )=FIRST(E)FIRST(i)=(,i 由此得到各非终结符的FOLLOW集合:FOLLOW(E)= ),$FOLLOW(E)=FOLLOW(E)=),$FOLLOW(T)=FIRST(E)FOLLOW(E)= +,),$FOLLOW(T)=FOLLOW(T)= +,),$FOLLOW(F)=FIRST1、构造LL(1)分析表采用手工操作构造LL(1)分析表。LL(1)分析表用一个二维矩阵表示,其中每个非终结符对应一行,每个终结符对应一列,一个非终结符和一个终结符可以确定矩阵中的一个元素,元素的值表示该非终结符和该终结符对应的产生式。每个矩阵元素都是一个符号串,
7、所有元素初始化为”;构造LL(1)表时,根据文法和各个产生式的First集,填写LL(1)分析表的内容。各产生式只要降右端填入到对应的表项中即可,用空串表示Error。在根据LL(1)分析表选择产生式进行推导时,若查到的产生式为空串表示无相应的产生式可选,不匹配错误;否则根据符号串得到相应的产生式进行推导,即进行压栈操作。步骤分析栈(栈顶符号,当前输入符)剩余串所用产生式1$E(E,i)查表i+i*i$E-TE2$ET(T,i)查表i+i*i$T-FT3$ETF(F,i)查表i+i*i$F-i4$ETi(i,i) i匹配i+i*i$5$ET(T,+)查表+i*i$T-6$E(E,+)查表+i*
8、i$E-+T E7$ET+(+,+)+匹配+i*i$8$ET(T,i)查表i*i$T-FT9$ETF(F,i)查表i*i$F-i10$ETi(i,i)i匹配i*i$11$ET(T,*)查表*i$T-*F T12$ETF*(*,*)*匹配*i$13$ETF(F,i)查表i$F-i14$ETi(i,i)i匹配i$15$ET(T,$)查表$T-16$E(E,$)查表$E-17$2数据结构LL(1)语法分析程序共用到个栈,分别称为:符号栈,语法树栈,操作符栈和操作数栈。其中,符号栈用于进行LL(1)语法分析;其它的栈是为了在语法分析的过程中同时生成与源程序结构对应的语法树而设。语法树栈用于生成声明部分
9、和语句部分的语法树;操作符栈和操作数栈用于生成表达式部分的语法树。3. 构造驱动程序构造LL(1)驱动程序的算法:(1). 分析开始时,首先将标志符号#和文法开始符号S依次压入符号栈;输入流指针指向第一个输入符号,即由符号栈和输入流构成的初始格局为:(#S,a1a2.an#)然后,反复执行第2步所列的工作。(2). 设在分析的某一步,符号栈及剩余的输入流处于如下的格局(#X1X2.Xm-1Xm,aiai+1.an#)其中,X1X2.Xm-1Xm为分析过程中所得的文法符号,此时,可视栈顶符号Xm的不同情况,分别作如下动作:l 若XmVN,则以Xm及ai组成的符号对(Xm,ai)查分析表T。设T(
10、Xm,ai)为一产生式,假设是XmUVW,此时将Xm从分析栈中退出,并将UVW压入栈中,从而得到新的格局(#X1X2.Xm-1WVU,aiai+1.an#)但若T(Xm,ai)=Error,则调用出错处理程序进行处理;l 若Xm=ai#,则表明栈顶符号已经与当前扫描的输入符号得到匹配,此时应将Xm(即ai)从栈中退出,并将输入流指针向前移动一个位置。l 若Xm=ai=#,则表明输入串已经完全得到匹配,此时即可宣告分析成功而结束分析。其它情形,转错误处理程序。程序见附录七、 实验结果正确的语法:错误的语法:六、实验小结1、在本次实验中,通过设计、编制、调试一个递归下降语法分析程序,实现对词法分析
11、程序所提供的单词序列进行语法检查和结构分析,掌握LL(1)分析法的基本原理、掌握LL(1)分析表的构造方法、掌握LL(1)驱动程序的构造方法;2、通过本次实验,对LL(1)递归下降分析程序的构造和设计有了更为全面的认识,对LL(1)文法分析程序的实现有了进一步了解;3、实验输入串以$结束,才用栈的形式,依次弹出进行处理;附录:程序代码:#coding:utf-8from prettytable import PrettyTabledef LL1():global c,flagif(c=E):if(ak=i or ak=():table.add_row(ak:, E - TE)stack.app
12、end(X)stack.append(T)print stackc=stack.pop()else:error()flag=1elif(c=X):if(ak=+):table.add_row(ak:, E - +TE)stack.append(X)stack.append(T)stack.append(+)print stackc=stack.pop()elif(ak=) or ak=$):table.add_row(ak:, E - )print stackc=stack.pop()else:error()flag=1elif(c=T):if(ak=i or ak=():table.add_
13、row(ak:, T - FT)stack.append(Y)stack.append(F)print stackc=stack.pop()else:error()flag=1elif(c=Y):if(ak=*):table.add_row(ak:, T - *FT)stack.append(Y)stack.append(F)stack.append(*)print stackc=stack.pop()elif(ak=+ or ak=) or ak=$):table.add_row(ak:, T - )print stackc=stack.pop()else:error()flag=1elif
14、(c=F):if(ak=i):table.add_row(ak:, F - i)stack.append(i)print stackc=stack.pop()elif(ak=():table.add_row(ak:, F - (E)stack.append()stack.append(E)stack.append()print stackc=stack.pop()else:error()flag=1def error():global k table.add_row(ak, Error)print stackk+=1if _name_ = _main_:a=raw_input(Input Et
15、ablepression:)a=a+$for temp in a:if(temp!=i and temp!=+ and temp!=* and temp!=( and temp!=) and temp!=$):print You input is wrong!exit(0)table = PrettyTable(Input, Action)table.padding_width = 1table.alignInput = rtable.alignAction = lstack=k=0flag=0stack.append($)stack.append(E)table.add_row(ak:, )print stackc=stack.pop()while(c!=$):if(c=ak):table.add_row(ak+1:,+ak+ Matching)print stackk+=1c=stack.pop()elif(c=) and c!=ak):error()flag=1breakelif(flag=1):breakelif(ak=$ and c=$):breakelse:LL1()print tableif(flag=0):print Analyse success!else:print Analyse fail!-