Rust语法分析库lrtable的使用,lrtable提供高性能LR(1)解析表生成与语法分析功能
lrtable
从 cfgrammar
接收语法并从中创建 LR 状态表。很少有用户会直接对其功能感兴趣,除了那些进行高级语法分析形式的用户。
以下是一个使用 lrtable
的完整示例代码:
use cfgrammar::yacc::YaccKind;
use lrpar::Lexer;
use lrtable::{from_yacc, StateTable};
// 定义语法规则
const GRAMMAR: &str = r#"
%start Expr
%%
Expr -> Expr '+' Term
| Term;
Term -> Term '*' Factor
| Factor;
Factor -> 'id'
| '(' Expr ')';
"#;
fn main() {
// 生成 LR 解析表
let (gr, _) = cfgrammar::yacc::YaccGrammar::new(YaccKind::Original, GRAMMAR).unwrap();
let lrtable = from_yacc(&gr, YaccKind::Original).unwrap();
// 打印状态表信息
println!("Number of states: {}", lrtable.num_states());
println!("Number of actions: {}", lrtable.num_actions());
// 示例:解析输入字符串
let input = "id + id * id";
let lexer = lrlex::LRNonStreamingLexer::new(input.as_bytes());
let result = lrpar::parse(&lrtable, lexer);
match result {
Ok(ast) => println!("Parse successful: {:?}", ast),
Err(e) => println!("Parse error: {:?}", e),
}
}
完整示例代码:
// 引入必要的库
use cfgrammar::yacc::YaccKind;
use lrlex::LRNonStreamingLexer;
use lrpar;
use lrtable::{from_yacc, StateTable};
// 定义语法规则字符串
const GRAMMAR: &str = r#"
%start Expr
%%
Expr -> Expr '+' Term
| Term;
Term -> Term '*' Factor
| Factor;
Factor -> 'id'
| '(' Expr ')';
"#;
fn main() {
// 从YACC语法生成语法对象
let (gr, _) = cfgrammar::yacc::YaccGrammar::new(YaccKind::Original, GRAMMAR).unwrap();
// 从语法生成LR状态表
let lrtable = from_yacc(&gr, YaccKind::Original).unwrap();
// 打印状态表统计信息
println!("状态数量: {}", lrtable.num_states());
println!("动作数量: {}", lrtable.num_actions());
// 定义要解析的输入字符串
let input = "id + id * id";
// 创建词法分析器
let lexer = LRNonStreamingLexer::new(input.as_bytes());
// 使用LR状态表进行解析
let result = lrpar::parse(&lrtable, lexer);
// 处理解析结果
match result {
Ok(ast) => println!("解析成功: {:?}", ast),
Err(e) => println!("解析错误: {:?}", e),
}
}
1 回复
Rust语法分析库lrtable的使用指南
概述
lrtable是一个高性能的Rust库,专门用于生成LR(1)解析表和执行语法分析。它提供了完整的LR(1)解析器生成功能,支持构建自定义语法分析器。
主要特性
- 高效的LR(1)解析表生成算法
- 支持自定义语法规则定义
- 提供详细的语法分析错误报告
- 零成本抽象和高性能实现
安装方法
在Cargo.toml中添加依赖:
[dependencies]
lrtable = "0.4"
基本使用方法
1. 定义语法规则
use lrtable::lr1::{Grammar, Production, Symbol};
let mut grammar = Grammar::new();
// 定义非终结符
let expr = grammar.add_nonterminal("Expr");
let term = grammar.add_nonterminal("Term");
let factor = grammar.add_nonterminal("Factor");
// 定义产生式规则
grammar.add_production(expr, vec![
Production::new(expr, vec![Symbol::NonTerminal(term)]),
Production::new(expr, vec![
Symbol::NonTerminal(expr),
Symbol::Terminal("+".to_string()),
Symbol::NonTerminal(term)
])
]);
grammar.add_production(term, vec![
Production::new(term, vec![Symbol::NonTerminal(factor)]),
Production::new(term, vec![
Symbol::NonTerminal(term),
Symbol::Terminal("*".to_string()),
Symbol::NonTerminal(factor)
])
]);
2. 生成解析表
use lrtable::lr1::LRTables;
let lr_tables = LRTables::construct(&grammar).unwrap();
3. 执行语法分析
use lrtable::lr1::Parser;
let mut parser = Parser::new(&lr_tables);
let tokens = vec!["a", "+", "b", "*", "c"];
match parser.parse(tokens.iter().map(|s| s.to_string())) {
Ok(ast) => {
println!("解析成功: {:?}", ast);
}
Err(e) => {
println!("解析错误: {}", e);
}
}
高级用法示例
自定义词法分析器集成
use lrtable::lr1::{Parser, LRTables};
fn tokenize(input: &str) -> Vec<String> {
input.split_whitespace()
.map(|s| s.to_string())
.collect()
}
fn main() {
// 假设已经构建了语法和解析表
let lr_tables: LRTables = // ... 解析表构建代码
let input = "x + y * z";
let tokens = tokenize(input);
let mut parser = Parser::new(&lr_tables);
let result = parser.parse(tokens.into_iter());
// 处理解析结果
}
错误处理和恢复
use lrtable::lr1::{Parser, ParseError};
let result = parser.parse(tokens);
match result {
Ok(ast) => process_ast(ast),
Err(ParseError::SyntaxError { position, expected }) => {
eprintln!("语法错误在位置 {},期望: {:?}", position, expected);
}
Err(e) => {
eprintln!("其他解析错误: {}", e);
}
}
完整示例demo
use lrtable::lr1::{Grammar, Production, Symbol, LRTables, Parser, ParseError};
fn main() {
// 1. 定义语法规则
let mut grammar = Grammar::new();
// 定义非终结符
let expr = grammar.add_nonterminal("Expr");
let term = grammar.add_nonterminal("Term");
let factor = grammar.add_nonterminal("Factor");
// 定义产生式规则
grammar.add_production(expr, vec![
Production::new(expr, vec![Symbol::NonTerminal(term)]),
Production::new(expr, vec![
Symbol::NonTerminal(expr),
Symbol::Terminal("+".to_string()),
Symbol::NonTerminal(term)
])
]);
grammar.add_production(term, vec![
Production::new(term, vec![Symbol::NonTerminal(factor)]),
Production::new(term, vec![
Symbol::NonTerminal(term),
Symbol::Terminal("*".to_string()),
Symbol::NonTerminal(factor)
])
]);
grammar.add_production(factor, vec![
Production::new(factor, vec![Symbol::Terminal("id".to_string())]),
Production::new(factor, vec![
Symbol::Terminal("(".to_string()),
Symbol::NonTerminal(expr),
Symbol::Terminal(")".to_string())
])
]);
// 2. 生成解析表
let lr_tables = LRTables::construct(&grammar).unwrap();
// 3. 执行语法分析
let mut parser = Parser::new(&lr_tables);
// 模拟输入tokens
let tokens = vec!["id", "+", "id", "*", "id"];
match parser.parse(tokens.iter().map(|s| s.to_string())) {
Ok(ast) => {
println!("解析成功: {:?}", ast);
}
Err(ParseError::SyntaxError { position, expected }) => {
eprintln!("语法错误在位置 {},期望: {:?}", position, expected);
}
Err(e) => {
eprintln!("其他解析错误: {}", e);
}
}
}
// 自定义词法分析器函数
fn tokenize(input: &str) -> Vec<String> {
input.split_whitespace()
.map(|s| match s {
"+" => "+".to_string(),
"*" => "*".to_string(),
"(" => "(".to_string(),
")" => ")".to_string(),
_ if s.chars().all(|c| c.is_alphabetic()) => "id".to_string(),
_ => s.to_string()
})
.collect()
}
// 处理AST的函数
fn process_ast(ast: lrtable::lr1::AST) {
println!("处理抽象语法树: {:?}", ast);
}
性能优化建议
- 预生成解析表并序列化保存
- 使用&str而不是String作为token类型以减少分配
- 对于大型语法,考虑使用LALR(1)模式
注意事项
- 确保语法是LR(1)兼容的,否则构造解析表可能失败
- 复杂的语法可能需要调整解析表生成参数
- 生产环境建议添加适当的错误处理和日志记录
这个库特别适合需要自定义领域特定语言(DSL)或构建复杂解析器的场景。