1.2 预备工作 - Source
按照前文的介绍,我们本应该探索如何实现词法解析了。在进行词法分析器的讲解之前,我们最好还是先介绍辅助类 Source。
在读取字符串的过程中,我们需要统一换行符以及支持先行预测「Lookahead」,需要这些功能的原因后面会介绍。
Source 类的结构如下:
为了简化源文件的处理过程,我们将需要处理的源文件一次性整个地读取到属性 code
中,其余属性的含义分别为:
在 JS 中,可以通过下标来检索字符串中的字符。所以我们可以通过属性 ofst
作为下标来检索 code
中的字符,即 this.code[this.ofst]
的方式。
ch
表示我们当前读取到的字符。
ofst
被设定为指向当前字符 ch
在 code
中的索引位置。
比如,对于字符串 abcd
而言,当 ch
为 a
时,ofst
的值为 0
。为了读取下一个字符 b
,我们需要先将 ofst
加 1,以加 1 后的值作为索引来检索字符,即:
因此,ofst
的初始值被我们设定为 -1
。
在不断的读入字符的过程中,我们还需要维护行列号,行列号主要用作生成调试信息。
Source 类目前只包含两个方法,分别是 read
和 peak
。它们的作用都是读取给定数量的字符,组成字符串后返回给调用者。区别在于,read
方法会改变位置信息,包括 ch
、ofst
、line
、col
,而 peek
方法则不然。
我们使用 peek
方法来做先行预测,在出现可能分叉的地方进行使用。比如 Lua 中注释以 --
开头,我们可以直接向前 peek 两个字符,看看它们是否符合条件。
为了使读者能够快速地运行文中的代码,所有代码都可以在 node v11.5.0
下直接运行而不需要借助 Babel 之类的编译器。当然读者还是需要在运行前注意一下代码中的 require
路径是否和自己的环境相匹配。
下面给出 Source 的代码和注释:
对于类「Position」和方法 Source::getPos()
,很明显它们是分别用于存放和获取 Source 的位置信息的。
目前为止,我们 Source 类的功能有这几点:
所有对源码的读取操作将通过 Source 类的实例来完成
我们可以在读取的过程中维护当前的读取位置
我们将不同的换行符都进行了统一,返回 EOL
我们还提供了预读功能,就是在不改变当前位置信息的情况下,往前读取几个字符。
Last updated