E518a242692c326791cb5f58c829eaf6
Python 词法分析(二)

Python 词法分析(二)

上周写了初步词法分析生成涉及的数据结构以及对应产生的Token,但是有些同学反馈直接上手有点复杂,因此我决定今天先补充一章节,脱离Python的前提,谈谈词法分析该过程本身。

为什么需要词法分析

从词法分析的作用本身出发,我们输入一段源代码对应的文本,输出按照我们所使用的语言对应的词法记号。

这一段的目的是什么呢?本质上,我们所使用的任何高级语言,都不可能无限制的支持我们所需要的能力,比如我们不能在Objective-C里面使用guard,因为Objective-C里面关键字定义就不包含。因此,极简化考虑,我们需要一个办法能识别出我们的程序里面是不是使用了guard:如果在swift里面,那就是使用了这个关键字;而如果没有,则这个guard仅仅是个标识符,或是变量、或是函数名等等。

在词法分析的步骤中,只能知道其是个标识符,还不知道其具体含义。

因此,按照计算机分层的设计思想,我们需要一个层,来解决从源代码的文本到一个个字符记号的转换步骤。这就是词法分析在现在主流编译步骤中的作用。

词法记号

一般来说,词法记号分为如下几种:

  • 标识符:

    比如print, k, haha。在词法分析的步骤的时候,还不知道这标识符是什么含义。

  • 关键字:

    C语言来举例,关键字包含if, else, while, int, char等等,这些都是高级语言设计的时候定义好的,是个有限的集合。

  • 常量:

    比如char c = 'e',那这个e就是个字符常量。一般情况下还有数字常量以及字符串常量。一方面可以为这些常量做提前处理优化,比如二进制字符串节的字符共享,也可以为后续中间代码优化过程中涉及的常量传播做优化准备。这块我们后文再表。

  • 界符:
    包括运算符、分隔符等等,如+-, >=, ;

词法分析步骤

词法分析严格来说可以分为两个小步骤:(1)读取文件进行字符流解析(2)根据状态机将字符流转换成对应的词法记号以及必要时保存词法记号对应的值(比如常量)

读取文件流

本质上来讲,读取文件流没什么技术含量,一个个从磁盘文件中读字符就好了。但是处于性能考虑(避免多次大量IO操作),主流编译器在读取文件过程中,都采用了预取一批进入缓冲区,然后先逐字解析缓冲区中的内容,知道缓冲区了空了,再进行下次磁盘文件读取的过程。

在上文Python的词法分析中,我们也提到了tok_stateinp的作用是类似的。

词法记号状态机

名字上是状态机,必不可少的我们就要来画画状态转移图了,为了减少篇幅,我们以数字来举例:

一般情况下,C语言里面支持10进制数,8进制数,2进制数,16进制数。

  • 10进制数,0-9。(但是以0开头的数字后续不能跟数字)
  • 8进制数,0开头,后续只能跟0-7的数字
  • 2进制数,0b开头,后续只能跟0-1
  • 16进制数,0x开头,后续能跟0-9以及字符a-f或者(A-F)。

其实你把纯0的数字当成任一紧致都行,反正计算的结果是相同的。

根据这个描述,我们可以随手画出状态转移图:

top Created with Sketch.