您的位置:首页 > 其它

已有预测分析表时的语法分析

2015-11-19 19:36 323 查看
这篇是编译原理的课堂作业实验题

题目要求

为给定文法写预测分析程序,预测分析表已知(虽然求取预测分析表更重要,但是老师要求是给定预测分析表的情况下写预测分析程序),文法如下:

E–>TE’

E’–> +TE’|ε

T–>FT’

T’–> *FT’|ε

F–>(E) | i

预测分析表(太难打了):

表格i+*()#
EE–>TE’E–>TE’
E’E’–> +TE’E’–>εE’–>ε
TT–>FT’T–>FT’
T’T’–>εT’–> *FT’T’–>εT’–>ε
FF–>iF–>(E)
设计分析

预测分析程序的重点应该是预测分析表的创建,但是我猜老师的意思应该是考察我们的编程能力,时间有限,我们只做老师要求的在给定预测分析表的情况下写预测分析程序,关于预测分析表的生成等内容可以在任意编译原理课本上找到,这里不再赘述。

虽然给定预测分析表,但是编程时还是有很多东西需要考虑,首先是预测分析表用什么存储,我是用了一个Node结构体

struct Node{
char vn;        //非终结符
char vt[VT];    //所有终结符
int p[VT];      //产生式规则
Node(){
memset(p,-1,sizeof(p));
}
};


“vn”用于存储非终结符,“vt”数组存储所有的终结符号,在 p数组中存储预测分析表中,确定非终结符和确定终结符所需要的产生式规则,这里所找到的是产生式规则的索引,我们将产生式存放在一个字符指针数组中

const char* production[]


我们得到的索引就是对应的数组下标(这样存储在数据更多的时候可以节省很多空间)。

数据结构定义好之后,程序实现就很简单了,源代码如下:

代码实现

#include<iostream>
#include<cstring>
#include<ctype.h>
#include<cstdio>
#define VT 6 //终结符号个数
#define VN 5 //非终结符号个数
#define MAXLINE 100
using namespace std;
struct Node{ char vn; //非终结符 char vt[VT]; //所有终结符 int p[VT]; //产生式规则 Node(){ memset(p,-1,sizeof(p)); } };
Node MTable[VN];
const char* production[]={"Te","Ft","i","+Te","$","*Ft","(E)"}; //所有的产生式右部
void getTable(Node *); //获得预测分析表
void out(int cnt,const char* st,const char *tex,int j,int k,char c); //输出当前状态
char st[MAXLINE]; //栈
int sp=0; //栈顶指针
int main()
{
int c,l;
getTable(MTable);
char tex[MAXLINE];
memset(st,' ',sizeof(st));
gets(tex);
/*
while((c=getchar())!='#'&& c!=-1)
*(p++)=c;
*(p++)=c;
*p='\0';
*/

l=strlen(tex);
tex[l]='#'; tex[l+1]='\0';
st[sp++]='#';
st[sp++]='E';
int cnt=1,i,j,k=0;
cout<<"步骤"<<" "<<"分析栈"<<" "<<"剩余输入串"<<" "<<"指导所用产生式或函数"<<endl;
char cur,pd[MAXLINE],*pp; //pd:production缩写,cur当前栈顶元素
for(i=0;sp>0;cnt++){
cur=st[--sp];
if(st[sp]=='#'){
st[sp+1]='\0';
out(cnt,st,tex+i,j,-1,'#');
continue;
}
if(cur==(c=tex[i])&&i<l){
i++;
st[sp+1]='\0';
out(cnt,st,tex+i-1,j,-1,c);
continue;
}
pp=pd; memset(pd,0,sizeof(pd));
for(j=0;j<VN;j++) //查找该非终结符对应哪个结点
if(MTable[j].vn==cur) break;
if(MTable[j].vn!=cur){
cout<<"error:不能识别输入的字符串"<<endl;
break;
}
k=0;
while(k<VT&&MTable[j].vt[k]!=c) k++; //当前非终结符遇到该终结符对应的产生式规则
if(k==VT) { cout<<"Error:输入有误"<<endl; break;}
k=MTable[j].p[k]; //重用
st[sp+1]='\0';
out(cnt,st,tex+i,j,k,'a');

memcpy(pp,production[k],sizeof(production[k]));
if(k!=4){ //产生式不为空串'$'
int len=strlen(pp);
while(--len>=0) st[sp++]=*(pp+len); //逆序入栈
}
}
return 0;
}
void getTable(Node*t) //获得预测分析表
{
t[0].vn='E',t[1].vn='e',t[2].vn='T',t[3].vn='t',t[4].vn='F'; //非终结符
for(int i=0;i<VT;i++){ //终结符
t[i].vt[0]='i'; t[i].vt[1]='+'; t[i].vt[2]='*';
t[i].vt[3]='('; t[i].vt[4]=')'; t[i].vt[5]='#';
}
//下面用来存储相应的产生式的索引
t[0].p[0]=0; t[0].p[3]=0;
t[1].p[1]=3; t[1].p[4]=4; t[1].p[5]=4;
t[2].p[0]=1; t[2].p[3]=1;
t[3].p[1]=4; t[3].p[2]=5; t[3].p[4]=4; t[3].p[5]=4;
t[4].p[0]=2; t[4].p[3]=6;
}
/*cnt是步骤计数,st是栈底指针,tex是剩余输入符号指针,j表示第j个Node,k表示运用的产生式
*的索引号,如果k=-1表示一个非终结符匹配成功或者完成接受*/
void out(int cnt,const char* st,const char *tex,int j,int k,char ac) ////输出当前状态
{
char s[MAXLINE],*p,cu[3],cur=MTable[j].vn,pd[MAXLINE],*q;
p=s; q=pd;
int i=0,c;
while((c=*(st+i))!='\0'){
if(islower(c)&&c!='i'){
*(p++)=toupper(c);
*(p++)='\'';
}else
*(p++)=c;
i++;
}
*p='\0'; i=0;
if(k!=-1){
while((c=*(production[k]+i))!='\0'){
if(islower(c)&&c!='i'){
*(q++)=toupper(c);
*(q++)='\'';
}else
*(q++)=c;
i++;
}
}else
*(q++)=ac;
*q='\0'; i=0;
if(islower(cur)&&cur!='i'){
cu[i++]=toupper(cur);
cu[i++]='\'';
}else
cu[i++]=cur;
cu[i]='\0';
if(k!=-1)
printf("%4d %-15s %15s %-2s-->%s\n",cnt,s,tex,cu,pd);
else if(ac!='#')
printf("%4d %-15s %15s %s匹配\n",cnt,s,tex,pd);
else
printf("%4d %-15s %15s 接受\n",cnt,s,tex,cu,pd);
}


这个程序可以接受所有的 + *的表达式(要求表达式的字母只能为i)如:

i+i*i、 (i+i)*(i+i)+i 等等

程序测试 输入 (i+i)*(i+i)+i

注意括号为英文符号





所有的函数都有我编写的时候留下的注释,应该可以看得明白,如有疑问,可以留言,力所能及 乐意解答
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: