您的位置:首页 > 其它

编译原理实验——算符优先算法

2010-12-02 21:40 351 查看
/*本实验参照学校实验报告册的算法所作,行事仓促,有很多不足,望加指正*/

/*验证文法1:
E->E+T|T
T->T*F|F
F->(E)|a
语句示例:a+a$

验证文法2:
S->a|b|(T)
T->T,S|S
语句示例:(a,(a,a))$

因未加入对'|'的拆分,所以输入文法是需手动拆分产生式.
本程序所输文法,必须为算符优先文法
*/

/*结束符号是$;
vn[]中第一个字符是开始符号;
FIRST集、FOLLOW集和优先分析表T的字符顺序和vt[]及vn[]一致
*/

#include<iostream>
#include<stdio.h>
#include<fstream>
#include<malloc.h>
using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define N 200
#define Y 10
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10

int vtnum,vnnum,pronum;//依次是终结符、非终结符、产生式个数
int FIRST

;//FIRSTVT集
int LAST

;//LASTVT集
int T

;//优先关系表
char vt
;
char vn
; //终结符和非终结符集
char old

;//用于存储产生式

typedef struct{
char VN;
char VT;
}SqE;

typedef struct{
SqE *base;
SqE *top;
int stacksize;
}SqStack;//定义堆栈用于求FIRSTVT和LASTVT

void InitStack(SqStack &);
void Push(SqStack &,char,char);
int Pop(SqStack &,char &,char &);
bool Empty(SqStack &);
void first();
int test(char);
void insertf(char,char,SqStack &);
void last();
int tail(int);
void insertl(char,char,SqStack &);
void printf_ff();
void table();
void printf_t();
int control();

void main()
{
int i,j;
ifstream in("input1.txt",ios_base::in);
for(i=0;i<N;i++)
for(j=0;j<N;j++)
old[i][j]='/0';
in>>pronum>>vnnum>>vtnum;
in>>vn;
in>>vt;

for(i=0;i<pronum;i++)
in>>old[i];//从文件中读入pronum,vtnum,vnnum以及产生式

for(i=0;i<vnnum;i++)
for(j=0;j<vtnum;j++)
FIRST[i][j]=0;
for(i=0;i<vnnum;i++)
for(j=0;j<vtnum;j++)
LAST[i][j]=0;//初始化FIRSTVT和LASTVT,0意味着不存在
for(i=0;i<N;i++)
for(j=0;j<N;j++)
T[i][j]=3;//初始化T[][],3意味着不存在

first();
last();
printf_ff();
table();
printf_t();
control();

}

void InitStack(SqStack &S1)//堆栈操作,分别是初始化堆栈,压栈,弹出栈顶元素和判断是否为空
{
S1.base=(SqE *)malloc(STACK_INIT_SIZE * sizeof(SqE));
if(!S1.base)
exit(OVERFLOW);
S1.top=S1.base;
S1.stacksize=STACK_INIT_SIZE;

}

void Push(SqStack &S1,char e,char v)
{
if(S1.top-S1.base>=S1.stacksize)
{
S1.base=(SqE *)realloc(S1.base,(S1.stacksize+STACKINCREMENT)*sizeof(SqE));
if(!S1.base)
exit(OVERFLOW);
S1.top=S1.base+S1.stacksize;
S1.stacksize+=STACKINCREMENT;
}

(*S1.top).VN=e;
(*S1.top).VT=v;
S1.top++;

}

int Pop(SqStack &S1,char &e,char &v)
{
if(S1.top==S1.base)
return ERROR;
--S1.top;
e=(* S1.top).VN;
v=(* S1.top).VT;

return OK;
}

bool Empty(SqStack &S1)
{
if(S1.top==S1.base)
return true;
else
return false;
}

void first()//求所有非终结符的FIRSTVT集
{
int i;
char X,a;
SqStack S;
InitStack(S);
for(i=0;i<pronum;i++)//找到形如P->a...或者P->Qa...的产生式,并对(P,a)调用insertf()
{
if(test(old[i][1])<100)
insertf(old[i][0],old[i][1],S);

else
{
if(test(old[i][2])<100)
insertf(old[i][0],old[i][2],S);
}

}

while(!Empty(S))//假设弹出元素是(Q,a),找寻形如P->Q...的产生式,对(P,a)调用insertf()
{
Pop(S,X,a);
for(i=0;i<pronum;i++)
{
if(old[i][0]!=old[i][1])
{
if(old[i][1]==X)
insertf(old[i][0],a,S);
}
}
}
}

int test(char c)//判断符号的类型,0<=终结符返回值<100,100<=非终结符返回值<200,错误符号返回值=200
{
int i,j;
for(i=0;i<vtnum;i++)
{
if(vt[i]==c)
break;
}

if(i<vtnum)
return i;

else
{
for(j=0;j<vnnum;j++)
{
if(vn[j]==c)
break;
}

if(j<vtnum)
return (100+j);

else
return 200;
}
}

void insertf(char a,char b,SqStack &S)//插入FIRSTVT集,(a,b)是非终结符和终结符对
{
FIRST[test(a)-100][test(b)]=1;//赋值为1,表示存在
Push(S,a,b);//压栈
}

void last()//求所有非终结符的LASTVT集,思想和求FIRSTVT相同
{
int i;
char X,a;
SqStack S;
InitStack(S);
for(i=0;i<pronum;i++)//找到形如P->...a或者P->...aQ的产生式
{
if(test(old[i][tail(i)])<100)
insertl(old[i][0],old[i][tail(i)],S);

else
{
if(test(old[i][tail(i)-1])<100)
insertl(old[i][0],old[i][tail(i)-1],S);
}
}

while(!Empty(S))//假设弹出元素是(Q,a),找寻形如P->...Q的产生式
{
Pop(S,X,a);
for(i=0;i<pronum;i++)
{
if(old[i][0]!=old[i][tail(i)])
{
if(old[i][tail(i)]==X)
insertl(old[i][0],a,S);
}
}
}
}

int tail(int i)//返回产生式最后一位符号的下标
{
int j;
for(j=0;old[i][j]!='/0';j++)
{
}
return (j-1);
}

void insertl(char a,char b,SqStack &S)//插入LASTVT集
{
LAST[test(a)-100][test(b)]=1;
Push(S,a,b);
}

void printf_ff()//输出FIRSTVT和LASTVT
{
int i,j;
printf("注:1代表在集合中,0代表不在集合中/nFIRSTVT集为:/n ");
for(i=0;i<vtnum;i++)
printf("%c ",vt[i]);
printf("/n");
for(i=0;i<vnnum;i++)
{
printf("%c ",vn[i]);
for(j=0;j<vtnum;j++)
printf("%d ",FIRST[i][j]);
printf("/n");

}

printf("/nLASTVT集为:/n ");
for(i=0;i<vtnum;i++)
printf("%c ",vt[i]);
printf("/n");
for(i=0;i<vnnum;i++)
{
printf("%c ",vn[i]);
for(j=0;j<vtnum;j++)
printf("%d ",LAST[i][j]);
printf("/n");
}

}

void table()//构造优先关系表,0代表相等,1代表小于,2代表大于,3代表不存在
{
int i,j,k;
for(i=0;i<pronum;i++)
{
for(j=1;j<=tail(i)-1;j++)
{
if(test(old[i][j])<100&&test(old[i][j+1])<100)//如果P->...ab... 那么a=b
T[test(old[i][j])][test(old[i][j+1])]=0;

if(j<=tail(i)-2&&test(old[i][j])<100&&test(old[i][j+1])>=100&&test(old[i][j+1])<200&&test(old[i][j+2])<100)//如果P->...aQb... 那么a=b
T[test(old[i][j])][test(old[i][j+2])]=0;

if(test(old[i][j])<100&&test(old[i][j+1])>=100&&test(old[i][j+1])<200)//如果P->...aQ... 那么a<FIRSTVT(Q)
{
for(k=0;k<vtnum;k++)
{
if(FIRST[test(old[i][j+1])-100][k]==1)
T[test(old[i][j])][k]=1;
}
}

if(test(old[i][j])>=100&&test(old[i][j])<200&&test(old[i][j+1])<100)//如果P->...Qa... 那么LASTVT(Q)>a
{
for(k=0;k<vtnum;k++)
{
if(LAST[test(old[i][j])-100][k]==1)
T[k][test(old[i][j+1])]=2;
}
}
}
}

for(i=0;i<vtnum;i++)//对$的处理
{
if(FIRST[0][i]==1)
T[vtnum][i]=1;
}

for(i=0;i<vtnum;i++)
{
if(LAST[0][i]==1)
T[i][vtnum]=2;
}

T[vtnum][vtnum]=0;
}

void printf_t()
{
int i,j;
printf("/n优先关系表为:/n ");
for(i=0;i<vtnum;i++)
printf("%c ",vt[i]);
printf("$ /n");
for(i=0;i<vtnum;i++)
{
printf("%c ",vt[i]);
for(j=0;j<=vtnum;j++)
{
if(T[i][j]==0)
printf("= ");
else if(T[i][j]==1)
printf("< ");
else if(T[i][j]==2)
printf("> ");
else
printf(" ");
}
printf("/n");
}
printf("$ ");
for(j=0;j<=vtnum;j++)
{
if(T[i][j]==0)
printf("= ");
else if(T[i][j]==1)
printf("< ");
else if(T[i][j]==2)
printf("> ");
else
printf(" ");
}
printf("/n");
}

int control()//主控程序,核心是当前符号a[p]和s[j]的关系
{
char s
;//分析栈
char a[20]={'/0'};//存放待分析字符串
char q;//工作单元
int x,y,z,j=0,k=1,p=0;//j是栈的查找指针,k是栈顶指针,p是字符串指针,s[1]作为栈底

vt[vtnum]='$';
vtnum++;//把结束符'$'加入终结符集,后面将用到

printf("/n请输入要分析的字符串(以$结尾):");
cin>>a;

s[k]='$';//把$压栈
s[k+1]='/0';

printf("/n分析过程:/n堆栈 优先关系 当前符号 输入流 动作 /n");

if(test(s[k])<100)//判断s[k]是否是终结符或'$',如果是,j=k,s[j]是从栈顶向下首个终结符或者'$'
j=k;

else
j=k-1;

do
{
if(T[test(s[j])][test(a[p])]==3)//s[j]和a[p]间不存在关系,报错
{
printf("/nError,您输入的句型和文法不符!/n");
return ERROR;
}

for(x=1;s[x]!='/0';x++)
printf("%c",s[x]);
for(y=0;y<Y-x+1;y++)
printf(" ");//输出堆栈情况
if(T[test(s[j])][test(a[p])]==2)
printf(" > ");
else if(T[test(s[j])][test(a[p])]==1)
printf(" < ");
else
printf(" = ");//输出关系
printf(" %c ",a[p]);//输出当前符号
z=0;
for(x=p+1;a[x]!='/0';x++)
{
printf("%c",a[x]);
z++;
}
for(x=0;x<Y-z;x++)
printf(" ");//输出输入流
if(T[test(s[j])][test(a[p])]==1||T[test(s[j])][test(a[p])]==0)
printf(" 移进 ");
else
printf(" 归约 ");//输出动作
printf("/n");

if(T[test(s[j])][test(a[p])]==2)//s[j]>a[p],找到最左素短语,归约
{
do
{
q=s[j];
j--;
if(!(test(s[j])<100))
j--;
}while(!(T[test(s[j])][test(q)]==1));

k=j+1;
s[k]='N';//归约,'N'代表任意非终结符
s[k+1]='/0';
}

else//s[j]<=a[p],未找到最左素短语,移进
{
k++;
s[k]=a[p];//把当前符号移进
s[k+1]='/0';
p++;

if(test(s[k])<100)
j=k;

else
j=k-1;
}

}while(!(k==2&&a[p]=='$'&&s[k]=='N'));

printf("$N = $ 结束 /n");

printf("/nSucceed,您输入的句型和文法相符!/n");
return OK;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: