Chat | 词法分析与语法分析的原理及部分实现

作者:浅浅,目前就读于闽南师范大学,喜欢唱、跳、rap 和篮球。

1. 简介

词法分析器是用于识别单词所构筑的一个自动识别程序。其本质是词法分析,由一正规文法或是正规表达式推导出不确定的有穷自动机 NFA,再确定化得到确定的有穷自动机 DFA,最后最小化得到一个最简 DFA,输入符号串,识别单词。

语法分析器是在词法分析器的基础上实现识别一符号串是否符合相关文法,其本质是语法分析,而语法分析有两种分析方法:自顶向下与自底向上。自顶向下的代表方法是 LL(1) 分析;自底向上的代表方法是算符优先分析、LR(0) 分析、SLR(1) 分析。

本文的读者包括以下几类:

  1. 对编译原理有兴趣,想要了解的;

  2. 想要编写自制编译器的。

本文要求读者具有以下几点基础:

  1. 了解基本数据结构,例如:栈(因为在语法分析的过程中,使用了分析)。

  2. 对文法有基本的了解与认识。

通过本文能够收获以下内容:

  1. 词法分析的原理描述与实例化完全题解以及词法分析器的简易实现;

  2. LL(1) 分析法中对 First 集、Follow 集、Select 集的直接解析,带实例化题解;

  3. 算符优先分析法,这是一种只考虑终结符,不考虑非终结符的分析方法,带实例化题解;

  4. LR(0) 分析法,讲述活前缀与分析表的创建等一系列的先导知识,再带实例化题解;

  5. SLR(1) 分析法,相较于 LR(0) 分析,SLR(1) 引入了 Follow 集,带实例化题解。

备注:本文可能会带有不定时更新。

更新方向:LR(1) 分析,LALR(1) 分析,基于算符优先分析的语法分析器快速实现,语义分析。

2. 词法分析

当我们希望识别程序中的关键字、保留字、运算符、数字、标识符等等单词时,就会使用词法分析来构建词法分析器,这是一种识别单词的手段。

我们通过最初的文法,这里要求是正规文法,当然也可以是正规表达式,推导出 NFA,接着 NFA 会通过两种操作 ε-closure(I) 和 move(I,a) 确定化得到 DFA,最后是去掉 DFA 中的多余路线和有害路线得到最小化 DFA。针对本段中提到的几个名词,下面做个描述。

  • NFA:学名为不确定的有穷自动机(Nondeterministic Finite Automata)。它其实是由于通过正规文法或者正规表达式推导出图形时,会产生一些不确定的状态跳转,导致最后可能出现二义性,因此被称作是不确定的。

  • DFA:学名为确定的有穷自动机(Deterministic Finite Automata)。NFA通过 closure() 和 move() 操作后,得到一个没有冲突识别的自动机,称作是 NFA 的确定化,最终产物就是 DFA。

  • ε-closure(I):表示说I状态通过任意条ε弧能够跳到的其他状态,这是个闭包。比如说下图的状态 S,它的 ε-closure(S)={S,J,C,E,D}。

【闭包示意ε-closure(S)图2-1】

  • move(I,a):指的是,状态集合 I 通过一条 a 弧,能够跳转到的全部状态。例如说上图中的状态 S,我们已经得到了它的闭包 ε-closure(S)={S,J,C,E,D}。设这个闭包的集合为 A,那么 move(A,a)={g};如果是 b 弧,则 move(A,b)={g}。

至此,我们把所需要的概念已经理了一遍,如果有哪里尚未提及,会在后文学习时用粗体加粗。

2.1 词法分析的过程详解

词法分析的过程如下图所示。

【图2.1-2:词法分析流程图】

每一部分都采用例题解析的方法,最后慢慢地叠加成一个完整的词法分析过程。这样子更加符合人脑对知识的获取过程,如果一上来就把整个体系塞进读者的脑子里,这样子可能会不太友好,不断加叠的增量模型更贴合实际生产需要。

2.1.1 正规表达式推导 NFA

例题 A:给定一正规表达式:1(0|1)*101,请画出其 NFA,其中 * 表示 (0|1) 的闭包。

当我们看到题目的时候,实际上不管给的正规表达式抑或是正规文法,我们总能够构建出 NFA,因此就本例题而言,构建 NFA 图,不难。在做题之前,引入三个推导方向。

对于 ε 弧而言,可以有:

【图2.1.1-3ε弧图】

对于终结符弧,例如 a 弧,可以有:

【图2.1.1-4a弧图】

对于空集而言,可以有:

【图2.1.1-5空集图】

于是通过上述的推导方向,可以推导出例题 A 中给出的正规表达式所得到的 NFA 转换图。

【图2.1.1-6NFA图】

2.1.2 NFA 确定化为 DFA

NFA 确定化为 DFA 需要使用两种集合操作,一个叫做 ε-closure(),一个叫做 move(),这两个操作在上文中已经对其做出了明确的解释,那么此刻我们需要针对下图,做出一个状态确定。

【图2.1.2-7 NFA练习图】

分析过程如下表:

其中由于排版方便,状态一栏均省略

由上述确定化矩阵可以得到一 DFA 如下:

【图2.1.2-8 确定化后的DFA】

其中 a、b、c、d、e 均为集合 T 的下标。

2.1.3 DFA最小化

DFA最小化的目的就是去除多余路线以及有害路线。

【多余路线图示2.1.3-9】

【有害路线图示2.1.3-10】

举个简单的 DFA,如下图所示,请去掉其中的有害路线以及多余路线。

【简单的DFA图示2.1.3-11】

最小化后得到最小 DFA:

【最小化简单DFA图示2.1.3-12】

2.2 实例化练习题解

经过了前面冗长的原理 + 例题解析的增量学习模式,现在我们来尝试着完整地做一道较为复杂的练习题。

有一种用以证明两个正规表达式等价的方法,那就是构造它们的最小 DFA。请证明下面两个正规表达式等价。

(a|b)*
(a*|b*)*

首先按着词法分析的流程,先将上面两个正规表达式转化为不确定的有穷自动机 NFA。

【图2.2-10:(1)NFA图】

【图2.2-11:(2)NFA图】

接着通过 NFA 确定化方法,确定其 DFA,过程如下表。

的确定化过程:

的确定化过程:

接着由如上确定化过程表,得到对应的 DFA 图,如下:

【图2.2-11:(1)DFA图】

【图2.2-12:(2)DFA图】

最后最小化这两个 DFA 图,删掉有害路线和多余路线,如下:

【图2.2-13:(1)最小化的DFA】【图2.2-14:(2)最小化的DFA】

由上述最简 DFA 图可知,正规表达式 (a|b)*(a*|b*)* 是等价的。

至此,词法分析已经结束,第二节主要的知识点在于正规表达式与 NFA 之间的等价转化,还有 NFA 的确定化,而最简 DFA 实际上也不需要怎么考虑,因为有时候当你从 NFA 确定化成 DFA 时,就已经会将多余路线与有害路线过滤掉了。

由于篇幅有限,感兴趣的同学可以直接扫描下方二维码继续阅读。

词法分析器是用于识别单词所构筑的一个自动识别程序。其本质是词法分析,由一正规文法或是正规表达式推导出不确定的有穷自动机 NFA,再确定化得到确定的有穷自动机 DFA,最后最小化得到一个最简 DFA,输入符号串,识别单词。

语法分析器是在词法分析器的基础上实现识别一符号串是否符合相关文法,其本质是语法分析,而语法分析有两种分析方法:自顶向下与自底向上。自顶向下的代表方法是 LL(1) 分析;自底向上的代表方法是算符优先分析、LR(0) 分析、SLR(1) 分析。

本文的读者包括以下几类:

  1. 对编译原理有兴趣,想要了解的;

  2. 想要编写自制编译器的;

本文要求读者具有以下几点基础:

  1. 了解基本数据结构,例如:栈【因为在语法分析的过程中,使用了分析栈】

  2. 对文法有基本的了解与认识。

通过本文能够收获以下内容:

  1. 词法分析的原理描述与实例化完全题解以及词法分析器的简易实现;

  2. LL(1) 分析法中对 First 集、Follow 集、Select 集的直接解析,带实例化题解;

  3. 算符优先分析法,这是一种只考虑终结符,不考虑非终结符的分析方法,带实例化题解;

  4. LR(0) 分析法,讲述活前缀与分析表的创建等一系列的先导知识,再带实例化题解;

  5. SLR(1) 分析法,相较于 LR(0) 分析,SLR(1) 引入了 Follow 集,带实例化题解。

备注:本文可能会带有不定时更新。

更新方向:LR(1) 分析;LALR(1) 分析;基于算符优先分析的语法分析器快速实现;语义分析。

 

点击阅读原文,查看 Chat 详情

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个里面的都是测试数据,总共得分5分。从控制台输入,不能从文件中读取。实现了基本功能,加分项目都没有去实现,没有函数数组这些的实现。这是用C++语言写的,新建parser类别要选C++,其他对于VS的配置和C语言一样。for语句用的是枚举所有情况,你可以自行修改。 对预备工作中自然语言描述的简化C编译器的语言特性的语法,设计上下文无关文法进行描述 借助Yacc工具实现语法分析器 考虑语法树的构造: 1.语法树数据结构的设计:节点类型的设定,不同类型节点应保存哪些信息,多叉树的实现方式 2.实现辅助函数,完成节点创建、树创建等功能 3.利用辅助函数,修改上下文无关文法,设计翻译模式 4.修改Yacc程序,实现能构造语法树的分析器 考虑符号表处理的扩充 1.完成语法分析后,符号表项应增加哪些标识符的属性,保存语法分析的结果 2.如何扩充符号表数据结构,Yacc程序如何与Lex程序交互,正确填写符号表项 以一个简单的C源程序验证你的语法分析器,可以文本方式输出语法树结构,以节点编号输出父子关系,来验证分析器的正确性,如下例: main() { int a, b; if (a == 0) a = b + 1; } 可能的输出为: 0 : Type Specifier, integer, Children: 1 : ID Declaration, symbol: a Children: 2 : ID Declaration, symbol: b Children: 3 : Var Declaration, Children: 0 1 2 4 : ID Declaration, symbol: a Children: 5 : Const Declaration, value:0, Children: 6 : Expr, op: ==, Children: 4 5 7 : ID Declaration, symbol: a Children: 8 : ID Declaration, symbol: b Children: 9 : Const Declaration, value:1, Children: 10: Expr, op: +, Children: 8 9 11: Expr, op: =, Children: 7 10 12: if statement, Children: 6 11 13: compound statement, Children: 3 12

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值