1、编译原理课设正规式r与正规文法G相互转换的程序设计正规式r与正规文法G相互转换的程序设计摘要:在计算机编译理论中,正规式、正规文法、自动机的理论以及它们之间的 等价性问题是编译理论的等价基础,其中正规式和自动机,正规文法和自动机之间的等价性问题,已经得到了比较圆满的解决。本文主要讨论正规式和正规文法之间相互转换的方法。关键字:编译原理 正规式 正规文法 相互转换1、引言程序设计语言中的单词是基本语法符号。单词符号的语法可以用有效的工具加以描述,并且基于这类描述工具,可以建立词法分析技术,进而可以建立词法分析程序的自动构造方法。多数程序设计语言的单词的语法都能用正规文法或3型文法来描述。正规式也
2、称正则表达式,是表示正规集的工具,也是我们用以描述单词符号的方便工具。因此,熟练掌握正规文法、正规式以及它们之间的相互转化是非常必要的。2、设计原理2.1、正规文法的定义正规文法是左线性文法和右线性文法的统称。它们都是Chomsky分类下的3型文法。由正规文法产生的语言称为正规集。2.1.1、右线性文法设GS=(VN,VT,P,S),若P中的产生或均有如下的形式:AaB或Aa(AVN,aVT),则称G为右线性文法。例如,文法G1S=(S,A,B,a,b,P1,S)其中P1=SaA,AaA,AbB,Ab,BbB,Bb,由定义可知该文法为一右线性文法。2.1.2、左线性文法若一个文法GS=(VN,
3、VT,P,S)中的产生式均有如下的形式:ABa或Aa(A,BVN,aVT),则称G为左线性文法。例如,文法G2S=(S,A,a,b,P2,S)其中P2=SSb,SAb,AAa,Aa,由定义可知该文法为一左线性文法。 注:由于左线性文法和右线性文法是等价的,本次课程设计为简化需要,只考虑右线性文法和正规式之间的转换。2.2、正规式的定义正规式是描述程序语言单词的表达式,对于字母,其上的正规式及其表示的正规集可以递归定义如下: 是一个正规式,它表示集合L()=。 若a是上的字符,则a是一个正则式,它所表示的正规集L(a)=a。 若正规式r和s分别表示正规集L(r)=L(s),则(a)r|s是正规式
4、,表示集合L(r)L(s);(b)rs是正规式,表示集合L(r)L(s);(c)r*是正规式,表示集合(L(r)*;(d)(r)是正规式,表示集合L(r)。仅由有限次地使用上述三个步骤定义的表达式才是上的正规式。运算符“|”、“”、“*”分别称为“或”、“连接”和“闭包”。在正规式的书写中,连接运算符“”可省略。运算符的优先级从高到低顺序排列为:“*”、“”、“|”。2.3、正规文法和正规式的等价性一个正规语言可以由正规文法定义,也可以由正规式定义,对任意一个正规文法,存在一个定义同一个语言的正规式;反之,对每个正规式,存在一个生成同一语言的正规文法,有些正规语言很容易用文法定义,有些语言更容
5、易用正规式定义,这里两者间的转换,从结构上建立它们的等价性。2.3.1、将正规式转换成正规文法将上的一个正规式r转换成文法G=(VN,VT,S,P)。令VT =,确定产生式和VN 的元素用如下办法。选择一个非终结符S生成类似产生式的形式Sr,并将S定位G的识别符号。为表述方便,我们将Sr称作正规式产生式,因为在“”的右部含有:“*”、“”或“|”等正规式符号。不是V中的符号。若x和y都是正规式,对形如Axy的正规式产生式,重写成:AxB,By两产生式,其中B是新选择的非终结符,即BVN。对形如Ax*y的正规式产生式,重写为:AxBAyBxBBy 其中B为一新非终结符。 对形如Ax|y的正规式产
6、生式,重写为:Ax Ay不断利用上述规则做变换,直到每个产生式都符合正规文法的形式。2.3.2、将正规文法转换成正规式将正规文法装换成正规式。基本上是上述过程的逆过程,最后只剩下一个开始符号定义的正规式。其转化规则列于下表:文法产生式正规式规则1AxB ByA=xy规则2AxA|yA=x*y规则3Ax AyA=x|y 3、总体算法设计3.1、正规式转化为正规文法的算法利用编译原理中的算符优先分析方法对正规式进行分析,可以得到将正规式转化为正规文法的算法。为了顺利实现转化算法,使用了两个工作栈,一个是OPTR,用以寄存运算符,另一个是OPND,用以寄存操作数、中间结果或最后结果,算法如下:说明:
7、函数comp(x,y)的作用是:根据算符优先关系表,返回x和y的优先关系。函数operate(T,X,Y)的作用是:将文法符号X,Y所对应的文法(若X,Y是非终结符,则它们代表已知文法的开始符)按运算符T拼接成新的文法。operate返回新文法的开始符。3.2、正规文法转化为正规式的算法正规式与正规文法等价性的另一个方面即正规文法转换为正规式的问题,下面给出的转化算法可以将任意一个正规文法转化为与其等价的正规式。在使用该算法的过程中,应注意随时利用正规式的运算律对所得结果进行化简。4、详细设计4.1、算法涉及到的各个结构体4.1.1、每个文法规则右部非终结符前面的终结符串struct Node
8、a char a20; Nodea * nexta;例如右部产生式为:SabA|cdA|efB 可归为:S(ab|cd)A|efB 此时终结符A前面的终结符串ab存在Nodea结构体中char型数组中,指针指向下一个Nodea型结构体,其char型数组中存放cd。4.1.2、每个文法规则右部结构体struct NodeG /文法每一条规则右部结构体 Nodea *VTa; char VNA; NodeG *nextg;4.1.3、每条文法规则结构体struct HeadG char VNA; /文法每一条规则左部非终结符 NodeG *nextg; /文法规则右部产生式;4.1.4、文法规则结
9、合struct Paragraph/文法规则集合结构体 HeadG *Head;/本条规则的指针 Paragraph *nextH; /下一条规则指针 Paragraph *preH; /前一条规则指针,用于规则逆序查找,便于规则的逆序/替换。;4.2、主要函数4.2.1、创建文法的一条规则该函数可以实现文法规则的输入及存储。可以输入规则形式为:SaA|bA|cdB|!|e#; 其中!表示空串,#表示没有非终结符,e#表示该规则产生式为e.void creatG(HeadG *head)/给出该条规则首部,创建规则 char temp20; char cont=y; NodeG *nodeg;
10、 Nodea *nodea; NodeG *tail; nodeg=new(NodeG); nodea=new(Nodea); couttemp; strcpy(nodea-a,temp); nodea-nexta=NULL; nodeg-VTa=nodea; nodeg-VTa-nexta=NULL; /用!表示空串 if(temp0!=!) coutnodeg-VNA; else nodeg-VNA=; nodeg-nextg=NULL; head-nextg=nodeg; tail=nodeg; do coutcont; while(cont!=y&cont!=n); while(con
11、t=n) /该部分代码省略,和上面相同,可参见源代码 while(cont!=y&cont!=n); 4.2.2、合并规则右部相同非终结符的项该函数可以实现文法规则右部相同项的合并。对于如SaA|bA|cdB|!|e#; 改写后为S(a+b)A|cdB|!|e#;HeadG* changG(HeadG *head) while(n2!=NULL)/n2,n1为规则右部的一个产生式,当n2和n1非终结符相同时候合并 if(n2-VNA=n1-VNA) /合并 Nodea *na=ht-VTa; while(na-nexta!=NULL) na=na-nexta; na-nexta=n2-VTa;
12、 n2=n2-nextg;4.2.3、规则的替换用AaB|cD 替换SabA|cdC 中的A,替换后为SabaB|abcD|cdCHeadG * replaceG(HeadG *head1,HeadG *head2)/用head2规则替换head1中含有head2左部的项 while(th1!=NULL & th1-VNA!=head2-VNA)/找到head1中有head2左部得项 if (th1!=head1-nextg) preth1=preth1-nextg; th1=th1-nextg; if(th1!=NULL)/找到了之后串接起来 while(ta1!=NULL)/串接起来 wh
13、ile(ta2!=NULL) ss2-nexta=new(Nodea); ss2=ss2-nexta; strcpy(ss2-a,ta1-a); strcat(ss2-a,ta2-a); ss2-nexta=NULL; ta2=ta2-nexta; ta2=th2-VTa; /coutta1:anexta; 5、调试与运行结果5.1、 调试方法记录编辑好源程序,编译,出现多处错误,但多数是语法方面的错误,一一改正后。重新编译链接后运行,输入数据测试,经常出现指针错误提示。通过debug调试器,查看内存单元,一一分析比较,找出问题所在,返回源程序,修改,重新编译链接。这个过程是艰难和费时的,有时
14、候多次检查不出问题原因。调试还通过设置输出语句查看数据实现。例如不清楚a的值,可以通过cout”a=”a;查看a的值,分析其是否与理论值相等,若正确,则错误的原因很有可能在此句之后,否则在这句之前定有错误。经过多次修正,终于使得程序正确。5.2 、实验结果记录5.2.1、第一组测试数据对于正规文法Z0A;A0A|0B;B1A|;其正规式应为Z=0(0|01)*0.实验为Z=0(0)*0|0(01)*0可以化为0(0|01)*0。故实验结果正确。5.2.2、第二组测试数据对于正规文法SaA;AaA|bB|b;BbA|b;其正规式应为S=aa*(bb*b|b).实验为S=aa*bb*b|aa*b可
15、以化为aa*(bb*b|b)。故实验结果正确。5.2.3、第三组测试数据对于正规文法SaB;BbA|bB;Ac|cA;其正规式应为S=abb*c*c.实验为S= abb*c*c.故实验结果正确。6、课程设计总结与心得体会本课程设计主要是让我们掌握正规文法和正规式的转换算法,加深对正规文法和正规式的理解,正规文法和正规式是构造有穷自动机的前提,有穷自动机又是进行词法分析的工具,因此掌握转换方法对于编译很重要。总体来说通过这次的编译原理的课程设计,我学到了很多东西。平时的实验课程使我已经掌握了编译原理词法分析、语法分析、语义分析的方法。这些是我这次顺利做出课程设计的基础。课程设计过程中,我学会很重
16、要的调试方法,可以设计输出语句,查看内存单元是否正确,这在今后的学习工作中是很有用的,同时我还深刻体会到了耐心很重要,没有耐心,是很难把事情做成功的。课设中我也感觉到自身编程能力的欠缺,今后应该多加训练。感谢何九周老师的指导和同学们的帮助,没有你们的帮助和指导,我是很难做出这个课程设计的。课程设计锻炼了独立动手能力及创新设计思考的能力。这将会使我受益匪浅。7、参考文献1编译原理(第2版) 胡伦俊 徐兰芳 骆婷 编著 电子工业出版社出版2程序设计语言编译原理(第3版) 陈火旺 编著 国防工业出版社3数据结构(第2版) 严蔚敏 编著 清华大学出版社4编译原理课程设计王雷 刘志成 周晶 编著 机械工业出版社5编译原理学习指导胡元义 柯丽芳 著 西安电子科技大学出版社6正规式与正规文法的等价性及转化算法晏兴学 著 甘肃高师学报
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1