LALRPOP 解析器基础速成 文档/教程-中文翻译 | LALRPOP Crash course on parsers

✏️ 铅笔开头的内容为译者添加
✏️ 翻译自 LALRPOP 教程 | 解析器基础速 | Crash course on parsers, 这篇为基础速成, 如有基础可跳过, 正式内容在下一篇
✏️ 导航: <<[上篇-介绍] - [目录] - [下篇-快速开始]>>
✏️ 完整的中文文档(共9篇19k字): https://yuhanawa.github.io/posts/2023/57877

解析器基础速成 | Crash course on parsers

如果你以前从未使用过解析器生成器(parser generator), 或者对上下文无关文法(context-free grammars)并不熟悉,这节只是非常简要地介绍一下这个基本概念. 语法(grammar)是一种很好的方式, 可以写出哪些类型的输入是合法的.
在我们的例子中, 我们想支持括号内的数字, 像123, (123)等.我们可以用一个简单的语法来表达这一点, 比如:

Term = Num | "(" Term ")"

在这里, 我们说我们试图解析一个Term(术语), 一个Term可以是一个数字(Num)或其他括号内的Term(这里我们没有定义什么是数字, 但在真正的 LALRPOP 例子中, 我们将用正则表达式来定义). 现在想象一个潜在的输入如((123)). 我们可以通过写出一个叫做 “解析树(parse tree)” 的东西来说明如何解析这个数字:

(  (  1  2  3  )  )
|  |  |     |  |  |
|  |  +-Num-+  |  |
|  |     |     |  |
|  |   Term    |  |
|  |     |     |  |
|  +---Term----+  |
|        |        |
+------Term-------+

这里你可以看到, 我们解析((123))的方法是在中间找到一个Num, 把这个Num称为Term, 然后匹配小括号, 在这个基础上形成另外两个Term.

注意, 这个解析树不是一个数据结构, 而是解析的可视化. 我的意思是, 你可以建立一个解析树作为一个数据结构, 但通常你不会这样做: 因为你不需要这么详细.比如, 你可能对从 NumTerm 的无操作转换并不感兴趣. 关于解析树的另一个讨厌(weird)之处在于它与你的语法密切相关, 但往往你需要解析一些现有的数据结构 – 所以如果你建立了一个解析树, 那么你就必须将解析树转换为这些数据结构, 这可能是烦人的.

因此, 解析器生成器通常做的是让你选择如何表示解析树中的每个节点, 以及如何进行转换. 你给每个非终结符(nonterminal)一个类型, 它可以是任何Rust中的类型, 你写的代码将在每次解析树中的新节点被构建时执行. 实际上, 在后面的例子中, 我们最终会建立类似于解析树的东西, 但在开始时, 我们根本不会这样做. 相反, 我们将把每个数字和 term 表示为一个 i32 , 并且我们将在节点周围传播这个值.

为了使之更具体, 这里有一个用 LALRPOP 编写的上述语法(Term=Num|"(" Term ")")的版本(在后面详细的教程中会再次讲解). 你可以看到 Term 非终结符被赋予了 i32 类型, 每个定义都有一些代码跟在 => 符号后面.这些是将要执行的代码, 该代码会将匹配的内容(如数字或括号内的)Term转换为 i32:

Term: i32 = {
    Num => /* ... number code ... */,
    "(" Term ")" => /* ... parenthesized code ... */,
};

OK, 基础知识到此为止足够了, 让我们正式的开始吧!


LALRPOP 解析器基础速成 文档/教程-中文翻译 | LALRPOP Crash course on parsers
http://yuhanawa.github.io/posts/2023/51562/
作者
Yuhanawa
发布于
2023年1月24日
许可协议