编译原理实验词法分析器的设计与实现.docx
《编译原理实验词法分析器的设计与实现.docx》由会员分享,可在线阅读,更多相关《编译原理实验词法分析器的设计与实现.docx(27页珍藏版)》请在冰豆网上搜索。
编译原理实验词法分析器的设计与实现
南华大学
计算机科学与技术学院
实验报告
(2018~2019学年度第二学期)
课程名称
编译原理
实验名称
词法分析器的设计与实现
姓名
学号
专业
班级
地点
教师
1.实验目的及要求
实验目的
加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。
实验要求
1.对单词的构词规则有明确的定义;
2.编写的分析程序能够正确识别源程序中的单词符号;
3.识别出的单词以<种别码,值>的形式保存在符号表中,正确设计和维护符号表;
4.对于源程序中的词法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成整个源程序的词法分析;
2.实验步骤
1.词法分析规则
<标识符>:
:
=<字母>|<标识符><字母>|<标识符><数字>
<常数>:
:
=<数字>|<数字序列><数字>
<数字序列>:
:
=<数字序列><数字>|<数字>|<.>
<字母>:
:
=a|b|c|……|x|y|z
<数字>:
:
=0|1|2|3|4|5|6|7|8|9
<运算符>:
:
=<关系运算符>|<算术运算符>|<逻辑运算符>|<位运算符>|<赋值运算符>
<算数运算符>:
:
=+|-|*|/|...|--
<关系运算符>:
:
=<|>|!
=|>=|<=|==
<逻辑运算符>:
:
=&&||||!
<位运算符>:
:
=&|||!
<赋值运算符>:
:
==|+=|-=|/=|*=
<分界符>:
:
=,|;|(|)|{|}|:
|//|/**/
<保留字>:
:
=main|if|else|while|do|for|...|void
2.单词符号的编码
单词符号
种别码
单词符号
种别码
main
0
>
26
if
1
>=
27
else
2
<
28
while
3
<=
29
do
4
!
30
for
5
!
=
31
switch
6
=
32
case
7
==
33
int
8
(
34
double
9
)
35
float
10
{
36
long
11
}
37
void
12
;
38
+
13
:
39
+=
14
|
40
++
15
||
41
-
16
数字
42
-=
17
标识符
43
--
18
44
&
19
//
45
&&
20
/**/
46
#
21
*
22
*=
23
/
24
/=
25
3.状态转换图
......
&
;
(
{
}
,
:
)
33
其它
=
其它
>
+
其它
*
/
=
其它
4.算法分析
①词法分析器工作的第一步是输入源程序文本。
为了更好地对单词符号识别,把输入串预处理一下。
预处理主要滤掉空格,跳过注释、换行符等。
②对预处理后的输入串依次扫描单个字符,使用if-while嵌套语句和switchcase语句判断字符的类型,具体识别方法可看状态转换图。
有时为了确定词性,需要超前扫描,若超前扫描的字符对识别当前单词无用处,则需要退还给输入串,以备识别下一单词字符时使用。
③若读入的字符与单词符号编码表的字符匹配不上,则报错,并输出出错行数。
对识别处的单词符号以(单词符号,种别码)二元式的形式输出。
3.实验内容
1.流程图
2.程序的变量与函数说明
(1)input
全局字符数组,用来存放输入串
(2)word
全局字符数组,用来存放获取到的单词符号,限定长度为8
(3)ch
全局字符变量,用来存放最新读入的字符
(4)syn
全局整型变量,表示单词符号的编码
(5)p
全局整型变量,表示当前字符在input数组的位置
(6)m
全局整型变量,表示最新读入的字符在word数组的下标
(7)line
全局整型变量,当前行数
(8)keyword
全局字符数组,存放关键字
(9)init()
获取输入串
(10)isKey()
判断关键字的函数,若参数数组中是关键字,则把syn置为该关键字对应的编码并返回1,否则返回0
(11)isLetter()
判断字母的函数,若参数字符是字母,则返回1,否则返回0
(12)isDigit()
判断数字的函数,若参数字符是数字,则返回1,否则返回0
(13)isSpace()
判断空白符的函数,若参数字符是空格、TAB或换行符,则返回1,否则返回0
(14)scaner()
扫描输入串的函数,对读出的字符进行判断,若是单词符号表中的符号,则将syn置为对应的编码
3.源程序
#include
#include
charinput[1000];//输入串
charword[8];//获取到的单词
charch;
intsyn;//种别码
intp;
intm;
intline;//行数
//关键字
charkeyword[][8]={"main","if","else","while","do","for","switch","case","int","double","float","long","void"};
voidscaner(void);
//获取输入串
voidinit()
{
inti=0;
printf("\npleaseinputastring(endwith'#'):
\n");
do{
scanf("%c",&ch);
input[i++]=ch;
}while(ch!
='#');
}
//判断是不是关键字
intisKey(char*str)
{
intn;
for(n=0;n<13;n++)
{
if(strcmp(str,keyword[n])==0)
{
syn=n;
return1;
}
}
return0;
}
//判断是不是数字
intisDigit(charc)
{
if(c>='0'&&c<='9')
return1;
else
return0;
}
//判断是不是字母
intisLetter(charc)
{
if((c<='z'&&c>='a')||(c>='A'&&c<='Z'))
return1;
else
return0;
}
intisSpace(charc)
{
if(c==''||c=='\t'||c=='\n')
{
return1;
}
return0;
}
voidmain()
{
init();//输入字符串
line=0;
p=0;
do{
scaner();
switch(syn)
{
case-1:
printf("youhaveinputawrongstringinline%d\n",line);
break;
default:
printf("(%s,%d)\n",word,syn);
break;
}
}while(syn!
=21);
}
voidscaner(void)
{
//清空word
for(m=0;m<8;m++)
{
word[m]='';
}
//读取字符
ch=input[p++];
m=0;
//当ch为空格或换行符时,继续往下读
while(isSpace(ch))
{
if(ch=='\n')
{
line++;
}
ch=input[p++];
}
//如果以字母开头
if(isLetter(ch))
{
//如果往后是字母或数字,把字符存入word中,然后往下继续读
//串长超过8则截断
while((isLetter(ch)||isDigit(ch))&&m<8)
{
word[m++]=ch;
ch=input[p++];
}
p--;
syn=43;
word[m++]='\0';
isKey(word);//判断是不是关键字
}
//如果是以数字开头,并且往后是数字
elseif(isDigit(ch))
{
while((isDigit(ch)||ch=='.')&&m<8)
{
word[m++]=ch;
ch=input[p++];
}
//如果数字之后是字母,则出错
if(isLetter(ch))
{
while(!
isSpace(ch))
{
ch=input[p++];
}
syn=-1;
return;
}
p--;
syn=42;
}
else
{
switch(ch)
{
//比较运算符
case'<':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=29;
word[m++]=ch;
}
else
{
syn=28;
p--;
}
break;
case'>':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=27;
word[m++]=ch;
}
else
{
syn=26;
p--;
}
break;
case'!
':
ch=input[p++];
if(ch=='=')
{
syn=31;
word[m++]=ch;
}
else
{
syn=30;
p--;
}
break;
case'=':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=33;
word[m++]=ch;
}
else
{
syn=32;
p--;
}
break;
//算术运算符+、-、*、/
case'+':
word[m++]=ch;
ch=input[p++];
if(ch=='+')
{
syn=15;
word[m++]=ch;
}
elseif(ch=='=')
{
syn=14;
word[m++]=ch;
}
else
{
syn=13;
p--;
}
break;
case'-':
word[m++]=ch;
ch=input[p++];
if(ch=='-')
{
syn=18;
word[m++]=ch;
}
elseif(ch=='=')
{
syn=17;
word[m++]=ch;
}
elseif(isDigit(ch))
{
while(isDigit(ch))
{
word[m++]=ch;
ch=input[p++];
}
p--;
syn=42;
}
else
{
syn=16;
p--;
}
break;
case'*':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=23;
word[m++]=ch;
}
else
{
syn=22;
p--;
}
break;
case'/':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=25;
word[m++]=ch;
}
//如果是单行注释,则读到换行符为止
elseif(ch=='/')
{
word[m++]=ch;
syn=45;
while(ch!
='\n')
{
ch=input[p++];
}
line++;
}
//如果是多行注释,则读到匹配的*/为止
elseif(ch=='*')
{
word[m++]=ch;
syn=46;
intflag=1;
while(flag)
{
ch=input[p++];
if(ch=='*')
{
if(input[p++]=='/')
{
word[m++]='*';
word[m++]='/';
flag=0;
}
else
{
p--;
}
}
if(ch=='\n')
{
line++;
}
}
}
else
{
syn=24;
p--;
}
break;
//界符
case'(':
syn=34;
word[m++]=ch;
break;
case')':
syn=35;
word[m++]=ch;
break;
case'{':
syn=36;
word[m++]=ch;
break;
case'}':
syn=37;
word[m++]=ch;
break;
case';':
syn=38;
word[m++]=ch;
break;
case'#':
syn=21;
word[m++]=ch;
break;
case':
':
syn=39;
word[m++]=ch;
break;
case',':
syn=44;
word[m++]=ch;
break;
//逻辑运算符
case'&':
word[m++]=ch;
ch=input[p++];
if(ch=='&')
{
syn=20;
word[m++]=ch;
}
else
{
syn=19;
p--;
}
break;
case'|':
word[m++]=ch;
ch=input[p++];
if(ch=='|')
{
syn=41;
word[m++]=ch;
}
else
{
syn=40;
p--;
}
break;
default:
syn=-1;
break;
}
}
//字符串结束符
word[m++]='\0';
}
4.实验结果
因为printf和""不是单词符号表中的符号,因而判定输入有错
5.实验总结分析
这个程序实现了对所选词法子集的单词识别,并对识别出的单词以二元式的形式输出,对于存在的一些词法错误,能够做出简单的错误处理,比如,若标识符以数字开头或单词符号在符号表中不存在,则输出错误信息,并给出行号;同时该程序也能清除掉源程序中的注释,识别出实型常数。
当然,由于能力不足,该程序还存在着一些瑕疵,存在着对以数字开头的标识符的错误的处理不够全面,注释内容不能保存下来、对以\开头的字符串的识别不够全面等问题。
在设计和实现算法的过程中,我渐渐地弄懂了自己之前不懂的知识,理解了状态转换图中的状态是如何转换的,每个单词是怎样识别出来的。
总而言之,这次实验加深了我对词法分析原理的理解,加深了对词法分析器的工作过程的认识,使我熟练掌握了扫描和分析源程序中各类单词的方法,对编译原理的深入学习有很大的帮助。