使用旧的Rust 2015
0.3.1 |
|
---|
#8 in #分析器
7KB
RustLex:Rust词法分析器生成器
RustLex是一个词法分析器生成器,即一个程序,它可以从使用正则表达式描述的语言中生成用于编译器的词法分析器。它与众所周知的Lex类似,但它是用Rust编写的,并以Rust代码作为分析器输出。它与Lex的不同之处在于使用Rust的新语法扩展系统作为定义词法分析器的接口。因此,分析器的描述可以直接嵌入到Rust源文件中,而生成器代码将在Rustc的宏展开阶段被调用。
Rustlex可用性和Rust兼容性
Rustlex使用语法扩展,它必须处理rustc libsyntax
。 libsyntax
大约是编译器的核心,并且已经被明确排除在Rust 1.0路线图中。总之,RustLex的内联语法生成将无法与Rust 1.0兼容。
使用RustLex的方式取决于您用于构建项目的Rust版本。
夜间版本
这是一个简单的方法。只需在Cargo.toml中指定对rustlex
的依赖项,并在您的crate顶部添加以下几行
#![feature(plugin)]
#![plugin(rustlex)]
#[allow(plugin_as_library)] extern crate rustlex;
#[macro_use] extern crate log;
这将使rustc
加载包含生成代码所需一切内容的RustLex插件。
稳定版本
在稳定频道上,您必须首先使用[syntex] (https://github.com/erickt/rust-syntex)执行代码生成,然后将生成的代码包含到您的项目中。
您的Cargo.toml
应如下所示
[package]
name = "your package"
version = "0.0.0"
build = "build.rs"
[build-dependencies]
rustlex_codegen = { version = "*", features = ["with-syntex"] }
syntex = { version = "*", optional = true }
[dependencies]
rustlex_codegen = { version = "*", features = ["with-syntex"] }
您将需要编写一个build.rs
文件。该文件在Cargo.toml
文件中的build
变量之前自动由cargo
调用(根据Cargo.toml
文件中的build
变量)。在我们的情况下,它将使用syntex处理您的代码并调用RustLex的代码生成。
pub fn main() {
extern crate syntex;
extern crate rustlex_codegen;
use std::env;
use std::path::Path;
let mut registry = syntex::Registry::new();
rustlex_codegen::plugin_registrar(&mut registry);
let src = Path::new("src/foo.in.rs");
let dst = Path::new(&env::var_os("OUT_DIR").unwrap()).join("foo.rs");
registry.expand("", &src, &dst).unwrap();
}
将 foo.in.rs
替换为你将使用 RustLex 的文件名。请注意,所有子模块都将与其一起处理,所以即使它们也包含对 RustLex 宏的调用,你也不需要将它们也添加进去。
这将生成一个名为 foo.rs
(或你命名的任何名称)的文件,位于 Cargo 的 OUT_DIR
中。为了使用此文件,请在你的项目中添加类似以下内容(例如,在 foo.in.rs
旁边放置的 foo.rs
文件中)
如果你想构建一个可以使用 RustLex 构建的稳定或夜间构建的项目,你可以使用功能编写一个可移植的 Cargo.toml
文件,并在你的 build.rs
和代码的其余部分中使用 #[cfg()]
属性来使其同时使用这两个版本。你可以查看 rustlex_codegen
的 [测试项目](http://github.com/LeoTestard/RustLex/tree/master/codegen/tests/Cargo.toml/)以获取示例。
定义一个词法分析器
然后你可以在任何地方调用 rustlex!
宏。该宏将展开成一个描述词法分析器的单个词法分析器结构和实现。
rustlex!
宏接受结构名称和词法分析器的描述作为参数。描述由两部分组成
- 正则表达式的定义
- 规则的定义
一个最小词法分析器将看起来像
rustlex! SimpleLexer {
// expression definitions
let A = 'a';
// then rules
A => |lexer:&mut SimpleLexer<R>| Some(TokA ( lexer.yystr() ))
}
更复杂的正则表达式定义示例可以在 更复杂的示例 中找到。值得注意的是
- 字符(独立或字符类中的字符)和字符串必须像在 rust 或 C 中一样引用(字符使用简单引号,字符串使用双引号)
- 表达式定义可以通过其标识符在另一个表达式中“调用”
使用词法分析器
词法分析器将从标准 rust Reader
读取字符并实现一个 Token
迭代器。
let inp = BufReader::new("aa".as_bytes());
let mut lexer = SimpleLexer::new(inp);
for tok in lexer {
...
}
高级词法分析器功能
标记枚举
默认情况下,rustlex!
假设同一模块中存在一个名为 Token
的标记枚举,但可以在需要时覆盖此名称,例如 此示例 中的 OtherLexer
。
条件
与 flex 一样,可以定义条件来使词法分析器从一个模式切换到另一个模式。
查看 此示例。
任意的词法分析器属性和方法
可以使用 property
关键字添加特定字段到词法分析器结构,如 此处所示。
词法分析器方法(从操作代码中调用)也可以通过正常的 impl
部分