1、实验3LL1文法构造实 验 报 告实验课程: 编译原理 学生姓名: 学 号: 专业班级: 计科 实验3 LL(1)文法构造一、实验目的熟悉LL(1)文法的分析条件,了解LL(1)文法的构造方法。二、实验内容1、编制一个能够将一个非LL(1)文法转换为LL(1)文法;2、消除左递归;3、消除回溯。三、实验要求1、 将一个可转换非LL(1)文法转换为LL(1)文法,要经过两个阶段,1)消除文法左递归,2)提取左因子,消除回溯。2、 提取文法左因子算法:1)对文法G的所有非终结符进行排序2)按上述顺序对每一个非终结符Pi依次执行:for( j=1; j Pi| ,其中不以Pi开头,则修改产生式为:P
2、i PiPi Pi|3)化简上述所得文法。3、 提取左因子的算法: A 1|2|n|1|2|m (其中,每个不以开头)那么,可以把这些产生式改写成 A A|1| 2|m A1|2|n4、 利用上述算法,实现构造一个LL(1)文法:1) 从文本文件g.txt中读入文法,利用实验1的结果,存入实验1设计的数据结构;2) 设计函数remove_left_recursion()和remove_left_gene()实现消除左递归和提取左因子算法,分别对文法进行操作,消除文法中的左递归和提出左因子;3) 整理得到的新文法;4) 在一个新的文本文件newg.txt输出文法,文法输出按照一个非终结符号一行,
3、开始符号引出的产生式写在第一行,同一个非终结符号的候选式用“|”分隔的方式输出。四、实验环境PC微机DOS操作系统或 Windows 操作系统Turbo C 程序集成环境或 Visual C+ 程序集成环境五、实验步骤 1、学习LL(1)文法的分析条件; 2、学习构造LL(1)文法的算法;3、结合实验1给出的数据结构,编程实现构造LL(1)文法的算法;4、结合实验1编程和调试实现对一个具体文法运用上述算法,构造它的LL(1)文法形式;5、 把实验结果写入一个新建立的文本文件。六、测试数据 输入数据:编辑一个文本文文件g.txt,在文件中输入如下内容:S-Qc|c|cab;Q-Rb|b;R-Sa
4、|a; 正确结果: 本实验的输出结果是不唯一的,根据消除左递归是选择非终结符号的顺序不同,或选择新的非终结符号的不同,可能会得到不同的结果,下面只是可能的一个结果:S-Qc|cT;T-|ab; /由于无法输出,用代替Q-Rb|b;R-bcaU|caU|cabaU|aU;U-bcaU|; 七、实验报告要求实验报告应包括以下几个部分:1、 满足LL(1)文法的分析条件;2、 构造LL(1)文法的算法;3、 消除左递归文法和提取左因子算法实现方法;4、 整个测试程序的流程;5、 程序的测试结果和问题;6、 实验总结。代码#include #include using namespace std; t
5、ypedef struct Chomsky /定义一个产生式结构体 string left; /定义产生式的左部 string right; /定义产生式的右部 Chomsky; int n;/产生式总数 string strings;/存储产生式 char q20; void apart(Chomsky *p,int i) /分开产生式左右部i代表产生式的编号 int j; for(j=0;jstrings.length();j+) if(stringsj=-) pi.left=strings.substr(0,j);/从0开始的j长度的子串即0j-1 pi.right=strings.su
6、bstr(j+1,strings.length()-j);/从j+1开始的后面子串 int zero(Chomsky *p)/0型文法 int flag(0),count(0); int i,j; for(i=0;in;i+) for(j=0;j=A&pi.leftj0)/说明某一个产生式左部有非终结符 flag=0;/下个产生式判断前清零 count+;/左部存在非终结符的产生式 个数加1 else break; /左部没有非终结符结束 if(count=n) return 1; /属于0型文法 else coutendl所输产生式不属于任何文法。endl; return 0; int on
7、e(Chomsky *p)/1型文法 int flag(0); int i; if(zero(p) for(i=0;in;i+) if(pi.right.length()0) coutendl此文法属于0型文法即短语文法。endl; return 0; /不属于1型文法 else if(flag=0) return 1; /属于1型文法 else return 0; int two(Chomsky *p)/2型文法 int flag(0); int i; if(one(p) for(i=0;i=A&pi.left00) coutendl此文法属于1型文法即上下文有关文法。endl; retur
8、n 0; /不属于2型文法 else if(flag=0) return 1; /属于2型文法 else return 0; int remove(Chomsky *p,int n)/消除左递归 /把文法的所有非终结符按某一顺序排序 int i,j,count=1,count1=n,flag=0,m,x; q0=p0.left0; for(i=1;in;i+) for(j=0;ji;j+) if(pi.left=pj.left)break; if(j=i)qcount+=pi.left0; count-; for(i=0;in;i+)/判断第一个非终结符是否存在直接左递归 if(pi.left
9、0=q0&pi.left0=pi.right0) flag+; if(flag!=0)/消除第一个非终结符的直接左递归 for(i=0;in;i+) if(pi.left0=q0) if(pi.left0=pi.right0) pi.left=pi.left+; pi.right=pi.right.substr(1,pi.right.length()+pi.left; else pi.right=pi.right+pi.left+; pcount1.left=p0.left; pcount1+.right=#;/用#代替空产生式 /消一切左递归 for(m=0;m=count;m+) for(
10、i=0;in;i+) if(pi.left0=qm) for(j=0;jcount1;j+) for(x=m+1;x=count;x+) if(pj.left0=qx&pj.right0=qm) pcount1.left=pj.left; pcount1.right=pi.right+pj.right.substr(1,pj.right.length(); count1=count1+1; for(j=0;jcount1;j+) for(x=m+1;x=count;x+) if(pj.right0=qm&pj.left0=qx) pj.right=; pj.left=; for(x=0,fla
11、g=0;xcount1;x+)/判断第m个非终结符是否存在直接左递归 if(px.left0=qm&px.left0=px.right0) flag+; /消直接左递归 if(flag!=0) for(i=0;icount1;i+) if(pi.left0=qm) if(pi.left0=pi.right0) pi.left=pi.left+; pi.right=pi.right.substr(1,pi.right.length()+pi.left; pcount1.left=pi.left; pcount1.right=#;/用#代替空产生式 else pi.right=pi.right+p
12、i.left+; count1=count1+1; count1-; return count1; void main( ) int i,j,count1; cout.编译原理实验非LL(1)文法到LL(1)文法的转换.endl; cout请输入产生式总数及各产生式endl其中左右部之间用-表示空用#表示n; Chomsky *p=new Chomsky50; / 初始化产生式数组 for(i=0;istrings; apart(p,i); if(two(p) cout该文法属于二型文法实验继续.endl; count1=remove(p,n); cout转换后的文法输出如下endl; for(i=0;i=count1;i+) if(pi.left0!=NULL) coutpi.leftpi.rightendl; else cout该文法不是2型文法无需进行LL(1)的转换实验结束endl; system(pause); 八、思考题1、 是不是所有的文法都可以通过上述程序构造LL(1)文法? 2、 LL(1)文法在整个语法分析中的作用? 3、 实验1中设计的文法数据结构对本实验的影响?4、 如何更好地组合实验1和实验3,使之具有更高的效率?
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1