实验二  预测分析算法的设计与实现

(8学时)

一、实验目的

通过预测分析算法的设计与实现,加深对自上而下语法分析方法的理解,尤其是对自上而下分析条件的理解。

二、实验要求  

输入文法及待分析的输入串,输出其预测分析过程及结果。

三、实验步骤

1. 参考数据结构

(1)/*定义产生式的语法集结构*/

typedef struct{

char formula[200];//产生式

}grammarElement;

grammarElement  gramOldSet[200];//原始文法的产生式集

(2)/*变量定义*/

char terSymbol[200];//终结符号

char non_ter[200];//非终结符号

char allSymbol[400];//所有符号

char firstSET[100][100];//各产生式右部的FIRST集

char followSET[100][100];//各产生式左部的FOLLOW集

int M[200][200];//分析表

2. 判断文法的左递归性,将左递归文法转换成非左递归文法。(该步骤可以省略,直接输入非左递归文法)。

3.根据文法求FIRST集和FOLLOW集。

(1)/*求 First 集的算法*/

begin

if  X为终结符(XÎ)

在所有产生式中查找X所在的产生式

if  产生式右部第一个字符为终结符或空(即X®a(aÎ)或X®e)

then 把a或e加进FIRST(X)

if 产生式右部第一个字符为非终结符 then

if产生式右部的第一个符号等于当前字符 then

跳到下一条产生式进行查找

if 当前非终结符还没有求其FIRST集 then

查找它的FIRST集并标识此符号已求其FIRST集

求得结果并入到X的FIRST集

if  当前产生式右部符号可推出空字且当前字符不是右部的最后一个字符

then  获取右部符号下一个字符在所有字符集中的位置

if  此字符的FIRST集还未查找 then

找其FIRST集,并标其查找状态为1

把求得的FIRST集并入到X的FIRST集

if  当前右部符号串可推出空且是右部符号串的最后一个字符(即产生式为X®,若对一切1£ i£ k,均有e ÎFIRST(),则将eÎ符号加进FIRST(X))  then 把空字加入到当前字符X的FIRST集

else

不能推出空字则结束循环

标识当前字符X已查找其FIRST集。

end

(2)/*求 FOLLOW 集的算法*/

begin

if  X为开始符号 then # ÞFOLLOW(X)

对全部的产生式找一个右部含有当前字符X的产生式

if X在产生式右部的最后(形如产生式A®aX) then

查找非终结符A是否已经求过其FOLLOW集.避免循环递归

if  非终结符A已经求过其FOLLOW集 then

把FOLLOW(A)中的元素加入FOLLOW(X)

继续查下一条产生式是否含有X

else

求A的FOLLOW集,并标记为A已求其FOLLOW集

else if X不在产生式右部的最后(A®aBb) then

if  右部X后面的符号串b能推出空字e then

查找b是否已求过其FOLLOW集.避免循环递归

if 已求过b的FOLLOW集 then

把FOLLOW(A)中的元素加入FOLLOW(B)

结束本次循环

else if b不能推出空字 then

求 FIRST(b)

把FIRST(b)中所有非空元素加入到FOLLOW(B)中

     标识当前要求的非终结符X的FOLLOW集已求过

end

4.构造预测分析表。

/*构造分析表*/

//在AÎ所在行,aÎ所在列, M[A,a]的填写方法如下:

if (A®dÎP and aÎFIRST(d) ) do

M[A,a]=‘A®d’

if (dÞ*e(eÎFIRST(d)) and aÎFOLLOW(A)) do

M[A,a]=‘A®d’;

else    do  M[A,a]=‘ERR’.

5.构造总控程序。

程序流程图如图1所示:

图1

6.对给定的输入串,给出分析过程及结果。

 

四、实验报告要求

1.写出编程思路、源代码(或流程图);

2.写出上机调试时发现的问题,以及解决的过程;

3.写出你所使用的测试数据及结果;

4.谈谈你的体会。

5.上机8小时,完成实验报告2小时。

五、源程序:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
char grammer[200][200];//存储产生式
char stack[200]={'\0'};//堆栈初值
int sp=0;//栈顶指针
int p1=0;//输入句型指针
int vtnum,vnnum,pronum;
/*变量定义*/
char terSymbol[200];//终结符号
char non_ter[200];//非终结符号
char firstSet[200][200];//各产生式右部的FIRST集
char followSet[200][200];//各产生式左部的FOLLOW集
int M[200][200];//分析表
int ter(char ch)
{
for(int i=0;i<vtnum;i++)
if(terSymbol[i]==ch)
break;
return i;
}
int non_t(char ch)
{
for(int i=0;i<vnnum;i++)
if(non_ter[i]==ch)
break;
return i;
}
int addfirstSet(char X,char c)//加入first集
{
int i,j,k,m;
i=ter(c);
if(i<vtnum)
{
j=non_t(X);
firstSet[j][i]=1;
}
else{
j=non_t(X);
m=non_t(c);
for(k=0;k<=vtnum;k++)//把空字符加入
{
if(firstSet[m][k]==1)
firstSet[j][k]=1;
}
}
return 1;
}
bool haveEmpty(char c)//判断first集中是否包含空字符
{
int i,j;
i=ter(c);
if(i<vtnum)
return false;
else{
j=non_t(c);
if(firstSet[j][vtnum]==1)//first集中含空
return true;
else
return false;
}
}
int addfollowSet(char X,char c,int kind)//加入follow集,kind=0表示将follow加入,表示将first加入
{
int i,j,k,m;
i=ter(c);
if(i<vtnum)//c是终结符
{
j=non_t(X);
followSet[j][i]=1;
}
else{//c是非终结符
if(kind==0){
j=non_t(X);
m=non_t(c);
for(k=0;k<=vtnum;k++)
{
if(followSet[m][k]==1)
followSet[j][k]=1;
}
}
else{
j=non_t(X);
m=non_t(c);
for(k=0;k<vtnum;k++)
{
if(firstSet[m][k]==1)
followSet[j][k]=1;
}
}
}
return 1;
}
int first(char X)//求非终结符的first集
{
int i,j,k,m,p,flag;
for(i=0;i<pronum;i++)
{
if(grammer[i][0]==X)//找X所对应的产生式
{
p=3;
if(grammer[i][p]=='$')//产生式右部为空
{
j=non_t(X);
firstSet[j][vtnum]=1;
}
else{//产生式右部非空
while(grammer[i][p]!='\0')
{
int q=ter(grammer[i][p]);
if(q<vtnum){
addfirstSet(X,grammer[i][p]);
break;
}
else if(q>=vtnum){
k=non_t(grammer[i][p]);
flag=0;
for(m=0;m<=vtnum;m++)
{
if(firstSet[k][m]==1)
{
flag=1;
break;
}
}
if(flag==0)// First集未被求过
first(grammer[i][p]);
addfirstSet(X,grammer[i][p]);
if(haveEmpty(grammer[i][p]))//首字符First集是否为空,是则继续,否则跳出while循环
p++;
else
break;
}
}
}
}
}
return 1;
}
int follow(char X)//求非终结符的follow集
{
int i,j,k,p,flag;
char ch;
followSet[0][vtnum]=1;//将#加入开始符的follow集
for(i=0;i<pronum;i++)
{
p=3;
while(grammer[i][p]!='\0'&&grammer[i][p]!=X)
p++;
if(grammer[i][p]==X)
{
ch=grammer[i][p++];
if(grammer[i][p]=='\0')//X是右部的最后一个字符
{
j=non_t(grammer[i][0]);
flag=0;
for(k=0;k<=vtnum;k++)
{
if(followSet[j][k]==1)
{
flag=1;
break;
}
}
if(flag==0&&grammer[i][0]!=X)//follow集未被求过或者是左部字符不为X
follow(grammer[i][0]);
addfollowSet(X,grammer[i][0],0);
}
else{//X不是右部最后一个字符
while(haveEmpty(grammer[i][p])&&grammer[i][p]!='\0')
{
addfollowSet(X,grammer[i][p],1);
/*if(grammer[i][p]=='\0')
{*/
j=non_t(grammer[i][0]);
flag=0;
for(k=0;k<=vtnum;k++)
{
if(followSet[j][k]==1)
{
flag=1;
break;
}
}
if(flag==0&&grammer[i][0]!=X)//未求follow集或者不为X
follow(grammer[i][0]);
addfollowSet(X,grammer[i][0],0);
p++;
}
if(!haveEmpty(grammer[i][p]))
addfollowSet(X,grammer[i][p],1);
}
}
}
return 1;
}
int initAnalysis()
{
int i,j;
for(i=0;i<vnnum;i++)
for(j=0;j<=vtnum;j++)
{
M[i][j]=-1;
}
return 1;
}
int analysis()//构造预测分析表
{
int i,j,k,m,n,x;
for(x=0;x<pronum;x++)
{
i=non_t(grammer[x][0]);
m=ter(grammer[x][3]);
if(grammer[x][3]!='$')
{
for(j=0;j<vtnum;j++)//对每个终结符a属于firstSet(grammer[x][0]),把文法grammer[x]加入到M[x][a]
{
if(firstSet[i][j]==1)
{
if(m<vtnum)
{
if(M[i][j]==-1&&grammer[x][3]==terSymbol[j])
M[i][j]=x;
}
else{
n=non_t(grammer[x][3]);
if(M[i][j]==-1&&firstSet[n][j]==1)
M[i][j]=x;
}
}
}
}
if(haveEmpty(grammer[x][0]))//若$属于firstSet(grammer[x][0]),对任何b属于followSet(grammer[x][0])把grammer[x]加入到M[X][b]
{
for(k=0;k<=vtnum;k++)
{
if(followSet[i][k]==1)
M[i][k]=x;
}
}
}
return 1;
}
int control()//总控程序
{
int i,j,k,m,n,x,y,flag=0;
char c1[20]={'\0'};
char c2;//c1存放待分析字符串的当前字符,c2存放已弹出的栈顶元素
stack[sp++]='#';
stack[sp++]=non_ter[0];
printf("\n请输入要分析的句型(以#结尾):");
i=0;
char c=getchar();
while(c!='#')
{
c1[i++]=c;
c=getchar();
}
c1[i]='#';
printf("\n分析过程:\n\n分析栈              输入串              所用规则                ");
while(c1[p1]!='\0')
{
printf("\n");
for(i=0;stack[i]!='\0';i++)
printf("%c",stack[i]);
for(k=0;k<20-i;k++)
printf(" ");//输出栈内情况
m=0;
for(i=p1;c1[i]!='\0';i++)
{
printf("%c",c1[i]);
m++;
}
for(i=0;i<20-m;i++)
printf(" ");//输出当前字符串
c2=stack[sp-1];
stack[sp-1]='\0';
sp--;//弹出栈顶元素,并把栈顶后一位赋值为'\0',sp指向栈顶后一位
i=ter(c2);
if(i<vtnum)//c2是终结符
{
if(c2==c1[p1])
{
p1++;
printf(" ");
}
else
break;
}
else
{
if(c2=='#')//栈顶元素为#
{
if(c1[p1]==c2)
{
flag=1;//运行成功,跳出
break;
}
else
break;
}
else
{
m=non_t(c2);//c2是非终结符
n=ter(c1[p1]);
//if(M[m][n]=='0') break;
if(M[m][n]!=-1)
{
//输出对应的文法
j=M[m][n];
printf("%s",grammer[j]);
k=3;
while(grammer[j][k]!='\0')
k++;
/*printf("%c->",grammer[m][0]);
for(k=1;grammer[j][k]!='\0';k++)
printf("%c",grammer[j][k]);*/
//for(x=0;x<20-k;x++)
//  printf(" ");
if(grammer[j][3]!='$')//逆序压入,忽略空字符$
{
for(y=k-1;y>=3;y--)
{
stack[sp++]=grammer[j][y];
stack[sp]='\0';
}
}
}
else break;
}
}
}
if(flag==1)
printf("\n\nSucceed,您输入的句型符合该文法!\n");
else
printf("\n\nError,您输入的句型和文法不符!\n");
return 1;
}
int printf_table()//输出预测分析表
{
int i,j,p;
printf("\n预测分析表为:\n");;
printf("          ");
for(i=0;i<vtnum;i++)
{
printf("%c         ",terSymbol[i]);
}
printf("#         \n");
for(i=0;i<vnnum;i++)
{
printf("%c         ",non_ter[i]);
for(j=0;j<=vtnum;j++)
{
if(M[i][j]!=-1)
{
int k=M[i][j];
int m=strlen(grammer[k]);
printf("%s",grammer[k]);
for(p=0;p<10-m;p++)
printf(" ");
}
else{
for(p=0;p<10;p++)
printf(" ");
}
}
printf("\n");
}
return 1;
}
int main()
{
int i,j;
for(i=0;i<200;i++)
for(j=0;j<200;j++)
grammer[i][j]='\0';
printf("请输入文法的非终结符号串:");
scanf("%s",non_ter);
getchar();
vnnum=strlen(non_ter);
printf("请输入文法的终结符号串:");
scanf("%s",terSymbol);
getchar();
vtnum=strlen(terSymbol);
printf("请输入产生式个数:");
scanf("%d",&pronum);
printf("请输入文法:\n");
for(i=0;i<pronum;i++)
{
scanf("%s",grammer[i]);
getchar();
}
for(i=0;i<vnnum;i++)
for(j=0;j<=vtnum;j++)
firstSet[i][j]=0;//初始化FIRST集
for(i=0;i<vnnum;i++)
first(non_ter[i]);//对每个non_ter求FIRST集
/*for(i=0;i<vnnum;i++)
{   for(j=0;j<vtnum;j++)
printf("%d      ",firstSet[i][j]);
printf("\n");
}*/
for(i=0;i<vnnum;i++)
for(j=0;j<=vtnum;j++)
followSet[i][j]=0;//初始化FOLLOW集
for(i=0;i<vnnum;i++)
follow(non_ter[i]);//对每个non_ter求FOLLOW集
/*for(i=0;i<vnnum;i++)
{   for(j=0;j<=vtnum;j++)
printf("%d      ",followSet[i][j]);
printf("\n");
}*/
initAnalysis();
analysis();
printf_table();
control();
printf("\n谢谢使用!\n");
system("pause");
}

六、运行结果如下:

  输入相关文法后显示的预测分析表($表示表示空字):

输入对应句子后输出分析过程:

语法分析器---预测分析程序相关推荐

  1. LL(1)预测分析程序

    分析程序源代码: LL1分析程序(包含c源码) 文法: E -> E+F | E-F | T T -> T*F | T/F | F F -> i | (E) 注:这实际上就是包含括号 ...

  2. 编译原理预测分析程序

    直接上代码: 1 #include<cstdio> 2 #include<iostream> 3 #include<map> 4 #include<vecto ...

  3. LL(1)预测分析程序C++实现

    已知文法G如下,通过已知的预测分析表,输入要分析的字符串,得到分析结构附后. 已知文法G: E->TE' E'->+TE' E'->e T->FT' T'->*FT' T ...

  4. 编译原理:LL(1)文法 语法分析器(预测分析表法)

    设计要求:对于任意输入的一个LL(1)文法,构造其预测分析表,并对指定输入串分析其是否为该文法的句子. 思路:首先实现集合FIRST(X)构造算法和集合FOLLOW(A)构造算法,再根据FIRST和F ...

  5. 编译原理预测分析法c语言,编译原理预测分析法C语言的实验报告.doc

    题目:编写识别由下列文法所定义的表达式的预测分析程序. EàE+T | E-T | T TàT*F | T/F |F Fà(E) | i 输入:每行含一个表达式的文本文件. 输出:分析成功或不成功信息 ...

  6. 语法分析:自上而下分析(递归下降分析法+预测分析法)

    语法分析:自上而下分析 目录 语法分析:自上而下分析 知识背景 递归下降分析法 内容一:根据文法生成子程序 内容二:调用文法开始符号所对应的子程序 预测分析法 内容一:构造预测分析表 内容二:预测分析 ...

  7. 【编译原理】LL(1)语法分析器

    1.项目要求 文法要求: (1)从文件读入,每条产生式占用一行 (2)文法为LL(1)文法 从文件中读入文法,从键盘上输入待分析的符号串,采用 LL(1)分析算法判断该符号串是否为该文法的句子. 2. ...

  8. 编译原理课设---表驱动LL(1)语法分析器的设计

    前言:表驱动LL(1)语法分析程序是本人在大三上学期的<编译原理>这门课程的课程设计选做题目,在这次的课程设计中,主要实现判断给定文法是否为LL(1)文法,若是,则给出其预测分析表及对给定 ...

  9. 预测分析法语法分析器的设计

    文章目录 一.实验目的 二.实验内容 三.实验要求 四.实验设计方案 五.测试方案及测试结果 结语 附录 一.实验目的 根据文法编制预测分析法语法分析程序,以便对输入的符号串进行语法分析.通过编写预测 ...

最新文章

  1. Linuxshell之高级Shell脚本编程-创建菜单
  2. mysql的for循环_MySQL中的For循环示例
  3. 串口数据字节位的理解
  4. 语言inc c,汇编语言练习
  5. django-数据的插入-利用pymysql
  6. cocos creator基础-(五)cc.Component使用
  7. AVS2/AVS3测试视频和VLC播放器
  8. ajax常用吗,常用ajax请求
  9. Ubuntu下定时重启程序
  10. 深度学习之MNIST数据集
  11. 《我的眼睛--图灵识别》第九章:训练:制作识别字库
  12. http://www.ha97.com/
  13. 2017年计算机二级有什么好处,2017年计算机二级考试备考的五大法宝
  14. Aid Learning --除了爱奇艺也可以是生产力!!!
  15. 如何离线使用Google文档
  16. js增加透明css样式,如何配置透明发光的骚气 vscode
  17. 宾果消消消鸿蒙版,宾果消消消官方版
  18. 交换机的初始化配置(思科模拟器)
  19. 音频焦点(AudioFocus)应用与源码解析
  20. 基于阿里云IOT Studio和STM32的电机远程监测设计

热门文章

  1. 【DFT】DFT入门介绍
  2. LINUX JDK 安装与环境变量设置
  3. Quick BI 数据大屏快速入门
  4. 股票中的KD指标金叉和死叉
  5. 数据库系统概念 实验1~实验9
  6. smalltalk五个特性
  7. 屏保问题(即背光灯的关闭)
  8. 深度好文:一篇Paper带您读懂HTAP | StoneDB学术分享会第①期
  9. OpenCV配置(利用Source编译,并配置扩展库opencv_contrib)
  10. C# Xamarin For Android移动开发项目实战篇