1 弁言
重回 “手写 SQL 编辑器” 系列。之前几期引见了 词法、文法、语法的剖析,以及回溯功用的完成,此次引见怎样天生语法树。
基于 《回溯》 一文引见的思绪,我们应用 JS 完成一个微型 SQL 剖析器,并引见怎样天生语法树,怎样在 JS SQL 引擎完成语法树天生功用!
剖析目的是:
select name, version from my_table;
文法:
const root = () => chain(selectStatement, many(";", selectStatement));
const selectStatement = () => chain("select", selectList, fromClause);
const selectList = () => chain(matchWord, many(",", matchWord));
const fromClause = () => chain("from", matchWord);
const statement = () =>
chain(
"select",
selectList,
"from",
chain(tableName, [whereStatement, limitStatement])
);
这是本文为了轻易申明,完成的一个精简版本。完全版见我们的开源堆栈
cparser。
root
是进口函数,many()
包裹的文法能够实行恣意次,所以
chain(selectStatement, many(";", selectStatement));
示意许可恣意长度的 selectStatement
由 ;
号衔接,selectList
的写法也同理。
matchWord
示意婚配恣意单词。
语法树是工资对语法构造的笼统,本质上,假如我们到此为止,是能够天生一个 基础语法树 的,这个语法树是多维数组,比方:
const fromClause = () => chain("from", matchWord);
这个文法天生的默许语法树是:['from', 'my_table']
,只不过 from
my_table
详细是何寄义,只要当前文法晓得(第一个标志无寄义,第二个标志示意表名)。
fromClause
返回的语法树作为效果被通报到文法 selectStatement
中,其效果多是:['select', [['name', 'version']], ['from', 'my_table']]
。
人人不难看出题目:当默许语法树群集在一起,就没法离开文法构造零丁明白语法寄义了,为了离开文法构造明白语法树,我们须要将其笼统为一个有规可循的构造。
2 精读
经由历程上面的剖析,我们须要对 chain
函数供应修正部分 AST 构造的才:
const selectStatement = () =>
chain("select", selectList, fromClause)(ast => ({
type: "statement",
variant: "select",
result: ast[1],
from: ast[2]
}));
我们能够经由历程分外参数对默许语法树举行革新,将多维数组构造改变成对象构造,并增添 type
variant
属性标示当前对象的范例、子范例。比方上面的例子,返回的对象通知使用者:“我是一个表达式,一个 select 表达式,我的效果是 result,我的泉源表是 from”。
那末,chain
函数怎样完成语法树功用呢?
关于每一个文法(每一个 chain
函数),其语法树必需守候一切子元素实行完,才天生。所以这是个深度优先的运转历程。
下图形貌了 chain
函数实行机制:
天生构造中有四个基础构造,分别是 Chain、Tree、Function、Match,足以表达语法剖析须要的一切逻辑。(不包括 可选、多选 逻辑)。
每一个元素的子节点悉数实行终了,才会天生当前节点的语法树。实际上,每一个节点实行完,都邑挪用 callParentNode
接见父节点,实行到了这个函数,申明子元素已胜利实行终了,补全对应节点的 AST 信息即可。
关于修正部分 AST 构造函数,需守候全部 ChainNode
实行终了才挪用,并将返回的新 AST 信息存储下来,作为这个节点的终究 AST 信息并通报给父级(或许没有父级,这就是根结点的 AST 效果)。
3 总结
本文引见了怎样天生语法树,并申清楚明了 默许语法树 的存在,以及我们之所以要一个定制的语法树,是为了更轻易的明白寄义。
同时引见了怎样经由历程 JS 运转一套完全的语法剖析器,以及怎样供应自定义 AST 构造的才。
本文引见的模子,只是为了便于明白而定制的简化版,相识悉数细节,请接见 cparser。
末了说一下为什么要做这个语法剖析器。现在有很多开源的 AST 剖析东西,但笔者要处理的场景是语法自动提醒,须要在语句不完全,以至毛病的状况,给出当前光标位置的一切能够输入。所以经由历程完全重写语法剖析器内核,在剖析的同时,天生语法树的同时,也给出光标位置下一个能够输入提醒,在通用毛病场景自动从毛病中恢复。
现在在做机能优化,通用 SQL 文法还在连续完美中,现在仅可当进修参考,不要用于临盆环境。
4 更多议论
假如你想介入议论,请点击这里,每周都有新的主题,周末或周一宣布。