1 个不稳定版本
使用旧的 Rust 2015
0.0.1 | 2016年6月16日 |
---|
#34 in #lr
1MB
19K SLoC
此仓库包含 Menhir 的一个分支。Menhir 是一个最初为 [OCaml] (https://ocaml.org.cn) 语言设计的 LR(1) 解析生成器,能够生成 OCaml 和 Coq 代码。此仓库扩展并修改了 Menhir,以便它能够生成 [Rust] (https://rust-lang.net.cn) 代码。
该项目仍在进行中。目前 Rust 后端相当简单:它编码在表中,并通过一个简单的 LR(1) 自动机循环运行。Menhir 的大多数高级功能,如错误处理和记录令牌位置,尚未实现。
用法
可以使用以下命令编译和安装 Menhir:
make PREFIX=/somewhere
make PREFIX=/somewhere install
省略 PREFIX
将 Menhir 安装在 /usr/local
(需要 root 权限)。
要使用生成器,您必须使用一个 build.rs
脚本来指导 Cargo 如何调用生成器对您的语法进行操作。假设您在 src
文件夹中有一个 parser.rsy
文件。使用以下 build.rs
脚本:
use std::env;
use std::process::{Command, Stdio};
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let menhir = "/path/to/menhir";
let s = Command::new(menhir).args(&["--rust", "--no-stdlib", "--base"])
.arg(&format!("{}/parser", out_dir)).arg("src/parser.rsy")
.stdout(Stdio::inherit()).stderr(Stdio::inherit())
.status().unwrap();
assert!(s.success());
println!("cargo:rerun-if-changed=src/parser.rsy");
}
Menhir 的路径可能因您的安装而异。如果您将 Menhir 安装在二进制文件在 PATH 中,您可以使用 menhir
。请注意,我们在这里使用 --no-stdlib
选项,因为 Menhir stdlib 中包含 OCaml 语义动作,而 Rust 替代品尚未编写。
rerun-if-changed
行存在是为了确保每次 parser.rsy
改变时都会运行构建脚本。您可能希望省略它,因为 Cargo 的默认设置是在任何不属于 crate 的文件更改时运行它,但如果您在树中有其他要修改的文件,并且不想在修改时运行脚本,则它很有用。
然后在您的 Cargo.toml
文件中使用以下配置
[package]
# ...
build = "build.rs"
[dependencies]
# ...
menhir_runtime = { path = "/path/to/menhir/src/rust_runtime/" }
这次更改路径以指向 Menhir 源树的位置。这是必需的,因为 menhir_runtime
包尚未在 crates.io 上提供。
编写解析生成器
编写解析生成器的方式基本上与正常 Menhir 解析器相同,但有以下几个例外:
- 每个非终结符的类型都必须使用
%type <Type> 符号
指定,就像在编写 Coq 解析器时一样,因为 Rust 的类型推断能力不足。 - 如果您使用参数化非终结符,还必须指定实例的类型,例如为
list
非终结符使用%type <Type> 符号列表
。请注意,这是 Menhir 的一个非文档化特性,并且可能并不真正稳定。
解析器接口
生成的解析器包含一个针对每个起始非终结符的函数,以下是其签名(以 main
非终结符为例)
fn main<Lexer>(lexer: &mut Lexer) -> Result<T, ()>
where Lexer: Iterator<Item == Token>
其中 T 是 main
的语义动作类型,如语法描述中指定。Result 的第二个参数是 unit,因为尚未实现错误处理。请注意,这个接口完全不稳定,并且在实现错误处理时可能会很快改变。
此接口应与 [RustLex] (https://github.com/LeoTestard/RustLex) 词汇生成器兼容。