北邮 编译原理 词法分析.docx
《北邮 编译原理 词法分析.docx》由会员分享,可在线阅读,更多相关《北邮 编译原理 词法分析.docx(27页珍藏版)》请在冰豆网上搜索。
北邮编译原理词法分析
实验报告
编译原理与技术
ytinrete
程序设计1
题目:
词法分析程序的设计与实现。
实验内容:
设计并实现C语言的词法分析程序,要求如下。
(1)、可以识别出用C语言编写的源程序中的每个单词符号,并以记号的形式输出每个单词符号。
(2)、可以识别并读取源程序中的注释。
(3)、可以统计源程序汇总的语句行数、单词个数和字符个数,其中标点和空格不计算为单词,并输出统计结果
(4)、检查源程序中存在的错误,并可以报告错误所在的行列位置。
(5)、发现源程序中存在的错误后,进行适当的恢复,使词法分析可以继续进行,通过一次词法分析处理,可以检查并报告源程序中存在的所有错误。
实验要求:
方法1:
采用C/C++作为实现语言,手工编写词法分析程序。
方法2:
通过编写LEX源程序,利用LEX软件工具自动生成词法分析程序。
算法思路:
首先通过遍历,统计行号和字符数,并记录所有的注释。
其次,再次读取,利用一个字符数组作为buffer保存一行的数据,在对其中的数据进行处理,完成之后再读下一行,跳过注释。
对于整行数据的处理,依靠空格将其分成单个单词再具体处理。
对于查错问题实在是一个难题,只能根据一些规则判定有错并记录。
程序源代码:
//假设源程序存在相对路径下名为data.c
/*
Name:
词法分析程序
Author:
李睿
Date:
23/10/1300:
40
Description:
题目:
词法分析程序的设计与实现。
(1)、可以识别出用C语言编写的源程序中的每个单词符号,并以记号的形式输出每个单词符号。
(2)、可以识别并读取源程序中的注释。
(3)、可以统计源程序汇总的语句行数、单词个数和字符个数,其中标点和空格不计算为单词,并输出统计结果
(4)、检查源程序中存在的错误,并可以报告错误所在的行列位置。
(5)、发现源程序中存在的错误后,进行适当的恢复,使词法分析可以继续进行,通过一次词法分析处理,可以检查并报告源程序中存在的所有错误。
实验要求:
方法1:
采用C/C++作为实现语言,手工编写词法分析程序。
方法2:
通过编写LEX源程序,利用LEX软件工具自动生成词法分析程序。
*/
#include
#include
#include
#include
#include
usingnamespacestd;
constintMAX_INPUT_BUFFER=512;//默认输入缓存区
ifstreamfile;//打开文件
vectorkeyword;//预先记录关键字
vectorcomment;//存储注释
vectorid;//记录标示符
vectorpre;//预处理文件
intsum_char=0;//字符数
intsum_word=0;//单词数
intsum_line=0;//行数
intcurrent_line=0;//当前行数
boolin_comment=false;//标识此行是否在注释中
charbuffer[MAX_INPUT_BUFFER];//缓存区
intbig_bracket=0;//大括号
intsmall_bracket=0;//小括号
voidinit(void)//初始化关键字
{
keyword.clear();
keyword.push_back("auto");
keyword.push_back("break");
keyword.push_back("case");
keyword.push_back("char");
keyword.push_back("const");
keyword.push_back("continue");
keyword.push_back("default");
keyword.push_back("do");
keyword.push_back("double");
keyword.push_back("else");
keyword.push_back("enum");
keyword.push_back("extern");
keyword.push_back("float");
keyword.push_back("for");
keyword.push_back("goto");
keyword.push_back("if");
keyword.push_back("int");
keyword.push_back("long");
keyword.push_back("register");
keyword.push_back("return");
keyword.push_back("short");
keyword.push_back("signed");
keyword.push_back("static");
keyword.push_back("sizeof");
keyword.push_back("struct");
keyword.push_back("switch");
keyword.push_back("typedef");
keyword.push_back("union");
keyword.push_back("unsigned");
keyword.push_back("void");
keyword.push_back("volatile");
keyword.push_back("while");
}
voidsum(void)//计算字符数行数存注释
{
file.open("data.c");
intstate=0;//状态转换0:
正常1:
输入一个/2:
输入/*
chartemp;//暂存
stringtemp_comment;//暂存注释
file.seekg(0);//文件指针回到头
while(!
file.eof())//遍历全文
{
switch(state)
{
case0:
file.get(temp);
sum_char++;//增加字符
if('\n'==temp)
sum_line++;//增加行
if('/'==temp)
state=1;
break;
case1:
//前一个字符是/
file.get(temp);
sum_char++;//增加字符
if('/'==temp)//单行注释
{
temp_comment.clear();//清空注释缓存
while('\n'!
=temp)//输完整行
{
file.get(temp);
sum_char++;//增加字符
temp_comment.append(1,temp);//添加注释
}
sum_line++;//行增加
comment.push_back(temp_comment);//添加到注释记录表
state=0;//状态回归
}
else
if('*'==temp)//多行注释
{
temp_comment.clear();
state=2;
}
else//不是注释
{
if('\n'==temp)
sum_line++;//增加行
state=0;//状态回归
}
break;
case2:
file.get(temp);
sum_char++;//增加字符
if('*'==temp)
{
file.get(temp);//再取一个
sum_char++;//增加字符
if('/'==temp)//结束多行注释
{
comment.push_back(temp_comment);//存入注释表
state=0;
}
else//还在注释中
{
temp_comment.append(1,'*');
temp_comment.append(1,temp);
if('\n'==temp)
sum_line++;
}
}
else
{
if(file.eof())//当注释到尾时
{
if(!
temp_comment.empty())//不为空时存入最后一个注释
{
comment.push_back(temp_comment);
return;
}
}
if('\n'==temp)
sum_line++;
temp_comment.append(1,temp);
}
break;
default:
break;
}
}
}
voidword_analyse(void)
{
stringtemp_word;//暂存单词
char*p=buffer;//处理指针
while(in_comment)//处理多行注释问题
{
if('\0'==*p)
return;
if(('*'==*p)&&('/'==*(p+1)))
{
p+=2;
in_comment=false;
}
p++;
}
while('\0'!
=*p)//遍历整句
{
if(''==*p)//当是空格时后移
p++;
else
if(isalpha(*p)||'_'==*p)//以字母或下划线开头,关键字和标识符
{
temp_word.clear();
while(isalnum(*p)||'_'==*p)//记录关键字
{
temp_word.append(1,*p);
p++;
}//当为空格或别的符号时弹出
sum_word++;//单词+1
id.push_back(temp_word);//存入标示符
inti;
for(i=0;iif(keyword.at(i)==temp_word)
break;
if(icout<"<<"保留字:
"<else
cout<"<<"标示符:
"<}
else
if(isdigit(*p))//无符号数
{
temp_word.clear();
while(isdigit(*p))
{
temp_word.append(1,*p);
p++;
}
if(isalpha(*p)||'_'==*p)//非法字符
{
while(''!
=*p&&'\0'!
=*p)
{
temp_word.append(1,*p);
p++;
}
sum_word++;
id.push_back(temp_word);
cout<"<<"非法字符:
"<cout<<"error:
在第"<"<}
else
{
if('.'==*p||'E'==*p||'e'==*p)//小数和指数形式
{
temp_word.append(1,*p);
p++;
while(isdigit(*p))
{
temp_word.append(1,*p);
p++;
}
}
sum_word++;
id.push_back(temp_word);
cout<"<<"无符号数:
"<}
}
else
if('#'==*p)//预处理文件特殊处理
{
while('\0'!
=*p)
{
temp_word.append(1,*p);
p++;
}
//p指向换行,完成直接退出
pre.push_back(temp_word);
}
else
if('"'==*p)//字符串
{
temp_word.clear();
p++;
while('"'!
=*p)
{
temp_word.append(1,*p);
p++;
}
p++;
sum_word++;
cout<"<<"字符串:
"<}
else
if('+'==*p)//处理符号
{
temp_word.clear();
if('='==*(p+1))//自加
{
temp_word="+=";
id.push_back(temp_word);
sum_word++;
cout<"<<"自加号:
"<p+=2;//推进
}
else
if('+'==*(p+1))//自加1
{
temp_word="++";
id.push_back(temp_word);
sum_word++;
cout<"<<"自加1号:
"<p+=2;//推进
}
else
if(isdigit(*(p+1)))//有符号数
{
temp_word="+";
for(intj=1;isdigit(*(p+j));j++)
temp_word.append(1,*(p+j));
id.push_back(temp_word);
sum_word++;
cout<"<<"有符号数:
"<p+=2;//推进
}
else
{
temp_word="+";
id.push_back(temp_word);
sum_word++;
cout<"<<"加号:
"<p+=2;//推进
}
}
else
if('-'==*p)//处理符号
{
temp_word.clear();
if('='==*(p+1))//自减
{
temp_word="-=";
id.push_back(temp_word);
sum_word++;
cout<"<<"自减号:
"<p+=2;//推进
}
else
if('-'==*(p+1))//自减1
{
temp_word="--";
id.push_back(temp_word);
sum_word++;
cout<"<<"自减1号:
"<p+=2;//推进
}
else
if(isdigit(*(p+1)))//有符号数
{
temp_word="-";
for(intj=1;isdigit(*(p+j));j++)
temp_word.append(1,*(p+j));
id.push_back(temp_word);
sum_word++;
cout<"<<"有符号数:
"<p+=2;//推进
}
else
{
temp_word="-";
id.push_back(temp_word);
sum_word++;
cout<"<<"减号:
"<p+=2;//推进
}
}
else
if('*'==*p)//处理符号
{
temp_word.clear();
if('='==*(p+1))//自乘
{
temp_word="*=";
id.push_back(temp_word);
sum_word++;
cout<"<<"自乘号:
"<p+=2;//推进
}
else
{
temp_word="*";
id.push_back(temp_word);
sum_word++;
cout<"<<"乘号:
"<p+=2;//推进
}
}
else
if('/'==*p)//处理符号
{
temp_word.clear();
if('='==*(p+1))//自除
{
temp_word="*=";
id.push_back(temp_word);
sum_word++;
cout<"<<"自除号:
"<p+=2;//推进
}
else
if('/'==*(p+1))//行注释
return;//直接跳出
else
if('*'==*(p+1))//多行注释
{
in_comment=true;
p+=2;
while('\0'!
=*p)//判断这行为止注释能不能结束
{
if(('*'==*p)&&('/')==*(p+1))
{
in_comment=false;
break;
}
p++;
}
}
else
{
temp_word="/";
id.push_back(temp_word);
sum_word++;
cout<"<<"除号:
"<p+=2;//推进
}
}
else
if('='==*p)//处理等号
{
temp_word.clear();
if('='==*(p+1))//比较
{
temp_word="==";
id.push_back(temp_word);
sum_word++;
cout<"<<"比较号:
"<p+=2;//推进
}
else
{
temp_word="=";
id.push_back(temp_word);
sum_word++;
cout<"<<"赋值号:
"<p+=2;//推进
}
}
else
if('>'==*p)
{
temp_word.clear();
if('='==*(p+1))
{
temp_word=">=";
id.push_back(temp_word);
sum_word++;
cout<"<<"大于等于号:
"<p+=2;//推进
}
else
{
temp_word=">";
id.push_back(temp_word);
sum_word++;
cout<"<<"大于号:
"<p+=2;//推进
}
}
else
if('<'==*p)
{
temp_word.clear();
if('='==*(p+1))
{
temp_word="<=";
id.push_back(temp_word);
sum_word++;
cout<"<<"小于等于号:
"<p+=2;//推进
}
else
{
temp_word="<";