Rust词法分析器库lrlex的使用:高效构建自定义编程语言解析工具
Rust词法分析器库lrlex的使用:高效构建自定义编程语言解析工具
lrlex
是lex
/flex
的部分替代品。它接受一个输入字符串并根据.l
文件将其分割成词素(lexemes)。虽然许多现实世界的语言有超出lrlex
能力的特殊情况,但当适用时,它是表达词法分析的非常便捷的方式。
示例使用
lrlex
提供了一个简单的命令行界面,可以检查你的词法规则是否如预期工作:
$ cat C.java
class C {
int x = 0;
}
$ cargo run --lrlex java.l /tmp/C.java
Finished dev [unoptimized + debuginfo] target(s) in 0.18s
Running `target/debug/lrlex ../grammars/java7/java.l /tmp/C.java`
CLASS class
IDENTIFIER C
LBRACE {
INT int
IDENTIFIER x
EQ =
INTEGER_LITERAL 0
SEMICOLON ;
RBRACE }
完整示例
下面是一个完整的示例,展示如何使用lrlex
构建一个简单的词法分析器:
- 首先添加依赖到Cargo.toml:
lrlex = "0.13.10"
lrpar = "0.13.10"
- 创建词法规则文件
calc.l
:
%%
[0-9]+ "INTEGER" // 匹配数字并标记为INTEGER
\+ "ADD" // 匹配加号并标记为ADD
\* "MUL" // 匹配乘号并标记为MUL
\( "LPAR" // 匹配左括号并标记为LPAR
\) "RPAR" // 匹配右括号并标记为RPAR
[\ \t\n]+ ; // 忽略空格、制表符和换行符
- 创建解析规则文件
calc.y
:
%%
start: i64; // 起始规则返回i64类型
// 表达式规则
Expr: i64 = {
Term '+' Term => Ok($1? + $3?), // 加法运算
Term } ; // 或单个Term
// 项规则
Term: i64 = {
Factor '*' Factor => Ok($1? * $3?), // 乘法运算
Factor } ; // 或单个Factor
// 因子规则
Factor: i64 = {
'INTEGER' => Ok($1.parse().unwrap()), // 解析整数
'(' Expr ')' => Ok($2?) } ; // 或括号表达式
- 主程序
main.rs
:
use lrlex::lrlex_mod;
use lrpar::lrpar_mod;
// 使用lrlex_mod!和lrpar_mod!宏生成词法分析器和解析器模块
lrlex_mod!("calc.l"); // 生成calc_l模块
lrpar_mod!("calc.y"); // 生成calc_y模块
fn main() {
// 获取词法分析器定义和解析器
let lexerdef = calc_l::lexerdef();
let parser = calc_y::parser();
// 输入表达式
let input = "2 + 3 * (4 + 5)";
// 词法分析
let lexer = lexerdef.lexer(&input);
// 解析并获取结果和错误
let (res, errs) = parser.parse(&lexer);
// 处理错误
for e in errs {
println!("{}", e.pp(&lexer, &calc_y::token_epp));
}
// 处理结果
match res {
Some(Ok(r)) => println!("计算结果: {}", r),
_ => println!("无法计算表达式")
}
}
这个示例展示了如何:
- 定义简单的算术表达式词法规则
- 创建相应的解析规则
- 在Rust程序中使用生成的词法分析器和解析器
- 处理输入表达式并输出计算结果
lrlex
特别适合需要快速构建原型或处理相对简单语法的场景,它能够大大简化词法分析器的开发工作。
1 回复
Rust词法分析器库lrlex的使用:高效构建自定义编程语言解析工具
以下是基于提供内容整理的完整示例demo,展示如何使用lrlex构建一个简单的计算器解析器:
完整示例代码
1. 项目结构
calculator/
├── Cargo.toml
├── src/
│ ├── main.rs
├── calc.l # 词法规则文件
└── calc.y # 语法规则文件
2. Cargo.toml配置
[package]
name = "calculator"
version = "0.1.0"
edition = "2021"
[dependencies]
lrlex = "0.7.0"
lrpar = "0.7.0"
3. calc.l 词法规则文件
%[%
use std::str::FromStr;
%]%
%%
[0-9]+ "INT" => Ok(Some(YaccLexValue::new(i64::from_str(yytext).unwrap())))
"+" "PLUS" => Ok(Some(YaccLexValue::new(())))
"-" "MINUS" => Ok(Some(YaccLexValue::new(())))
"*" "MUL" => Ok(Some(YaccLexValue::new(())))
"/" "DIV" => Ok(Some(YaccLexValue::new(())))
"(" "LPAR" => Ok(Some(YaccLexValue::new(())))
")" "RPAR" => Ok(Some(YaccLexValue::new(())))
[\t\n ]+ => Ok(None) // 忽略空白字符
. => Err(lex::LexError::new(yytext.to_owned())) // 其他字符报错
%%
4. calc.y 语法规则文件
%start Expr
%avoid_insert "INT"
%%
Expr -> Result<i64, ()>:
Expr 'PLUS' Term { Ok($1? + $3?) }
| Expr 'MINUS' Term { Ok($1? - $3?) }
| Term { $1 }
;
Term -> Result<i64, ()>:
Term 'MUL' Factor { Ok($1? * $3?) }
| Term 'DIV' Factor { Ok($1? / $3?) }
| Factor { $1 }
;
Factor -> Result<i64, ()>:
'LPAR' Expr 'RPAR' { $2 }
| 'INT' { Ok($1) }
;
%%
5. src/main.rs 主程序
use lrlex::lrlex_mod;
use lrpar::lrpar_mod;
// 生成词法分析器和解析器模块
lrlex_mod!("calc.l");
lrpar_mod!("calc.y");
use calc_lex::Lexer;
use calc_y::parse;
fn main() {
// 示例输入表达式
let inputs = vec![
"1 + 2 * 3",
"(4 + 5) * 6",
"10 / 2 - 3",
"2 * (3 + 4)",
];
for input in inputs {
println!("计算表达式: {}", input);
// 创建词法分析器
let lexer = Lexer::new(input);
// 解析表达式
let res = parse(lexer);
// 处理解析结果
match res {
Ok(Some(val)) => println!("结果: {}\n", val),
Ok(None) => println!("错误: 没有输入\n"),
Err(e) => println!("解析错误: {:?}\n", e),
}
}
}
6. 构建和运行
- 在项目目录下运行:
cargo build
cargo run
- 预期输出示例:
计算表达式: 1 + 2 * 3
结果: 7
计算表达式: (4 + 5) * 6
结果: 54
计算表达式: 10 / 2 - 3
结果: 2
计算表达式: 2 * (3 + 4)
结果: 14
关键点说明
-
词法分析器(calc.l):
- 定义了数字、运算符和括号的识别规则
- 使用正则表达式匹配各种词法单元
- 对匹配到的文本进行转换(如将字符串数字转为i64)
-
语法分析器(calc.y):
- 定义了表达式的语法结构
- 处理运算符优先级(乘除高于加减)
- 支持括号改变运算顺序
-
错误处理:
- 词法分析阶段会报告无法识别的字符
- 语法分析阶段会报告语法错误
这个完整示例展示了如何使用lrlex和lrpar构建一个功能完整的计算器,包括词法分析、语法分析和表达式求值。开发者可以基于此框架扩展更复杂的语言特性。