编译原理之OPG实验报告.docx
《编译原理之OPG实验报告.docx》由会员分享,可在线阅读,更多相关《编译原理之OPG实验报告.docx(22页珍藏版)》请在冰豆网上搜索。
![编译原理之OPG实验报告.docx](https://file1.bdocx.com/fileroot1/2022-11/30/7595625c-f369-43d7-9845-13ee8e7159d9/7595625c-f369-43d7-9845-13ee8e7159d91.gif)
编译原理之OPG实验报告
编译原理之算符优先文法分析
——**学院1105班
安
雨
雅
班级:
11**
学号:
11****
实验语法分析实验报告
1、实验题目
算符优先文法分析程序
2、实验内容及要求
(1)根据给定文法,先求出FirstVt和LastVt集合,构造算符优先关系表(要求算符优先关系表输出到屏幕和文件);
(2)根据算法和优先关系表分析给定表达式是否是该文法识别的正确的算术表达式(要求输出归约过程)
(3)给定表达式文法为:
(OPG文件中还有其他文法可作为测试)
B~BoT|T
T~TaF|F
F~nF|(B)|t|f
(4)分析的句子为:
ntofat#
3、设计思想之重点:
v构造算符优先表:
求FirstVT集和LastVT集
判断是否是算符文法
判断是否是算符优先文法
v算符优先分析:
、求最左素短语
、根据算符优先分析表分析
(“<”或”=”时移进;“>”时归约)
4、程序源代码(C语言)
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#defineSTR_MAX80//串的最大长度
#defineMAX_NUM100//符号的最大个数
#defineMAX32767//文件中符号的最大个数
#defineN20//栈的长度
classstack{//符号栈
private:
chars[N];
inttop;
public:
stack();
voidpush(char);
voidpop();
intTOP();//返回top的值
char*S();//返回s的值
};
stack:
:
stack()
{top=-1;}
voidstack:
:
push(charch)//进栈操作
{s[++top]=ch;
s[top+1]='\0';}
voidstack:
:
pop()//出栈操作
{top--;}
intstack:
:
TOP()//返回top的值
{returntop;}
char*stack:
:
S()//返回s的值
{returns;}
charM[MAX_NUM][MAX_NUM];
structPRO
{//产生式类型
charleft;
charright[STR_MAX];
};
structVNstru
{
charvn;
charfirstVT[MAX_NUM];
charlastVT[MAX_NUM];
};
charSOUR[STR_MAX];//源文件名
charOBJ[STR_MAX];//目标文件名
charERR[STR_MAX];//错误信息文件名
FILE*INF;//源程序文件指针
FILE*OUTF;//分析结果文件指针
FILE*ERRF;//错误信息文件指针
charOG[MAX];//存放上下文无关文法
intOGlen;//上下文无关文法长度
VNstruVN[MAX_NUM];//非终结符数组
intVN_CNT;//非终结符个数
charVT[MAX_NUM];//终结符数组
intVT_CNT;//终结符个数
charS0;//开始符号
PROP[MAX_NUM];//产生式数组
intP_CNT;//产生式个数
boolisIN(charch,VNstruarr[]);//判别符号ch是否在arr数组中
intisVN(charch);//判别符号ch是否在VN数组中,存在则返回下标,否则返回-1
intisVT(charch);//判别符号ch是否在VT数组中,存在则返回下标,否则返回-1
voidgetOG();//从源文件取得OG文法串
voidgetVN_VT_S_P();//从OG文法提取VN,VT,S,P
voidFirstVT(charch,charfirstVT[]);//求FirstVT[]集firstVT
voidLastVT(charch,charlastVT[]);//求LastVT[]集lastVT
boolO_G();//判别是否是OG文法
boolO_P_G();//判别是否是OPG文法
voidleftphase(charstr[],charsubstr[],chara);//求最左素短语substr
voidleft_str(charw[],charsubw[],intip);//求剩余输入串subw
boolisIN(charch,VNstruarr[])//判别符号ch是否在arr数组中
{
for(inti=0;iif(ch==arr[i].vn)
return1;
return0;
}
intisVN(charch)//判别符号ch是否在VN数组中,存在则返回下标,否则返回-1
{
for(inti=0;i{
if(ch==VN[i].vn)
returni;
}
return-1;
}
intisVT(charch)//判别符号ch是否在VT数组中,存在则返回下标,否则返回-1
{
for(inti=0;i{
if(ch==VT[i])
returni;
}
return-1;
}
voidgetOG()//从源文件取得OG文法串
{
OGlen=0;
charch;
while(!
feof(INF))
{
ch=fgetc(INF);
if(ch!
='')
OG[OGlen++]=ch;
}
OG[OGlen]='\0';
printf("TheGrammaris:
\n");//将文法输出到屏幕
puts(OG);
fprintf(OUTF,"TheGrammaris:
\n");
fputs(OG,OUTF);//将文法输出到文件
}
voidgetVN_VT_S_P()//从OG文法提取VN,VT,S,P
{
VN_CNT=0;
VT_CNT=0;
P_CNT=0;
intnewPF=0;//是否进入新产生式的标志
intrightLen=0;
charprech,ch,nextch;
for(inti=0;i{
if(i!
=0)prech=OG[i-1];//取文法文件中的前一个符号
ch=OG[i];//取文法文件中的当前符号
nextch=OG[i+1];//取文法文件中的下一个符号
if(nextch=='~')//下一个符号是~,代表箭头
{
if(isVN(ch)==-1){//当前符号不是已经识别到的VN
VN[VN_CNT].vn=ch;//加入VN
VN_CNT++;
}
P[P_CNT].left=ch;//记入新产生式的左部
if(P_CNT==0)
S0=ch;//第一条产生式的左部是开始符号
i++;//跳过~
}
if(prech=='~'||prech=='|')
{
newPF=1;//进入新的产生式
rightLen=0;
}
if(newPF==1)
{
P[P_CNT].right[rightLen++]=ch;
}
if(nextch=='\n'||nextch=='|')
{
newPF=0;//一条产生式结束
P_CNT++;//产生式个数加1
P[P_CNT].left=P[P_CNT-1].left;
i++;//跳过回车和|
}
}
for(intj=0;j{
ch=OG[j];
if(ch!
='~'&&ch!
='|'&&ch!
='\n'&&isVN(ch)==-1&&isVT(ch)==-1&&ch!
='')
VT[VT_CNT++]=ch;
}
VT[VT_CNT++]='#';
VT[VT_CNT]='\0';
//输出VN
printf("\nVN:
\t");
fprintf(OUTF,"\nVN:
\t");
for(intx=0;x{
printf("%c",VN[x].vn);
fprintf(OUTF,"%c",VN[x].vn);
}
//输出VT
printf("\nVT:
\t%s\n",VT);
fprintf(OUTF,"\nVT:
\t%s\n",VT);
//输出S
printf("S0:
\t%c\n\n",S0);
fprintf(OUTF,"S0:
%c\n\n",S0);
//输出P
for(intk=0;k{
printf("P[%d]:
\t%c-->%s\n",k,P[k].left,P[k].right);
fprintf(OUTF,"P[%d]:
\t%c-->%s\n",k,P[k].left,P[k].right);
}
printf("\n");
fprintf(OUTF,"\n");
}
//FIRSTVT(B)={b|B=>b...或B=>Cb...}
intf=0;
voidFirstVT(charch,charfirstVT[])//求非终结符的FirstVT集,存至firstVT中
{
if(isIN(ch,VN))
for(inti=0;i{
if(ch==P[i].left)
{
intj=0;
chara=P[i].right[j];
//B->b...
if(isVT(a)!
=-1)
{
firstVT[f++]=a;
firstVT[f]='\0';
}
//B->Cb...
if(isVN(a)!
=-1&&isVT(P[i].right[j+1])!
=-1)
{
firstVT[f++]=P[i].right[j+1];
firstVT[f]='\0';
}
//B->C,C->b...||Db...
if(isVN(a)!
=-1&&strlen(P[i].right)==1)
FirstVT(a,firstVT);
}
}
f=0;//f清零,便于重复调用此函数
}
//LASTVT(B)={a|B=>...a或B=>...aC}
intl=0;
voidLastVT(charch,charlastVT[])//求非终结符的LastVT集,存放至lastVT中
{
if(isIN(ch,VN))
for(inti=0;i{
if(ch==P[i].left)
{
intj=strlen(P[i].right)-1;//'j'记录右部的最后一个字符位置
chara=P[i].right[j];
//B->...a;
if(isVT(a)!
=-1)
{
lastVT[l++]=a;
lastVT[l]='\0';
}
//B->...aC;
if(isVN(a)!
=-1&&isVT(P[i].right[j-1])!
=-1)
{
lastVT[l++]=P[i].right[j-1];
lastVT[l]='\0';
}
//B->C,C->...a||...aD;
if(isVN(a)!
=-1&&j==0)
LastVT(a,lastVT);
}
}
l=0;//l清零,便于重复调用此函数
}
boolO_G()//判别是否是OG文法[没有两个连续的非终结符,即形如A->...BC...的产生式]
{
//求所有非终结符的firstVT集
for(inti=0;i{
charfvt[STR_MAX];
FirstVT(VN[i].vn,fvt);
strcpy(VN[i].firstVT,fvt);
printf("FirstVT(%c)={",VN[i]);
fprintf(OUTF,"FirstVT(%c)={",VN[i]);
for(intj=0;j<(int)strlen(fvt);j++)
{
printf("%c",fvt[j]);
fprintf(OUTF,"%c",fvt[j]);
}
printf("}\n");
fprintf(OUTF,"}\n");
}
printf("\n");
fprintf(OUTF,"\n");
//求所有非终结符的lastVT集
for(i=0;i{
charlvt[STR_MAX];
LastVT(VN[i].vn,lvt);
strcpy(VN[i].lastVT,lvt);
printf("LastVT(%c)={",VN[i]);
fprintf(OUTF,"LastVT(%c)={",VN[i]);
for(intj=0;j<(int)strlen(lvt);j++)
{
printf("%c",lvt[j]);
fprintf(OUTF,"%c",lvt[j]);
}
printf("}\n");
fprintf(OUTF,"}\n");
}
//判别是否是OG文法
for(i=0;i{
intj=0;
while(P[i].right[j+1]!
='\0')
{
charch=P[i].right[j];
charnextch=P[i].right[j+1];
if(isVN(ch)!
=-1&&isVN(nextch)!
=-1)
return0;
else
j++;
}
}
return1;
}
boolO_P_G()//判别是否是OPG文法[不含空产生式或任意两个终结符a,b之间至多有一种(<,>,=)关系]
{
for(intm=0;mfor(intn=0;nM[m][n]='';
for(inti=0;i{
intj=0;
charprech='',ch='',nextch='';//当进入新的产生式时,要清空三字符的值;
while(P[i].right[j]!
='\0')
{
if(j!
=0)
prech=ch;
ch=P[i].right[j];
nextch=P[i].right[j+1];
if(isVT(ch)!
=-1&&isVT(nextch)!
=-1)//A->..ab..(a=b)
{
if(M[isVT(ch)][isVT(nextch)]=='')//当M[][]为空时赋号
{
M[isVT(ch)][isVT(nextch)]='=';
j++;
continue;
}
else//当有a,b有两种关系时返回
{
printf("\n%c,%c有两种关系!
",ch,nextch);
fprintf(ERRF,"\n%c,%c有两种关系!
",ch,nextch);
return0;
}
}
if(isVT(ch)!
=-1&&isVN(nextch)!
=-1)//A->..aB...(a{
FirstVT(nextch,VN[isVN(nextch)].firstVT);
for(intm=0;VN[isVN(nextch)].firstVT[m]!
='\0';m++)
{
if(M[isVT(ch)][isVT(VN[isVN(nextch)].firstVT[m])]=='')
M[isVT(ch)][isVT(VN[isVN(nextch)].firstVT[m])]='<';
else//当有a,b有两种关系时返回
{
printf("\n%c,%c有两种关系!
",ch,VN[isVN(nextch)].firstVT[m]);
fprintf(ERRF,"\n%c,%c有两种关系!
",ch,VN[isVN(nextch)].firstVT[m]);
return0;
}
}
j++;
continue;
}
if(isVT(prech)!
=-1&&isVN(ch)!
=-1&&isVT(nextch)!
=-1)//A->..aBb..(a=b)
{
if(M[isVT(prech)][isVT(nextch)]=='')
M[isVT(prech)][isVT(nextch)]='=';
else
{
printf("\n%c,%c有两种关系!
",prech,nextch);
fprintf(ERRF,"\n%c,%c有两种关系!
",prech,nextch);return0;
}
}
if(isVN(ch)!
=-1&&isVT(nextch)!
=-1)//A->..Bb..(LastVT[B]>b)
{
LastVT(ch,VN[isVN(ch)].lastVT);
for(intm=0;VN[isVN(ch)].lastVT[m]!
='\0';m++)
{
if(M[isVT(VN[isVN(ch)].lastVT[m])][isVT(nextch)]=='')
M[isVT(VN[isVN(ch)].lastVT[m])][isVT(nextch)]='>';
else//当有a,b有两种关系时返回
{
printf("\n%c,%c有两种关系!
",VN[isVN(ch)].lastVT[m],nextch);
fprintf(ERRF,"\n%c,%c有两种关系!
",VN[isVN(ch)].lastVT[m],nextch);
return0;
}
}
j++;
continue;
}
else
j++;
}//(while)
}//(for)
M[VT_CNT-1][VT_CNT-1]='=';//#=#
for(intx=0;x<(int)strlen(VN[isVN(S0)].firstVT);x++)//#M[VT_CNT-1][isVT(VN[isVN(S0)].firstVT[x])]='<';
for(x=0;x<(int)strlen(VN[isVN(S0)].lastVT);x++)//LastVT(S0)>#
M[isVT(VN[isVN(S0)].lastVT[x])][VT_CNT-1]='>';
return1;
}
voidleftphase(charstr[],charsubstr[],chara)//求最左素短语,用substr储存
{
intslen=strlen(str);
intbegin,end=slen-1;
for(inti=slen-1;i>0;i--)
{
if(M[isVT(str[i])][isVT(a)]=='>')
{
if(M[isVT(str[i-1])][isVT(str[i])]=='<')
begin=i;
else
{
begin=i-1;
continue;
}
}
if(isVN(str[i]))
continue;
}
intj=0;intb=begin;//必须将begin的值记录,因为while的循环条件与begin有关,否则会影响素短语的取值。
while(jsubstr[j++]=str[b++];
substr[j]='\0';
}
voidleft_str(charw[],charsubw[],intip)//求剩余输入串subw
{
intj=0,begin;
for(begin=ip+1;begin<(int)strlen(w);begin++)
{
subw[j]=w[begin];
j++;
}
subw[j]='\0';
}
#include"OG&OPG.cpp"
#include"stack.cpp"
voi