1、 编译原理实验报告 实验名称: 编写词法分析程序_______ 实验类型: 设计型实验 指导教师: 专业班级: 姓 名: 学 号: 实验地点: 实验成绩:
2、日期: 2017年 4月 15日 实验一 编写语法分析程序 一、 实验目的 1) 通过设计、调试词法分析程序,掌握词法分析程序的设计工具,即有穷自动机,进一步理解自动机理论; 2) 掌握正则文法和正则表达式转换成有穷自动机的方法及有穷自动机的实现方法; 3) 会确定词法分析程序的输出形式及标识符与关键字的区分方法; 4) 加深对课堂教学的理解,提高词法分析方法的实践能力,掌握使用实验环境的技能技巧以及程序的调试方法。 二、实验设计 1、写出TEST语言每条词法规则对应的正则文法或者正则表达式 1) 标识符:字母打头,后接任意字母或数字。 正则表
3、达式: ( a|b|……|z|A|B……|Z )( 0|1|……|9| a|b|……|z|A|B……|Z )* 2) 保留字:标符的子集,包括:if, else, for, while, do, int, write, read。 正则表达式: if | else | for | while | do | int | write | read 3) 无符号整数:由数字组成,但最高位不能为0,允许一位的0。 正则表达式:( (1……|9 )( 0|1|……|9)* )|0 4) 分界符:(、)、;、{、} 正则表达式:( | ) | ; | { | } 5) 运算符:+、-、*、
4、/、=、<、>、>=、<=、!=、== 正则表达式:+ | - | * | / | = | < | > | >= | <= | != | == 6) 注释符:/* */ 正则表达式:/*(没有连续的*/的任意字符串|ℇ)*/ 2、对每个文法或者正则表达式分别构造NFA 1) 标识符: ( a|b|……|z|A|B……|Z )( 0|1|……|9| a|b|……|z|A|B……|Z )* 2) 无符号整数:( (1|2|……|9 )( 0|1|……|9)* )|0 3) 分界符:( | ) | ; | { | } 4) 运算符:+ | - | * | /
5、 = | < | > | >= | <= | != | == 5) 注释符:/*(没有连续的*/的任意字符串|ℇ)*/ 3、将NFA合并,确定化,化简得到最终的DFA。 NFA: DFA: 三、实验过程 1、完成整个实验的先后步骤 a) 根据TEST语言的词法规则,分别写出每条规则的正则文法或者正则表达式; b) 将每一个正则文法或者正则表达式转换为NFA; c) 将多个NFA合并后进行确定化并化简; d) 根据化简后的DFA画出流程图; e) 参阅教材PP.69-71的TEST语言语法规则,确定单词分类、单词输出方案; f) 编写词法分析程序;
6、 g) 对下面的TEST语言源程序进行词法分析,将合法单词存入lex.txt,并报告词法错误及其位置。注:不能修改源程序 { /*This a test program.*/ int abc; int 123; int A$@; int i; int n; int b,c; int 2a; int a2; read n; n = 012345; for (i=1;i<=n; i= i+1) { abc=abc+i; } if(i!=n) n = n+i; if (!n) b = b+c; /*The loop ended write abc; }
7、 2、实验调试记录(问题表现,分析原因,解决方案,解决结果) a) 问题表现: 1. 不能处理除号 2. 不能处理不完整的注释符 3. 对于”0123” 这类字符串的处理不正确,我之前处理为直接报错说一位以上的数字首位不能为0 b) 分析原因: 问题1,2的原因都是在“/”符号处理时出现的问题导致的,程序中出现bug使得一遇到‘/’就会进入死循环。 问题3 ,不应该直接报错说一位以上的数字首位不能为0,遇到0应该直接输出0这个单词,再接着读数字。 c) 解决方案: d) 对于问题1,2,重新梳理逻辑,一步一步对照流程图和DFA来调试修改代码。 对于问题3,遇到0应该直
8、接输出0这个单词,再接着读数字。 e) 解决结果: 成功解决了程序遇到‘/’进入死循环问题和“0123”这类字符串的处理。 三、实验结果 列出实验结果并进行分析(含分步测试结果)。 lex.txt文件(存放编译的合法内容)内容: 1 { { 2 /*This a test program.*/ /*This a test program.*/ 3 int int 3 ID abc 3 ; ; 4 int int 4 NUM 123 4 ; ; 5 int int 5 ID A 5 ; ; 6 int int 6 ID i 6 ; ; 7 int in
9、t 7 ID n 7 ; ; 8 int int 8 ID b 8 ID c 8 ; ; 9 int int 9 NUM 2 9 ID a 9 ; ; 10 int int 10 ID a2 10 ; ; 11 read read 11 ID n 11 ; ; 12 ID n 12 = = 12 NUM 0 12 NUM 12345 12 ; ; 13 for for 13 ( ( 13 ID i 13 = = 13 NUM 1 13 ; ; 13 ID i 13 <= <= 13 ID n 13 ; ; 13 ID i 13
10、 = 13 ID i 13 + + 13 NUM 1 13 ) ) 14 { { 15 ID abc 15 = = 15 ID abc 15 + + 15 ID i 15 ; ; 16 } } 17 if if 17 ( ( 17 ID i 17 != != 17 ID n 17 ) ) 17 ID n 17 = = 17 ID n 17 + + 17 ID i 17 ; ; 18 if if 18 ( ( 18 ID n 18 ) ) 18 ID b 18 = = 18 ID b 18 + + 18 ID c 18 ; ;
11、 四、讨论与分析 1. 你的编写词法分析程序满足最长匹配原则吗?如果满足请给出你的实现方案。如果不满足请给出改进方案。 答:不满足,我的处理先后顺序是:标识符或保留字、数字、分界符、运算符(除开/)、除或者注释,我应该吧注释放在前面,因为一般来说注释都比其它类型符号长些。改进措施便是将注释这一条词法规则最早处理。 2. 给出你的单词分类方案,并说明理由。 答:根据TEST语言可将单词分为六类: a) 标识符:字母打头,后接任意字母或数字。 b) 保留字:标识符的子集,包括:if, else, for, while, do, int, write, read。 c) 无符号整数:
12、由数字组成,但最高位不能为0,允许一位的0。 d) 分界符:(、)、;、{、} e) 运算符:+、-、*、/、=、<、>、>=、<=、!=、== f) 注释符:/* */ 3. 构建词法分析程序一般过程是怎样的? 答:构建词法分析程序的一般过程: 1、 根据词法规则写出正则文法或者正则文法。 2、 为每一个正则表达式构造一个NFA,然后将多个NFA合并为一个NFA 3、 将NFA转化成DFA,并且化简最小化DFA 4、 确定单词的输出形式 5、 根据化简后的DFA和单词输出程序构造词法分析程序 (主要部分:通过实验对课程知识点的理解;回答实验指导书的实验思
13、考提出的问题等)
五、附录:关键代码(给出适当注释,可读性高)
# include
14、 //关键字 "if", "else", "for", "while", "do", "int", "read", "write"}; int line = 1; //行号 int errors = 0; //记录错误个数 ofstream fout; //输出文件流 ifstream fin; //输入文件流 ofstream lexout; //存放合法单词的文
15、件流
char type[6][30]={
"ID",
"保 留 字",
"NUM",
"分 界 符",
"运 算 符",
"注 释 符"};
int main()
{
int TEST(); //函数声明
TEST();
if(errors==0)
{
cout<<"编译成功。"< 16、
}
////判断是否为字母
int is_Char(char ch)
{
if ((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
{
return 1;
}
return 0;
}
////判断是否为无符号整数
int is_Uint(char ch)
{
if('0'<=ch&&ch<='9')
{
return 1;
}
return 0;
}
////判断是否为分界符
i 17、nt is_Deli(char ch)
{
if(ch=='('||ch==')'||ch==';'||ch=='{'||ch=='}')
{
return 1;
}
return 0;
}
////判断是否为操作符
int is_Oper(char ch)
{
char Operater[10]="+-*!=><";//没有考虑/号
for(int i=0;i<8;i++)
{
if(ch==Operater[i])
{
return 18、1;
}
}
return 0;
}
////输入控制
int in(char &ch)
{
fin.get(ch);
if('\n'==ch)
{
line++;
}
if(fin.eof())
{
ch=EOF;
}
return 1;
}
////输出控制
void out(char *type,char *buf)
{
if(strcmp(type,"ID")==0||strcmp(type,"NUM")==0)
19、 lexout< 20、/打开编译程序存放合法单词的文件
lexout.open("lex.txt");
//打开用户的文件
//cout<<"请输入要编译的文件的路径:"< 21、
{
cout<<"文件打开失败,请重新输入文件路径:"< 22、rojects\编译原理实验一\out.txt"};
fout.open("out.txt");
if(fout==NULL)
{
cout<<"文件打开失败,请重新输入文件路径:"< 23、 '||ch=='\n'||ch=='\t'||ch=='\r')
{
in(ch);
}
//判断是否为标识符或保留字
if(is_Char(ch))
{
int t=0;
while(is_Char(ch))
{
buf[t++]=ch;
in(ch);
}
buf[t]='\0';
//判断保留字
int j=0;
for(;j 24、p(kword[j],buf)==0)
{
out(type[1],buf);
break;
}
}
//ID 标识符
if(j>=KWN)
{
while(is_Char(ch)||is_Uint(ch))
{
buf[t++]=ch;
in(ch);
}
buf[t]='\0';
out(type[0],buf);
}
}
//判断是否为数字
25、
else if(is_Uint(ch))
{
int t=0;
while(is_Uint(ch))
{
buf[t++]=ch;
in(ch);
}
buf[t]='\0';
if(t==1)
{
out(type[2],buf);
}
else if(buf[0]=='0')
{
int i=-1;
while(i 26、 out(type[2],&"0");
}
out(type[2],buf+i);
}
else
{
out(type[2],buf);
}
}
//判断是否为分界符
else if(is_Deli(ch))
{
buf[0]=ch;
buf[1]='\0';
out(type[3],buf);
in(ch);
}
//判断是否为运算符(除开/)
else if(is_Oper 27、ch))
{
if(ch=='+'||ch=='-'||ch=='*')
{
buf[0]=ch;
buf[1]='\0';
out(type[4],buf);
in(ch);
}
else if(ch=='!')
{
buf[0]=ch;
in(ch);
if(ch=='=')
{
buf[1]=ch;
buf[2]='\0';
out(type[4],buf); 28、
in(ch);
}
else
{
cout<<"error"<<++errors<<" line"< 29、4],buf);
in(ch);
}
else
{
buf[1]='\0';
out(type[4],buf);
}
}
}
else if(ch=='/')//判断是除还是注释
{
int t=0;
buf[t++]=ch;
char ch0 ;
in(ch0);
while(1)
{
if(ch0 == EOF)
{
cout<<" 30、error"<<++errors<<" line"< 31、 else
{
cout<<"error"<<++errors<<" line"< 32、ual C++ 6.0\Microsoft Visual Studio\MyProjects\编译原理实验一\out.txt
/*This a test program.
/*The loop ended
write abc;
*//*
char ch1 = getc(fin);
while(true)
{
if(ch1 == EOF)
{
printf("Line %d\t%s\t没有匹配!\n", line,"错误:" );
break;
}
ch = ch1;
ch1 = getc(fin);
if(ch =='*' && ch1 == '/')
brea 33、k;
}
ch = getc(fin);
/*The loop ended
write abc;
*/
六、实验者自评(主要从实验态度、方法、效果上给一个客观公正的自我评价)
我自认为实验态度很好,只是实验的方法不太好,实验的效果一般。我是看着DFA图来敲的代码,而不是看流程图来写的代码,这导致我敲到后面出现好几个难以发现的bug,这两个bug花了我相当多的时间,后来为了解决这个问题,我画出流程图再来一点一点对照我的代码,最终终于发现了bug,过程相当艰辛,光只是敲代码画了足足两天时间。实验效果一般,实验所花的总时长太长,效率不高。其中专业理论知识内 34、容包括:保安理论知识、消防业务知识、职业道德、法律常识、保安礼仪、救护知识。作技能训练内容包括:岗位操作指引、勤务技能、消防技能、军事技能。
二.培训的及要求培训目的
安全生产目标责任书
为了进一步落实安全生产责任制,做到“责、权、利”相结合,根据我公司2015年度安全生产目标的内容,现与财务部签订如下安全生产目标:
一、目标值:
1、全年人身死亡事故为零,重伤事故为零,轻伤人数为零。
2、现金安全保管,不发生盗窃事故。
3、每月足额提取安全生产费用,保障安全生产投入资金的到位。
4、安全培训合格率为100%。
二、本单位安全工作上必须做到以下内容:
1、对本单位的安全生 35、产负直接领导责任,必须模范遵守公司的各项安全管理制度,不发布与公司安全管理制度相抵触的指令,严格履行本人的安全职责,确保安全责任制在本单位全面落实,并全力支持安全工作。
2、保证公司各项安全管理制度和管理办法在本单位内全面实施,并自觉接受公司安全部门的监督和管理。
3、在确保安全的前提下组织生产,始终把安全工作放在首位,当“安全与交货期、质量”发生矛盾时,坚持安全第一的原则。
4、参加生产碰头会时,首先汇报本单位的安全生产情况和安全问题落实情况;在安排本单位生产任务时,必须安排安全工作内容,并写入记录。
5、在公司及政府的安全检查中杜绝各类违章现象。
6、组织本部门积极参加 36、安全检查,做到有检查、有整改,记录全。
7、以身作则,不违章指挥、不违章操作。对发现的各类违章现象负有查禁的责任,同时要予以查处。
8、虚心接受员工提出的问题,杜绝不接受或盲目指挥;
9、发生事故,应立即报告主管领导,按照“四不放过”的原则召开事故分析会,提出整改措施和对责任者的处理意见,并填写事故登记表,严禁隐瞒不报或降低对责任者的处罚标准。
10、必须按规定对单位员工进行培训和新员工上岗教育;
11、严格执行公司安全生产十六项禁令,保证本单位所有人员不违章作业。
三、 安全奖惩:
1、对于全年实现安全目标的按照公司生产现场管理规定和工作说明书进行考核奖励;对于未实现安全目标的按照公司规定进行处罚。
2、每月接受主管领导指派人员对安全生产责任状的落
21






