编译原理课程设计0904杨杰.docx

上传人:b****5 文档编号:7738046 上传时间:2023-01-26 格式:DOCX 页数:20 大小:176.64KB
下载 相关 举报
编译原理课程设计0904杨杰.docx_第1页
第1页 / 共20页
编译原理课程设计0904杨杰.docx_第2页
第2页 / 共20页
编译原理课程设计0904杨杰.docx_第3页
第3页 / 共20页
编译原理课程设计0904杨杰.docx_第4页
第4页 / 共20页
编译原理课程设计0904杨杰.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

编译原理课程设计0904杨杰.docx

《编译原理课程设计0904杨杰.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计0904杨杰.docx(20页珍藏版)》请在冰豆网上搜索。

编译原理课程设计0904杨杰.docx

编译原理课程设计0904杨杰

学号:

0120910680405

 

课程设计

 

题目

正规文法G转换为有穷自动机FA的程序设计

学院

计算机学院

专业

软件工程

班级

0904班

姓名

杨杰

指导教师

何九周

 

2011

12

30

 

课程设计任务书

学生姓名:

杨杰专业班级:

软件0904

指导教师:

何九周工作单位:

计算机学院

题目:

正规文法G转换为有穷自动机FA的程序设计

初始条件:

程序设计语言:

主要使用C语言的开发工具,或者采用LEX、YACC等工具,也可利用其他熟悉的开发工具。

算法:

可以根据《编译原理》课程所讲授的算法进行设计。

要求完成的主要任务:

(包括课程设计工作量及其技术要求,说明书撰写等具体要求)

1.明确课程设计的目的和重要性,认真领会课程设计的题目,读懂课程设计指导书的要求,学会设计的基本方法与步骤,学会如何运用前修知识与收集、归纳相关资料解决具体问题的方法。

严格要求自己,要独立思考,按时、独立完成课程设计任务。

2.主要功能包括:

输入先行正规文法,根据输入文法判断是否为正规文法,判断产生的是确定型文法还是非确定型文法。

判断出终结符号,非终结符号,输出自动机标准形式。

3.进行总体设计,详细设计:

包括算法的设计和数据结构设计。

系统实施、调试,合理使用出错处理程序。

4.设计报告:

要求层次清楚、整洁规范、不得相互抄袭。

正文字数不少于0.3万字。

包含内容:

①课程设计的题目。

②目录。

③正文:

包括引言、需求分析、总体设计及开发工具的选择,设计原则(给出语法分析方法及中间代码形式的描述、文法和属性文法的设计),数据结构与模块说明(功能与流程图)、详细的算法设计、软件调试、软件的测试方法和结果、有关技术的讨论、收获与体会等。

④结束语。

⑤参考文献。

⑥附录:

软件清单(或者附盘)。

时间安排:

消化资料、系统调查、形式描述1天

系统分析、总体设计、实施计划3天

撰写课程设计报告书1天

指导教师签名:

2011年12月30日系主任(或责任教师)签名:

2011年12月30日

 

摘要4

一、引言5

二、设计原理6

三、设计方案13

1、总体设计13

2、详细设计14

四、程序调试与体会24

五、运行结果24

五、结论26

六、参考文献26

 

摘要

如果我们把一个程序设计语言的每类单词都视为一种语言,那么,一般说来,各类单词的词法都能用相应的正规文法(左线性文法或右线性方法)来描述。

正规文法是左线性文法和右线性文法的统称。

它们都是Chomsky分类下的3型文法。

由正规文法产生的语言称为正规集。

一般的高级语言转化成机器语言都要经过词法分析、语法分析、语义分析、中间代码的生成与目标代码的生成。

其中,在词法分析环节中可以用LEX等语言来自动进行词法分析,在其分析过程中,要用到正规式、DFA与NFA之间的互相转化的过程。

本课程设计从理论和实践上分析和实现正规式到NFA转化的方法及其C程序实现。

关键词:

正规文法、确定化有限自动状态机、非确定的有限自动状态机、自动机类型判定、

 

《编译原理》课程设计

——正规式G转化成有穷自动机FA

一、引言

编程语言是由一个个句子构成的,而句子是由一个个单词构成的,因此单词是构成程序语言的基本单位。

词法就是单词的构成法则,用这些法则来检查程序的单词构成是否合乎词法规则。

进行词法分析的形式化工具目前主要有正规式、DFA与NFA,而且正规式、DFA、NFA在表现能力上是等价的,可以互相转化。

正规式是一种形式化表达,而DFA和NFA是一种图形化的表达。

二、设计原理

1、文法形式

如果我们把一个程序设计语言的每类单词都视为一种语言,那么,一般说来,各类单词的词法都能用相应的正规文法(左线性文法或右线性方法)来描述。

例如,某种语言中的标识符可定义为:

〈标识符〉→〈标识符〉字母

〈标识符〉→〈标识符〉数字

〈标识符〉→字母

如果我们把“字母”和“数字”视为终结符号,则上述产生式均为左线性文法中的产生式。

又如,把C语言中〈无符号数〉的定义稍加改写,我们可得到如下的产生式(请注意,在下列产生式中,d是一个“字符类”记号,它代表0至9中的任一数字):

〈无符号数〉→d〈余留无符号数〉

〈无符号数〉→·〈小数部分〉

〈无符号数〉→d

〈余留无符号数〉→d〈余留无符号数〉

〈余留无符号数〉→·〈十进小数〉

〈余留无符号数〉→E〈指数部分〉

〈余留无符号数〉→·

〈余留无符号数〉→d

〈十进小数〉→E〈指数部分〉

〈十进小数〉→d〈十进小数〉

〈十进小数〉→d

〈小数部分〉→d〈十进小数〉

〈小数部分〉→d

〈指数部分〉→d〈余留整指数〉

〈指数部分〉→+〈整指数〉

〈指数部分〉→-〈整指数〉

〈指数部分〉→d

〈整指数〉→d〈余留整指数〉

〈整指数〉→d

〈余留整指数〉→d〈余留整指数〉

〈余留整指数〉→d

如果我们把由上述产生式所组成的文法记作

G[〈无符号数〉]=(VN,VT,P,〈无符号数〉)

其中:

VN={〈无符号数〉,〈余留无符号数〉,〈十进小数〉,…,〈余留整指数〉}

VT={d,·,E,+,-}

则G[〈无符号数〉]为一右线性文法。

我们将会看到,凡能用正规文法描述的语言,均可由某种有限状态算法进行分析。

下面,我们先介绍由正规文法构造状态转换图的方法,然后再说明如何利用状态转换图识别相应文法中的句子(即程序语言的单词)。

一个状态转换图是由一组矢线连接的有限个结点所组成的有向图。

每一结点均代表在识别或分析过程中扫描器所处的状态。

其中含有一个初始状态和若干个终态,分别指示分析的开始和结束。

在状态转换图中,结点用小圆圈表示(为醒目起见,初态结点用箭头指示,终态结点则用双圆圈表示)。

圆圈中标入状态的名字或编号。

此外,为以后叙述上的方便,对于状态转换图中用矢线连接的任两个结点,我们把靠箭尾一侧的结点称为该矢线的射出结点,而把箭头指向的结点称为进入结点。

而且,从一个结点可以同时射出若干条矢线,每一矢线均标上一个字符或字符类记号,表示当扫描器处于射出结点所指示的状态时,可能扫视到的输入字符;而这些矢线的进入结点则表示在射出结点所指示的状态下,当扫视到矢线上所标记的字符类时应进入的状态。

2、正规文法转换为状态转换图的方法

分别就左、右线性文法给出构造相应状态转换图的方法。

2.1对于右线性文法的情况

1设G=(VN,VT,P,S)是一右线性文法,并设|VN|=k,则所要构造的状态转换图共有k+1结点,即有k+1个状态。

我们用VN中的各个非终结符号(或其编号)分别标记其中的k个结点,且令G的开始符号S所标记的结点为初态结点;余下的一个结点作为终态结点,且用不属于V的一个符号F来标记。

我们将按如下的规则用矢线来连接这k+1个结点:

(1)对于G中每一形如A→aB的产生式,从结点A引一条矢线到结点B,并用符号a标记这条矢线;

(2)对于G中每一形如A→a的产生式,从结点A引一条矢线到终态结点F,并用符号a标记这条矢线。

应当指出,上述构造状态转换图的方法仅针对G中不含有ε产生式的情况。

如果G中含有ε产生式,则可按下述两种方法加以处理。

其一,是用第2章242节中所给的算法先消去G中的ε产生式,然后再按所得的文法G′构造其状态转换图;另一种方法则是对于G中的所有ε产生式A→ε,都从结点A引一矢线到终态结点,且在这矢线上标记这样的终结符号,它们还未曾在结点A的射出弧上出现过。

例如,对于上面所列的文法G[〈无符号数〉],若把非终结符号〈无符号数〉、〈余留无符号数〉、〈十进小数〉、〈小数部分〉、〈指数部分〉、〈整指数〉及〈余留整指数〉分别用编号0,1,2,…,6代表,并用1,2和6代表终态,则按上述方法所构造的状态转换图如图3-3所示。

2对于已给的字符串w=a1a2…an,ai∈VT,利用状态转换图对w识别的步骤如下:

(1)从初始状态S出发,并自左至右逐个扫视w中的各个字符,显然,在状态S之下所扫视的输入字符为a1,此时在结点S所射出的诸矢线中,寻找标记为a1的矢线(如这样的矢线不存在,则表明w有语法错误),读入a1并沿矢线所指的方向前进,过渡到下一个状态(由进入结点的标记给出,假定它是A1)。

(2)设在状态Ai的情况下,所扫视的输入字符为ai+1,在结点Ai所射出的诸矢线中寻找标记为ai+1的矢线(若这样的矢线不存在,则w有语法错误),读入ai+1,并过渡到下一状态Ai+1。

(3)重复上面的过程,直到w中全部字符读完且恰好进入终态F时,宣告整个识别结束,w已被接受。

显然,如果我们从状态转换图的初态出发,分别沿着一切可能的路径到达终态结点,并将每条路径各矢线上的标记字符依次连接起来,便得到状态转换图所能识别的全部符号串,这些符号串所组成的集合也就是该状态转换图所识别的语言。

应当指出,上述利用状态转换图识别符号串w的过程,也就是为w建立一个推导S*[]Gw的过程。

事实上,识别过程的第一步(即在状态为S的情况下,扫视到输入字符a1而过渡到下一状态A1)表明,在G中必有形如S→a1A1的产生式;对于识别过程的后续各步,由状态转换图的构造方法我们同样能够断言,在G中必相应地存在着形如

A1→a2A2A2→a3A3…An-2→an-1An-1

的产生式;最后,因为在状态An-1扫视到输入字符an而进入终态F,故由构造状态图的规则

(2)可知,G中有形如An-1→an的产生式,于是我们就有

Sa1A1a1a2A2…a1a2…an-1An-1a1a2…an

3设G是一右线性文法,M是相应的状态转换图,则从上面的讨论我们不难看出如下的事实:

(1)在利用M对符号串w进行识别的过程中,M中每一次状态转换都模拟了G中的一步直接推导,所以,上述用M对符号串进行识别的方法是一个自顶向下的分析算法。

(2)由于右线性文法G中仅有形如A→aB及A→a的产生式,故G的任何句型中至多只含一个非终结符号,且必然出现在句型的最右端,因此,如果我们从M的初态出发,沿着某一路径到达状态Ak,则把此路径上各矢线的标记(设其分别为a1,a2,…,ak)和Ak依次连接起来所得到的符号串a1a2…akAk就是G的一个句型,并且它们都是规范句型(注意,形如A→a的产生式仅用于句子推导的最后一步,故当所达的状态Ak为终态F时,a1a2a3…ak则为G的一个句子)。

(3)对于M所识别的任一符号串x,必存在G中的一个推导S*x(即有x∈L(G));而对于L(G)中任一句子y,必存在M的一条从初态结点S到终态结点F的路径,将此路径上各矢线的标记依次连接起来所组成的符号串就是y。

于是可知,M所能识别的恰好是L(G)中的全部句子

2.2、对于左线性文法的情况

设G=(VN,VT,P,S)是一左线性文法,我们将按下述的方法构造相应的状态转换图M。

首先仍用G的非终结符号(或其编号)来标记M中的结点,与右线性文法不同的是,现在我们不用G的开始符号S来标记初态结点,而是引入一个不属于V的新符号R作为初态结点的标记,并用S作为M的终态。

其次,按如下的规则用矢线连接各个结点:

(1)对于G中每一形如A→a的产生式,从初态结点R引一条矢线到结点A,且用符号a标记此矢线;

(2)对于G中每一形如A→Ba的产生式,从结点B引一条矢线到结点A,且用符号a标记此矢线。

例如,对于文法G=({S,U},{0,1},P,S),其中

P={S→S1,S→U1,U→U0,U→0}

按上述方法构造的状态转换图如图34(a)所示。

用对左线性文法所构造的状态转换图来识别文法的句子,其过程与上面对右线性文法中所述的过程并无二致,兹不再赘述。

不过,就识别的方法而论,它却属于自底向上的分析。

例子:

文法G[S]的状态转换图(b)识别句子00011的步骤

由构造状态转换图的方法(对左线性文法)可知,从初态到下一状态的转换,总是相对于文法中形如A→a的产生式来进行的。

所以,作为识别的第一步,实质上总是把输入串中的第一个符号归约为文法的一个非终结符号(即下一状态的名字,在本例,就是首先把第一个输入符号0归约为U),从而得到了一个由当前状态名和余留的输入符号所组成的符号串(在本例,即为U0011),此符号串显然是G的一个句型。

由于从第二步开始的各次状态转换,总是相对于形如A→Ba的产生式来进行的,其中B为当前状态,a是正扫视的输入符号。

A是下一状态,因此,每一步总是把当前句型最左的两个符号Ba按产生式A→Ba归约为A,而此非终结符号A和余留的输入符号便组成了归约之后所得的下一句型(例如,对于本例的第二步状态转换,当前的句型为U0011,按产生式U→U0归约所得的下一句型为U011)。

由此可见,从第二步开始,在每一步识别所得到的句型中,其最左符号必然是该句型所含有的惟一非终结符号。

此非终结符号(当前状态名)和跟随其后的终结符号(即正扫视的输入符号)便是该句型的句柄,且每归约一次,都抹去句型中的一个终结符号。

继续这样的归约,如果能抹去句型中的全部终结符号,且最后得到惟一的符号S,则宣告相应的输入符号串已被识别。

对于输入串00011,其相应的语法树如图35所示。

如果我们在图中用数字将归约顺序标出,则容易看出:

每次归约所得的句型都是规范句型。

而且,如果G的任两个产生式无相同的右部,则每次所得的符号都是惟一的。

二、设计目的

因为在词法分析时为了分析的方便我们有时要用到正规式,有时要用到DFA,而有时可能还要用到NFA。

这三种工具在词法分析时互相参照,互相补充。

词法分析器的自动产生语言LEX编译器的工作过程是首先根据正规式产生出NFA,再由NFA构造出DFA,再来产生我们的词法分析器。

因此,我们设计的目的是来模仿其中的一个步骤,设计的任务是根据不同的输入正规式转化成NFA的形式输出,输出形式为M={S0,S,&,$,F}五元式的形式。

三、设计方案

1、总体设计

(1)首先初始化对构造的数组进行初始化。

(2)把屏幕上的一个正规文法读入到一个缓冲区中保存起来,以便以后对正规式的分析与处理。

进行input操作时判断其是否为正规文法。

判断方法详见详细设计。

(3)对正规文法进行预处理,去掉里面的一些对分析不起作用的控制字符,为以后的分析与处理带来方便。

区分终结符与非终结符。

并进行输出。

(4)判断输入的正规文法为确定性还是非确定性。

并进行输出。

(5)输出FA,以五元式的形式输出输出自动机。

以下为总体设计的层次图:

图1.总体设计层次图

2、详细设计

第一个模块设计理论为:

进行定义,并对数组进行初始化。

voidinput()//输入文法

{

for(inti=0;i<10;i++)

a[m][i]='#';

scanf("%s",a[m]);

while(strcmp(a[m],"end"))

{

if((a[m][0]>='A')&&(a[m][0]<='Z'))//判断是否为正则文法

{

inth=4;

if((a[m][h]>='A')&&(a[m][h]<='Z'))//U-->WT

{

if((a[m][h+1]<'A')||(a[m][h+1]>'Z'))

{

if(a[m][h+2]!

='\0')

{

printf("此规则不是正则文法的规则,请重新输入\n");input();break;

}

}

else

{

printf("此规则不是正则文法的规则,请重新输入\n");input();break;

}

}

else

{

if(a[m][h+1]!

='\0')//U-->T

{

printf("此规则不是正则文法的规则,请重新输入\n");input();break;

}

}

}

m++;

scanf("%s",a[m]);

}

}

第二个模块的设计理论为:

把屏幕上的一个正规文法读入到一个缓冲区中保存起来,以便以后对正规式的分析与处理。

进行input操作时判断其是否为正规文法。

voidinput()//输入文法

{

for(inti=0;i<10;i++)

a[m][i]='#';

scanf("%s",a[m]);

while(strcmp(a[m],"end"))

{

if((a[m][0]>='A')&&(a[m][0]<='Z'))//判断是否为正则文法

{

inth=4;

if((a[m][h]>='A')&&(a[m][h]<='Z'))//U-->WT

{

if((a[m][h+1]<'A')||(a[m][h+1]>'Z'))

{

if(a[m][h+2]!

='\0')

{

printf("此规则不是正则文法的规则,请重新输入\n");input();break;

}

}

else

{

printf("此规则不是正则文法的规则,请重新输入\n");input();break;

}

}

else

{

if(a[m][h+1]!

='\0')//U-->T

{

printf("此规则不是正则文法的规则,请重新输入\n");input();break;

}

}

}

m++;

scanf("%s",a[m]);

}

}

第三个模块的设计理论为:

对正规文法进行预处理,去掉里面的一些对分析不起作用的控制字符,为以后的分析与处理带来方便。

区分终结符与非终结符。

并进行输出。

voidgroup()//判断终结符号与非终结符

{

for(intk=0;a[k][0]!

='e';k++)

{

for(intf=0;a[k][f]!

='\0';f++)

{

if((a[k][f]>='A')&&(a[k][f]<='Z'))

{

for(intx=0;x<=M&&M<=27;x++)

if(Vn[x]==a[k][f])

break;

if((x-1)==M)

{

Vn[M]=a[k][f];

M++;

}

}

else

{

for(inty=0;y<=N&&N<=20;y++)

{

if(a[k][f]=='-'||a[k][f]=='>')

break;

else

{

if(Vt[y]==a[k][f])

break;

}

}

if((y-1)==N)

{

Vt[N]=a[k][f];

N++;

}

}

}

}

}

第四个模块的设计理论为:

voidrecongnise()//判断是确定还是非确定

{

for(inti=0;a[i][0]!

='e';i++)

{

for(intj=i+1;a[j][0]!

='e';j++)

{

intn=4;

if(a[i][n]==a[j][n])n++;

if(a[i][n]==a[j][n])break;

}

inth=4;

if(a[i][h]==a[j][h])h++;

if(a[i][h]==a[j][h])//U-->T

{

printf("此文法对应的有穷状态自动机是非确定的\n\n");

flag=0;

break;

}

}

if(a[i][0]=='e')//U-->WT

{

printf("此文法对应的有穷状态自动机是确定的\n\n");

flag=1;

}

第五个模块的设计理论为:

以五元组形式输出自动机。

voidoutput()//输出文法相应的有穷状态自动机

{

if(flag==0)

{printf("NFAN=({");

for(inti=0;Vn[i]!

='#';i++)

printf("%c,",Vn[i]);

printf("S},{");

for(intj=0;Vt[j]!

='#';j++)

printf("%c,",Vt[j]);

printf("},M',{S},{%c})\n",Vn[0]);

printf("其中M':

\n");

for(intx=0;Vn[x]!

='#';x++)

{

for(inty=0;Vt[y]!

='#';y++)

{

printf("M'(%c,%c)=",Vn[x],Vt[y]);

for(intz=0;a[z][0]!

='e';z++)

if(a[z][4]==Vn[x])

if(a[z][5]==Vt[y])

printf("%c",a[z][0]);

if(a[z][0]=='e')

printf("\t");

}

printf("\n");

}

for(intu=0;Vt[u]!

='#';u++)

{

printf("M'(S,%c)=",Vt[u]);

for(intk=0;a[k][0]!

='e';k++)

if(a[k][4]==Vt[u])

printf("%c",a[k][0]);

if(a[k][0]=='e')

printf("\t");

}

}

if(flag==1)

{

printf("DFAN=({");

for(intb=0;Vn[b]!

='#';b++)

printf("%c,",Vn[b]);

printf("S},{");

for(intc=0;Vt[c]!

='#';c++)

printf("%c,",Vt[c]);

printf("},M',S,{%c})\n",Vn[0]);

printf("其中M':

\n");

for(intp=0;Vn[p]!

='#';p++)

{

for(intq=0;Vt[q]!

='#';q++)

for(intr=0;a[r][0]!

='#';r++)

if(a[r][4]==Vn[p])

if(a[r][5]==Vt[q])

printf("M'(%c,%c)=%c\t",Vn[p],Vt[q],a[r][0]);printf("\n");

}

for(intd=0;Vt[d]!

='#';d++)

{

for(inte=0;a[e][0]!

='e';e++)

if(a[e][4]==Vt[d])printf("M'(S,%c)=%c\t",Vt[d],a[e][0]);

}

}

}

四、程序调试与体会

程序编写初期在纠结于正规文法的输入和自动机的输出形式,编一个程序并不难,难的是要把这个程序完全调试正确。

从输入开始就要进行输入文法的判定,首先要判定是否输入为正规文法,否则以后的输入都将是出错的。

其次重点是进行确定机非确定机的判定。

判定方法在课本上有既定算法。

正因为程序的执行路径变化多样,所以给我们的程序调试带来了不少的困难,我在调试这个程序的时候,就遇到了不少了困难,在处理NFA分叉的情况时,就花费了两天的时间来处理。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1