今天查资料的时候看见一句话:「我写博客的习惯,一直都在假想一个小白看我的文章,要怎么样才能说得让他看完我的博客就能明白我讲解的知识点。」,觉得对于我写文章具有指导性的意见,在这里记录下来。

这篇文章是在阅读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,执行代码

执行代码的逻辑具体是什么,参见下一篇文章。