使用旧的Rust 2015
0.3.2 |
|
---|---|
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)进行代码生成,然后将生成的代码include!()
到您的项目中。
您的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
在构建前自动调用(根据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.rs
文件中,该文件位于foo.in.rs
旁边):
如果您想构建一个可以使用RustLex构建的项目,该项目可以使用稳定版或nightly版,您可以编写一个使用功能的可移植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中一样进行引用(字符使用简单引号,字符串使用双引号)
- 表达式定义可以通过其标识符在另一个表达式中“调用”
使用词法分析器
词法分析器将读取标准RustReader
中的字符并实现Token
迭代器。
let inp = BufReader::new("aa".as_bytes());
let mut lexer = SimpleLexer::new(inp);
for tok in lexer {
...
}
高级词法分析器功能
令牌枚举
默认情况下,rustlex!
假设在相同的作用域中存在一个名为Token
的令牌枚举,但在需要时可以覆盖此名称,如此示例中的OtherLexer
。
条件
与flex类似,可以定义条件以使词法分析器在模式之间切换。
查看此示例。
任意的词法分析器属性和方法
可以使用property
关键字添加特定的字段到词法分析器结构,如这里所示。
词法分析器方法(从操作代码中调用)也可以通过正常的impl
部分定义。