北邮编译原理词法分析报告程序报告材料.docx
《北邮编译原理词法分析报告程序报告材料.docx》由会员分享,可在线阅读,更多相关《北邮编译原理词法分析报告程序报告材料.docx(23页珍藏版)》请在冰豆网上搜索。
北邮编译原理词法分析报告程序报告材料
程序设计一
词法分析程序
一.实验题目和要求
题目:
词法分析程序的设计与实现。
实验容:
设计并实现C语言的词法分析程序,要求如下。
(1)、可以识别出用C语言编写的源程序中的每个单词符号,并以记号的形式输出每个单词符号。
(2)、可以识别并读取源程序中的注释。
(3)、可以统计源程序汇总的语句行数、单词个数和字符个数,其中标点和空格不计算为单词,并输出统计结果
(4)、检查源程序中存在的错误,并可以报告错误所在的行列位置。
(5)、发现源程序中存在的错误后,进行适当的恢复,使词法分析可以继续进行,通过一次词法分析处理,可以检查并报告源程序中存在的所有错误。
实验要求:
方法1:
采用C/C++作为实现语言,手工编写词法分析程序。
方法2:
通过编写LEX源程序,利用LEX软件工具自动生成词法分析程序。
二.程序设计思路
采用C++来编写此程序。
根据书上的函数、变量提示写出各种函数、整体框架。
大部分变量名称与书上相同。
画出符号间转换自动机模型,之后根据自动机写函数、错误判断。
缓冲区用数组完成,标记位置的指针用int型来表示。
用lnum存储语句行数,wordnum存储单词个数,charnum存储字符个数。
标点和空格不计算为单词。
错误所在的行列位置存储在error.txt文件当中。
3.程序运行结果举例
Code.txt:
#include
main()
{
intnum,n=0,m,l,t;
printf("pleaseinputaninteger:
");
scanf("%d",&num);//dsfsdf
for(l=0;num!
=0;l++){
m=num%10;//sdfafda
for(t=0;t!
=l;t++)
m=m*2;//dafdaf
n=nm;
num=num/10;/*dafdas2323*/
}
printf("//theresultis%d//",n);
return0;
}
窗口运行结果:
=============================================================
*词法分析系统*
=============================================================
请输入需要分析的文件名称:
code.txt
-------------------------------------------------------------
处理完毕。
共出现1个错误。
共有21行,33个单词,236个字符。
结果请在token_table.txt中查看。
=============================================================
请按任意键继续...
Token.txt;
单词记号
##
includeid
stdioid
hid
>relop,GT
mainid
((
))
{{
intint
numid
,
nid
=relop,EQ
0num
,
mid
,
lid
,
tid
;;
printfid
((
))
;;
scanfid
((
,
&&
numid
))
;;
forfor
((
lid
=relop,EQ
0num
;;
numid
!
=RELOP,UE
0num
;;
lid
++
++
))
{{
mid
=relop,EQ
numid
%%
10num
;;
forfor
((
tid
=relop,EQ
0num
;;
tid
!
=RELOP,UE
lid
;;
tid
++
++
))
mid
=relop,EQ
mid
**
2num
;;
nid
=relop,EQ
nmid
;;
numid
=relop,EQ
numid
//
10num
;;
}}
printfid
((
,
nid
))
;;
returnreturn
0num
;;
}}
Error.txt:
1.在第1行第15列出现非法字符
Note.txt:
line6.双引号间字符:
pleaseinputaninteger:
line7.双引号间字符:
%d
line7.ddsfsdf
line10.ssdfafda
line12.ddafdaf
line14.dafdas2323
line17.双引号间字符:
//theresultis%d//
Count.txt:
共有21行,33个单词,236个字符。
四.源代码
头文件:
#include
#include
#include
#include
#include
#include
usingnamespacestd;
全局变量:
constintMAXBUFFER=62;//缓冲区容量
constintLB=30;//左缓冲区大小
constintLRB=61;//左+右缓冲区大小
constintKEY=32;//关键字个数
fstreamcode_file;
intum;//列数
intlb_end,rb_end,forward;//左右缓冲区结束位置,向前指针
intlready,rready;//标记左右缓冲区是否已经录入过容
charbuffer[MAXBUFFER];//缓冲区
charC;//当前读入的字符
stringtoken;//存放单词的字符串
intkeynum,errornum;//关键字的序列号;error的个数
intlnum,wordnum,charnum;//语句数单词数字符数
char*key[KEY]={"auto","const","double","float","int","short","struct"
"unsigned","break","continue","else","for","long","signed"
"switch","void","case","default","enum","goto","register"
"static","typedef","volatile","char","do","extern","if"
"return","sizeof","union","while"};//关键字表
函数:
voidfillbuf(intx)
{
if(x==0){//填充左半区
if(lready==0){//左半区未填充
code_file.read(buffer,LB);//读入LB个字符到buffer左半区中
if(code_file.gcount()!
=lb_end)
//如果读入的字符不足LB个在之后添加EOF
buffer[code_file.gcount()]=EOF;
}
else
lready=0;
}
else{//填充右半区
if(rready==0){
code_file.read(buffer+LB+1,LB);
//读入LB个字符到buffer右半区中
if(code_file.gcount()!
=LB)
buffer[code_file.gcount()+LB+1]=EOF;
}
else
rready=0;
}
}
voidget_nbc();
voidget_char()
{
C=buffer[forward];//获取当前字符
if(C==EOF)
return;
elseif(C=='\n'){
um=0;//列=0
lnum++;//+1行
}
elseif(C>=33&&C<=126){
charnum++;//字母或数字或符号的话+1字符
//cout<<"第"<um++;
}
forward++;
if(buffer[forward]==EOF){
if(forward==lb_end){
//到左区结束位置填充右半区
fillbuf
(1);
forward++;
}
if(forward==rb_end){
//到右区结束位置填充左半区向前指针回到开始位置
fillbuf(0);
forward=0;
}
}
}
voidretract()
{//向前指针后退一个字符
charnum--;
um--;
if(forward==0){
lready=1;//避免重新读取
forward=rb_end-1;//后退一个字符
}
elseif(forward==lb_end){
rready=1;
forward--;
}
elseforward--;
}
voidget_nbc()
{//若C中的字符为空字符则反复调用直到非空字符为止
while(C==''||C=='\t'||C=='\0'||C=='\n')
get_char();
retract();
}
intreserve(stringword)
{//查关键字表返回0表示token中的字符串是标识符1表示关键字
for(keynum=0;keynumif(pare(key[keynum])==0)
return1;
}
return0;
}
主函数:
main(){
cout<<"============================================================="<cout<<"*词法分析系统*"<cout<<"=============================================================="<cout<<"请输入需要分析的文件名称:
"<chars[30];//存储文件名称
cin>>s;
code_file.open(s);
intp;
while(code_file==NULL){
cout<<"无此文件,打开失败。
请重新输入:
"<cin>>s;
code_file.open(s);
}
//初始化
lb_end=LB;rb_end=LRB;forward=0;
lready=rready=0;
lnum=1;
um=0;
wordnum=charnum=0;
buffer[lb_end]=buffer[rb_end]=EOF;
fillbuf(0);
errornum=0;
cout<<"-------------------------------------------------------------"<fstreamtoken_table,error,count,note;
error.open("error.txt",ios_base:
:
out);//保存错误
count.open("count.txt",ios_base:
:
out);//保存语句数单词数字符数计数
note.open("note.txt",ios_base:
:
out);//保存注释
token_table.open("token.txt",ios_base:
:
out);//输出的记号
token_table<<"单词\t\t记号"<while(C!
=EOF){
get_char();
token="";
if((C>64&&C<91)||(C>96&&C<123)||C=='_'){
//标示符判断字母或者下划线开头
token=token+C;
get_char();
while((C>64&&C<91)||(C>96&&C<123)
||(C>47&&C<58)||C=='_'){
//字母或数字或下划线
token=token+C;
get_char();
}
if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();
wordnum++;//这是一个单词
if(reserve(token)==0)//这是一个标识符
token_table<else//这是一个关键字
token_table<}
elseif(C=='"'){
get_char();
while(C!
='"'){
token=token+C;
get_char();
}
note<<"line"<"<}
elseif(C==''||C=='\t'||C=='\0'||C=='\n')
get_nbc();
elseif(C>47&&C<58){//数字判断
while(C>47&&C<58){
token=token+C;
get_char();
}
if(C=='.'){
token=token+C;
get_char();
if(C>47&&C<58){
//小数点后必须有数字否则报错
token=token+C;
get_char();
while(C>47&&C<58){
token=token+C;
get_char();
}
if(C=='E'||C=='e'){
token=token+C;
get_char();
if(C=='+'||C=='-'){
//E后面可以是+-号
if(C>47&&C<58){
//+-后面必须有数字否则报错
token=token+C;
get_char();
while(C>47&&C<58){
token=token+C;
get_char();
}
if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();//后退一位后退出
}
else{
retract();
errornum++;
error<"行"<<"第"<<}
}
elseif(C>47&&C<58){
//E后面也可以是数字其他情况则报错
token=token+C;
get_char();
while(C>47&&C<58){
token=token+C;
get_char();
}
if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();//后退一位后退出
}
else{
retract();
errornum++;
error<<}
}
else{//退出
if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();
}
}
else{//记录错误退出此if重新判断
retract();
errornum++;
error<"<}
}
elseif(C=='E'||C=='e'){
token=token+C;
get_char();
if(C=='+'||C=='-'){//E后面可以是+-号
if(C>47&&C<58){//+-后面必须有数字否则报错
token=token+C;
get_char();
while(C>47&&C<58){
token=token+C;
get_char();
}
if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();//后退一位后退出
}
else{
retract();
errornum++;
error<<<"第"<}
}
elseif(C>47&&C<58){
//E后面也可以是数字其他情况则报错
token=token+C;
get_char();
while(C>47&&C<58){
token=token+C;
get_char();
}
if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();//后退一位后退出
}
else{
retract();
errornum++;
error<<}
}
else{
if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();
}
token_table<}
else{
switch(C){
case'<':
//<或者<=或者<>
get_char();
if(C=='=')
token_table<<"<=\t\trelop,LE"<elseif(C=='>')
token_table<<"<>\t\trelop,NE"<else{
token_table<<"<\t\trelop,LT"<if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();
}
break;
case'>':
//>或者>=
get_char();
if(C=='=')
token_table<<">=\t\trelop,GE"<else{
token_table<<">\t\trelop,GT"<if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();
}
break;
case'=':
//=
token_table<<"=\t\trelop,EQ"<break;
case':
':
//:
=或者:
get_char();
token_table<\t\t:
"<if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();
break;
case'!
':
//!
=
get_char();
if(C=='=')
token_table<<"!
=\t\tRELOP,UE"<else{
if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();
token_table<<"!
\t\t!
"<}
break;
case'/':
//过滤注释
get_char();
if(C=='/'){//过滤掉//开头的注释
get_char();
note<<"line"<while(C!
='\n'){
note<et_char();
}
note<}
elseif(C=='*'){//过滤掉/*开头的注释
note<<"line"<while
(1){
get_char();
while(C!
='*'){
note<get_char();
}
get_char();
if(C=='/'){
note<break;
}
else{
note<<"*"<}
}
}
else{
if(C!
=''&&C!
='\t'&&C!
='\0'&&C!
='\n')
retract();
token_table<<"/\t\t/"<}
break;
case'#':
case'+':
case'-':
case'(':
case')':
case'[':
case']':
case';':
case'%':
case',':
case'*':
case'&':
case'{':
case'}':
token_table<break;
default:
errornum++;error<}
}
}
cout<<"处