算符优先词法分析器编译原理完整课程设计.docx
《算符优先词法分析器编译原理完整课程设计.docx》由会员分享,可在线阅读,更多相关《算符优先词法分析器编译原理完整课程设计.docx(13页珍藏版)》请在冰豆网上搜索。
算符优先词法分析器编译原理完整课程设计
1、设计目的………………………………………………1
2、设计原理………………………………………………1
3、设计思想………………………………………………2
4、设计要求………………………………………………3
5、设计流程图及程序……………………………………4
6、运行结果及分析………………………………………14
7、设计总结………………………………………………16
8、参考文献………………………………………………16
算符优先词法分析器
一、设计目的
算符优先算法是自底而上分析方法的一种。
所谓自底向上分析,也称移进—规约分析,粗略地说他的实现思想是对输入符号串自左向右进行扫描,并将输入符逐个移入一个后进先出的栈中,边移进边分析,一旦栈顶符号串形成某个句型的句柄或可规约串是,就用该产生式的左部非终结符代替相应右部的文法符号串,这称为一部规约。
重复这一过程直到规约到栈中只剩文法的开始符号是则为分析成功,也就确认输入串是文法的句子。
而算符优先分析的基本思想是只规定算符之间的优先关系,也就是只考虑终结符之间的优先关系。
本课程设计的主要目的:
1、通过本次课程设计,全面系统的了解编译原理程序构造的一般原理和基本实现方法,尤其是对自底向上的优先分析方法的认识和理解;
2、提高对编译程序工作基本过程及其各阶段基本任务的分析技能;
3、加强对编译程序的生成过程、构造工具及编译程序总流程框图的理解,巩固所学的课本知识。
二、设计原理
算符优先分析法是一种有效的自底向上的分析方法。
自底向上分析方法面临的主要问题是如何确定可归约串,而算符优先分析法根据两个终结符号之间的优先关系比较,成功的解决了可归约串的问题。
算符优先分析法是采用最左素短语进行归约的,严格来讲不属于规范规约的范畴。
因此,在设计以前我们必须要知道什么是素短语和最左素短语。
所谓素短语就是指句型中具有这样性质的短语:
至少含有一个终结符,且除了自身之外,不再含有任何更小的素短语的短语。
最左素短语,是指在句型的所有素短语中,处于句型最左边的素短语。
了解了素短语和最左素短语,那么如何构造这种算法呢?
首先,根据非终结符的FIRSTVT集和LASTVT集找出它们之间的优先关系,构造算符优先矩阵。
然后,由此矩阵构造相应符号串的算符优先分析表并编写程序。
三、设计思想
在算符优先算法中,存在定理:
一个算符优先文法G的任何句型
#N1a1N2a2…NnanNn+1#
(a∈VT,Nj∈VN,i=1,2,…,n,n+1,Nj可有可无)
的最左素短语是满足下列条件的最左子串:
NjajNj+1aj+1…NiaiNi+1
其中,aj-1aj=aj+1,…,ai-1=ai
ai>ai+1
由该定理可以看出,在算符优先文法的句型中,任何素短语中最相近的两个终结符的优先级相等,且素短语中位于最前面的终结符的优先级高于在句型中紧临其前的终结符的优先级,而素短语中处于最后面的终结符的优先级高于在句型中紧随其后的终结符的优先级。
设有算符优先文法G[S]=(VN,VT,P,S),则得出如下步骤:
1、根据G[S]文法构造优先关系矩阵;
2、设置一个符号栈S,存放已经归约的或待形成最左素短语的符号串,另设一个工作单元R,存放当前的待输入符号;
3、采用移进归约的方法,当符号栈S的栈顶形成可归约串——最左素短语时,进行归约。
具体方法如下:
①分析开始时,符号栈S中只有一个符号“#”,工作单元R中存放输入串的第一个终结符;
②查优先关系矩阵,比较符号栈中最靠栈顶的终结符号(假设为a)与工作单元R中的终结符(假设为b)的优先关系;
ⅰ)若a,b之间无优先关系,则出错并退出分析程序;
ⅱ)若a
ⅲ)若a>b,则表明此时栈顶已经形成最左素短语,转③;
③从符号栈中最靠栈顶的终结符Xn开始,依次向前(向栈底方向)与最近的终结符比较,若Xn-1=Xn,则继续比较Xn-2和Xn-1如此反复,直至
Xi-1为止,
于是最左素短语的左界也确定,此时最左素短语为从Ni开始(Ni为在Xi之前紧临Xi的非终结符,若为“空”,则从Xi开始)一直到栈顶的符号串:
NiXiNi+1Xi+1…NnXnNn+1
④在文法G[S]的产生式中,选择其右部具有NiXiNi+1Xn+1…NnXnNn+1形式的规则进行规约(注意:
此时非终结符号不必完全相同):
弹出符号栈栈顶的最左素短语,相应规则的左部非终结符进栈。
若此时分析栈中只有#和文法的一个非终结符,且待分析符号串只剩下#(即工作单元R中符号为#),则表明分析成功,所分析的输入串(源程序)是文法G[S]的句子,退出分析程序;否则,重复②。
有了以上的思路,我们首先对已经给定的文法按其产生式构造算符优先关系表,有了算符优先关系表并满足算符优先文法时,我们就可以对任意给定的符号串进行归约分析,形成句柄时就归约,最后判定输入串是否为该文法的句子。
在分析过程中可以设置一个符号栈S,用以寄存归约或待形成最左素短语的符号串,用一个工作单元a存放当前读入的终结符号,归约成功的标志是当读到句子结束时,S栈中只剩#N,即只剩句子最左括号‘#’和一非终结符N。
四、设计要求
使用算符优先分析算法分析下面的文法:
E’→#E#
E→E+T|T
T→T*F|F
F→P^F|P
P→(E)|i
其中i可以看作是一个终结符,无需作词法分析。
具体要求如下:
1、如果输入符号串为正确句子,显示分析步骤,包括分析栈中的内容、优先关系、输入符号串的变化情况;
2、如果输入符号串不是正确句子,则显示出错。
五、设计流程图及程序
1、分析
文法为:
(0)E'→#E#
(1)E→E+T
(2)E→T
(3)T→T*F
(4)T→F
(5)F→P^F
(6)F→P
(7)P→(E)
(8)P→i
根据算符优先文法的分析规则求得终结符优先矩阵
+
*
^
i
(
)
#
+
>
<
<
<
<
>
>
*
>
>
<
<
<
>
>
^
>
>
<
<
<
>
>
i
>
>
>
>
>
(
<
<
<
<
<
=
)
>
>
>
>
>
#
<
<
<
<
<
=
2、程序流程图
图1算符优先算法流程图
3、程序:
#include
#include
#include
#include
#include
#include
#include
#defineSIZE128
charyouxian[7][7]; //算符优先关系数组
charlexbuf[SIZE];//存放输入的要进行分析的句子
charlex[SIZE]; //存放剩余串
charfenxizhan[SIZE];//分析栈
voidfenxi();
intpanduanyou(charx);
voidshengyuchuan();
intk;
voidzengjia();
voidmain()
{
{//将算符优先关系存放在算符优先关系数组里
youxian[0][0]='>';
youxian[0][1]='<';
youxian[0][2]='<';
youxian[0][3]='<';
youxian[0][4]='<';
youxian[0][5]='>';
youxian[0][6]='>';
//______________________________________________________________
youxian[1][0]='>';
youxian[1][1]='>';
youxian[1][2]='<';
youxian[1][3]='<';
youxian[1][4]='<';
youxian[1][5]='>';
youxian[1][6]='>';
//_______________________________________________________________
youxian[2][0]='>';
youxian[2][1]='>';
youxian[2][2]='<';
youxian[2][3]='<';
youxian[2][4]='<';
youxian[2][5]='>';
youxian[2][6]='>';
//_______________________________________________________________
youxian[3][0]='>';
youxian[3][1]='>';
youxian[3][2]='>';
youxian[3][3]='$';//无优先关系的用$表示
youxian[3][4]='$';
youxian[3][5]='>';
youxian[3][6]='>';
//_________________________________________________________________
youxian[4][0]='<';
youxian[4][1]='<';
youxian[4][2]='<';
youxian[4][3]='<';
youxian[4][4]='<';
youxian[4][5]='=';
youxian[4][6]='$';
//_________________________________________________________________
youxian[5][0]='>';
youxian[5][1]='>';
youxian[5][2]='>';
youxian[5][3]='$';
youxian[5][4]='$';
youxian[5][5]='>';
youxian[5][6]='>';
//__________________________________________________________________
youxian[6][0]='<';
youxian[6][1]='<';
youxian[6][2]='<';
youxian[6][3]='<';
youxian[6][4]='<';
youxian[6][5]='$';
youxian[6][6]='=';
//_________________________________________________________________
}
printf("将要进行算符优先分析,请做好准备 \n");
printf("**********************************\n");
printf("请输入要进行分析的句子\n");
cin.get(lexbuf,SIZE);//将输入的字符串存到数组
printf("步骤 栈 优先关系 当前符号 剩余输入串 移进或归约\n");
k=0;fenxizhan[k]='#';
fenxizhan[k+1]='\0';
intlenth,i1;//初始化剩余串数组为输入串
lenth=strlen(lexbuf);
for(i1=0;i1 lex[i1]=lexbuf[i1];
lex[i1]='\0';
fenxi();
}
voidfenxi()
{
inti,j,f,z,z1,n,n1,z4,n4;
intflag=0;//操作的步骤数
chara;//存放正在分析的字符
charp6,Q,p1,p4;
f=strlen(lexbuf); //测出数组的长度
for(i=0;i {
a=lexbuf[i];
if(fenxizhan[k]=='+'||fenxizhan[k]=='*'||fenxizhan[k]=='^'||fenxizhan[k]=='i'||fenxizhan[k]=='('||fenxizhan[k]==')'||fenxizhan[k]=='#')
j=k;
else
j=k-1;
z=panduanyou(fenxizhan[j]);//从优先关系表中查出s[j]和a的优先关系
if(a=='+'||a=='*'||a=='^'||a=='i'||a=='('||a==')'||a=='#')
n=panduanyou(a);
else//如果句子含有不是终结符集合里的其它字符,不合法
{
printf("error!
不合法的句子");
break;
}
p6=youxian[z][n];
if(p6=='>')
{
loop:
Q=fenxizhan[j];
if(fenxizhan[j-1]=='+'||fenxizhan[j-1]=='*'||fenxizhan[j-1]=='^'||fenxizhan[j-1]=='i'||fenxizhan[j-1]=='('||fenxizhan[j-1]==')'||fenxizhan[j-1]=='#')
j=j-1;
else
j=j-2;
z1=panduanyou(fenxizhan[j]);
n1=panduanyou(Q);
p1=youxian[z1][n1];
if(p1=='<') //fenxizhan[j+1]…fenxizhan[k]归约为N
{
k=j+1;
shengyuchuan();
flag++;
printf("(%d) %s %c %c %s 归约\n",flag,fenxizhan,p6,a,lex);
i--;
if(fenxizhan[k]=='i')fenxizhan[k]='P';
elseif(fenxizhan[k+1]=='*')fenxizhan[k]='T';
elseif(fenxizhan[k+1]=='+')fenxizhan[k]='E';
inthou,hou1;
hou=strlen(fenxizhan);
for(hou1=k+1;hou1 fenxizhan[hou1]='\0';//多个字符归约,把栈顶后面的舍弃
zengjia();//归约剩余串没变化
}
else
goto loop;
}
else
{
if(p6=='<') //移进有一个问题就是如果上一步是不归约,剩余的字符串减少一个
{
shengyuchuan();
lexbuf[f]='\0';
flag=flag+1;
printf("(%d) %s %c %c %s 移进\n",flag,fenxizhan,p6,a,lex);
k=k+1;
fenxizhan[k]=a;
}
else
{
if(p6=='=')
{
z4=panduanyou(fenxizhan[j]);
n4=panduanyou('#');
p4=youxian[z4][n4];
if(p4=='=')
{
shengyuchuan();
flag++;
printf("(%d) %s %c %c %s 接受
\n",flag,fenxizhan,p6,a,lex);
printf("合法的句子");
break;
}
else
{
k=k+1;
fenxizhan[k]=a;
}
}
else
{
printf("出错");
break;
}
}
}
}
}
intpanduanyou(charx)
{intm;
if(x=='+')
m=0;
if(x=='*')
m=1;
if(x=='^')
m=2;
if(x=='i')
m=3;
if(x=='(')
m=4;
if(x==')')
m=5;
if(x=='#')
m=6;
returnm;
}
voidshengyuchuan()
{
inti4,i5;
i4=strlen(lex);
for(i5=0;i5 lex[i5]=lex[i5+1];
lex[i4-1]='\0';
}
voidzengjia()
{
inth1,h2;
h1=strlen(lex);
for(h2=0;h2
lex[h1-h2]=lex[h1-h2-1];
lex[0]='$';//存入一字符个特殊
}
六、运行结果及分析
1、对输入串进行举例,并得出如下运行结果:
<1>输入串为i+i*i#,运行结果为
图2
<2>输入串为i+i#,运行结果为
图3
〈3〉输入串为i*(i)#,运行结果为
图4
2、结合理论知识进行分析,〈1〉和〈2〉为合法的输入符号串(即是文法的句子),本设计中的程序也能对其进行正确的分析,并在图2和图3中显示结果为“合法的句子”;但是〈3〉不是合法的输入符号串,此程序就不能进行正确的分析,且在运行后显示“出错”,这说明理论与本设计的程序所要实现的结果相符。
从上面的结果,我们可以看出算符优先分析法的优点:
大大加快了分析过程,但这也是它的缺点:
存在某种错误危险性,可能导致把本来不满足文法的输入串误认为是文法的句子。
七、设计总结
1、通过编译原理课程设计,掌握了什么是编译程序,编译程序工作的基本过程及其各阶段的基本任务,熟悉了编译程序总流程框图,了解了编译程序的生成过程、构造工具及其相关的技术对课本上的知识有了更深的理解,课本上的知识只是表面的,通过把该算法的内容,算法的执行顺序在计算机上实现,把深奥的书本知识变的更为简单与具体化。
2、通过该课程设计,全面系统的理解了编译原理程序构造的一般原理和基本实现方法。
把学过的计算机编译原理的知识强化,能够把课堂上学的知识通过自己设计的程序表示出来,加深了对理论知识的理解,通过实际动手做实验,从实践上认识了操作系统是如何处理命令的,对计算机编译原理的认识更加深刻。
课程设计中程序比较复杂,在调试时应该仔细有耐心。
3、本次课程设计程序部分是用C++语言编写的,把各个学科之间的知识融合起来,把各门课程的知识联系起来,理解了该知识点以及学科之间的渗透。
使我加深了对《编译原理》,《面向对象程序设计》等课程的认识。
八、参考文献
《编译技术》王力红主编---重庆大学出版社,2001,9
《C++程序设计》谭浩强