课程设计 C语言子集的词法分析程序.docx
《课程设计 C语言子集的词法分析程序.docx》由会员分享,可在线阅读,更多相关《课程设计 C语言子集的词法分析程序.docx(26页珍藏版)》请在冰豆网上搜索。
课程设计C语言子集的词法分析程序
**大学
计算机科学与技术学院
实验报告
(2007~2008学年度第1学期)
课程名称
编译原理
实验名称
C语言子集的词法分析程序
姓名
学号
专业
班级
地点
教师
一.实验目的及要求
1、目的:
通过设计、编制、调试一个具体的词法分析程序,加深对词法分析原理的理解,并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法.
2、软、硬件环境:
windowsxp,MicrosoftvisualC++.
二.实验步骤
1、原理分析,单词符号一般分为关键字、标识符、常数、运算符、界符号五种。
对于一个具体源程序而言,在扫描字符串时识别出一个单词,若这个单词的类型是以上五种中之一,那么就以单词的二元式形式输出。
每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直到整个源程序全部扫描完毕,从而形成相应的单词串。
各类单词的二元式表述均具有相同的结构与长度,形式如下:
(单词种别t,单词自身的值i)
t是单词种别,而单词种别共分为五类且每类对应一张表格.
所以整个的词法分析过程就是从源程序中获得一个个的单词符号,将这些符号分别填入五张类表中,并且有一个二元式序列构成一个索引,这个索引为以后的语法分析提供处理上的方便.
为了方便期间本程序中引用了Const.txt常量表Sign.txt标识符(32个)表。
在这里将主要的保留字及标识符作一个列举(放在一个表中)。
Keyform
单词种别t
单词符号i
单词种别t
单词符号i
单词种别t
单词符号i
1
auto
21
short
41
{
2
break
22
sizeof
42
}
3
case
23
static
43
[
4
char
24
struct
44
]
5
const
25
switch
45
?
6
continue
26
union
46
:
7
default
27
unsigned
47
‘’
8
do
28
void
48
“”
9
double
29
while
49
;
10
else
30
typedef
50
.
11
enum
31
volatile
51
!
12
extern
32
signed
52
#
13
float
33
+
53
<
14
for
34
-
54
>
15
goto
35
=
55
|
16
if
36
*
56
&&
17
int
37
%
57
==
18
long
38
(
58
<=
19
register
39
)
59
-=
20
return
40
\
60
!
=
2、编写源程序代码。
本程序用c语言实现。
此程序采用一缓冲方式读入程序源码,首先进行预处理去掉注释和无效空格。
然后再进行详细的词法分析,为了便于后续处理,程序设置了几个表:
符号表和常数表。
3、调试程序。
三.实验内容
1、流程图
2、程序
#include
#include
#include
#include
#include
#defineKEYWORD_LEN32//保留字个数
#defineSTR_MAX_LEN300//标识符最大长度
#definePRO_MAX_LEN20480//源程序最大长度
#defineSTB_MAX_LEN1000//符号表最大容量
#defineCTB_MAX_LEN1000//常数表最大容量
#defineERROR0//错误
#defineID(KEYWORD_LEN+1)//标识符
#defineCONST(KEYWORD_LEN+2)//常量
#defineOPERAT(KEYWORD_LEN+3)//运算符
#defineDIVIDE(KEYWORD_LEN+4)//界符
interrorLine=0;
charproBuffer[PRO_MAX_LEN]="";//存储程序代码的全局缓冲区
charch;//读出来的当前字符
charwordget[STR_MAX_LEN];//标识符或常量
intpoint=0;//源程序当前位置指针
charsignTab[STB_MAX_LEN][STR_MAX_LEN];//符号表
intpointSTB=0;//符号表指针
charconstTab[CTB_MAX_LEN][STR_MAX_LEN];//常量表
intpointCTB=0;//常数表指针
charkwTab[KEYWORD_LEN][10]={//保留字表C语言一共有32个保留字[关键字]
"auto","break","case","char","const",
"continue","default","do","double","else",
"enum","extern","float","for","goto",
"if","int","long","register","return",
"short","signed","sizeof","static","struct",
"switch","typedef","union","unsigned","void",
"volatile","while"};
charerrorTab[][50]={//错误代码表
/*0*/"未知错误",/*1*/"非法的字符",/*2*/"不正确的字符常量表达",
/*3*/"不正确的字符串表达",/*4*/"不正确的数字表达",/*5*/"注释丢失'*/'"};
typedefstructsignDuality
{
intkind;
intvalue;
}*pDualistic,Dualistic;
voidpretreatment();//预处理
voidProcError(intid);//错误
boolGetChar();//获得一个字符不包括结束标记
boolGetBC();//获得一个非空白字符
voidConcat(char*str);//将ch连接到str后
intReserve(char*str);//对str字符串查找保留字表若是一个保留字-返回其编码否则返回0
voidRetract();//将搜索指示器回调一个字符位置
intInsertId(char*str);//将str串以标识符插入符号表,并返回符号表指针
intInsertConst(char*str);//将str串以常数插入符号表,并返回常数表指针
boolwordAnalyse(pDualisticpDu);//词法分析true正常
//预处理将缓冲区内的源代码去掉注释和无效空格
voidpretreatment()
{intlines=0;
chartmp[PRO_MAX_LEN];//先将处理结果保存到临时空间
inttmpp=0;//这个临时空间的末尾指针
boolflg;
chartmpc;
//去掉注释先
//注释有两种一种是//另一种是/**/
point=0;
do
{
flg=GetChar();
if(ch=='/')
{
flg=GetChar();
switch(ch)
{
case'/':
do
{
flg=GetChar();
}while(!
(ch=='\n'||flg==false));//注释一直到行尾或文件结束
if(ch=='\n')
Retract();//归还换行
break;
case'*':
do
{
flg=GetChar();
tmpc=ch;
//为了保证出错处理程序能正确定位出错位置保留注释中的换行
if(tmpc=='\n')
tmp[tmpp++]=tmpc;
flg=GetChar();
Retract();//归还一个字符
}while(flg&&!
(flg&&tmpc=='*'&&ch=='/'));
flg=GetChar();
if(!
flg)
{
ProcError(5);
}
break;
default:
//不是任何一种注释
Retract();
Retract();
GetChar();
tmp[tmpp++]=ch;
flg=GetChar();
tmp[tmpp++]=ch;
}
}
else
{
tmp[tmpp++]=ch;
}
}while(flg);
tmp[tmpp]='\0';
strcpy(proBuffer,tmp);
}
//错误
voidProcError(intid)
{
printf("\nError:
第%d行,%s\n",errorLine,errorTab[id]);
}
//获得一个字符
boolGetChar()
{
if(point='\0')
{//如果当前下标合法且当前字符为结束标记则取字符增游标
ch=proBuffer[point++];
if(ch=='\n')
errorLine++;
returntrue;
}
ch='\0';
returnfalse;
}
//获得一个非空白字符
boolGetBC()
{
do
{
if(!
GetChar())//获取字符失败
{
ch='\0';
returnfalse;
}
}while(isspace(ch));//直到获得一个非空白字符
returntrue;
}
//将ch连接到str后
voidConcat(char*str)
{
inti;
for(i=0;str[i];++i);
str[i]=ch;
str[i+1]='\0';
}
//对str字符串查找保留字表若是一个保留字-返回其编码否则返回0
intReserve(char*str)
{
inti;
for(i=0;i{
if(0==strcmp(kwTab[i],str))
returni+1;//注意,这里加一原因是0值被错误标记占用
}
return0;
}
//将搜索指示器回调一个字符位置
voidRetract()///char*ch
{
if(proBuffer[point]=='\n'&&errorLine>0)
errorLine--;
point--;
}
//将str串以标识符插入符号表,并返回符号表指针
intInsertId(char*str)
{
inti;
for(i=0;iif(0==strcmp(signTab[i],str))
returni;
strcpy(signTab[pointSTB++],str);
return(pointSTB-1);
}
//将str串以常数插入常量表,并返回常数表指针
intInsertConst(char*str)
{
inti;
for(i=0;iif(0==strcmp(constTab[i],str))
returni;
strcpy(constTab[pointCTB++],str);
return(pointCTB-1);
}
//词法分析false--分析结束
boolwordAnalyse(pDualisticpDu)
{
intcode,value;
charjudge;//这里有个技巧借用此变量巧妙的运用SWITCH结构
inti=0;//辅助
GetBC();
judge=ch;
if(isalpha(ch)||ch=='_')judge='L';
if(isdigit(ch))judge='D';
switch(judge)
{
case'L':
while(isalnum(ch)||ch=='_')
{//标识符
wordget[i++]=ch;
GetChar();
}
wordget[i]='\0';
Retract();//回退一个字符
code=Reserve(wordget);
if(code==0)
{
value=InsertId(wordget);
pDu->kind=ID;
pDu->value=value;
}
else
{
pDu->kind=code;
pDu->value=-1;
}
returntrue;
case'D':
while(isdigit(ch))
{
wordget[i++]=ch;
GetChar();
}
wordget[i]='\0';
Retract();
value=InsertConst(wordget);
pDu->kind=CONST;
pDu->value=value;
returntrue;
//( ) [ ] . , !
!
= ~ sizeof < << <= > >> >= = == & && &= | || |= ?
:
+ ++ +=
// - -> -- -= * *= / /= % %= >>= <<= ^ ^=
case'"':
//字符串常量
do
{
wordget[i++]=ch;
GetChar();
}while(ch!
='"'&&ch!
='\0');
wordget[i++]=ch;wordget[i]='\0';
if(ch=='\0')
{
printf("%s",wordget);
ProcError(3);
pDu->kind=ERROR;
pDu->value=0;
}
else
{
value=InsertConst(wordget);
pDu->kind=CONST;
pDu->value=value;
}
returntrue;
//字符常量
case'\'':
wordget[i++]=ch;//'
GetChar();
wordget[i++]=ch;
if(ch=='\\')//'\n'
{//如果是转义字符则要多接收一个字符
GetChar();//ch='
wordget[i++]=ch;
}
GetChar();
wordget[i++]=ch;
wordget[i]='\0';
if(ch!
='\'')
{//'\b'
printf("%s",wordget);
ProcError
(2);
pDu->kind=ERROR;
pDu->value=0;
}
else
{
value=InsertConst(wordget);
pDu->kind=CONST;
pDu->value=value;
}
returntrue;
case'(':
case')':
case'[':
case']':
case'.':
case',':
case'~':
case'?
':
case':
':
case';':
case'{':
case'}':
case'#':
wordget[i++]=ch;wordget[i]='\0';
pDu->kind=DIVIDE;//界符
pDu->value=-1;
returntrue;
case'!
':
//!
=
wordget[i++]=ch;
GetChar();
if(ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'<':
//<<<=
wordget[i++]=ch;
GetChar();
if(ch=='<'||ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'>':
//>>>=
wordget[i++]=ch;
GetChar();
if(ch=='>'||ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'=':
//==
wordget[i++]=ch;
GetChar();
if(ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'&':
//&&&=
wordget[i++]=ch;
GetChar();
if(ch=='&'||ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'|':
//|||=
wordget[i++]=ch;
GetChar();
if(ch=='|'||ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'+':
//+++=
wordget[i++]=ch;
GetChar();
if(ch=='+'||ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'-':
//---=->
wordget[i++]=ch;
GetChar();
if(ch=='-'||ch=='='||ch=='>')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'*':
//***=
wordget[i++]=ch;
GetChar();
if(ch=='*'||ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'/':
///=
wordget[i++]=ch;
GetChar();
if(ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'%':
//%=
wordget[i++]=ch;
GetChar();
if(ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'^':
//^=
wordget[i++]=ch;
GetChar();
if(ch=='=')wordget[i++]=ch;
elseRetract();
wordget[i]='\0';
break;
case'\0':
returnfalse;
default:
ProcError
(1);
returnfalse;
}
pDu->kind=OPERAT;
returntrue;
}
intmain()
{
Dualistictmp;
pDualisticptmp=&tmp;
FILE*fin,*fout;
inti;
charc;
charfilename[20];
printf("源代码读入\n");
//scanf("%s",filename);
//将源程序读入缓冲区
if((fin=fopen("Test.txt","r"))==NULL)
{
printf("Cannotopeninfile\n");
return0;
}
i=0;
//c=fgetc(fin);
while((c=fgetc(fin))!
=EOF)
{
if(i>=PRO_MAX_LEN-1)
{
printf("\n程序代码太长,无法处理\a");
return0;
}
proBuffer[i++]=c;
}
fclose(fin);//关闭文件
proBuffer[i++]='\0';
printf("\n***************************\n源代码读入成功,源代码如下:
\n%s",proBuffer);
printf("\n按任意键继续\n");
getch();
//预处理
printf("\n预处理\n");
pretreatment();
printf("\n***************************\n预处