1个不稳定版本

0.3.0 2021年10月5日

#134 in 解析工具

BSD-3-Clause

465KB
10K SLoC

antlr4rust

Crate docs ANTLR4 testsuite cargo test

ANTLR4 Rust编程语言的运行时。

示例请参阅grammarstests/gen(对应生成的代码)和tests/my_tests.rs(实际使用示例)。

ANTLR4工具(解析器生成器)

生成器部分目前位于我的antlr4分叉的rust-target分支rrevenantt/antlr4/tree/rust-target。最新版本会自动构建到这个仓库的发布中。所以如果你只想生成解析器或者只想贡献运行时部分,你不需要自己构建。

但如果你想自己构建或修改生成器

  • git clone -b rust-target https://github.com/rrevenantt/antlr4 - 克隆我的antlr4分叉
  • git submodule update --init --recursive - 更新Rust目标子模块
  • mvn -DskipTests install - 构建生成器

实现状态

目前开发正在进行此仓库中,但最终将合并到主ANTLR4仓库中

自版本0.3起支持稳定的Rust。之前的版本不再维护,因此如果发生nightly中断,你应该迁移到最新版本。

使用方法

你应该使用ANTLR4 "工具"生成一个解析器,它将使用这里定位的ANTLR运行时。你可以使用以下命令运行它

java -jar <path to ANTLR4 tool> -Dlanguage=Rust MyGrammar.g4

有关antlr4工具选项的完整列表,请访问工具文档页面

您还可以将 build.rs 作为 build.rs 配置的示例,以自动重建解析器,如果语法文件已更改。

然后,将以下内容添加到将使用生成的解析器的 crate 的 Cargo.toml

[dependencies]
antlr-rust = "0.3"

解析树结构

可以生成惯用的 Rust 语法树。为此,您需要使用 ANTLR 工具的标签功能。例如,您可以查看 Labels 语法。考虑以下规则

e   : a=e op='*' b=e   # mult
    | left=e '+' b=e   # add
		 

对于此类规则,ANTLR 将生成包含 multadd 选项的枚举 EContextAll,因此您可以在代码中匹配它们。此外,每个选项对应的 struct 将包含您标记的字段。例如,对于 MultContext struct 将包含包含子子树的 ab 字段以及具有 TerminalNode 类型(对应于单个 Token)的 op 字段。还可以通过 parser.build_parse_trees = false 禁用泛型解析树创建,以仅保留所选子树,但遗憾的是,这会阻止访问者工作。

Rust 与 Java 的差异

尽管 Rust 运行时 API 已经尽可能地接近 Java,但由于 Rust 不是一个面向对象的编程语言,并且更加明确,所以存在相当多的差异。

  • 如果您正在使用标记的替代方案,为规则生成的 struct 是一个具有每个替代方案变体的枚举
  • 解析器需要拥有监听器的所有权,但可以通过 ListenerId 获取监听器,否则应使用 ParseTreeWalker
  • 在嵌入式操作中访问解析器时,应使用 recog 变量而不是 self/this
  • 基于 str 的 InputStream 在存在 Unicode 字符时具有不同的索引行为。如果需要完全相同的行为,请使用基于 u32InputStream,或实现自定义 CharStream
  • 在操作中,您必须使用 \\ 在 Rust 生命周期中转义 \',因为 ANTLR 将它们视为字符串,例如 Struct<\\\'lifetime>
  • 要创建自定义令牌,应使用 @tokenfactory 自定义操作,而不是通常的 TokenLabelType 解析器选项。ANTLR 解析器选项只能接受单个标识符,而 Rust 目标需要了解生命周期。此外,在 Rust 目标中,TokenFactory 是指定令牌类型的方法。例如,您可以在 CSV 测试语法中看到。
  • 所有规则上下文变量(规则参数或规则返回)都应该实现 Default + Clone

基准测试

以下是antlr生成的XML词法分析和解析器(基于默认XML语法,但使用自定义的最小Token/TokenFactory/InputStream/RuleContext)与Rust生态系统中的手写实现进行比较。请注意,xmlparserquick_xml更接近词法分析器而不是解析器,因此它们应该与antlr词法分析器进行比较。此外,尽管生成的词法分析和解析器使用的结构体已定制以跟踪所需的最小数据(这是antlr-rust的任何用户都可以实现的),但词法分析器的内部仍然无法定制到足够程度,并且仍然跟踪了大量可能特定情况下未使用的数据。因此,仍有改进的空间。

lexers:
large/large_xmlparser        time:   [1.8598 ms 1.8607 ms 1.8619 ms]                                   
large/large_quick_xml        time:   [1.4623 ms 1.4645 ms 1.4675 ms]                                   
large/large_antlr_xml_lexer  time:   [5.7866 ms 5.7877 ms 5.7891 ms]
parsers:
large/large_xmlrs            time:   [16.734 ms 16.748 ms 16.766 ms]
large/large_minidom          time:   [7.0639 ms 7.0792 ms 7.0975 ms]                                
large/large_roxmltree        time:   [4.9341 ms 4.9360 ms 4.9380 ms]                                   
large/large_antlr_xml_full   time:   [10.243 ms 10.248 ms 10.252 ms]                                  

不安全

目前,仅使用不安全操作进行向下转型(通过单独的crate)和通过get_mut_unchecked更新Rc内部数据(返回的可变引用立即使用且不存储任何地方)

版本控制

除了常规的Rust语义版本控制之外,crate的补丁版本更改不应需要更新生成器部分

许可证

BSD 3条款。除非您明确声明,否则您提交给此项目的任何有意包含的贡献应按上述方式许可,不得附加任何额外条款或条件。

依赖项

~1–1.4MB
~23K SLoC