编译原理课程设计.docx
《编译原理课程设计.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计.docx(12页珍藏版)》请在冰豆网上搜索。
编译原理课程设计
课程论文
学年学期2017—2018学年第一学期
课程名称编译原理课程设计
题目词法分析
姓名
学号
学院计算机科学与信息工程学院
任课教师
词法分析
摘要:
在网络世界中,我们往往对功能强大的程序叹为观止。
而这些强大程序的背后是编译这些程序的编译软件,是这些编译软件承托起了这些功能强大的运行程序。
我们有不少的同志致其自身于无尽的运行程序上。
而只有很少的人搞编译程序。
这就是为什么中国的可运行程序满天飞,而编译程序却很少。
本课程设计就是在这方面的探索,为你解读编译程序的奥秘。
关键词:
词法,字符,数字,标识符
一、实验目的
在学习《编译原理》课程设计中,结合各章节的构造编译程序的基本理论,总共用20学时的时间完成课程设计。
要求用C或java语言描述及上机调试,实现词法分析器的设计,是将理论与实际应用结合起来,受到软件设计等开发过程的全面训练,从而提高我们的软件开发的能力。
二、实验要求
词法分析器的设计:
状态转换图,简称转换图,是设计词法分析器的有效工具。
状态转换图是有限有向图,图中的结点代表状态,结点间的有向边代表状态之间的转换关系,有向边上标记的字符表示状态转换的条件。
状态的数量是有限的,其中必有一个初始状态,若干个终止状态。
大部分终止状态可对应一类单词符号的成功识别,所以也被成为识别状态。
在识别状态下,可以给出相应单词的类别编码和属性值。
某些终止状态是在多识别了一个字符后才成为识别状态的,对于这种情况,多识别的字符应予以退回,在终态上标以“*”作为区别。
有了状态转换图后,就可以方便地设计和实现词法分析器了。
下面以一个简单的程序语言的词法分析器为例作为介绍。
表中列出了该语言的所有单词符号及其编码,其中助记符是用于方便书写和记忆的。
2.1待分析的简单词法
1、标识符
用来命名程序中出现的变量、数组、函数、过程、标号等,通常是一个字母开头的字母数字串,如length,nextch等。
2、基本字
也可以成为关键字或保留字。
如if,while,for,do,goto等。
他们具有标识符的形式,但他们不是由用户而是由语言定义的,其意义是约定的。
多数语言中规定,他们不能作为标识符或者标识符的前缀,即用户不能使用它们来定义用户使用的名字,故我们称它为保留字,这些语言如Pascal和C等。
但也有的语言允许将基本字作为标识符或者标识符的前缀,这类语言如Fortran等。
3、常数
包括各种类型的常数,如整型、实型、字符型、布尔型等。
如:
5、3.1415926、’a’、TRUE等都是常数。
4、运算符
算术运算符+、-、×、÷;关系运算符<,<=,>,>=,==,!
=等。
5、界符
如’,’、’;’等界符。
2.2各种单词符号对应的简单编码
表2.2-1
2.3词法分析程序的功能
1.具备预处理功能。
将不翻译的注释等符号先滤掉,只保留要翻译的符号串,即要求设计一个供词法分析调用的预处理子程序;
2.能够拼出语言中的各个单词;
3.将拼出的标识符填入符号表;
4.返回(种别码,属性值)。
2.4识别语言单词的状态转换图
图2.4-1
三、词法分析程序的算法思想
词法分析子程序名为getsyn,功能是从源程序中读出一个单词符号(token),把它的信息放入全局变量syn、id和num中,语法分析器需要单词时,直接从这三个变量中获得。
(语法分析器每次用完这三个变量的值就立即调用getsyn子程序获取新的单词供下一次使用。
而不是在需要新单词时才调用getsyn过程。
)getsyn过程通过反复调用getch子过程从源程序过获取字符,并把它们拼成单词。
getch过程中使用了行缓冲区技术以提高程序运行效率。
词法分析器的分析过程:
调用getsyn时,它通过getch过程从源程序中获得一个字符。
如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把syn变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把syn置为ident,把这个单词存入id变量。
查保留字表时使用了二分法查找以提高效率。
如果getch获得的字符是数字,则继续用getch获取数字,并把它们拼成一个整数,然后把syn置为number,并把拼成的数值放入num变量。
如果识别出其它合法的符号(比如:
赋值号、大于号、小于等于号等),则把syn则成相应的类型。
如果遇到不合法的字符,把syn置成nul。
图3.1-1
四、运行结果
4.1正确的输入(test.in)及结果
1.hstBeginx:
=10;hstIfx>0;hstThenx:
=5/x-2*3;hstEnd#
2.figures10and11saidOtherindicators
3.figures10and11saidOperators
图4.1-1
图4.1-2
4.2有误的输入及结果
五、源程序
#include
#include
#include
#include
#definegetchgetchar
charprog[80]={'\0'};
chartoken[8];
charch;
intsyn;
intn;
intsum;
intm,p;
char*rwtab[6]={"hstBegin","hstIf","hstThen","hstWhile","hstDo","hstEnd"};
voidscaner(){
m=0;
sum=0;
for(n=0;n<8;n++)
token[n]='\0';
ch=prog[p++];
while(ch=='')
ch=prog[p++];
if(isalpha(ch)){
while(isalpha(ch)||isdigit(ch)){
token[m++]=ch;
ch=prog[p++];}
token[m++]='\0';
ch=prog[p--];
syn=10;
for(n=0;n<6;n++)
if(strcmp(token,rwtab[n])==0){
syn=n+1;
break;}}
else
if(isdigit(ch)){
while(isdigit(ch)){
sum=sum*10+ch-'0';
ch=prog[p++];}
ch=prog[p--];
syn=3111;}
else
switch(ch){
case'<':
m=0;token[m++]=ch;ch=prog[p++];
if(ch=='>'){
syn=3119;
token[m++]=ch;}
elseif(ch=='='){
syn=3122;
token[m++]=ch;}
else{
syn=3120;
ch=prog[p--];}
break;
case'>':
m=0;token[m++]=ch;ch=prog[p++];
if(ch=='='){
syn=3122;
token[m++]=ch;}
else{
syn=3123;
ch=prog[p--];}
break;
case':
':
m=0;token[m++]=ch;ch=prog[p++];
if(ch=='='){
syn=3127;
token[m++]=ch;}
else{
syn=3117;
ch=prog[p--];}
break;
case'+':
syn=3113;token[0]=ch;break;
case'-':
syn=3114;token[0]=ch;break;
case'*':
syn=3115;token[0]=ch;break;
case'/':
syn=3116;token[0]=ch;break;
case')':
syn=3118;token[0]=ch;break;
case'=':
syn=3124;token[0]=ch;break;
case';':
syn=3125;token[0]=ch;break;
case'(':
syn=3126;token[0]=ch;break;
case'#':
syn=3100;token[0]=ch;break;
case'{':
syn=3128;token[0]=ch;break;
case'}':
syn=3129;token[0]=ch;break;
default:
syn=-1;}}
intmain()
{
p=0;
printf("\npleaseinputstring:
\n");
do{
ch=getchar();
prog[p++]=ch;
}while(ch!
='#');
p=0;
do{
scaner();
switch(syn){
case3111:
printf("(%d,%d)\n",syn,sum);break;
case-1:
printf("\nERROR;\n");break;
default:
printf("(%d,%s)\n",syn,token);
}
}while(syn!
=0);
getch();
}