DO-WHILE循环语句的翻译程序设计(简单优先法、输出三地址表示)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
附件1:
学号:
0120910340525
课程设计
题目
DO-WHILE(简单优先法、输出三地址表示)
学院计算机科学与技术专业计算机科学与技术班级0905
姓名明正超
指导教师杨克俭
2012 年 1 月 3 日
课程设计任务书
学生姓名:明正超专业班级:计算机0905班
指导教师:杨克俭工作单位:计算机科学与技术学院题目: DO-WHILE循环语句的翻译程序设计(简单优先法、输出三地址表示)
初始条件:
理论:学完编译课程,掌握一种计算机高级语言的使用。
实践:计算机实验室提供计算机及软件环境。
如果自己有计算机可以在其上进行设计。
要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写
等具体要求)
(1)写出符合给定的语法分析方法的文法及属性文法。
(2)完成题目要求的中间代码三地址表示的描述。
(3)写出给定的语法分析方法的思想,完成语法分析和语义分析程序设计。
(4)编制好分析程序后,设计若干用例,上机测试并通过所设计的分析程序。
(5)设计报告格式按附件要求书写。
课程设计报告书正文的内容应包括:
1 系统描述(问题域描述);
2 文法及属性文法的描述;
3 语法分析方法描述及语法分析表设计;
4 按给定的题目给出中间代码形式的描述及中间代码序列的结
构设计;
5 编译系统的概要设计;
6 详细的算法描述(流程图或伪代码);
7 软件的测试方法和测试结果;
8 研制报告(研制过程,本设计的评价、特点、不足、收获与体
会等);
9 参考文献(按公开发表的规范书写)。
时间安排:
设计安排一周:周1、周2:完成系统分析及设计。
周3、周4:完成程序调试及测试。
周5:撰写课程设计报告。
设计验收安排:设计周的星期五第1节课开始到实验室进行上机验收。
设计报告书收取时间:设计周的次周星期一上午10点。
指导教师签名: 2011年 11月23日
系主任(或责任教师)签名: 2011年 11月 23日
(一)系统描述
根据所学编译原理有关词法分析,语法分析,语义分析有关规则,对DO_WHILE循环语句的翻译程序进行设计,使用高级语言或者伪代码形式,进行编写,其中要求使用简单优先法法并在程序的最终结果中显示出表达式的三地址形式。
(二)文法及属性文法的描述
2.1文法描述
G(s): S->do B while E,
B->c:=a+1,
E->a>b
2.2属性文法描述
G(s): S->do B while E, {S.begin:=newlabel;
B.next:=S.begin;
E.true:=newlabel;
E.false:= S.next;
S.code:=gen(S.begin’:’) ‖B.code ‖E.code ‖
gen(E.true’:’) ‖gen(‘goto’S.begin) } B->c:=a+1 { B.code:= ’c:=a+1’ }
E->a>b { E.code=gen(‘if’’a>b’’goto’ E.true) ‖
Gen(‘goto’ E.fals e) }
E->true {E.code:=gen(‘goto’ E.true) }
E->false {E.code:=gen(‘goto’ E.false) }
3语法分析方法及中间代码形式的描述
3.1语法分析方法描述
3.1.1简单优先法的定义
一个文法G,若它不含ε产生式,也不含任何右部相同的不同产生式,并且它的任何符号对(X,Y),或者没有关系,或者存在下述三种关系:=、<、>之一,则称该文法是一个简单优先文法。
A)X=Y当且仅当G中含有形如P→…XY…的产生式
B)X<Y当且仅当G中含有形如P→…XQ…的产生式,其中Q为非终结符,且Q →Y...
C)X>Y当且仅当Y为G的终结符,G中含有形如P→…QR…的产生式,其中Q,R为非终结符,且Q →…X,Y∈First(R)
D)对任何X,若文法开始符号S→X…,则#<X,若S→…X,则X>#。
3.1.2简单优先法的基本思想
根据优先关系的定义,将简单优先文法中各文法符号之间的这种关系用一个矩阵表示,称作简单优先矩阵。
PDA读入一个单词后,比较栈顶符号和该单词的优先级,若栈顶符号优先级低于该单词,继续读入;若栈顶符号优先级高于或等于读入符号,则找句柄进行归约,找不到句柄就继续读入。
直到最后栈内只剩下开始符号,输入串读到“#”为止。
此时识别正确。
可分点描述如下:
1、对句型中相邻的文法符号规定优先关系,以寻找句型中的句柄;
2、规定句柄内各相邻符号之间具有相同的优先级;
3、规定句柄两端符号优先级要比位于句柄之外而又和句柄相邻的符号的优先级高,以先归约句柄;
4、对于文法中所有符号,只要它们可能在某个句型中相邻,就要为它们规定相应的优先关系,若某两个符号永远不可能相邻,则它们之间就无关系.
3.1.3简单优先矩阵
用于表示文法符号之间的简单优先关系的矩阵。
3.1.4简单优先法的优缺点
优点:技术简单
缺点:适用范围小,分析表尺寸太大。
3.2中间代码形式描述
四元式是一种比较普遍采用的中间代码形式。
四元式的四个组成成分是:算符op,第一和第二运算对象ARG1和ARG2及运算结果RESULT。
运算对象和运算结果有时指用户自己定义的变量,有时指编译程序引进的临时变量。
有时,为了更直观,也把四元式的形式写成简单赋值形式,即三地址。
例如:输入字符串a:=b*c+b*d则输出三地址:
(1)t:=b*c
(2)m:=b*d
(3)n:=t+m
(4)a:=n
4详细算法描述
字符栈
#include<iostream>
using namespace std;
#define STACKSIZE 100
class SeqStack
{
private:
int top;
char *data;
int maxSize;
public:
SeqStack();
~SeqStack(){delete []data;}
void InitStack();
void Push(char);
void Pop(char);
void PrintStack();
char TopValue();
char NextTop();
bool Empty();
};
SeqStack::SeqStack()
{
data=new char[STACKSIZE];
}
void SeqStack::InitStack()//初始化符号栈
{
top = -1;
}
bool SeqStack::Empty() //判断操作符栈是否为空{
if(top>=0)
return false;
else
return true;
}
void SeqStack::Push(char c)//压栈
{
if (top < STACKSIZE)
{
top++;
data[top] = c;
}
}
void SeqStack::Pop(char c)//出栈
{
if (!Empty())
{
c = data[top];
top--;
}
}
char SeqStack::TopValue()//取栈顶元素值{
if (!Empty())
{
char c = data[top];
return c;
}
else return NULL;
}
char SeqStack::NextTop()//取次栈顶元素{
if(top>0)
{
char c=data[top-1];
return c;
}
else return NULL;
}
void SeqStack::PrintStack()//打印栈的元素{
for(int i=0;i<=top;i++)
cout<<data[i];
cout<<endl;
}
主要程序
#include"Stack.h"
#include<iostream>
#include<fstream>
#include <string>
using namespace std;
#define norw 13 //关键字的个数
#define nmax 14 //数字的最大位数
#define al 10 //符号的最大长度
#define N -10
#define getchdo if(getch()==-1)return -1
#define getsymdo if(getsym()==-1)return -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
};
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;
//设置保留字名字,
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->do{B}while(E)\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<A\0",
"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<<ch;
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<al)
{
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!"<<endl;
}
}
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 d o { B } w h i l e E 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 },
/* d */ { N, N, 0, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N },
/* o */ { 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, N, N, N, -1, N, N },
/* B */ { 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, N, N, N, N },
/* w */ { N, N, N, N, N, N, N, 0, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N },
/* h */ { N, N, N, N, N, N, N, N, 0, N, N, N, N, N, N, N, N, N, N, N, N, N, N },
/* i */ { N, N, N, N, N, N, N, N, N, 0, N, N, N, N, N, N, N, N, N, N, N, N, N },
/* l */ { N, N, N, N, N, N, N, N, N, N, 0, N, N, N, N, N, N, N, N, N, N, N, N },
/* e */ { N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, 0, N, N, N, N },
/* E */ { 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 }};
int Compare(char m,char n)//定义矩阵
{
switch (m)
{
case 'S': row=0;break;
case 'd': row=1;break;
case 'o': row=2;break;
case '{': row=3;break;
case 'B': row=4;break;
case '}': row=5;break;
case 'w': row=6;break;
case 'h': row=7;break;
case 'i': row=8;break;
case 'l': row=9;break;
case 'e': row=10;break;
case 'E': 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 'd': line=1;break;
case 'o': line=2;break;
case '{': line=3;break;
case 'B': line=4;break;
case '}': line=5;break;
case 'w': line=6;break;
case 'h': line=7;break;
case 'i': line=8;break;
case 'l': line=9;break;
case 'e': line=10;break;
case 'E': 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<<"归约失败,语法有错误!"<<endl;
}
void Succeed()//规约成功
{
cout<<"归约成功,语法正确."<<endl;
}
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<<"归约过程如下:"<<endl;
Sym.Push('#');
while (*p!='\0')
{
c=Sym.TopValue();
if (c=='S')//如果栈顶为S或#,规约成功
{
Succeed();
cout<<"语法分析完成!\n"<<endl;
cout<<"三地址码如下所示:"<<endl;
ThreeAddr();
cout<<endl;
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<<endl;
return;
}
}
}
}
}
void ThreeAddr() //产生并输出三地址码
{
int m=0,nextstat=100;
char op1,op2,opt,c;
for(int i=0;i<count1;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<<nextstat++<<" "<<op2<<" "<<opt<<" "<<op1<<m-1<<endl;
else if(Opt.TopValue()=='>')
{
cout<<nextstat++<<" t"<<m-1<<"= "<<op2<<opt<<op1<<endl;
cout<<nextstat++<<" if"<<" t"<<m-1<<" goto 100"<<endl;
}
else cout<<nextstat++<<" t"<<m<<" = "<<op2<<opt<<op1<<endl;
Opt.Pop(c);
if(!Opr.Empty()) Opr.Push('t');
m++;
}
}
cout<<nextstat++<<endl;
}
int main()
{
fin = new ifstream("simple.txt");
if(!fin)
{
cout<<"文件打开失败!"<<endl;
}
init();
Sym.InitStack();
Opt.InitStack();
Opr.InitStack();
cout<<"\n DO-WHILE循环语句的翻译程序(简单优先法、输出三地址)\n"<<endl;
cout<<"文法为:"<<endl;
for(int i=0;i<12;i++)
cout<<rule[i]<<endl;
cout<<"\n源程序为:"<<endl;
while(getsym() !=-1 && sym != neq);
cout<<"\n词法分析完成!"<<endl;
fin->close();
cout<<endl;
inputstr[ip]='#';
p=inputstr;
Parse();
return 0;
}
5测试方法和结果
测试用例为do
{
c=a+1;
}while(a>b)
结果如下
6研制报告
这次编译原理课程设计的题目是用简单优先分析法进行DO-WHILE循环语句的语法分析,并输出三地址.设计的特点是利用定义每个终极符和非终极符之间优先关系,来进行符号的移进与规约,如果栈顶符号优先级低于该单词,继续读
入;若栈顶符号优先级高于或等于读入符号,则找句柄进行归约,找不到句柄就继续读入。
这样使得程序简化,只需定义一个栈用来存放移进的字符,然后用栈顶指针指向它后与待移进字符比较优先级即可,设计简单.此设计的严重不足是只能进行一个固定句子的词法与语法分析,因为在定义优先关系时已固定了DO,和WHILE的每个字符之间的优先关系,且赋值表达式和条件式也已固定,所以只能进行本程序已约定好的语句.
最大的收获是在提出一个难题以后,如果能比较顺手的解决的话,那是一件比较开心的事。
只是有些时候越想问题就会越多,也越难解决,那就得慢慢调试,慢慢推导了。
相信只要想得出,就能调得出,当然耐心是很重要的,花在上面的时间也是要多一点的。
完成此次课程设计以后,觉得自己在编译原理的学习中存在很多的不足和需要提高的地方.通过对简单优先法翻译程序的编程也使自己在编写编译程序上有了感官的认识,且能力也得到了一定的提高!虽然此程序还存在很多的缺点与不足,但在将来的学习中我会不断的完善此部分知识.独立的完成程序以后也有不少收获,为自己在以后的学习中做了很好的铺垫!
7参考文献
《编译原理》清华大学出版社张素琴吕映芝
本科生课程设计成绩评定表
班级:计算机0905姓名:明正超学号:0120910340525
及格(60-69分)、60分以下为不及格
指导教师签名:
201 年月日。