《编译原理》第三章:词法分析(笔记二)

第三章.词法分析

  • 3.1 词法分析简介
  • 3.2 词法分析器的手工构造
  • 3.3 正则表达式
  • 3.4 有限状态自动机
  • 3.5 正则表达式转NFA
  • 3.6 NFA转DFA
  • 3.7 DFA的最小化
  • 3.8 DFA的代码表示

3.1 词法分析简介

  1. 编译器可以拆分成为两个“盒子”,一个前端,一个后端
    《编译原理》第三章:词法分析(笔记二)_第1张图片
    前端又可以拆分成为三个盒子,分别是词法分析器语法分析器语义分析器
    《编译原理》第三章:词法分析(笔记二)_第2张图片
  2. 词法分析器的任务:字符流到记号流
    (1)字符流:和被编译的语言密切相关(ASCII, Unicode, or …)。
    (2)记号流:编译器内部定义的数据结构,编码所识别出的词法单元。
    在这里插入图片描述
  3. 例子:如图所示,把输入的C语言字符流转化成为特定的记号流
    《编译原理》第三章:词法分析(笔记二)_第3张图片
    记号的数据结构定义(也可以采用其他的数据结构)
    《编译原理》第三章:词法分析(笔记二)_第4张图片

3.2 词法分析器的手工构造

  1. 词法分析器的实现方法
    (1)手工编码实现法 :相对复杂、且容易出错。但是是目前非常流行的实现方法,如GCC, LLVM, …
    (2)词法分析器的生成器:可快速原型、代码量较少,但较难控制细节
  2. 转移图
    最开始输入时,我们先判断输入的是>,<还是=,如果是<则继续判断下一个输入是=,>还是其他符号,根据判断返回最终结果。
    《编译原理》第三章:词法分析(笔记二)_第5张图片
    C语言代码实现:rollback()表示回滚到上一个状态
    《编译原理》第三章:词法分析(笔记二)_第6张图片
    扩展内容:
#include  //头文件
fseek(FILE *stream,long offset,int fromwhere)
/*
功能:重新定位流上的文件指针。
具体:函数设置文件指针stream的位置,如果执行成功stream会指向以fromwhere为基准,
      偏移offset个字节的位置(offset可负),如果失败则不改变stram指向的位置。
返回值:成功返回0,失败返回其他值
获取文件位置:
(1)SEEK_SET:文件开头
(2)SEEK_CUR:当前位置
(3)SEEK_END:文件结尾
*/
//例子:
FILE *fp;
fp=fopen(filename,"rb+");
fseek(fp,100L,SEEK_SET);  //把fp指针移到离文件开头100字节处
fseek(fp,-1L*sizeof(S),SEEK_END);  //offset为负数
  1. 标识符的转移图
    《编译原理》第三章:词法分析(笔记二)_第7张图片
  2. 关键字
    (1)从词法分析的角度看,关键字是标识符的一部分
    (2)以C语言为例:
标识符 关键字
以字母或下划线开头,后跟零个或多个字母,下划线,或数字 if,while,else

(3)识别方法:切分转移图关键字表算法
(4)切分转移图(以if为例子):
《编译原理》第三章:词法分析(笔记二)_第8张图片
(5)关键字表算法
对给定语言中所有的关键字,构造关键字构成的哈希表H
对所有的标识符和关键字,先统一按标识符的转移图进行识别
识别完成后,进一步查表H看是否是关键字
通过合理的构造哈希表H(完美哈希),可以O(1)时间完成
《编译原理》第三章:词法分析(笔记二)_第9张图片

3.3 正则表达式

  1. 手工 VS. 自动生成
    《编译原理》第三章:词法分析(笔记二)_第10张图片
  2. 正则表达式
    (1)定义
    《编译原理》第三章:词法分析(笔记二)_第11张图片
    (2)例子
    《编译原理》第三章:词法分析(笔记二)_第12张图片《编译原理》第三章:词法分析(笔记二)_第13张图片
  3. 语法糖
    《编译原理》第三章:词法分析(笔记二)_第14张图片

3.4 有限状态自动机

  1. 有限状态自动机(FA)
    《编译原理》第三章:词法分析(笔记二)_第15张图片
  2. 自动机例子
    (1)确定状态有限自动机DFA:对任意的字符,最多有一个状态可以转移。
    《编译原理》第三章:词法分析(笔记二)_第16张图片
    (2)非确定的有限状态自动机NFA:对任意的字符,有多于一个状态可以转移。
    《编译原理》第三章:词法分析(笔记二)_第17张图片

3.5 正则表达式转NFA

  1. DFA因为状态转移唯一,所以可以通过如图所示列表的方式进行实现。
    《编译原理》第三章:词法分析(笔记二)_第18张图片
    NFA情况复杂,所以实现会复杂一些。需要把NFA转化成为DFA再进行词法分析
    在这里插入图片描述
  2. Thompson算法
    《编译原理》第三章:词法分析(笔记二)_第19张图片
    例子:a (b | c)*
    《编译原理》第三章:词法分析(笔记二)_第20张图片

3.6 NFA转DFA

  1. 算法思想消除非确定性——找出一个字符可能转移到的所有状态,将这些状态的集合做为一个状态。(读入这个字符去往的状态肯定属于该集合)
    《编译原理》第三章:词法分析(笔记二)_第21张图片
  2. 例子
    《编译原理》第三章:词法分析(笔记二)_第22张图片
    《编译原理》第三章:词法分析(笔记二)_第23张图片
  3. 子集构造算法伪代码
    (1)NFA=(∑, S, q0, F, D),DFA=(∑, S*, q0*, F*, D*)
    《编译原理》第三章:词法分析(笔记二)_第24张图片
    (2)算法不可能无限运行下去,因为该算法的时间复杂度在最坏的情况下为O(2^N),而最坏情况基本不会出现,因为并不是每个子集都出现。
  4. ε-闭包的计算的伪代码(深度优先)
    《编译原理》第三章:词法分析(笔记二)_第25张图片

3.7 DFA的最小化

  1. 状态压缩合并
    《编译原理》第三章:词法分析(笔记二)_第26张图片
  2. 伪代码
    (1)将状态最开始分为两类N和A,A为终止状态。
    《编译原理》第三章:词法分析(笔记二)_第27张图片

3.8 DFA的代码表示

  1. DFA是一个有向图,其代码表示可为转移表,跳转表,哈希表等,选择哪一种表示方式取决于在实际现实中对时间空间的权衡。
  2. 转移表
    《编译原理》第三章:词法分析(笔记二)_第28张图片
    (1)最短匹配驱动代码:如果识别的是if,则在读取字符串ifif时,读取到第一个if时直接返回。
    《编译原理》第三章:词法分析(笔记二)_第29张图片

(2)最长匹配驱动代码:最后返回ifif。
《编译原理》第三章:词法分析(笔记二)_第30张图片
3. 跳转表
《编译原理》第三章:词法分析(笔记二)_第31张图片

你可能感兴趣的:(#,编译原理,编译器)