语法分析器.docx
《语法分析器.docx》由会员分享,可在线阅读,更多相关《语法分析器.docx(25页珍藏版)》请在冰豆网上搜索。
语法分析器
《编译原理》课程实验报告
课程实验题目:
语法分析器
学院:
计算机科学与技术
班级:
软件工程1101班
学号:
04113026
姓名:
刘宇
指导教师姓名:
陈燕
完成时间:
2014年5月14日
1、实验目的
设计一个语法分析器,并更好的理解语法分析实现原理,掌握语法分析的方法(预测分析法、算符优先法)。
2、实验要求
算符优先分析法基本要求:
1)任意输入一个文法G;
2)判断该文法是否为算符文法;
3)对文法中的每个非终结符自动生成并打印输出:
①FIRSTVT集;②LASTVT集;
4)判断该文法是否为算符优先文法,
5)如果是自动生成并打印输出其算符优先矩阵;
6)模拟分析过程:
如输入一个句子,如果该句子合法则输出与句子对应的语法树;能够输出分析过程中每一步符号栈的变化情况以及根据当前最左素短语进行归约的过程。
如果该句子非法则进行相应的报错处理。
3、实验内容
算符优先分析法
1)文法通过读取相应的文件获取;
2)用大写字母和小写字母分别表示非终结符和终结符;
3)产生式使用->;
4)文法中的空字符串统一使用@表示;
5)打印每一个非终结符的FIRSTVT集和LASTVT集和算符优先关系表;
6)判定给定的文法是否是算符优先文法;
7)对任意句子使用当前文法归约,打印分析过程。
4、采用的数据结构
两个结构体:
//分析各非终结符的FIRSTVT集和LASTVT集时的栈元素
typedefstruct
{
charnonterm;//非终结符
charterm;//终结符
}StackElement;
//存放(A,a)的栈的初始化
typedefstruct
{
StackElement*top;//栈顶
StackElement*bottom;//栈底
intstacksize;//个数
}stack;
5、算法描述
算符优先分析法的具体过程如下:
1)按照实现定义的文件路径,使用ReadFile()函数中,将需要分析的文法通过输入流文件打开函数open()复制到sen[row][col]中。
2)利用FirstVt()构造产生式sen[row][col]的非终结符的FirstVt表。
先找出形如A->…a…(a为第一个终结符)的产生式,把(A,a)压入Operator栈中。
从Operator栈顶抛出项(A,a),填入first表相应位置。
在找出形如B->A…的产生式,把(B,a)压入Operator栈中。
循环直到Operator栈为空,此时FirstVt表构造完毕。
3)将产生式右部翻转,调用FirstVt函数求出LastVt表。
4)调用OpPriotable()构造算符优先关系表opTable。
先把产生式中所有终结符填入opTable表第一行和第一列,然后利用产生式和FirstVt表LastVt表分别找出满足=关系、<关系、>关系的算符填表。
若相应位已有关系,说明两个终结符之间至少有两种优先关系,该文法不是算符优先文法。
5)调用InputAnalyse()对输入句子进行分析。
初始化分析栈S,依次判断当前输入符a和分析栈中离栈顶最近的终结符S[j]的关系,若S[j]a,将S[j-1]到栈顶S[k]规约,若S[j]=a,如果S[j]=#,则接受,如果S[j]!
=#,则移进。
直到接受或者出错,算符优先分析结束。
6、运行结果
1.非算符优先文法的文法分析结果:
2.是算符优先文法的文法分析结果:
成功归约句子:
归约句子失败:
7、调试情况
如下所示为测试的文法:
其中文法不是算符优先文法,文法是算符优先文法。
8、设计技巧及体会
将算符优先法的手工分析过程用程序的方式写出来,实现了算符优先法的判断过程,很容易理解。
通过本次实验,我对算符优先法的分析过程更加熟练了,同时让我对本章内容有了更深入的理解。
9、源程序清单(电子版)
#include
#include
usingnamespacestd;
#definerow20
#definecol20
#defineSIZE20
//两个重要结构体的定义
//FIRSTVT表或LASTVT表中一个表项(A,a)结构体的初始化
typedefstruct
{
charnonterm;//非终结符
charterm;//终结符
}StackElement;
//存放(A,a)的栈的初始化
typedefstruct
{
StackElement*top;//栈顶
StackElement*bottom;//栈底
intstacksize;//个数
}stack;
//读文件函数
intReadFile(charsen[][col])
{
ifstreamfin;
inti=0;
fin.open("e:
//in2.txt",ios:
:
in);
cout<<"文法的产生式为:
"<fin>>sen[0];
for(i=1;!
fin.eof();i++)
{
fin>>sen[i];
cout<}
returni;
}
//初始化(A,a)栈
voidInitStack(stack&S)
{
S.bottom=newStackElement[SIZE];
S.top=S.bottom;
S.stacksize=SIZE;
}
//判断(A,a)栈是否为空
boolifEmpty(stackS)
{
if(S.top==S.bottom)
returntrue;//如果栈为空,则返回true
returnfalse;//否则不为空,返回false
}
//插入栈顶(A,a)元素
voidInsert(stack&S,StackElemente)
{
if(S.top-S.bottom>=S.stacksize)
cout<<"栈已满,无法插入!
"<else
{
S.top->nonterm=e.nonterm;
S.top->term=e.term;
S.top++;
}
}
//弹出栈顶(A,a)元素
StackElementPop(stack&S)
{
StackElemente;
e.nonterm='\0';
e.term='\0';
if(S.top==S.bottom)
cout<<"栈为空,无法进行删除操作!
"<else
{
S.top--;
e.nonterm=S.top->nonterm;
e.term=S.top->term;
}
returne;
}
//终结符与非终结符的判断函数(布尔类型)
boolTerminalJud(charc)
{
if(c>='A'&&c<='Z')
returnfalse;//非终结符返回false
returntrue;//终结符返回true
}
//判断非终结符在first表中是否已存在
boolItemJud(charfirst[][col],intfirst_len,charC)
{
for(inti=0;iif(first[i][0]==C)
returntrue;//如果first表中已存在此非终结符c,则返回true
returnfalse;
}
//FIRSTVT表和LASTVT表中表项的初始化
voidItemInit(charsen[][col],charfirst[][col],charlast[][col],intsen_len,int&first_len)
{
inti;
first_len=1;//是当前first和last表的长度
//初始化表
first[0][0]=sen[0][0];
last[0][0]=sen[0][0];
for(i=1;i{
if(TerminalJud(sen[i][0])==false&&ItemJud(first,first_len,sen[i][0])==false)
{
first[first_len][0]=sen[i][0];
last[first_len][0]=sen[i][0];
first_len++;
}
}
}
//构造FIRSTVT集
voidFirstVt(charsen[][col],charfirst[][col],intsen_len,intfirst_len)//sen_len是产生式的个数
{
StackElementDFS,record[SIZE];
stackOperator;//创建存放(A,a)的栈
inti,j,r=0;
InitStack(Operator);
//第一次扫描,将能直接得出的first(A,a)放进栈中
for(i=0;ifor(j=3;sen[i][j]!
='\0';j++)//候选式开始处
if(TerminalJud(sen[i][j])==true)//遇到的第一个终结符压入
{
intexist=0;
DFS.nonterm=sen[i][0];
DFS.term=sen[i][j];
for(inti1=0;iif(record[i1].nonterm==sen[i][0]&&record[i1].term==sen[i][j])
{
exist=1;
break;
}
//如果不在则压入栈中
record[r].nonterm=sen[i][0];
record[r].term=sen[i][j];
if(exist==0)
{
Insert(Operator,DFS);
record[r].nonterm=sen[i][0];
record[r].term=sen[i][j];
r++;
}
break;
}
//第二次扫描,考虑候选式第一个符号为非终结符的情况
intlocation[col];//记录first表中放入终结符的位置
for(i=0;ilocation[i]=1;
while(!
ifEmpty(Operator))
{
intexist=0;//标志位,记录即将入栈的元素是否已经存在
StackElementIDElement,DElement;
DElement=Pop(Operator);//弹出栈顶元素
for(i=0;iif(first[i][0]==DElement.nonterm)
{
intn=location[i];
first[i][n]=DElement.term;//将终结符填入相应的first表中
location[i]++;
break;
}
for(j=0;j{
if(sen[j][3]==DElement.nonterm)//找出能推出当前非终结符的产生式的左部
{
IDElement.nonterm=sen[j][0];
IDElement.term=DElement.term;
//判断将要放进栈里的元素曾经是否出现过,若没有,才压入栈
for(intr0=0;r0if(record[r0].nonterm==IDElement.nonterm&&record[r0].term==IDElement.term)
{//已存在在栈中
exist=1;
break;
}
if(exist==0)
{//不存在则压入栈中
Insert(Operator,IDElement);
record[r].nonterm=IDElement.nonterm;
record[r].term=IDElement.term;
r++;
}
}
}
}
}
//构造LASTVT集
voidLastVt(charsen[][col],charlast[][col],intsen_len,intfirst_len)//first_len表示last表的行数
{
inti,j,i1,j1;
charc,record[row][col]={'\0'};
for(i=0;i{
for(j=0;sen[i][j]!
='\0';j++)
record[i][j]=sen[i][j];
j=j-1;
for(i1=3,j1=j;i1{
c=record[i][i1];
record[i][i1]=record[i][j1];
record[i][j1]=c;
}
}
FirstVt(record,last,sen_len,first_len);
}
//判断非终结符在term表中是否已存在
boolTermTableJud(charterm[col],intterm_len,charC)
{
for(inti=0;iif(term[i]==C)
returntrue;//如果first表中已存在此非终结符,则返回1
returnfalse;
}
//构造算符优先关系表
boolOpPriotable(charsen[][col],charfirst[][col],charlast[][col],charopTable[][col],intsen_len,intfirst_len,int&opTable_len)
{
inti,j,term_len=0;
inti2,i3,opr,opc;
charc1,c2,c3;
charterm[SIZE]={'\0'};
for(i=0;ifor(j=3;sen[i][j]!
='\0';j++)
if(TerminalJud(sen[i][j])==true)
if(TermTableJud(term,term_len,sen[i][j])==false)//term_len记录term表的长度
{
term[term_len]=sen[i][j];
term_len++;
}//得到终结符表
//给优先关系表赋初值,都等于空
for(i=0;ifor(j=0;jopTable[i][j]='';
//设置优先关系表的表头,即将所有终结符存储
for(i=1;i{
opTable[i][0]=term[i-1];
opTable[0][i]=term[i-1];
}
//找等于关系
for(i=0;i{//形如#E#的情况
for(j=5;sen[i][j]!
='\0';j++)
if(TerminalJud(sen[i][j-2])==true&&TerminalJud(sen[i][j-1])==false&&TerminalJud(sen[i][j])==true)
{
c1=sen[i][j-2];
c2=sen[i][j];
//在opTable表中找到该存入的行标opr
for(opr=1;oprif(opTable[opr][0]==c1)
break;
//在opTable表中找到该存入的列标opc
for(opc=1;opcif(opTable[0][opc]==c2)
break;
//若这两者优先级关系之前已定义了,则表示该文法非算符优先
if(opTable[opr][opc]!
='')
{
cout<<"不是算符优先文法!
"<returnfalse;
}
else
opTable[opr][opc]='=';
}
//形如()的情况
for(j=4;sen[i][j]!
='\0';j++)
if(TerminalJud(sen[i][j-1])==true&&TerminalJud(sen[i][j])==true)
{
c1=sen[i][j-1];
c2=sen[i][j];
//在opTable表中找到该存入的行标opr
for(opr=1;oprif(opTable[opr][0]==c1)
break;
//在opTable表中找到该存入的列标j2
for(opc=1;opcif(opTable[0][opc]==c2)
break;
if(opTable[opr][opc]!
='')
{
cout<<"不是算符优先文法!
"<returnfalse;
}
else
opTable[opr][opc]='=';
}
}
//找小于关系
for(i=0;i{//形如aA情况
for(j=3;sen[i][j]!
='\0';j++)
{
if(TerminalJud(sen[i][j])==true&&TerminalJud(sen[i][j+1])==false)
{
c1=sen[i][j];//c1记录终结符
c2=sen[i][j+1];//c2记录非终结符
//在opTable表中找到该存入的行标opr
for(opr=1;oprif(opTable[opr][0]==c1)
break;
//找出非终结符在first表中的列标opc
for(opc=0;opcif(first[opc][0]==c2)
break;
for(i2=1;first[opc][i2]!
='\0';i2++)
{
c3=first[opc][i2];
for(i3=1;i3if(opTable[0][i3]==c3)
{
if(opTable[opr][i3]!
='')
{
cout<<"不是算符优先文法!
"<returnfalse;
}
else
opTable[opr][i3]='<';
break;
}
}
}
}
}
//找大于关系
for(i=0;i{//形如Aa情况
for(j=3;sen[i][j]!
='\0';j++)
{
if(TerminalJud(sen[i][j])==false&&sen[i][j+1]!
='\0'&&TerminalJud(sen[i][j+1])==true)
{
c1=sen[i][j];//c1记录非终结符
c2=sen[i][j+1];//c2记录终结符
//在opTable表中找到该存入的列标j1
for(opr=1;oprif(opTable[0][opr]==c2)