编译原理课设正规式r与正规文法G相互转换的程序设计Word文档格式.docx
- 文档编号:17624031
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:13
- 大小:467.48KB
编译原理课设正规式r与正规文法G相互转换的程序设计Word文档格式.docx
《编译原理课设正规式r与正规文法G相互转换的程序设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《编译原理课设正规式r与正规文法G相互转换的程序设计Word文档格式.docx(13页珍藏版)》请在冰豆网上搜索。
在计算机编译理论中,正规式、正规文法、自动机的理论以及它们之间的等价性问题是编译理论的等价基础,其中正规式和自动机,正规文法和自动机之间的等价性问题,已经得到了比较圆满的解决。
本文主要讨论正规式和正规文法之间相互转换的方法。
关键字:
编译原理正规式正规文法相互转换
1、引言
程序设计语言中的单词是基本语法符号。
单词符号的语法可以用有效的工具加以描述,并且基于这类描述工具,可以建立词法分析技术,进而可以建立词法分析程序的自动构造方法。
多数程序设计语言的单词的语法都能用正规文法或3型文法来描述。
正规式也称正则表达式,是表示正规集的工具,也是我们用以描述单词符号的方便工具。
因此,熟练掌握正规文法、正规式以及它们之间的相互转化是非常必要的。
2、设计原理
2.1、正规文法的定义
正规文法是左线性文法和右线性文法的统称。
它们都是Chomsky分类下的3型文法。
由正规文法产生的语言称为正规集。
2.1.1、右线性文法
设G[S]=(VN,VT,P,S),若P中的产生或均有如下的形式:
A→aB或A→a(A∈VN,a∈VT),则称G为右线性文法。
例如,文法G1[S]=({S,A,B},{a,b},P1,S)
其中P1={S→aA,A→aA,A→bB,A→b,B→bB,B→b},由定义可知该文法为一右线性文法。
2.1.2、左线性文法
若一个文法G[S]=(VN,VT,P,S)中的产生式均有如下的形式:
A→Ba或A→a(A,B∈VN,a∈VT),则称G为左线性文法。
例如,文法G2[S]=({S,A},{a,b},P2,S)
其中P2={S→Sb,S→Ab,A→Aa,A→a},由定义可知该文法为一左线性文法。
[注:
]由于左线性文法和右线性文法是等价的,本次课程设计为简化需要,只考虑右线性文法和正规式之间的转换。
2.2、正规式的定义
正规式是描述程序语言单词的表达式,对于字母∑,其上的正规式及其表示的正规集可以递归定义如下:
①ε是一个正规式,它表示集合L(ε)={ε}。
②若a是∑上的字符,则a是一个正则式,它所表示的正规集L(a)={a}。
③若正规式r和s分别表示正规集L(r)=L(s),则
(a)r|s是正规式,表示集合L(r)∪L(s);
(b)r·
s是正规式,表示集合L(r)L(s);
(c)r*是正规式,表示集合(L(r))*;
(d)(r)是正规式,表示集合L(r)。
仅由有限次地使用上述三个步骤定义的表达式才是∑上的正规式。
运算符“|”、“·
”、“*”分别称为“或”、“连接”和“闭包”。
在正规式的书写中,连接运算符“·
”可省略。
运算符的优先级从高到低顺序排列为:
“*”、“·
”、“|”。
2.3、正规文法和正规式的等价性
一个正规语言可以由正规文法定义,也可以由正规式定义,对任意一个正规文法,存在一个定义同一个语言的正规式;
反之,对每个正规式,存在一个生成同一语言的正规文法,有些正规语言很容易用文法定义,有些语言更容易用正规式定义,这里两者间的转换,从结构上建立它们的等价性。
2.3.1、将正规式转换成正规文法
将∑上的一个正规式r转换成文法G=(VN,VT,S,P)。
令VT=∑,确定产生式和VN的元素用如下办法。
选择一个非终结符S生成类似产生式的形式S→r,并将S定位G的识别符号。
为表述方便,我们将S→r称作正规式产生式,因为在“→”的右部含有:
”或“|”等正规式符号。
不是V中的符号。
若x和y都是正规式,对形如A→xy的正规式产生式,重写成:
A→xB,B→y两产生式,其中B是新选择的非终结符,即B∈VN。
对形如A→x*y的正规式产生式,重写为:
A→xB
A→y
B→xB
B→y其中B为一新非终结符。
对形如A→x|y的正规式产生式,重写为:
A→x
不断利用上述规则做变换,直到每个产生式都符合正规文法的形式。
2.3.2、将正规文法转换成正规式
将正规文法装换成正规式。
基本上是上述过程的逆过程,最后只剩下一个开始符号定义的正规式。
其转化规则列于下表:
文法产生式
正规式
规则1
A→xB B→y
A=xy
规则2
A→xA|y
A=x*y
规则3
A→x A→y
A=x|y
3、总体算法设计
3.1、正规式转化为正规文法的算法
利用编译原理中的算符优先分析方法对正规式进行分析,可以得到将正规式转化为正规文法的算法。
为了顺利实现转化算法,使用了两个工作栈,一个是OPTR,用以寄存运算符,另一个是OPND,用以寄存操作数、中间结果或最后结果,算法如下:
说明:
函数comp(x,y)的作用是:
根据算符优先关系表,返回x和y的优先关系。
函数operate(T,X,Y)的作用是:
将文法符号X,Y所对应的文法(若X,Y是非终结符,则它们代表已知文法的开始符)按运算符T拼接成新的文法。
operate返回新文法的开始符。
3.2、正规文法转化为正规式的算法
正规式与正规文法等价性的另一个方面即正规文法转换为正规式的问题,下面给出的转化算法可以将任意一个正规文法转化为与其等价的正规式。
在使用该算法的过程中,应注意随时利用正规式的运算律对所得结果进行化简。
4、详细设计
4.1、算法涉及到的各个结构体
4.1.1、每个文法规则右部非终结符前面的终结符串
structNodea
{
chara[20];
Nodea*nexta;
};
例如右部产生式为:
S→abA|cdA|efB可归为:
S→(ab|cd)A|efB此时终结符A前面的终结符串ab存在Nodea结构体中char型数组中,指针指向下一个Nodea型结构体,其char型数组中存放cd。
4.1.2、每个文法规则右部结构体
structNodeG//文法每一条规则右部结构体
Nodea*VTa;
charVNA;
NodeG*nextg;
4.1.3、每条文法规则结构体
structHeadG
//文法每一条规则左部非终结符
//文法规则右部产生式
4.1.4、文法规则结合
structParagraph//文法规则集合结构体
HeadG*Head;
//本条规则的指针
Paragraph*nextH;
//下一条规则指针
Paragraph*preH;
//前一条规则指针,用于规则逆序查找,便于规则的逆序
//替换。
4.2、主要函数
4.2.1、创建文法的一条规则
该函数可以实现文法规则的输入及存储。
可以输入规则形式为:
S→aA|bA|cdB|!
@|e#;
其中!
@表示空串ε,#表示没有非终结符,e#表示该规则产生式为e.
voidcreatG(HeadG*head)//给出该条规则首部,创建规则
chartemp[20];
charcont='
y'
;
NodeG*nodeg;
Nodea*nodea;
NodeG*tail;
nodeg=new(NodeG);
nodea=new(Nodea);
cout<
<
"
输入规则右部终结符:
cin>
>
temp;
strcpy(nodea->
a,temp);
nodea->
nexta=NULL;
nodeg->
VTa=nodea;
VTa->
//用!
@表示空串ε
if(temp[0]!
='
!
'
)
{
输入规则右部非终结符:
nodeg->
VNA;
}
else
nodeg->
VNA='
@'
nextg=NULL;
head->
nextg=nodeg;
tail=nodeg;
do{
该条规则结束了吗(y/n)?
cin>
cont;
}while(cont!
&
cont!
n'
);
while(cont=='
//该部分代码省略,和上面相同,可参见源代码
}while(cont!
}
4.2.2、合并规则右部相同非终结符的项
该函数可以实现文法规则右部相同项的合并。
对于如S→aA|bA|cdB|!
改写后为S→(a+b)A|cdB|!
HeadG*changG(HeadG*head)
while(n2!
=NULL)
//n2,n1为规则右部的一个产生式,当n2和n1非终结符相同时候合并
if(n2->
VNA==n1->
VNA)
//合并
{
Nodea*na=ht->
VTa;
while(na->
nexta!
na=na->
nexta;
na->
nexta=n2->
n2=n2->
nextg;
4.2.3、规则的替换
用A→aB|cD替换S→abA|cdC中的A,替换后为S→abaB|abcD|cdC
HeadG*replaceG(HeadG*head1,HeadG*head2)
//用head2规则替换head1中含有head2左部的项
while(th1!
=NULL&
th1->
VNA!
=head2->
//找到head1中有head2左部得项
if(th1!
=head1->
nextg)preth1=preth1->
th1=th1->
if(th1!
=NULL)//找到了之后串接起来
while(ta1!
=NULL)//串接起来
while(ta2!
{
ss2->
nexta=new(Nodea);
ss2=ss2->
strcpy(ss2->
a,ta1->
a);
strcat(ss2->
a,ta2->
ta2=ta2->
}
ta2=th2->
//cout<
ta1:
ta1->
a<
endl;
ta1=ta1->
5、调试与运行结果
5.1、调试方法记录
编辑好源程序,编译,出现多处错误,但多数是语法方面的错误,一一改正后。
重新编译链接后运行,输入数据测试,经常出现指针错误提示。
通过debug调试器,查看内存单元,一一分析比较,找出问题所在,返回源程序,修改,重新编译链接。
这个过程是艰难和费时的,有时候多次检查不出问题原因。
调试还通过设置输出语句查看数据实现。
例如不清楚a的值,可以通过cout<
”a=”<
a;
查看a的值,分析其是否与理论值相等,若正确,则错误的原因很有可能在此句之后,否则在这句之前定有错误。
经过多次修正,终于使得程序正确。
5.2、实验结果记录
5.2.1、第一组测试数据
对于正规文法
Z→0A;
A→0A|0B;
B→1A|ε;
其正规式应为
Z=0(0|01)*0.
实验为
Z=0(0)*0|0(01)*0
可以化为0(0|01)*0。
故实验结果正确。
5.2.2、第二组测试数据
S→aA;
A→aA|bB|b;
B→bA|b;
S=aa*(bb*b|b).
S=aa*bb*b|aa*b
可以化为aa*(bb*b|b)。
5.2.3、第三组测试数据
S→aB;
B→bA|bB;
A→c|cA;
S=abb*c*c.
S=abb*c*c.
6、课程设计总结与心得体会
本课程设计主要是让我们掌握正规文法和正规式的转换算法,加深对正规文法和正规式的理解,正规文法和正规式是构造有穷自动机的前提,有穷自动机又是进行词法分析的工具,因此掌握转换方法对于编译很重要。
总体来说通过这次的编译原理的课程设计,我学到了很多东西。
平时的实验课程使我已经掌握了编译原理词法分析、语法分析、语义分析的方法。
这些是我这次顺利做出课程设计的基础。
课程设计过程中,我学会很重要的调试方法,可以设计输出语句,查看内存单元是否正确,这在今后的学习工作中是很有用的,同时我还深刻体会到了耐心很重要,没有耐心,是很难把事情做成功的。
课设中我也感觉到自身编程能力的欠缺,今后应该多加训练。
感谢何九周老师的指导和同学们的帮助,没有你们的帮助和指导,我是很难做出这个课程设计的。
课程设计锻炼了独立动手能力及创新设计思考的能力。
这将会使我受益匪浅。
7、参考文献
[1]《编译原理》(第2版)胡伦俊徐兰芳骆婷编著电子工业出版社出版
[2]《程序设计语言编译原理》(第3版)陈火旺编著国防工业出版社
[3]《数据结构》(第2版)严蔚敏编著清华大学出版社
[4]《编译原理课程设计》王雷刘志成周晶编著机械工业出版社
[5]《编译原理学习指导》胡元义柯丽芳著西安电子科技大学出版社
[6]《正规式与正规文法的等价性及转化算法》晏兴学著甘肃高师学报
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 正规 文法 相互 转换 程序设计