这是用 Go 创建新的智能合约语言项目的第二篇文章。在上一篇文章中,介绍了项目的概念,为什么我们决定去构建新的智能合约语言和简要的架构。这个项目就是 WIP 并且开放了源码,你可以在 访问它并随时向我们做出贡献。

koa 架构

项目由四个组件组成:词法分析器,语法分析器,编译器,VM。在这篇文章中我们将深入讨论第一个组件:词法分析器

词法分析器?

tokeneof

词法分析器是怎么工作的?

eof

Token ?

是的,词法分析器制作 tokens …但…什么是 token 呢?我们可以将‘ func ’是视为原始数据,但如果不处理这些数据,这些数据就不能轻易地在其他组件中被使用。token 就是为我们做那样的工作,token 是帮助数据结构化地被表达的数据结构。

TypeValToken

如何进行标记?

状态,行为

我们的词法分析器设计的灵感来源于使用了 状态和行为 概念的 。实际上 也使用了这个概念。

  • 状态 表示词法分析器来自给定输入文本的位置以及我们希望接下来看到的内容。
  • 行为 表示当前状态我们将要做的事情。

我们可以看到词法分析器的工作 - 读取字符,生成 token,继续下一个字符 - 当前状态所做的行为然后前进到下一个状态。在每一个操作过后,你知道你想要到的地方,新的状态是这个行为的结果。

状态函数

这是我们状态函数的声明。状态函数利用当前状态和发送器,返回另外的状态函数。被返回的状态函数是基于当前状态并且知道接下来做什么。我知道虽然状态函数的定义是递归的,但是这样简单且清晰。

emitteremitteremitteremitter

运行我们的状态机

runstateemitteremitter

获取到当前状态,做一些事,运行到下一个状态。

这样做的优势是什么呢?好了,首先,我们没有必要每次都去检测我们处于什么状态。那不是我们关心的。我们总是处于正确的地方。在我们的机器中需要做的唯一的事情就是运行状态函数知道我们遇到空的状态函数。

并发地运行我们的机器

我们没有过多地谈论如何向客户端发送我们生成地 token,并且我认为这里就是恰当的时间了。这个想法就是我们将要运行词法分析器作为一个 Go 协程,附带着可能像是解析器样的客户端,这样两个独立的机器做它们的工作,无论什么时候,当词法分析器有新的东西时,客户端将会取到它并且做它们自己的工作。这种机制能够被 Go channel 所处理。

channel 是 Go 语言最伟大的特性之一并且确实很复杂,但是在我们的词法分析器中,它只是把数据传输到另外一个程序的一种方法,它可能正在完全独立的运行。

NewLexer

怎样实现状态函数?

我们已经看到了我们的词法分析器如何被构建的大图,让我们深入一些:状态函数应该是长什么样的呢?

defaultStateFnnext()
nextpeeknextbackupcut
++
numberStateFn
Illegal

为什么我们像这样设计?当然,我们认为处理错误不是词法分析器的部分,因此传递这个责任给其他接收 token 的。通过这样做,我们可以保持简单,这里没有错误处理的代码,因此有更好的可读性,专注于它的工作。

就这样了!我们已经明白状态函数是如何基本地工作的了。在读取的字符不能充分得制作 token 的情况下就多读一个,如果充分了就生成 token 并且发送。有的情况下字符应该被区别处理然后回退,并且使用选择该字符的不同状态函数处理它。如果字符没有被定义在我们的字符集中,那么生成非法 token 并继续。

结论

所以在这篇文章中我们已经看到词法分析器如何被设计和工作。我们使用状态和动作去给给定的输入字符串做词法分析。伴随它的状态做出行为并继续到下一个状态。通过这样做,我们可以让我们的状态机保持简单和可扩展。

另外,使用 Go 协程同时运行我们的状态机。词法分析器可以独立于其客户端运行,且无论什么时候客户端需要从词法分析器获取 token,客户端可以从发送器推送的通道中获取生成的 token。

在下一篇文章中,我们将要介绍从词法分析器接收 tokens 的解析器并做它自己的工作



本文由 原创编译, 荣誉推出