编译原理:基础算法逻辑实现词法分析器初步

编译原理结课了,把实验报告发上来凑个篇数,语言学的不行,算法也学的不行,就可能是最笨的实现方法。代码效率什么的一概没考虑,测试也没搞那么多分支测试,我们实验要求比较低,然后就尽力应付了一下。献丑了。
实验一:词法分析器

实验名称:词法分析器
在线编译器代码地址
完成时间:2020.4.16

(1) 词法分析器概述(主要介绍完成的词法分析器的主要功能,使用场景和限制条件)
 实现的主要功能:
用汤普森算法将正规式转化为NFA -> 将NFA转化为状态转移矩阵 -> 将状态转移矩阵去除空转移 ->确定化为DFA -> 状态集合重命名 -> 简化DFA
 使用场景:
将正规式转化为简化后的DFA
 限制条件:无法处理状态转移矩阵死循环的情况
(2) 词法分析器使用手册(主要介绍采用软件运行环境、数据准备、使用方法和限制条件)
 软件运行环境:
我是使用在线编译器:
https://ideone.com/hp4pee
(代码已上传,直接访问链接即可 上边是代码下边是由测试数据(a|b).a.b.b.(a|b) 跑出来的测试数据的结果)
 数据准备:
准备正规式一个:要求操作数都为 单个 小写 字母,中间用符号闭包:星号 * ,连接:小写句号 . ,括号:( ) ,或:| 连接,例如:(a|b).a.b.b.(a|b) ,(a|b).c*
 使用方法:
直接更改main函数中的str正规式字符串即可(或者解开注释的cin>>str输入也可),然后直接run就行
 限制条件:无法处理状态转移矩阵死循环的情况
(3) 功能分析(主要介绍采用数据结构和设计理由,以及各算法功能;对得意部分请着墨)
 数据结构:

  1. NFA数据结构
    在这里插入图片描述
  2. 状态转移矩阵数据结构
    说明:因为一个状态经过某条件后状态转移结果可能是多个状态,所以相当于二维表每个格子中填写的是一位数组,所以设置了accessType结构作为每个格子中填写的数据结构,其中包含一个一维数组(可达状态)以及一个int类型常数表示可达状态数量
    在这里插入图片描述
  3. 确定化的数据结构
    说明:确定化路径的矩阵与状态转移矩阵的区别在于其二维表格最左侧的起始状态列可以由多个状态构成数组组成,所以设置了一个stateType数据结构,里边包含一个一维数组存储起始状态集合,另一个整型常量存储含有起始点常量个数。
    在这里插入图片描述
  4. 简化DFA所需要的数据结构:ProStateType
    说明:在将DFA简化时候需要将原来一个状态数组拆开为多个,ProStateType的产生方便存储,这个数据结构中第一个元素是存储多个stateType的一维数组,初始时候只有一个状态集合,然后先分终态/非终态,将其分为两个,接着再继续分裂,分裂出的每一个新的状态集合直接存储在一维数组的最后边;length就是存储的分裂开的所有状态集合的数量;target二维数组存储每个state数组中按顺序每个元素在每种条件下的单个终点集合的序号(非此终点集合的都被分裂出去了)
    在这里插入图片描述

 核心算法功能:

  1. EvalutionExpression函数:
    关于汤普森算法将正规式转化为NFA的过程我直接照搬了大二的算术表达式的计算的思想以及代码,需要在此基础上修改的有计算符号优先顺序:
    在这里插入图片描述
    以及原来计算只是简单的获取操作数和操作符,±*/由计算机完成,而此时的闭包,连接,或等运算需要自己定义函数计算,实现起始点,终止点的更改,新边的添加等,由函数:OperOr,OperJoint,OperClosure完成。
    亮点:一个是之前代码的重用节省了时间,另一个是关于产生新的节点的时候如何设置节点的数字,想到了用一个全局变量,当有需要新节点时候直接从这里拿就行,拿以后全局变量+1,这样保证了之前生成的节点数字不必被推翻就可以直接续上。
  2. changeNFAtoSCGraph函数
    该函数用来将原来存储的NFA结构变化为状态转移矩阵,之前老师上课说最好重新定义NFA结构,可是当时我汤普森已经写完了所以决定自己转换一下就行,其实也不麻烦,原来的点集和条件集合直接从NFA拷贝就可以,而边的存储为了方便后续查找等操作需要按点的数字大小有序存储,从move中的s确定二维表的第几行,再用move中的ch确定是哪一列,填入move中的f即可。
  3. deleteAllEmpty,deleteEmptytrans函数:
    这两个函数用来去除状态转移矩阵中的空转移
    思路:deleteAllEmpty函数中使用循环遍历每一行的空转移使用deleteEmptytrans函数消除空转移
    deleteEmptytrans函数:
  1. 如果当前行有空转移则跳到空转移可达行,递归调用deleteEmptytrans
  2. 如果当前行无空转移,则将前面所有可达点插入到原来的行中,删除原来行中的这个空转移
  1. defNFA,DefineOneRow两个函数:
    用于将NFA确定化。defNFA函数将转移矩阵原来的起点添加进DFGraph数据结构中然后调用起DefineOneRow
    DefineOneRow函数功能:(想象做题的表)
  1. 如果是第一次调用,则只用根据状态转移矩阵填充第一行的格子
  2. 从第一行填入的第一个格子开始,只要当前的格子里的可达状态集合未成新一行就加进去,然后填后边的格子
  3. 如果当前格子里的已成一行,则跳到下一个可达状态
  4. 重复2,3,直到无新的可达状态集合产生
  1. Simplify,isleast函数
    这两个函数是用于DFA简化的主要函数。
    Simplify函数作用:
    用于将终态和非终态集合分开,然后对其分别调用isleast函数。
    isleast函数作用:用来判断一个集合是否已经最小化,如果没有就处理到最小化
    步骤:
  1. 为当前的集合选取每个条件下的唯一目标集合 填入对应的target数组中
  2. 比较当前集合其中包含的各个状态在同一条件下和这个目标不一样的状态都分裂出去,调用EnableMerge函数判断当前要从原来集合中分离出来的那个状态是否可以与其它分离出来的状态合并为一个状态,如果可以的话调用MergeStates函数(将一个状态从一个状态中分离出来与另一个状态合并的处理),如果不行就调用DepartStates函数(将一个状态从另一个状态集中剥离出来成为新状态的处理)
  3. 分裂出去以后该状态属于的集合就有变化,而原来指向该状态所以指向该集合的target都要改变,所以更新target,调用updateTarget函数(遍历状态列表看看当前状态的target是属于哪个状态集合)
    (4) 测试概述
    ① 测试用例的设计方案
    用了两个测试用例:
    一个是包含所有运算方式的最简单的正规式(a|b).c*
    另一个布置作业中一个比较复杂的,包含21个节点的正规式(a|b).a.b.b.(a|b)
    ② 测试结果
    包含形成NFA的过程,NFA转换成矩阵,确定化矩阵,重命名,简化几个结果
    结果1:
    在这里插入图片描述
    在这里插入图片描述
    结果2:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    ③ 优缺点分析
    优点:要求的功能基本完成,善用数据结构
    缺点:数据结构定义的有些多,可能会对产生阅读障碍,每次打开继续写都会跟不上思路,要半个小时才能进入状态,然后代码完全未考虑效率问题,所以可能效率低下,代码冗余等问题
    (5) 存在问题和改进方向
    不太会用指针,所以没有用,可能造成浪费大量内存空间。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值