// 请移步《从零开发一个JVM语言》系列。 // 由于这篇文章有人收藏就不删除了。。
看下面这个表达式
1 + 2 * 3.4 - variable.field
它表达了什么呢?
人在观察一个表达式的过程中,实际上已经对它进行了词法分析。
没有接受过编程训练的人看到它的第一眼也会认为它的组成大概是这样:
| 1
| +
| 2
| *
| 3.4
| -
| variable
| .
| field
|
这也就是词法分析要做的事。
词法(lexical
)分析做的事情很简单,仅仅是将给出的一个或几个句子拆分成便于处理的token
流。token流是指一串token。
我在进行词法分析时做的事情很少。仅仅是生成了包含token原始字符和所在位置,外加一些额外信息组成的节点串。
为了说明我的词法分析器,首先定义一个概念,层
class C
a=1
<<<>>>
每遇到4个缩进,则视为一个新的“层”。 此例中,有3个层次。class C
,a=1
,<<<>>>
(getter/setter)
此外,有一些符号必然开启一个层
,即使后面的字符没有换行并添加缩进。
我规定了几个简易的规则,使得其处理起来非常简便。
- 节点分为3种
ElementStartNode
该节点开启一条独立的节点链Element
该节点记录了实际信息EndingNode
该节点表示一个表达式/语句的结束(分为STRONG
和WEAK
,STRONG表示此语句必然结束,WEAK表示,若该语句尚未完成,则可以跨越该节点到下一条继续取token)
- 规定若干
层
的开启符号 - 规定若干
强结束
符号 - 规定若干
分隔
符号(表示他们之前和之后是不同的节点,而其本身是否记录为节点要看另一个量:不记录符号) - 规定若干
不记录
符号 - 规定注释符号
- 规定若干
字符串
起始字符 - 规定若干
层起始结束对
(PAIR)(由一个开始,由另一个结束) - 规定若干
特殊符号
(这类符号需要特殊处理)
而它们所有,都汇总到一个ListSPLIT
中 这个List是有顺序的。所有字符按其字符串长度降序排序。
##解析 一行一行读取。 检查其缩进,若=上一行+4,则视为新的层
,创建一个ElementStartNode
,并在其上链接之后解析的内容 若比上一行小,则视为跳出层
,找到对应层的ElementStartNode,然后在其后面继续添加节点
取出这一行.trim()
后的串LINE,进行如下算法
- 取
SPLIT
中字符串存在于LINE中,且在LINE中位置的下标最小 且 该串的长度最长
的串 - 对其进行分析,分解出token
- 取该串之后的字符串,进行递归。
中间的分析过程最重要。不过也很简单
取该串在LINE位置下标之前的LINE的子串,若该串不为空,则记录为token
若该串是层开启符号,则记录该串为token后开启一个新ElementStartNode 若该串是强结束符号,则添加一个EndingNode并标记为强结束 若该串是分隔符号,则判断是否是不记录符号,若不是则记录该串为token 若该串是注释符号,则直接清空这一行后面所有的内容 若该串是字符串起始字符,则找到与之相同的符号,且前面没有转义标记的最先找到的字符,将其视为字符串,记录 若该串是PAIR中的起始
,则记录该串后开启一个新ElementStartNode 若该串是PAIR中的结束
,则找到对应ElementStartNode后在其后追加该串 若该串是特殊符号,则进行特殊处理
对LINE中尚未被解析的部分进行该算法。
##例子
class C(x=1):S
y
<-<>->
会被解析成
class
C
(
x
=
1
)
:
S
y
<-<
(STRONG)
>->