【编译原理】词法分析(C/C++源代码+实验报告)
文章目录
- 1 实验目的和内容
- 1.1实验目的
- 1.2实验内容
- 2 设计思想
- 2.1单词种类及其正规式
- 2.2 根据正规式构造NFA
- 2.3根据NFA构造DFA
- 2.3.1根据替换规则构造未化简的DFA
- 2.3.2最小化DFA
- 3算法流程
- 4源程序
- 5调试数据
- 5.1 测试样例一
- 5.2 测试样例二
- 5.3 测试样例三
- 6实验调试情况及体会
- 6.1 实验调试情况
- 6.2 实验体会
1 实验目的和内容
1.1实验目的
(1)根据 PL/0 语言的文法规范,编写PL/0语言的词法分析程序;或者调研词法分析程序的自动生成工具LEX或FLEX,设计并实现一个能够输出单词序列的词法分析器。
(2)通过设计调试词法分析程序,实现从源程序中分离出各种类型的单词;加深对课堂教学的理解;提高词法分析方法的实践能力。
(3)掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。
(4)掌握词法分析的实现方法。
(5)上机调试编出的词法分析程序。
1.2实验内容
根据PL/0语言的文法规范,编写PL/0语言的词法分析程序。要求:
(1)把词法分析器设计成一个独立一遍的过程。
(2)词法分析器的输出形式采用二元式序列,即:(单词种类, 单词的值)
2 设计思想
2.1单词种类及其正规式
(1)基本字
单词的值 | 单词类型 | 正规式r |
---|---|---|
begin | beginsym | begin |
call | callsym | call |
const | constsym | const |
do | dosym | do |
end | endsym | end |
if | ifsym | if |
odd | oddsym | odd |
procedure | proceduresym | procedure |
read | readsym | read |
then | thensym | then |
var | varsym | var |
while | whilesym | while |
write | writesym | write |
(2)标识符
单词的值 | 单词类型 | 正规式r |
---|---|---|
标识符 | ident | (字母)(字母|数字)* |
(3)常数
单词的值 | 单词类型 | 正规式r |
---|---|---|
常数 | number | (数字)(数字)* |
(4)运算符
单词的值 | 单词类型 | 正规式r |
---|---|---|
+ | plus | + |
- | minus | - |
* | times | * |
/ | slash | / |
= | eql | = |
<> | neq | <> |
< | lss | < |
<= | leq | <= |
> | gtr | > |
>= | geq | >= |
:= | becomes | := |
(5)界符
单词的值 | 单词类型 | 正规式r |
---|---|---|
( | lparen | ( |
) | rparen | ) |
, | comma | , |
; | semicolon | ; |
. | period | . |
2.2 根据正规式构造NFA
下面我们根据上述的正规式来构造该文法的NFA,如下图所示,其中状态0为初态,凡带双圈的状态均为终态,状态24是识别不出单词符号的出错情形,其他状态的识别情况如下图中右边的注释所示。
图1 根据正规式构造的NFA
2.3根据NFA构造DFA
2.3.1根据替换规则构造未化简的DFA
替换规则如下图所示。
图2 替换规则
根据替换规则对NFA进行分裂,结果如下图所示。
图3 未化简DFA
2.3.2最小化DFA
一个确定有限自动机M的化简是指,寻找一个状态数比M少的DFA M’,使得L(M)=L(M’)。一个DFA M的状态最小化过程旨在将M的状态集分割成一些不相交的子集,使得任何不同的两子集中的状态都是可区别的,而同一子集中的任何两个状态都是等价的。最后,在每个子集中选一个代表,同时消去其它的等价状态。
最小化后的DFA如下图所示。
图4 最小化DFA
3算法流程
词法分析程序的输入是源程序,输出是一个个单词符号的二元组,它的任务是从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为单词符号串的中间程序。
首先逐行扫描源程序,然后遍历串的每一个字符,判断字符是不是空格、数学、字母、运算符或者界符,再进行下一步的判断,如果不符合这几种情况,将会归入出错处理。完整算法流程如下图所示。
图5 算法流程图
4源程序
#include <iostream>
#include <string>
using namespace std;//用于识别是基本字或标识符
void Letter(string str)
{//识别基本字if(str=="begin")cout<<"(beginsym,begin)"<<endl;else if(str=="call")cout<<"(callsym,call)"<<endl;else if(str=="const")cout<<"(constsym,const)"<<endl;else if(str=="do")cout<<"(dosym,do)"<<endl;else if(str=="end")cout<<"(endsym,end)"<<endl;else if(str=="if")cout<<"(ifsym,if)"<<endl;else if(str=="odd")cout<<"(oddsym,odd)"<<endl;else if(str=="procedure")cout<<"(proceduresym,procedure)"<<endl;else if(str=="read")cout<<"(readsym,read)"<<endl;else if(str=="then")cout<<"(thensym,then)"<<endl;else if(str=="while")cout<<"(whilesym,while)"<<endl;else if(str=="var")cout<<"(varsym,var)"<<endl;else if(str=="write")cout<<"(writesym,write)"<<endl;//识别标识符elsecout<<"(ident,"<<str<<")"<<endl;
}int main()
{string str1,str;while(cin>>str1){//读入代码(字符串形式)str = str+' '+str1;}//开始处理读入的代码int length_str = str.length();for(int i=0;i<length_str;i++){//当遇到空格或换行时,跳过继续执行if(str[i]==' ' || str[i]=='\n') continue;//识别常数else if(isdigit(str[i])){string digit;//以字符串形式表示这个常数while(isdigit(str[i])){digit +=str[i];i++;}i--;cout<<"(number,"<<digit<<")"<<endl;}//识别基本字或标识符else if(isalpha(str[i])){string lett;//以字符串形式表示这个基本字或者标识符while(isdigit(str[i])||isalpha(str[i])){lett +=str[i];i++;}i--;Letter(lett);}//识别运算符else{switch(str[i]){case '+':cout<<"(plus,+)"<<endl;break;case '-':cout<<"(minus,-)"<<endl;break;case '*':cout<<"(times,*)"<<endl;break;case '/':cout<<"(slash,/)"<<endl;break;case '=':cout<<"(eql,=)"<<endl;break;case '<':i++;if(str[i]=='>'){cout<<"(neq,<>)"<<endl;}else if(str[i]=='='){cout<<"(leq,<=)"<<endl;}else{i--;cout<<"(lss,<)"<<endl;}break;case '>':i++;if(str[i]=='='){cout<<"(geq,>=)"<<endl;}else{i--;cout<<"(gtr,>)"<<endl;}break;case ':':i++;if(str[i]=='='){cout<<"(becomes,:=)"<<endl;}break;//识别界符case '(':cout<<"(lparen,()"<<endl;break;case ')':cout<<"(rparen,))"<<endl;break;case ',':cout<<"(comma,,)"<<endl;break;case ';':cout<<"(semicolon,;)"<<endl;break;case '.':cout<<"(period,.)"<<endl;break;//错误处理default:cout<<"error"<<endl;break;}}}cout<<"Yes,it is correct."<<endl;return 0;
}
5调试数据
5.1 测试样例一
【样例输入】
const a=10;
var b,c;
begin
read(b);
c:=a+b;
write(c)
end. 【样例输出】
(constsym,const)
(ident,a)
(eql,=)
(number,10)
(semicolon,;)
(varsym,var)
(ident,b)
(comma,,)
(ident,c)
(semicolon,;)
(beginsym,begin)
(readsym,read)
(lparen,()
(ident,b)
(rparen,))
(semicolon,;)
(ident,c)
(becomes,:=)
(ident,a)
(plus,+)
(ident,b)
(semicolon,;)
(writesym,write)
(lparen,()
(ident,c)
(rparen,))
(endsym,end)
(period,.)
样例一结果如下所示
图6 样例一测试结果
5.2 测试样例二
【样例输入】
const a=10;
var b,c,d;
begin
read(b);
read(c);
d:=a+b+c;
write(d)
end. 【样例输出】
(constsym,const)
(ident,a)
(eql,=)
(number,10)
(semicolon,;)
(varsym,var)
(ident,b)
(comma,,)
(ident,c)
(comma,,)
(ident,d)
(semicolon,;)
(beginsym,begin)
(readsym,read)
(lparen,()
(ident,b)
(rparen,))
(semicolon,;)
(readsym,read)
(lparen,()
(ident,c)
(rparen,))
(semicolon,;)
(ident,d)
(becomes,:=)
(ident,a)
(plus,+)
(ident,b)
(plus,+)
(ident,c)
(semicolon,;)
(writesym,write)
(lparen,()
(ident,d)
(rparen,))
(endsym,end)
(period,.)
样例二结果如下所示
图7 样例二测试结果
5.3 测试样例三
【样例输入】
const a=10;
const b=10;
var c;
begin
c:=a+b;
write(c)
end.【样例输出】
(constsym,const)
(ident,a)
(eql,=)
(number,10)
(semicolon,;)
(constsym,const)
(ident,b)
(eql,=)
(number,10)
(semicolon,;)
(varsym,var)
(ident,c)
(semicolon,;)
(beginsym,begin)
(ident,c)
(becomes,:=)
(ident,a)
(plus,+)
(ident,b)
(semicolon,;)
(writesym,write)
(lparen,()
(ident,c)
(rparen,))
(endsym,end)
(period,.)
样例三结果如下所示
图8 样例三测试结果
6实验调试情况及体会
6.1 实验调试情况
由上一步中的三个测试样例可以得到,所有的测试样例均得到了相应的输出结果,说明代码编写成功,并且在代码中设置了出错处理,以便解决其他情况。
6.2 实验体会
本次实验通过先写出正规式到NFA到DFA再到画出程序的流程图,一步一步地优化自己的编程流程,可以在自己脑海中形成清晰的框架,不会出现一些大的方向上的判断错误。同时也理解了从正规式到最小化DFA的每一步的含义。正规式是正规集的表现形式,通过正规式更好的人工设计成NFA(NFA与正规式的等价性),根据NFA运用子集法转换成DFA,解决了编程问题(DFA和NFA的等价性),最后用最小化简法对DFA进行化简,以达到最简的效果,有利于编程实现。
在程序编写时,用到了C++自带的头文件string,可以很好地处理输入串并对串进行分割,将界符、运算符和其他区分开,便于遍历。在调试程序过程中,一开始出现空格和换行无法识别的情况,于是就把这种情况单独编写了一个函数进行识别,便于串的后续识别。
通过这次实验对之前学到的词法分析有了进一步的了解,加深了对于词法分析的步骤的理解与领悟,对于今后对编译原理的学习有很大的帮助。
最后,感谢刘善梅老师和其他同学在这次实验中给予我的帮助,不胜感激!
【编译原理】词法分析(C/C++源代码+实验报告)相关推荐
- c++实现编译原理词法分析实验(含代码)
c++实现编译原理词法分析实验(含代码) 一.实验目的: 通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解.并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法. ...
- DFA的构造C语言,DFA的编程实现含源代码实验报告剖析
<DFA的编程实现含源代码实验报告剖析>由会员分享,可在线阅读,更多相关<DFA的编程实现含源代码实验报告剖析(20页珍藏版)>请在人人文库网上搜索. 1.实验一(一)程序设计 ...
- 编译原理词法分析程序设计
编译原理词法分析程序设计 1. 课程设计目的: 结合讲授内容,设计与实现一个简单词法分析器,通过设计编制调试一个具体的词法分析程序,加深对词法分析程序的功能及实现方法的理解.并掌握在对程序设计语言 ...
- 编译原理 词法分析 算符优先分析法
编译原理 词法分析 算符优先分析法 实验目的 加深对语法分析器工作工程的理解,加强对算符优先分析法实现语法分析程序的掌握:能够采用一种编程语言实现简单的语法分析程序:能够使用自己辨析的分析程序对简单的 ...
- java实现词法分析_编译原理(词法分析) Java 实现
编译原理(词法分析) Java 实现 编译原理(词法分析) Java 实现 1. 项目目录 2. 需要解释的源代码 PROGRAM SOURCE; /*定义变量*/ VAR X, Y, Z:INTEG ...
- 声速的测量的实验原理和应用_示波器的原理和使用声速测量实验报告.docx
示波器的原理和使用声速测量实验报告.docx 示波器的原理和使用.声速测量一实验目的1了解示波器的基本结构及其工作原理,学习并掌握示波器的基本使用方法2学习电信号有关参数的基本概念及其测量3了解声波在 ...
- 编译原理词法分析实验
目录 实验内容描述 实验设计 输入输出形式 样例输入和样例输出 实验设计原理(步骤) 主要函数和辅助函数 核心代码截图 实验结果 可以找我代做,包满分.QQ1975728171可以写完整实验报告 实验 ...
- 实验一 词法分析java,java词法分析器实验报告
java词法分析器实验报告 Java 词法分析器实验报告 --07111101 --奥特曼 一.词法分析器功能概述: 1. 使用DFA实现词法分析器的设计: 2. 实现对Java 源程序中注释和空格( ...
- 编译原理---词法分析
词法分析的原理 词法分析是编译程序进行编译时第一个要进行的任务,主要是对源程序进行编译预处理之后,对整个源程序进行分解,分解成一个个单词,这些单词有且只有五类,分别时标识符.关键字(保留字).常数.运 ...
- 编译原理——词法分析
根据上课内容顺序写的博客,并不是按照书的目录来的 使用龙书以及编译程序设计原理(第二版)金成植.金英编著 老师的PPT是英文的,我自己随便翻的,不一定对 文章目录 词法分析(scanning) 概述 ...
最新文章
- 爆气球这道题目,展开了新的思路
- 影响数千万APP的安卓APP“寄生兽”漏洞技术分析
- java23种模式之单例模式
- 64位Linux下安装mysql-5.7.13-linux-glibc2.5-x86_64 || 转载:http://www.cnblogs.com/gaojupeng/p/5727069.html
- 使用JDK Logging - Java异常处理
- 11.13模拟:总结
- python出现的次数最多的元素_【Python 秘籍】序列中出现次数最多的元素
- 在Spring项目中集成使用MongoDB
- 背包九讲(超详细 :算法分析 + 问题分析 + 代码分析)
- yum安装freeswitch
- java打包跳过test_Maven打包跳过测试的命令
- 教师考核成绩评定c语言程序,C语言课设--教师评价系统
- 何恺明目前的学术成果是否够得上计算机视觉领域历史第一人?
- 计算机毕业设计JAVA二手物品置换平台mybatis+源码+调试部署+系统+数据库+lw
- [入门篇]Linux操作系统fork子进程的创建以及进程的状态 超超超详解!!!我不允许有人错过!!!
- python——json数据格式的转换
- r中将数据框中数据类型转化_R中的数据类型
- 视频教程-ShardingSphere:SpringBoot2+MybatisPlus+Swagger读写分离-Java
- IOS 图片自动旋转
- 2017安徽省高中计算机考试,2017年安徽省普通高中学业水平考试 - 物理
热门文章
- 自动化睡眠分期工具:开源、免费、高效
- 电子商务B2C:尾巴上的比特生存法则
- 响应式高端大气的模板源码图库素材资源下载平台网站源码,无加密无后门
- 黑客X档案PDF完整版(06年1月-12年12月)
- 一道经典的C++题,关于分钱的问题,适合新手阅读(黑客X档案论坛题目)
- commandname
- html中描文本链接,锚文本、超链接和纯文本链接的区别以及使用方法
- 计算机驱动打不开,驱动人生打不开怎么办
- 【兼容封装】addEventListener()和attachEvent()跨浏览器的兼容性处理
- ROS教程(四):RVIZ使用教程(详细图文)