admin 管理员组文章数量: 1086019
2024年4月27日发(作者:电脑编程14岁入门自学)
编译技术课程设计
班 级 计算机0802
学 号 **********
姓 名 周勇
指导老师 朱玉全
二零一一年 七 月
编译技术课程设计
一、目的
<<编译技术>>是理论与实践并重的课程,而其实验课要综合运用一、二年级所学的多门
课程的内容,用来完成一个小型编译程序。从而巩固和加强对词法分析、语法分析、语义分
析、代码生成和报错处理等理论的认识和理解;培养学生对完整系统的独立分析和设计的能
力,进一步培养学生的独立编程能力。
二、任务及要求
基本要求:
1. 词法分析器 产生下述小语言的单词序列
这个小语言的所有的单词符号,以及它们的种别编码和内部值如下表:
单词符号
DIM
IF
DO
STOP
END
标识符
常数(整)
=
+
*
**
,
(
)
种别编码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
助记符
$DIM
$IF
$DO
$STOP
$END
$ID
$INT
$ASSIGN
$PLUS
$STAR
$POWER
$COMMA
$LPAR
$RPAR
内码值
-
-
-
-
-
-
内部字符串
标准二进形式
-
-
-
-
-
-
对于这个小语言,有几点重要的限制:
首先,所有的关键字(如IF﹑WHILE等)都是“保留字”。所谓的保留字的意思是,用
户不得使用它们作为自己定义的标示符。例如,下面的写法是绝对禁止的:
IF(5)=x
其次,由于把关键字作为保留字,故可以把关键字作为一类特殊标示符来处理。也就是
说,对于关键字不专设对应的转换图。但把它们(及其种别编码)预先安排在一张表格中(此
表叫作保留字表)。当转换图识别出一个标识符时,就去查对这张表,确定它是否为一个关
键字。
再次,如果关键字、标识符和常数之间没有确定的运算符或界符作间隔,则必须至少用
一个空白符作间隔(此时,空白符不再是完全没有意义的了)。例如,一个条件语句应写为
IF i>0 i= 1;
而绝对不要写成
IFi>0 i=1;
因为对于后者,我们的分析器将无条件地将IFI看成一个标识符。
这个小语言的单词符号的状态转换图,如下图:
2. 语法分析器 能识别由加+ 减- 乘* 除/ 乘方^ 括号()操作数所组成的算术表达
式,其文法如下:
E→E+T|E-T|T
T→T*F|T/F|F
F→P^F|P
p→(E)|i
使用的算法可以是:预测分析法;递归下降分析法;算符优先分析法;LR分析法等。
3. 中间代码生成器 产生上述算术表达式的中间代码(四元式序列)
较高要求:
1. 扩充上述小语言的单词;
2. 增加语法分析器的功能,能识别条件语句和循环语句等;
3. 增加中间代码生成器的功能,能产生条件语句和循环语句等的中间代码(四元
式序列)
4. 增加报错功能;
5. 将中间代码翻译成汇编语言。
三、实现过程说明
给出各题目的详细算法描述,数据结构和函数说明,流程图。
(1) 词法分析器:
1算法描述:
词法分析阶段的基本任务是从以字符串表示的源程序中识别出具有独立
意义的单词符号。通过DOS环境手动输入字符串序列(以’$’作为结束标志)作
为带分析的源程序,调用词法扫描子程序将字符串以二元组的形式输出(若有
不属于该语言单词符号出现,则进行出错处理),词法扫描子程序包括了对源程
序的预处理(忽略、回车换行符等字符),以及对单词的识别和分类,以形成(单
词种别,单词自身的值)形式的二元组。
具体思路如下:
首先建立关键字表,将关键字作为特殊标示符处理,把它们预先安排在char
*keywords[13]中,将需要被识别出的关键字存入表中,当扫描程序识别出标识
符时,查关键字表。如能查到匹配的单词,则该单词为关键字,否则为一般标
识符。
在主函数中让用户输入要识别的符号串,然后将输入的符号串读入到
program[500],遇$结束。再依次扫描program[500]中的每一个符号,调用Scan
()子函数分析每一个符号,再将分析的结果输出,也是遇$结束。
2函数说明和数据结构:
在Scan ()子函数中,先全部初始化,然后读一个字符,分析它是什么类型:
如果是字母类型,则接着往下读,直到读到非字母的字符,存入words[10]
中,依次对比关键字表中的元素,如果相同,则将flags[]置为相应的种别码,
如果全都扫描后没发现相同的关键字,则为普通的标识符,返回主函数输出。
如果是数字类型,首先分析第一个符号,接着读下一个字符串,直到读到
一个不是数字的字符串位置,每读一个数字字符,就将他们转化为相应的数字,
使用辗转相乘法,每次都让number先自乘10,然后加上这个数字,这样就将
字符串表示的数字转化成了相应的数,返回主函数输出。
如果是其他单词表的符号,则将他们的flags[]置为相应的种别码,并将
字符存到words[] 中返回主函数输出。
主要变量说明: 用words[10]存放构成单词符号的字符串,并且用于判断是
否为关键字。flags[500] 存放单词符号的种别码。Number存放整数值,words[]
存放标识符,关键字或者其他符号。cnt[num]按顺序存放读到的字符,为下面语
义分析做准备。Status用于判断是否为关键字,1是,0不是。
3 具体的种别编码和内部值:
单词符号
void
main
if
then
break
int
char
fioat
include
for
while
printf
scanf
标识符
常数(整)
= =
=
>=
>
<=
<
!=
!
种别编码
1
2
3
4
5
6
7
8
9
10
11
12
13
100
200
401
402
403
404
405
406
407
408
内部字符串
二进制数值表示
单词值
+=
++
+
-=
- -
-
*=
*
/=
/
^
;
(
)
[
409
410
411
412
413
414
415
416
417
418
419
501
502
503
504
]
{
}
:
“
%=
%
,
#
@
空格
$
505
506
507
508
509
510
511
512
513
514
515
0
4. 流程图:
主流程图
扫描程序流程图:
(a),标识符词法分析流程图
(b), 数字(整)词法分析流程图
(c), 其他字符流程图
(a)
(b) (c)
(2) 语法分析器
1算法描述:
语法分析阶段的基本任务是将词法分析阶段产生的二元组作为输入,根据
语言的语法规则,识别出各种语法成分,并判断该单词符号序列是否是该语言
的一个句子。
在语法分析阶段,采用自上而下的递归下降分析法,根据递归下降分析函
数编写规则来编写相应的函数,在各个函数的分析过程中调用词法分析程序中
的扫描程序,发出“取下一个单词符号”的命令,以取得下一个单词符号的语
法分析。
词法分析和语法分析的整体设计思想可由以下图示表示:
单词符号
字符
词
法
分
析
器
取一下个
单词符号
语
法
分
析
器
字符串表示的源程序
语法分析是在词法分析的基础上加上判断是否符合语法规则的语句。语法
分析的基本任务是使用词法分析的结果,使用递归下降算法分析是否符合语法规
则,如果符合,则输出“分析成功”,若果不符合,则输出“分析失败”。
2.函数说明和数据结构
在main函数调用e()函数,如果调用之后返回时,如果
((flags[temp]==0)&&is_right)为真,就输出“分析成功”,否则输出“分析失
败”。其中is_right为设定的标志,初值为1,如果在调用子函数的过程中如果
有错误,则置is_right为0。
e函数: 调用t函数,调用f函数, 调用p函数,返回后看是否是’+’或’-’,
如果是,则调用 e1函数,再调用e2函数,如果不是,进行出错处理,置is_right
为0。
e1函数:判断是不是”+”或者“-” 如果是,调用f函数,如果不是,进行
出错处理,置is_right为0。
t函数: 调用f函数, 调用p函数,返回后看是否是’*’或’/’,如果是,则
调用t1函数,再调用t2函数,如果不是,进行出错处理,置is_right为0。
t1函数:判断是不是”*”或者“/” 如果是,调用f函数,如果不是,进行
出错处理,置is_right为0。
f函数:调用p函数,f1函数。
f1函数:判断是不是”^”,如果是,调用f函数,如果不是,进行出错处理,
置is_right为0。
p函数: 检查是否标识符,如果是,调用f1函数,如果不是,检查是否是
数值,如果是,调用f1函数,如果不是,检查是否是’(’,如果不是,进行出
错处理,置is_right为0。如果是,调用e函数,返回后检查是否是’)’,如果
不是,进行出错处理,置is_right为0。如果是,调用f1函数,返回。
3 流程图:
主流程图
e函数流程图:
调用t函数
p函数流程图:
t函数流程图:
f函数流程图:
(3) 中间代码生成器
1算法描述:
下面以简单算术表达式语句的翻译为例详细说明算法设计。
实现简单算术表达式的翻译一般采取下列步骤:
i. 分析文法。
ii. 设置一系列语义变量,定义语义过程,语义函数。
iii. 设计算术表达式的递归下降子程序的程序分析算法。
2.函数说明和数据结构:
Strn用来存放临时变量的序号。
temp用来存放数组的下表,在主程序中语法分析结束后,置0.
定义函数newtemp()用于门生一个新的临时变量的名字,具体实现时每
产生一个T,就及时送到符号表中,也可以不进符号表,直接将单词值用整数
码表示。
定义函数siyuan(),输出一个四元式。
定义函数ye() 进行中间代码生成
3主流程图
(4) 较高要求
i. 扩充上述小语言的单词;
ii. 增加语法分析器的功能,能识别条件语句和循环语句等;
iii. 增加中间代码生成器的功能,能产生条件语句和循环语句等的中
间代码(四元式序列)
iv. 增加报错功能;
v. 将中间代码翻译成汇编语言。
其中1,4功能完成;
四.实验程序
#include "stdafx.h"
#include
#include
using namespace std;
#include
#include
#include
int i,j,k,flag,number,status;
/*status which is use to judge the string is keywords or not!*/
char ch;
char words[10] = {" "};
char program[500];
int flags[500]; //存储输入句子
string cnt[500];//标识符
int temp=0; //数组下标
int is_right; //判断输出信息
//-----------------------词法分析-----------------------------
int Scan(char program[])
{
char *keywords[13] = {"void","main","if","then","break","int",
"char","float","include","for","while","printf","scanf"}; //关键字
number=0;
status=0;
j=0;
ch=program[i++];
//遍历
if ((ch >= 'a') && (ch <= 'z' )) //字母
{
while ((ch >= 'a') && (ch <= 'z' ))
{
words[j++]=ch;
ch=program[i++];
}
i--;
words[j++] = '0';
for (k = 0; k < 13; k++)
if (strcmp (words,keywords[k]) == 0) //判断是否为关键字
switch(k)
{
case 0:{
flag = 1;
status = 1;
break;
}
case 1:{
flag = 2;
status = 1;
break;
}
case 2:{
flag = 3;
status = 1;
break;
}
case 3:{
flag = 4;
status = 1;
break;
}
case 4:{
flag = 5;
status = 1;
break;
}
case 5:{
flag = 6;
status = 1;
break;
}
case 6:{
flag = 7;
status = 1;
break;
}
case 7:{
flag = 8;
status = 1;
break;
}
case 8:{
flag = 9;
status = 1;
break;
}
case 9:{
flag = 10;
status = 1;
break;
}
case 10:{
flag = 11;
status = 1;
break;
}
case 11:{
flag = 12;
status = 1;
break;
}
case 12:{
flag = 13;
status = 1;
break;
}
}
if (status == 0)
{
flag = 100; //标识符()
}
}
else if ((ch >= '0') && (ch <= '9')) //数字()
{
number = 0;
while ((ch >= '0' ) && (ch <= '9' ))
{
number = number*10+(ch-'0');
ch = program[i++];
}
flag = 200;
i--;
}
else switch (ch) //运算符和标点符号
{
case '=':{
if (ch == '=')
words[j++] = ch;
words[j] = '0';
ch = program[i++];
if (ch == '=')
{
words[j++] = ch;
words[j] = '0';
flag = 401;
}
else
{
i--;
flag = 402;
}
break;
}
case'>':{
if (ch == '>')
words[j++] = ch;
words[j] = '0';
ch = program[i++];
if (ch == '=')
{
words[j++] = ch;
words[j] = '0';
flag = 403;
}
else
{
i--;
flag = 404;
}
break;
}
case'<':{
if (ch == '<')
words[j++] = ch;
words[j] = '0';
ch = program[i++];
if (ch == '=')
{
words[j++] = ch;
words[j] = '0';
flag = 405;
}
else
{
i--;
flag = 406;
}
break;
}
case'!':{
if (ch == '!')
words[j++] = ch;
words[j] = '0';
ch = program[i++];
if (ch == '=')
{
words[j++] = ch;
words[j] = '0';
flag = 407;
}
else
{
i--;
flag = 408;
}
break;
}
case'+':{
if (ch == '+')
words[j++] = ch;
words[j] = '0';
ch = program[i++];
if (ch == '=')
{
words[j++] = ch;
words[j] = '0';
flag = 409;
}
else if (ch == '+')
{
words[j++] = ch;
words[j] = '0';
flag = 410;
}
else
{
i--;
flag = 411;
}
break;
}
case'-':{
if (ch == '-')
words[j++] = ch;
words[j] = '0';
ch = program[i++];
if (ch == '=')
{
words[j++] = ch;
words[j] = '0';
flag = 412;
}
else if( ch == '-')
{
words[j++] = ch;
words[j] = '0';
flag = 413;
}
else
{
i--;
flag = 414;
}
break;
}
case'*':{
if (ch == '*')
words[j++] = ch;
words[j] = '0';
ch = program[i++];
if (ch == '=')
{
words[j++] = ch;
words[j] = '0';
flag = 415;
}
else
{
i--;
flag = 416;
}
break;
}
case'/':{
if (ch == '/')
words[j++] = ch;
words[j] = '0';
ch = program[i++];
if (ch == '=')
{
words[j++] = ch;
words[j] = '0';
flag = 417;
}
else
{
i--;
flag = 418;
}
break;
}
case'^':{
words[j] = ch;
words[j+1] = '0';
flag = 419;
break;
}
case';':{
words[j] = ch;
words[j+1] = '0';
flag = 501;
break;
}
case'(':{
words[j] = ch;
words[j+1] = '0';
flag = 502;
break;
}
case')':{
words[j] = ch;
words[j+1] = '0';
flag = 503;
break;
}
case'[':{
words[j] = ch;
words[j+1] = '0';
flag = 504;
break;
}
case']':{
words[j] = ch;
words[j+1] = '0';
flag = 505;
break;
}
case'{':{
words[j] = ch;
words[j+1] = '0';
flag = 506;
break;
}
case'}':{
words[j] = ch;
words[j+1] = '0';
flag = 507;
break;
}
case':':{
words[j] = ch;
words[j+1] = '0';
flag = 508;
break;
}
case'"':{
words[j] = ch;
words[j+1] = '0';
flag = 509;
break;
}
case'%':{
if (ch == '%')
words[j++] = ch;
words[j] = '0';
ch = program[i++];
if (ch == '=')
{
words[j++] = ch;
words[j] = '0';
flag = 510;
}
else
{
i--;
flag = 511;
}
break;
}
case',':{
words[j] = ch;
words[j+1] = '0';
flag = 512;
break;
}
case'#':{
words[j] = ch;
words[j+1] = '0';
flag = 513;
break;
}
case'@':{
words[j] = ch;
words[j+1] = '0';
flag = 514;
break;
}
case' '://空格
{
words[j] ='_';
words[j+1] = '0';
flag = 515;
break;
}
case'$':{
words[j] = '#';
words[j+1] = '0';
flag = 0;
break;
}
default:{
flag = -1;
break;
}
}
return flag;
}
//------------------语法分析(递归下降)---------------------------
void e();
void e1();
void e2();
void t();
void t1();
void t2();
void f();
void f1();
void p();
void e()
{
cout<<"E->TE''"< t(); e2(); } void e1() { if(flags[temp]==411) { cout<<"E'->+T"< temp++; t(); } else if(flags[temp]==414) { cout<<"E'->-T"< temp++; t(); } else is_right=0; } void e2() { e1(); e2(); } else if (flags[temp]!=0||flags[temp]!=503) { cout<<"E''->^"< return ; } else is_right=0; } void t() { } void t1() { } void t2() } else is_right=0; temp++; f(); } else if(flags[temp]==418) { cout<<"T'->/F"< temp++; f(); if(flags[temp]==416) { cout<<"T'->*F"< f(); t2(); cout<<"T->FT''"< if(flags[temp]==411||flags[temp]==414){ cout<<"E''->E'E''"< { return ; } else is_right=0; } void f() { } void f1() { { } else if (flags[temp]!=0&&flags[temp]!=503&&flags[temp]!=411&&flags[temp]!=414&&flags[temp]!=416&&fla gs[temp]!=418) { } } void p() { if(flags[temp]==100||flags[temp]==200) { cout<<"P->i"< cout<<"F'->^"< is_right=0; cout<<"F'->^F"< temp++; f(); if(flags[temp]==419) cout<<"F->PF'"< p(); if(flags[temp]==416||flags[temp]==418) { } else if (flags[temp]!=0||flags[temp]!=503) cout<<"T''->^"< cout<<"T''->T'T''"< t1(); t2(); { f1(); temp++; } else if(flags[temp]==502) { cout<<"P->(E)"< temp++; e(); if(flags[temp]==503) { cout<<"P->(E)"< temp++; } else is_right=0; } else is_right =0; } //----------------------语义分析以及中间代码生成----------------------- int ye(); int ye1(int a); int ye2(int a); int yt(); int yt1(int a); int yt2(int a); int yf(); int yf1(int a); int yp(); int v=-1; int num=0; int ww; string strn; int nn; int newTemp() { num++; nn++; stream< stream>>strn; stringstream stream; } (); cnt[num-1]="temp"; //cnt[num-1]=strcat("Temp",strn); // cnt[num-1]="temp"; return num-1; cnt[num-1].operator+=(strn);//把字符串s连接到当前字符串的结尾 void siyuan(int a,int b,int c,int d)//输出四元 { } int ye() { } int ye1(int a) { { } else if(flags[temp]==414) //减法 { temp++; int tt=v+1; v++; int t2=yt(); int rr=newTemp(); siyuan(tt,t1,t2,rr); rt=rr; return rt; temp++; int tt=v+1; v++; int t2=yt(); int rr=newTemp(); siyuan(tt,t1,t2,rr); rt=rr; return rt; int rt,t1; t1=a; int rt,t1; rt=yt(); t1=rt; rt=ye2(t1); return rt; cout<<"("< if(flags[temp]==411) //加法 } else return t1; } int ye2(int a) { { rt=ye1(t1); } else if (flags[temp]!=0||flags[temp]!=503) { return t1; } else return t1; } int yt() { } int yt1(int a) { { return rt; int tt=v+1; v++; temp++; int t2=yf(); int rr=newTemp(); siyuan(tt,t1,t2,rr); int rt,t1; t1=a; int rt,t1; rt=yf(); t1=rt; rt=yt2(t1); return rt; t1=rt; return rt; rt=ye2(t1); int rt,t1; t1=a; if(flags[temp]==411||flags[temp]==414) if(flags[temp]==416) //乘法 rt=rr; } else if(flags[temp]==418) //除法 { return rt; } else return t1; } int yt2(int a) { } int yf() { int t1,rt; t1=rt; int rt,t; t=a; if(flags[temp]==416||flags[temp]==418) { } else return t; rt=yt1(t); t=rt; return rt; temp++; int tt=v+1; v++; int rr=newTemp(); siyuan(tt,t1,t2,rr); rt=rr; int t2=yf(); rt=yt2(t); rt=yp(); rt=yf1(t1); return rt; } int yf1(int a) //乘方 { { temp++; int tt=v+1; int rt,t1; t1=a; if(flags[temp]==419) } v++; int t2=yf(); int rr=newTemp(); siyuan(tt,t1,t2,rr); rt=rr; return rt; else return t1; } int yp() { { v++; rt=v; int rt,t1; if(flags[temp]==100||flags[temp]==200) temp++; return rt; } else if(flags[temp]==502) //( { v++; temp++; rt=ye(); if(flags[temp]==503) //) { v++; temp++; return rt; } else return ww; } else return ww; } void main() { int i=0; cout<<"请输入测试程序或者表达式,以$结束"< do { ch =getchar(); program[i++] = ch; }while(ch != '$'); i = 0; cout<<"词法分析:"< do{ flag = Scan(program);//词法分析 if (flag == 200) { cout<<"("< flags[num]=flag; stringstream stream; stream< (); num++; stream>>cnt[num]; } else if (flag == -1) { cout<<"error!"< } else { cout<<"("< if(flag!=515) { flags[num]=flag; cnt[num]=words; num++; } } }while (flag != 0); flags[num]=0; is_right=1; cout<<"语法分析:"< e(); if((flags[temp]==0)&&is_right) { temp=0; ye(); } cout<<"分析成功"< cout<<"四元式序列:"< else cout<<"分析失败"< system("pause"); } 五 实验结果分析 1.输入一个算术表达式: 2.词法分析结果: 3,语法分析结果: 4四元式生成: 根据实际证明可知,结果是正确的。 六 实验总结 编译原理的编译过程一般包括:词法分析、语法分析、语义分析与中间 代码产生、优化、目标代码生成五个阶段。通过本次设计,要求我们做前3 个阶段,也是最重要的3个阶段。3个子阶段的设计并不是孤立的,这样, 就实现了引导我们在编译系统总体结构的指导下逐渐地完成整个系统的构 建。无论采用哪种方式,在最后一个实验完成后,我们已经开发出一个功能 基本完备的简易编译程序,从而在有限的上机时间内完成了实践。 这次课程设计使我对编译原理有了进一步的了解,更加巩固了所学习的 知识。编译原理是一门比较抽象的课程,也比较难以学得透。从一开始老师 就对我们说,这个课程,如果你不认真去学,你就学不懂;如果你想不听课, 然后自学的话,你肯定会花比人家多很多的时间。确实是这样,现在课程已 经结束了,我庆幸当初听老师的话,比较认真地去听课。即使如此,还是有 很多东西很模糊的。但至少对编译这个概念有一定的了解。由于课堂上的上, 学习的东西比较浅,难免眼高手低,故而,通过实验和课程,遇到了很多课 本上面见不到的问题,完成实验后,个人在成就感的同时,也学习到了编程 的具体过程中的很多知识。 如果要成为一名优秀的软件开发工作者,则这门课程必不可少。它是软件 工程的基础,学好它,对软件的设计有很大的帮助。通过本次的设计,我更加 体会到这一点。刚开始设计的时候,我根本就找不着路。平时的实验老师都有 给出部分代码或者代码,而这次,却是要自己通过学习来完成。在网上找了一 些资料,也参考过别人所写的代码,慢慢开始写。无论如何,当初只是在想, 只要我有得交就是了。后来写着写着,来感觉了,就觉得,其实学习也是一件 挺有趣的事。特别是当自己的代码能运行的时候,那种心情真的特兴奋。尽管 代码并不完善,并且有不足之处,这个实验仍然有很多其他功能可以实现,但 是时间原因,没有全部实现,比如增加语法分析器的功能,能识别条件语句和 循环语句等;增加中间代码生成器的功能,能产生条件语句和循环语句等的中 间代码。如果有时间,暑假期间抽空进行完善。今后我会再次努力学习,然后 把它做得更好。 最后在这里感谢学院和老师给我们提供良好的环境进行本次课程设计。
版权声明:本文标题:编译原理词法语法语义分析器设计 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/p/1714178277a668550.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论