WHILE循环语句的翻译程序设计(简单优先法,三地址输出)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

目录
1 问题域描述 (3)
2 文法及属性文法的描述 (3)
2.1 WHILE循环语句的文法 (3)
2.2 WHILE循环语句的属性文法 (4)
3 语法分析方法及中间代码形式的描述 (4)
3.1语法分析方法 (4)
3.2中间代码形式描述 (6)
4 编译系统的概要设计 (7)
4.1词法分析 (7)
4.2语法制导翻译 (8)
5 详细的算法描述 (8)
5.1 文法设计 (8)
5.2 算法描述 (8)
5.3 源程序代码 (9)
6 软件的调试过程和结果测试 (19)
6.1调试过程 (19)
6.2结果测试 (19)
7 使用说明 (20)
8 课设总结 (20)
9 参考文献 (22)
WHILE循环语句的翻译程序设计
(简单优先法、输出三地址表示)
1 问题域描述
while循环语句的翻译程序设计(简单优先法,输出单地址表示),要求完成:
(1)用C++语言正确编写程序,完成WHILE循环语句的翻译程序设计。

(2)求能正确进行词法分析,语法分析,并能正确的输出预期结果。

(3)根据指定的文法,判定程序的正确性。

本次课程设计中要求设计一个WHILE循环语句的词法﹑语法及语义分析程序,语法分析选择简单优先法,采用语法制导翻译输出中间代码三元式。

通过设计、编制、调试一个WHILE循环语句的语法及语义分析程序,加深对语法及语义分析原理的
理解,实现功能。

while循环语句的格式为:while(P){do A},其中A为循环体,可为一个或多个赋值语句;P为循环控制条件。

while循环语句首先根据循环控制条件P进行判断,若满足条件则执行循环体A,否则执行下面的程
序段;
本次课程设计中系统首先要进行词法分析,即从左到右把源文件的字符序列逐个进行扫描,产生一个个的单词序列,作为语法分析的输入
从而继续编译过程。

该程序的语法分析读入词法分析的结果,并判断输入语句是否满足while循环语句的文法所描述的形式。

通过简单优先法对语句进行分析,看是否能通过给定的输入串归约到文法的开始符号。

在语法分析的同时进行语义分析,最后输出三元式的代码。

2 文法及属性文法的描述
2.1WHILE循环语句的文法
定义一个文法,文法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->E rop id
rop-> > | < | >= | <= | != | ==
2.2 WHILE循环语句的属性文法
产生式语义规则
S→while P{A} S.addr:=newlabel;
E.true:=newlabel;
E.false:=S.next;
S1.next:=S.begin;
S.code:=gen(S.begin’:’‖E。

code‖
gen(E.true’:’ ‖S1.code‖
gen(‘goto’ S.begin
3 语法分析方法及中间代码形式的描述
3.1语法分析方法
简单优先分析法是按照文法符号(终结符和非终结)的优先关系确定句柄的,因此我们首先介绍任意两个文法符号之间的优先关系是怎样确定的,及如何构造优先关系表。

首先定义优先关系的表示:
X=Y 表示X和Y的优先关系相等
X>Y 表示X的优先性比Y的优先性大
X 表示 X 的优先性比 Y 的优先性小
这样我们就可对已知文法中的任意两个文法符号X,Y按其在举行中可能会出现的相邻关系确定他们的优先关系。

对文法的要求高,而且也要把文法符号的关系首先表示出来,这普遍性不是
太好。

{/** S w h i l e E d o { B }a = + 1 ; > ( b c # **/
/* 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中间代码形式描述
三元式是一种普遍采用的中间代码形式。

它由三个部分组成:算符op,第一
和第二运算对象ARG1和ARG2。

运算对象有时候指用户自己定义的变量。

对c=a+1翻译结果如下
1)(+,a,1)
2),(=, c, (1)
为方便和直观,将while语句翻译为if a> b goto do.addr
4 编译系统的概要设计
本程序开始,需先对输入字符串进行词法分析,将其识别为一个个独立的单词序列,得到的字符单词要和关键字比较,看是否是关键字,根据比较结果进行返回相应的单词类型。

单词类型主要包括标识符,关键字,常量,运算符和分界符。

在语法分析程序中,根据词法分析得到的结果,进行判断是否是当前需要的单词类型,如果不是就说明输入字符串不能由该文法推导出来;如果是当前需要的类型,就相应得做该单词类型分支程序。

根据简单优先法分析的字符串,看是否能得到接受状态。

此外,在进行语法分析的同时进行语义分析,审查程序有无语义错误,每个算符是否具有语言规范允许的运算对象,当不符合语言规范时,编译程序应报告错误。

在进行了上述的语法分析和语义分析阶段的工作之后,将源文件变成三元式表示。

源程序目录下建立“input.txt”文本文档,在文档中输入while(P{A}格式的WHILE语句,再通过调用程序中的get_word(string word函数进行对文本文档中语句的读取操作。

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->E rop id
rop-> > | < | >= | <= | != | ==
5.2 算法描述
(1)word_node * word_link(word_node,word_node,string//给结点赋值,并设置type值。

(2)void get_word(string word函数设计:从文本文档中读取字符,存入word_array
(3)简单优先子程序如下:
void rop(word_node *&p //rop-> > | < | >= | <= | != | ==
void F(word_node *&p //F->(E | id
void extend_T(word_node *&p //T'->*FT' | /FT' | e
void T(word_node *&p //T->FT'
void extend_E(word_node *&p //E'->+TE' | -TE' | e
void E(word_node *&p //E->TE'
void P(word_node *&p //P->E rop b
void A(word_node *&p //A->id=E;
bool S(word_node *&p // while(p {doA};
5.3 源程序如下
#include"Stack.h" //定义栈,便于归约时运用。

#include
#include //文件输入
#include
using namespace std;
#define norw 13 //关键字的个数
#define nmax 14 //数字的最大位数
#define al 10 //符号的最大长度
#define N -10
#define getchdo if(getch(==-1return -1
#define getsymdo if(getsym(==-1return -1 ifstream *fin;
SeqStack Sym,Opt,Opr;
char *p,ch;
char str[20];
char inputstr[100]; //保存从文件读入的所有字符char buf[5][20];
int count1=0,count2=0;
int ip=0,row,line;
enum symbol sym; //当前的符号
int num; //当前number
char a[al+1]; //临时符号
char id[al+1]; //当前ident
char word[norw][al]; //保留字
enum symbol wsym[norw]; //关键字的符号值
enum symbol ssym[256]; //单字符的符号值
enum symbol{
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 };
void ThreeAddr(;
void init(
{
//设置单字符符号
for(int i=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;
}
char rule[12][20]={
"S-> while(E {do B}/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",}; //文法
int getch(
{
if(fin->get(ch
{
if(ch!=' ' && ch!=9 && ch!=10 {
inputstr[ip]=ch;
ip++;
}
cout<
return 0;
}
else return -1;
}
//词法分析
int getsym(
{
int i,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:too large number!"< }
}
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;
}
}
}
}
}
}
return 0;
}
//优先关系模块
//定义优先关系
int PreTable[23][23] =
{/** S w h i l e E d o { B }a = + 1 ; > ( b c # **/
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 },
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 }};
int Compare(char m,char n//定义矩阵
{
switch (m
{
case 'S': row=0;break;
case 'w: row=1;break;
case 'h: row=2;break;
case 'i row=3;break;
case 'l: row=4;break;
case 'e: row=5;break;
case 'E: row=6;break;
case 'o row=8;break;
case '{: row=9;break;
case 'A: row=10;break;
case '}: row=11;break;
case 'a': row=12;break; case '=': row=13;break; case '+': row=14;break; case '1': row=15;break; case ';': row=16;break; case '>': row=17;break; case '(': row=18;break; case 'b': row=19;break; case 'c': row=20;break; case '': row=21;break;
case '#': row=22;break; default: return -100;break; }
switch (n
{
case 'S': line=0;break; case 'w: line=1;break;
case 'h: line=2;break;
case 'l: line=4;break;
case 'e: line=5;break;
case 'E: line=6;break;
case 'd: line=7;break;
case 'o: line=8;break;
case '{: line=9;break;
case 'A: line=10;break; case '}: line=11;break; case 'a': line=12;break; case '=': line=13;break; case '+': line=14;break; case '1': line=15;break; case ';': line=16;break; case '>': line=17;break; case '(': line=18;break; case 'b': line=19;break; case 'c': line=20;break; case '': line=21;break; case '#': line=22;break; default: return -100;break; }
return PreTable[row][line];
}
void Error(//规约不成功
{
cout<<"归约失败,语法有错误!"<
}
void Succeed(//规约成功
{
cout<<"归约成功,语法正确."<
}
char Reduce(char c //将终极符或非终极符规约为非终极符{
if (c == 'd' { return 'S'; }
else if (c == 'c'
{ return 'B'; }
else if (c == 'a'
{ return 'E'; }
else return NULL;
}
void Parse(//简单优先语法分析
{
char c; //保存栈顶元素
char t1; //规约时判断是否规约的栈顶元素
char t2; //规约时判断是否规约的次栈顶元素
cout<<"归约过程如下:"<
Sym.Push('#';
while (*p!='\0'
{
c=Sym.TopValue(;
if (c=='S'//如果栈顶为S或#,规约成功
{
Succeed(;
cout<<"语法分析完成!\n"<
cout<<"三地址码如下所示:"<
ThreeAddr(;
cout<
return;
}
else
{
switch (Compare(c, *p
{ //如果优先符是小于或等于则压栈,否则进栈case -1:
case 0:
{
Sym.Push(*p;//压栈
Sym.PrintStack(;
p++;
break;
}
case 1:
{
do
{
t1 = Sym.TopValue(;
buf[count1][0]=0;
buf[count1][count2]=t1; count2++;
t2 = Sym.NextTop(;
Sym.Pop(c;//栈顶出栈
}while(Compare(t2, t1 != -1; count1++;
t1 = Reduce(t1;
Sym.Push(t1;
Sym.PrintStack(;
break;
}
default:
{
Error(;
cout<<"语法分析完成!\n";
cout<
return;
}
}
}
}
}
void ThreeAddr( //产生并输出三地址码
{
int m=0,nextstat=100;
char op1,op2,opt,c;
for(int i=0;i
{
for(int j=(count2-1;j>=0;j--
{
if(buf[i][j]>='a'&&buf[i][j]<='z'||buf[i][j]>='A'&&buf[i][j]<='Z'||buf[i ][j]>='0'&&buf[i][j]<='9'
Opr.Push(buf[i][j];
else if(buf[i][j]=='+'||buf[i][j]=='-
'||buf[i][j]=='*'||buf[i][j]=='/'||buf[i][j]=='<'||buf[i][j]=='>'||buf[i ][j]=='='
Opt.Push(buf[i][j];
}
while(!Opr.Empty( && !Opt.Empty(
op1=Opr.TopValue(;
Opr.Pop(c;
op2=Opr.TopValue(;
Opr.Pop(c;
opt=Opt.TopValue(;
if(Opt.TopValue(=='='
cout<
else if(Opt.TopValue(=='>'
{
cout< cout<
}
else cout< Opt.Pop(c;
if(!Opr.Empty( Opr.Push('t';
m++;
}
}
cout<
}
int main(
{
fin = new ifstream("simple.txt"; if(!fin
cout<<"文件打开失败!"<
}
init(;
Sym.InitStack(;
Opt.InitStack(;
Opr.InitStack(;
cout<<"\n DO-WHILE循环语句的翻译程序(简单优先法、输出三地址\n"< cout<<"文法为:"<
for(int i=0;i<12;i++
cout<
cout<<"\n源程序为:"<
while(getsym( !=-1 && sym != neq;
cout<<"\n词法分析完成!"<
fin->close(;
cout<
inputstr[ip]='#';
p=inputstr;
Parse(;
return 0;
}
6 软件的调试过程和结果测试
6.1调试过程
进行分析,运行结果分析
1)语法错误
程序编写过程中有些地方由于输入法切换不及时,导致有些地方分号“;”错误地在中文状态下去输入,使程序调试时出现语法错误;此外,由于程序编写过程中存在很多条件语句及循环语句的嵌套,在各个函数的设计中有些括号忘记写右括号“}”,也导致出现语法错误,改正后均无误。

2)逻辑错误
(1)函数get_word(string word中没有对txt文件是否存在进行判断,产生错误(2)对于符号定义中那个<,>没有定义,导致后边语法分析产生脱节。

6.2结果测果。

相关文档
最新文档