今天查资料的时候看见一句话:「我写博客的习惯,一直都在假想一个小白看我的文章,要怎么样才能说得让他看完我的博客就能明白我讲解的知识点。」,觉得对于我写文章具有指导性的意见,在这里记录下来。
这篇文章是在阅读GitHub - mattn/anko: Scriptable interpreter written in golang时候的笔记
anko
GitHub - mattn/anko: Scriptable interpreter written in golang是一个语法类似于 go,并且使用 go 作为引擎执行的脚本语言。
公司目前使用的最常见的语言是 go,在某些业务(如:提供用户在某些条件下触发 trigger 的能力)下,需要执行一些用户的脚本,这个时候,我们就用到了 anko。
但是有几处地方使用到了 anko,大家对于 anko 不断的重复封装,所以决定在公司内部封装一套含有我们内部 API 的 anko。
我可能会涉及到这部分业务代码的编写和 review,所以看了一下 anko 的源代码,这也是本篇文章的由来(如果有下一篇文章,那么也是本系列文章的由来。
注意:本代码阅读,截止 commit:https://github.com/mattn/anko/commit/45d93882b6a0a4a02bd31a9265d325c44a8a4964 。
我的疑问
- 我以前没有接触过编译器相关,一直有一个疑问:如何识别代码
- import 如何处理
- import 的包和定义的函数怎么就调用到了
代码结构
anko 代码里面有一些包,本节要讲的是:
ast // 抽象语法树结构
parser // 解析脚本字符串,生成抽象语法树
vm // 执行脚本
其他的暂时忽略掉
解析脚本,生成抽象语法树
代码参见:https://github.com/mattn/anko/blob/45d93882b6a0a4a02bd31a9265d325c44a8a4964/parser/lexer.go#L518
解析脚本的入口
import "github.com/mattn/anko/ast"
func ParseSrc(src string) ([]ast.Stmt, error)
这里面的步骤如下:
- goyacc 将 parse 包下的 parsr.go.y 文件生成为 parse.go
- lexer.go 里面的
type Lexer struct
实现了生成的代码里面的type yyLexer interface
-
Lexer
被传递给生成的代码里面的yyParser
,进行解析 - 最后返回
l.stmts
作为解析结果,类型是[]ast.Stmt
到底如何解析,参见下一篇文章。
执行脚本
https://github.com/mattn/anko/blob/45d93882b6a0a4a02bd31a9265d325c44a8a4964/vm/vmStmt.go#L23
- 循环
l.stmts
,执行代码
执行代码的逻辑具体是什么,参见下一篇文章。