这样我们就可对已知文法中的任意两个文法符号X,Y按其在举行中可能会出现的相邻关系确定他们的优先关系。
3.1.2简单优先法的缺点
对文法的要求高,而且也要把文法符号的关系首先表示出来,这普遍性不是太好。
{/**SwhileEdo{B}a=+1;>(bc)#**/
/*S*/{N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,1},
/*w/{N,N,0,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N},
/*h*/{N,N,N,0,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N},
/*i/{N,N,N,N,0,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,-1,N,N},
/*l/{N,N,N,N,N,0,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N},
/*e*/{N,N,N,N,N,N,0,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N},
/*E*/{N,N,N,N,N,N,N,0,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N},
/*d*/{N,N,N,N,N,N,N,N,0,N,N,N,N,N,N,N,N,N,N,N,N,N,N},
/*o*/{N,N,N,N,N,N,N,N,N,0,N,N,N,N,N,N,N,N,N,N,N,N,N},
/*{{N,N,N,N,N,N,N,N,N,N,0,N,N,N,N,N,N,N,N,N,N,N,N},
/*A/{N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,0,N,N,N,N},
/*}*/{N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,0,N},
/*a*/{N,N,N,N,N,N,N,N,N,N,N,N,N,N,0,N,N,0,N,N,N,N,N},
/*=*/{N,N,N,N,N,N,N,N,N,N,N,N,0,N,N,N,N,N,N,N,N,N,N},
/*+*/{N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,0,N,N,N,N,N,N,N},
/*1*/{N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,0,N,N,N,N,N,N},
/*;*/{N,N,N,N,N,1,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N},
/*>*/{N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,0,N,N,N},
/*(*/{N,N,N,N,N,N,N,N,N,N,N,0,-1,N,N,N,N,N,N,N,N,N,N},
/*b*/{N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,1,N},
/*c*/{N,N,N,N,N,N,N,N,N,N,N,N,N,0,N,N,N,N,N,N,N,N,N},
/*)*/{N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,1},
/*#*/{-1,-1,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,0}};
其中N表示的是没有优先关系,-1表示优先级小于,0表示优先级相同,1表示优先级大于
3.2中间代码形式描述
3.2.1三元式
三元式是一种普遍采用的中间代码形式。
它由三个部分组成:
算符op,第一和第二运算对象ARG1和ARG2。
运算对象有时候指用户自己定义的变量。
3.2.2赋值语句的四元式
对c=a+1翻译结果如下
1)(+,a,1)
2),(=,c,
(1))
3.2.3while(a>b)语句翻译
为方便和直观,将while语句翻译为ifa>bgotodo.addr
4编译系统的概要设计
本程序开始,需先对输入字符串进行词法分析,将其识别为一个个独立的单词序列,得到的字符单词要和关键字比较,看是否是关键字,根据比较结果进行返回相应的单词类型。
单词类型主要包括标识符,关键字,常量,运算符和分界符。
在语法分析程序中,根据词法分析得到的结果,进行判断是否是当前需要的单词类型,如果不是就说明输入字符串不能由该文法推导出来;如果是当前需要的类型,就相应得做该单词类型分支程序。
根据简单优先法分析的字符串,看是否能得到接受状态。
此外,在进行语法分析的同时进行语义分析,审查程序有无语义错误,每个算符是否具有语言规范允许的运算对象,当不符合语言规范时,编译程序应报告错误。
在进行了上述的语法分析和语义分析阶段的工作之后,将源文件变成三元式表示。
源程序目录下建立“input.txt”文本文档,在文档中输入while(P){A}格式的WHILE语句,再通过调用程序中的get_word(stringword)函数进行对文本文档中语句的读取操作。
4.1词法分析
词法分析是编译的第一阶段,它的主要任务是从左至右逐个字符地对源程序进行扫描,产生一个单词序列,用于语法分析。
编程中,建立操作数栈和运算符栈,设定运算符优先级。
对于读取的字符进行判定,若是运算符,就与栈顶符号比较优先级,高则入栈,否则栈内运算符出栈;若是非运算符,则送入操作数栈。
4.2语法制导翻译
在语法分析过程中,随着分析的步步进展,根据每个产生式所对应的语义子程序(或语义规则描述的语义动作)进行翻译。
属性文法的每个符号有属性,所以每个符号入栈时,必须连属性一起入栈,这样,栈符号就由文法符号及存放该符号属性的域所组成。
由于属性类型不同,属性域存放的内容就要根据属性的类型来定。
有的可能直接存放属性值,也有的存放的是指向属性值的指针。
对于综合属性,其属性域不存放其属性值,而是存放一个指针,指向存贮该属性值的单元。
对于继承属性,其属性域直接保存其属性值。
继承属性的属性域刚入栈时为空,但是在该栈符号变成栈顶符号之前的某一时刻,它们必须接受相应的属性值,即在成为栈顶时,继承属性的属性域必须有值。
5详细的算法描述
5.1文法设计
为顺利完成本次课程设计,实现要求的功能,设计测试文法G(S)如下:
S->while(P){A};
A->id=E;
E->TE'
E'->+TE'|-TE'|e
T->FT'
T'->*FT'|/FT'|e
F->(E)|id
P->Eropid
rop->>|<|>=|<=|!
=|==
5.2算法描述
(1)word_node*word_link(word_node,word_node,string)//给结点赋值,并设置type值。
(2)voidget_word(stringword)函数设计:
从文本文档中读取字符,存入word_array
(3)简单优先子程序如下:
voidrop(word_node*&p)//rop->>|<|>=|<=|!
=|==
voidF(word_node*&p)//F->(E)|id
voidextend_T(word_node*&p)//T'->*FT'|/FT'|e
voidT(word_node*&p)//T->FT'
voidextend_E(word_node*&p)//E'->+TE'|-TE'|e
voidE(word_node*&p)//E->TE'
voidP(word_node*&p)//P->Eropb
voidA(word_node*&p)//A->id=E;
boolS(word_node*&p)//while(p){doA};
5.3源程序如下
#include"Stack.h"//定义栈,便于归约时运用。
#include
#include//文件输入
#include
usingnamespacestd;
#definenorw13//关键字的个数
#definenmax14//数字的最大位数
#defineal10//符号的最大长度
#defineN-10
#definegetchdoif(getch()==-1)return-1
#definegetsymdoif(getsym()==-1)return-1
ifstream*fin;
SeqStackSym,Opt,Opr;
char*p,ch;
charstr[20];
charinputstr[100];//保存从文件读入的所有字符
charbuf[5][20];
intcount1=0,count2=0;
intip=0,row,line;
enumsymbolsym;//当前的符号
intnum;//当前number
chara[al+1];//临时符号
charid[al+1];//当前ident
charword[norw][al];//保留字
enumsymbolwsym[norw];//关键字的符号值
enumsymbolssym[256];//单字符的符号值
enumsymbol{
nul,ident,number,plus,minus,times,
slash,oddsym,eql,neq,lss,leq,
gtr,geq,lparen,rparen,lbrace,rbrace,
comma,semicolon,period,becomes,beginsym,endsym,
ifsym,elsesym,whilesym,writesym,readsym,dosym,
callsym,constsym,varsym,procsym,greater,less
};
voidThreeAddr();
voidinit()
{
//设置单字符符号
for(inti=0;i<=255;i++)
{
ssym[i]=nul;
}
ssym['+']=plus;
ssym['-']=minus;
ssym['*']=times;
ssym['/']=slash;
ssym['(']=lparen;
ssym[')']=rparen;
ssym['{']=lbrace;
ssym['}']=rbrace;
ssym['=']=eql;
ssym[',']=comma;
ssym['.']=period;
ssym['#']=neq;
ssym[';']=semicolon;
ssym[>]=greater;
ssym[<]=less;
//设置保留字名字,
strcpy(&(word[0][0]),"begin");
strcpy(&(word[1][0]),"call");
strcpy(&(word[2][0]),"const");
strcpy(&(word[3][0]),"do");
strcpy(&(word[4][0]),"end");
strcpy(&(word[5][0]),"if");
strcpy(&(word[6][0]),"odd");
strcpy(&(word[7][0]),"procedure");
strcpy(&(word[8][0]),"read");
strcpy(&(word[9][0]),"then");
strcpy(&(word[10][0]),"var");
strcpy(&(word[11][0]),"while");
strcpy(&(word[12][0]),"write");
//设置保留字符号
wsym[0]=beginsym;
wsym[1]=callsym;
wsym[2]=constsym;
wsym[3]=dosym;
wsym[4]=endsym;
wsym[5]=ifsym;
wsym[6]=oddsym;
wsym[7]=procsym;
wsym[8]=readsym;
wsym[9]=elsesym;
wsym[10]=varsym;
wsym[11]=whilesym;
wsym[12]=writesym;
}
charrule[12][20]={
"S->while(E){doB}/0;
"B->d=C;\0",
"C->A+A\0",
"C->A-A\0",
"C->A*A\0",
"C->A/A\0",
"C->A\0",
"E->A>A\0",
"E->A"E->A==A\0",
"E->A\0",
"A->d\0",};//文法
intgetch()
{
if(fin->get(ch))
{
if(ch!
=''&&ch!
=9&&ch!
=10)
{
inputstr[ip]=ch;
ip++;
}
cout<return0;
}
elsereturn-1;
}
//词法分析
intgetsym()
{
inti,j,k;
while(ch==''||ch==10||ch==9)
{
getchdo;
sym=nul;
}
if(ch>='a'&&ch<='z')
{
k=0;
do{
if(k{
a[k]=ch;
k++;
}
getchdo;
}while(ch>='a'&&ch<='z'||ch>='0'&&ch<='9');
a[k]=0;
strcpy(id,a);
i=0;
j=norw-1;
do{//搜索当前符号是否为保留字
k=(i+j)/2;
if(strcmp(id,word[k])<=0)
{
j=k-1;
}
if(strcmp(id,word[k])>=0)
{
i=k+1;
}
}while(i<=j);
if(i-1>j)
{
sym=wsym[k];
}
else
{
sym=ident;//搜索失败,则是名字或数字
}
}
else{
if(ch>='0'&&ch<='9')//检测是否为数字
{
k=0;
num=0;
sym=number;
do{
num=num*10+ch-'0';
k++;
getchdo;
}while(ch>='0'&&ch<='9');
k--;
if(k>nmax)
{
cout<<"error:
toolargenumber!
"<}
}
else
{
if(ch=='=')//检测赋值符号
{
sym=becomes;
getchdo;
}
else
{
if(ch=='<')//检测小于或小于等于符号
{
getchdo;
if(ch=='=')
{
sym=leq;
getchdo;
}
else
{
sym=lss;
}
}
else{
if(ch=='>')//检测大于或大于等于符号
{
getchdo;
if(ch=='=')
{
sym=geq;
getchdo;
}
else
{
sym=gtr;
}
}
else
{
sym=ssym[ch];
if(sym!
=period)
{
getchdo;
}
}
}
}
}
}