资源描述
南华大学
计算机科学与技术学院
实 验 报 告
( ~ 第二学期 )
课程名称
编译原理
实验名称
词法分析器设计与实现
姓名
学号
专业
班级
地点
教师
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.状态转换图
2
字母
非字母与数字
1
字母与数字
0
空白
4
数字
非数字
数字
3
8
/
6
11
+
10
=
12
!
13
=
15
其他
34
18
<
其他
17
19
21
......
&
;
,
(
{
}
,
:
)
33
其他
22
20
=
其他
>
16
14
+
其他
7
9
*
/
=
其他
5
4.算法分析
①词法分析器工作第一步是输入源程序文本。为了更好地对单词符号辨认,把输入串预解决一下。预解决重要滤掉空格,跳过注释、换行符等。
②对预解决后输入串依次扫描单个字符,使用if-while嵌套语句和switch case语句判断字符类型,详细辨认办法可看状态转换图。有时为了拟定词性,需要超前扫描,若超前扫描字符对辨认当前单词无用处,则需要退还给输入串,以备辨认下一单词字符时使用。
③若读入字符与单词符号编码表字符匹配不上,则报错,并输出出错行数。对辨认处单词符号以(单词符号,种别码)二元式形式输出。
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 <stdio.h>
#include <string.h>
char input[1000];//输入串
char word[8];//获取到单词
char ch;
int syn;//种别码
int p;
int m;
int line;//行数
//核心字
char keyword[][8]={"main","if","else","while","do","for","switch","case","int","double","float","long","void"};
void scaner(void);
//获取输入串
void init()
{
int i=0;
printf("\n please input a string(end with '#'):\n");
do{
scanf("%c",&ch);
input[i++]=ch;
}while(ch!='#');
}
//判断是不是核心字
int isKey(char *str)
{
int n;
for(n=0;n<13;n++)
{
if(strcmp(str,keyword[n])==0)
{
syn=n;
return 1;
}
}
return 0;
}
//判断是不是数字
int isDigit(char c)
{
if (c>='0'&&c<='9')
return 1;
else
return 0;
}
//判断是不是字母
int isLetter(char c)
{
if ((c<='z'&&c>='a')||(c>='A'&&c<='Z'))
return 1;
else
return 0;
}
int isSpace(char c)
{
if (c==' '||c=='\t'||c=='\n')
{
return 1;
}
return 0;
}
void main()
{
init();//输入字符串
line=0;
p=0;
do{
scaner();
switch(syn)
{
case -1:
printf("you have input a wrong string in line %d\n",line);
break;
default:
printf("( %s,%d )\n",word,syn);
break;
}
}while(syn!=21);
}
void scaner(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);//判断是不是核心字
}
//如果是以数字开头,并且往后是数字
else if(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;
}
else if(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;
}
else if(ch=='=')
{
syn=17;
word[m++]=ch;
}
else if (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;
}
//如果是单行注释,则读到换行符为止
else if (ch=='/')
{
word[m++]=ch;
syn=45;
while (ch!='\n')
{
ch=input[p++];
}
line++;
}
//如果是多行注释,则读到匹配*/为止
else if(ch=='*')
{
word[m++]=ch;
syn=46;
int flag=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. 实验总结分析
这个程序实现了对所选词法子集单词辨认,并对辨认出单词以二元式形式输出,对于存在某些词法错误,可以做出简朴错误解决,例如,若标记符以数字开头或单词符号在符号表中不存在,则输出错误信息,并给出行号;同步该程序也能清除掉源程序中注释,辨认出实型常数。固然,由于能力局限性,该程序还存在着某些瑕疵,存在着对以数字开头标记符错误解决不够全面,注释内容不能保存下来、对以\开头字符串辨认不够全面等问题。
在设计和实现算法过程中,我徐徐地弄懂了自己之前不懂知识,理解了状态转换图中状态是如何转换,每个单词是如何辨认出来。综上所述,这次实验加深了我对词法分析原理理解,加深了对词法分析器工作过程结识,使我纯熟掌握了扫描和分析源程序中各类单词办法,对编译原理进一步学习有很大协助。
展开阅读全文