编译原理之美
宫文学
北京原点代码 CEO
46197 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 45 讲
开篇词 (1讲)
编译原理 · 期中考试周 (1讲)
编译原理之美
15
15
1.0x
00:00/00:00
登录|注册

02 | 正则文法和有限自动机:纯手工打造词法分析器

软件工具因支持正则表达式而变得强大
正则表达式的应用
理解原理的重要性
实现词法分析器的步骤
示例程序输出
修改有限自动机和代码
增加的词法规则
示例程序输出
有限自动机修改
关键字和标识符的冲突
词法规则的正则表达式
正则表达式的重要性
正则表达式规则
示例程序输出
有限自动机的状态
标识符、比较操作符和数字字面量的词法规则
有限自动机示意图
有限自动机
正则表达式
一边读取一边识别字符串
Token
将一个长长的字符串识别出一个个的单词
一课一思
课程小结
解析算术表达式
解析int age = 40,处理标识符和关键字规则的冲突
初识正则表达式
解析 age >= 45
词法分析的核心机制
词法分析的工作
如何纯手工打造一个词法分析器

该思维导图由 AI 生成,仅供参考

上一讲,我提到词法分析的工作是将一个长长的字符串识别出一个个的单词,这一个个单词就是 Token。而且词法分析的工作是一边读取一边识别字符串的,不是把字符串都读到内存再识别。你在听一位朋友讲话的时候,其实也是同样的过程,一边听,一边提取信息。
那么问题来了,字符串是一连串的字符形成的,怎么把它断开成一个个的 Token 呢?分割的依据是什么呢?本节课,我会通过讲解正则表达式(Regular Expression)和有限自动机的知识带你解决这个问题。
其实,我们手工打造词法分析器的过程,就是写出正则表达式,画出有限自动机的图形,然后根据图形直观地写出解析代码的过程。而我今天带你写的词法分析器,能够分析以下 3 个程序语句:
age >= 45
int age = 40
2+3*5
它们分别是关系表达式、变量声明和初始化语句,以及算术表达式。
接下来,我们先来解析一下“age >= 45”这个关系表达式,这样你就能理解有限自动机的概念,知道它是做词法解析的核心机制了。

解析 age >= 45

在“01 | 理解代码:编译器的前端技术”里,我举了一个词法分析的例子,并且提出词法分析要用到有限自动机。当时,我画了这样一个示意图:
我们来描述一下标识符、比较操作符和数字字面量这三种 Token 的词法规则。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文详细介绍了如何通过纯手工打造一个词法分析器,通过讲解正则表达式和有限自动机的知识来解决这个问题。作者首先解析了一个关系表达式“age >= 45”,并提出了词法分析要用到有限自动机。然后详细描述了标识符、比较操作符和数字字面量这三种Token的词法规则,并构造了相应的有限自动机。接着,作者介绍了初识正则表达式,将词法规则用正则表达式表达,并解释了几种规则中用到的符号。最后,作者表示在后续课程中将带领读者用工具生成词法分析器,而工具读取的就是用正则表达式描述的词法规则。整体来看,本文通过实例和代码示例生动地介绍了词法分析的原理和实现过程,为读者提供了一种纯手工打造词法分析器的方法。文章内容涵盖了词法分析器的原理、正则表达式和有限自动机的应用,对于想要深入了解词法分析的读者来说,是一篇值得阅读的技术文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《编译原理之美》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(102)

  • 最新
  • 精选
  • KnowNothing
    老师,在关键字和保留字的识别上,我认为有不需要加入中间状态的更简单的方式: 完成词法分析后,遍历所有ID token,如果其text在关键字和保留字集合内,将该token类型改成对应的关键字/保留字类型。 或者, 每当识别出一个ID token,都检查其text,如果是在关键字和保留字集合内,纠正type。

    作者回复: 没错,可以的。 但是构造成有限自动机的话,程序就可以标准化处理。不需要再手写其他代码。比如正则表达式工具。 当然,如果纯手写词法分析器,不受任何标准算法的限制的话,那发挥空间就会大很多。 爱动脑的好同学!

    2019-08-16
    14
    63
  • 傲娇的小宝
    感觉有限状态机有点类似图灵机的工作方式。我一般只用正则匹配一下文件名或者某个字符串是否符合我的预期。

    作者回复: 有限自动机是比较简单的一种自动机,对应于正则文法,也叫做3型文法。 比它强大的是下推自动机,对应于上下文无关文法,也叫做2型文法。 比它更强大的是线性有界自动机,对应于上下文相关文法,也叫1型文法。 图灵机的范围比它们都大,它对应0型文法。你任何能用产生式写出来的文法规则,都属于0型文法。 希望对你有帮助,了解有限自动机和图灵机的关系:)

    2019-08-18
    2
    61
  • 易林林
    宫老师,例子里面的词法分析大多是靠条件判断来实现,如果对一门完整的语言来进行分析的话,工作量会不会很大。我在想,是否有其他方式可以实现?

    作者回复: 课程的示例代码的主要目的是把意思讲明白,我甚至把状态都用枚举表示,就是为了易读。性能不是第一考虑。 从性能的角度,词法分析可以用查表的方法实现状态迁移。在每个状态,接收什么字符,切换到另外的状态。那样更快,这是常用的方法。 不光词法分析可以这么做,语法分析也可以。基于表驱动。这时候,最重要的是构造那张表。代码的话,就不大看明白是啥意思。

    2019-08-17
    50
  • Fan
    宫老师,有没有一些词法分析的demo可以推荐看看呢?

    作者回复: 最好的demo,就是现有语言的词法分析器,比如Java的、GNU c的,都能拿到源代码。比如Java的编译器在JDK的源代码里就有。 此外,我们在后端时会讲到LLVM工具。LLVM的文档里有一个小的教程,做了一个完整的前端。你也可以参考一下。http://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.html 回头我整理一份清单放到github上,告诉大家去哪里下载。你的需求估计其他同学也有。 谢谢你!

    2019-08-16
    2
    31
  • 逗逼师父
    老师您好,我的疑问是,age>=45的有限状态机图中,为什么比较操作符不像标识符那样停留在同一个状态?我觉得>和>=都是属于比较操作符呀

    作者回复: 很好的问题。 是这样的。从Token分类的角度,我们确实可以把这两个归为一类。 但如果把它们看做同一个状态,就会有一些问题。比如,接收到=号应该怎么处理呢?接收第一个=号,仍然处于比较操作符状态。那么接收第二个呢?问题是,有限状态机接收字符的时候,是没法数个数的。如果你要记个数,也就相当于在内部新增加了一个状态,还是等价于两个状态。我这么说你理解吗?

    2019-08-17
    5
    22
  • 宋健
    老师,我写完这一节激动的浑身发抖,自己果然实现了一个简单的词法分析器!老师讲得太棒了!

    作者回复: 主要是你自己的功劳:) 在技术领域,有时候你会觉得某个领域高山仰止,其实你自己也可以成为高山上的一棵青松。知识这东西,就在那里,只要想学,没有可能学不会。一旦学会,没有可能再变得不会,是个只会增加的过程,这是多便宜的事情! 不过,学习过程中,肯定还是会遇到挫折的,会觉得难懂,会觉得坚持不下去。这也没关系。你吃的苦越多,进入的境界就越高,这都是值得的!

    2020-03-24
    20
  • 诺亚
    isAlpha 的 alpha 好像没有字母的意思吧?用 alphabet 会不会比较合适点?

    作者回复: 你很细心,所以我也仔细给你解答下:-) isAlpha是 is alphabetic 的缩写。isalpha()函数是好几个语言的标准库里都提供的,比如C、python等。 alphabet指的是整个字母表,不是字母表里的单个字母。

    2019-08-25
    2
    20
  • (╯‵□′)╯︵┻━┻
    有回随手发现Google搜索可以使用正则表达式……然后感觉星星都亮了

    作者回复: 嗯。等你学了算法篇第16讲,了解了正则表达式的机制后,可以设计点正则表达式测试一下谷歌的性能,看看能否把谷歌的服务器累趴下...

    2019-10-03
    15
  • 请叫我赓哥
    您好,老师,初步接触编译原理,您讲的手工打造词法分析,是用已知的java或c或其他语言实现,我想问一下,c语言的编译器是用什么实现的呢,或者其他语言的编译器?另外其他的词法分析器又是用什么语言编写的呢,谢谢

    作者回复: 在编译领域,有一个事情,叫做自举(bootstraping),也就是这门语言的编译器可以用自己这门语言编写。这是语言迈向成熟的标志。一般前面的版本,是要借助别的语言编写编译器,但后面就应该用自己的语言来编译了。 著名的语言都实现了自举。比如,go语言的编译器是用go编写的(早期版本应该是用C语言写的编译器。能实现自举,还是go发展历程上的一个历程碑),jdk里面自带了java语言的编译器,本身也是用java写的。 更早的语言,那当然是用汇编写编译器。比尔盖茨当年就是用汇编写。 掌握编译原理之后,其实用什么语言都可以写。 这门课程的示例语言是playscript。我有计划后面把playscript实现自举。

    2019-08-28
    2
    15
  • 梓航(﹏)
    我是来提意见的,麻烦老师在讲示例的时候,把对应的github链接贴上,而不是在最后贴一个总的地址,我点进去一脸懵,哪个文件对应哪个例子啊?

    作者回复: 好的,谢谢您提意见!已通知后台调整一下。 02课的文件是目录中的SimpleLexer.java文件。 另,如果到github的https://github.com/RichardGong/PlayWithCompiler项目主页,里面有每堂课的课件的介绍,供您参考。

    2019-08-17
    15
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部