【编译原理】第二章,词法分析(2022.3.7更新)

词法分析

这一章,简而言之就是如何实现词法分析器,完成以下的流程

image-20220224200615063

如何实现?词法单元如下,我们要将字符流提取出词素

image-20220224201102985

以下面这个举例:我们要从下面的字符流中提取出 常量,变量,预保留字,如何扫描一次就能区分?

return ( initial <= 10 ) ? 100 : ( position + initial ** 2 ) ;

为了能够更容易的区分,变量的定义要以下划线或字符开始,只能由字符,数字,下划线组成。这就是为什么我们在写程序的时候,变量要这么定义,目的是为了编译!

下面是解析的举例过程

image-20220224202238256

当forward指向( 时,什么都不符合了。从Ps 至 (forword - 1)的串, 为一个保留字。保留字优先变量

我们可以得到一个结论,常量和变量很容易提取出来,保留字的提取就要根据特定的正则表达式了。return符合特定的保留字正则表达式,所以被认为保留字提取了出来。我想之后的也能被提取。


2022.3.3更新,才进入正题

首先明白语法分析的三个概念

  • 词法单元(和类相似)
    • 自定义符号:变量(数据和函数),常量(数值和字符串)
    • 预定义符号:if,for,while,++,+
  • 词素(和实例相似)
    • 词法单元的实例,比如说,123是数值的实例,abc是数据变量的实例
    • 预定义符的实例只有一个
  • 词法单元的模式(类的构成法则)

第一个问题来了,如何判断哪个词素属于哪个词法单元?这是非常重要的问题,123321我们判断为数值,还是变量,还是预定义符?

我们要根据词法单元的模式进行区分,也就是词法单元本身的构成规则来找到匹配的模式,我们用正则表达式来描述这种匹配规则,来描述字符串的集合


2022.3.7更新

正则表达式

正则语言是一门最简单的语言,用它描述目标语言的词法单元及其构成法则,其本质是描述字符串的集合

正则表达式运算方式有:

  • 并运算 例如:L∪M = L | M= {s| s∪L 或者s∪M}
  • 连接运算 例如:{st |s∈L ,t∈M}
  • 闭包运算 例如:L*=∪i=0Li

下面是要记住的正则表达式例子,将用来进行词法分析

  • letter_ → [A- Z a - z _ ] 字母和下划线
  • digit → [0 - 9] 数字0到9
  • id → letter_ (letter_ | digit)* 自定义变量
  • digits → digit+ 0到正无穷
  • number → digits (.digits )?( E [± ]?digits)? 常量

C语言的语法工构成法则为

lexicalRulereservedWord | id | numberConst|stringConst | note | blankSpace | crlfLexeme

语法构成为:预定义符,变量,数字常量,字符常量,注释,空格,回车

正则表达式的状态图

将字符流切分成词素流,表达了一个词素的获取过程

image-20220307164018724

正则表达式: id → letter_ (letter_ | digit)*

image-20220307171110973

正则表达式: if → if

image-20220307171128337

我们知道了C语言的词法分析可以由一个正则表达式来表示,且正则表达式有唯一的状态图,那我们就可以用一个状态图来描述C语言的词法分析

如果用代码来表示状态图之间的变换?

状态图的数据结构是:

class State(
    currentState INT,
    driverChar CHAR,nextState INT,
    type CHAR(CHECK VALUE IN('0','M','E','I');
    category VARCHAR IN ('reserved','id','num','string');
);

0’: 起始状态,‘M’:中间状态,‘E’:匹配状态(不包含exclude),‘I’:匹配状态(包含include)

基于状态转换图的词法分析框架,所有的语言都是类似的

image-20220307172306025

现在问题转化成了如何得出正则表达式的状态转换图?

有穷计算机

将状态转换图形式化,上升为一种理论知识,被称作有穷自动机,分为下面两类

  • 非确定有穷自动机NFA(Nondeterministic Finite Automata)
    特点:一个驱动符号(即边上的符号)可以引出多条边,ε可以是边上的符号

    下面是 (a|b)*abb正则表达式的NFA

    image-20220307173741393

  • 确定性有穷自动机DFA(Deterministic Finite Automata)
    特点:有且仅有一条出边。驱动符号不包含ε

    下面是 (a|b)*abb正则表达式的DFA

    image-20220307173705008

由正则表达式到NFA,再由NFA到DFA,再由DFA到状态图转换程序,这就是上面的答案,并且我们每一步都要完成
image-20220307173950091

正则表示式到NFA

  • 对于单个字符的表达式r = a,构建其NFA
    image-20220307174535248

  • 对于表达式r =s | t ,构建其NFA
    image-20220307174629341

  • 对于表达式r =s t ,构建其NFA
    image-20220307174700154

  • 对于表达式r =s + ,构建其NFA
    image-20220307174726754

  • 对于表达式r =s* = ε| s+ ,构建其NFA
    image-20220307174758029

  • 对于表达式:r =s?=s | ε
    image-20220307174934106

NFA到DFA

对正则表达式的NFA,并不能用于词法分析器的构造。因为NFA中存在不确定

使用穷举办法,把所有可能情况列举出来,把不确定性转变成确定性

例如:

image-20220307175518619

image-20220307175542667

一系列转化过程后,得到转换表,以及最后的结果

image-20220307175618276

值得注意的是,这个得到DFA并不是最简的状态,还能继续简化,可以使用相同的操作,穷举

image-20220307175753892

在构建运算符的NFA时,消去或者减少ε边,就会得到最简的DFA

从正则表达式到DFA,看似不难,却又无从下手。一个由空字符ε驱动的状态迁移,从表面上来看,显得多此一举,毫无意义。但它把问题梳理得直观易懂了,很有说服力了,条理很清晰了。它使得正则表达式到NFA有个一一对应关系,NFA到DFA也有个一一对应关系。这就是数学思维的魅力,艺术的魅力。

DFA到状态图转换程序

留给我们之后具体实现

如果写得不错就麻烦点个赞吧👍,个人博客网站http://www.liangyuanshao.top

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小梁说代码

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值