5个版本
0.1.4 | 2021年2月3日 |
---|---|
0.1.3 | 2020年8月20日 |
0.1.2 | 2020年8月19日 |
0.1.1 | 2020年8月17日 |
0.1.0 | 2020年8月16日 |
#92 in 解析器工具
在 2 个crate中使用(通过 lemon-tree-derive)
150KB
3.5K SLoC
lemon-mint
著名的柠檬解析器生成器,作为库实现并提供API。
示例
extern crate lemon_mint;
use std::fs::File;
use std::sync::Arc;
use lemon_mint::LemonMintBuilder;
fn main()
{ let builder = LemonMintBuilder::new().load_y
( &Arc::new("source.y".to_string()), // fake source name, that will appear in error messages
" %trace {>> }
%extra_argument {()}
%left PLUS MINUS.
%left TIMES DIVIDE.
%token_type {f64}
%type Expr {super::Expr}
%type Exprs {Vec<super::Expr>}
%type Program {Vec<super::Expr>}
Program ::= Exprs(exprs). exprs
Program ::= Exprs(exprs) NEW_LINE. exprs
Exprs ::= Expr(item). vec![item]
Exprs ::= Exprs(items) NEW_LINE Expr(item). let mut items = items; items.push(item); items
Expr ::= NUM(value). super::Expr {value}
Expr ::= PAR_OPEN Expr(a) PAR_CLOSE. a
Expr ::= PLUS Expr(a). a
Expr ::= MINUS Expr(a). let mut a = a; a.value = -a.value; a
Expr ::= Expr(a) PLUS Expr(b). super::Expr{value: a.value + b.value}
Expr ::= Expr(a) MINUS Expr(b). super::Expr{value: a.value - b.value}
Expr ::= Expr(a) TIMES Expr(b). super::Expr{value: a.value * b.value}
Expr ::= Expr(a) DIVIDE Expr(b). super::Expr{value: a.value / b.value}
%code {
use code::{Parser, Token};
#[derive(Debug, PartialEq)]
pub struct Expr {value: f64}
fn main()
{ let mut parser = Parser::new(()); // () is our extra argument, that will be accessible in actions, and also through parser.extra
parser.add_token(Token::NUM, 15.0).unwrap();
parser.add_token(Token::DIVIDE, 0.0).unwrap();
parser.add_token(Token::NUM, 5.0).unwrap();
parser.add_token(Token::NEW_LINE, 0.0).unwrap();
let result = parser.end().unwrap(); // if Program
assert_eq!(result, vec![Expr {value: 3.0}]);
println!(\"Result: {:?}\", result);
}
}
".as_bytes()
).unwrap();
let lemon = builder.try_into_lemon().unwrap();
let mut out_rust = File::create("/tmp/main.rs").unwrap();
let mut out_y = File::create("/tmp/main.y").unwrap();
lemon.gen_rust(&mut out_rust).unwrap();
lemon.gen_log(&mut out_y, false, false).unwrap();
}
第一步是创建 LemonMintBuilder
对象,并使用其方法描述所需的解析器。可以通过 load_y_file()
从文件加载 "y" 语法,或者通过 load_y()
从字符串加载,如上例所示,或者您可以单独使用方法设置每个解析器规则,例如 set_start_symbol()
、set_token_type()
、add_type()
、add_rule()
以及其他方法。
然后可以将构建器对象转换为 LemonMint
对象,该对象代表解析器转换表。这一步是通过上述示例中的 try_into_lemon()
方法完成的。
最后一步是生成包含解析器表及其驱动代码的Rust文件。这是通过 gen_rust()
方法完成的。可选地,您可以使用 gen_log()
生成日志文件,就像经典的柠檬程序一样。
Y-语法
Lemon-mint 使用与经典 Lemon 解析器类似的 y-语法。有一些区别
- 如果一个符号名称包含至少一个小写字母,则它被认为是非终结符。在经典 Lemon 中,只有第一个字母是重要的。
- 要启用跟踪,使用
%trace
指令。在 Lemon 中需要调用 ParseTrace() 函数。 - 无需使用
%name
指令,因为 Rust 中每个文件都是一个独立的模块。 - 不需要析构函数。
生成的解析器将被分成2个子模块:code
和 rules
。在 code
模块中只有两个有趣的东西:Parser
和 Token
。请参见上面的示例,了解它们的用法。在 rules
模块中包装了动作,您不需要直接使用它。如果您的动作使用全局空间中的类型、常量或函数,它们可以像这样访问:super::Expr
,或者 crate::Expr
等。
支持以下指令
- %token_type
- %type
- %default_type
- %start_symbol
- %trace
- %extra_argument - 只是其类型。名称始终是
extra
。默认类型是()
。 - %left
- %right
- %nonassoc
- %fallback
- %code 或 %include - 相同
语法自由且宽容
%start_symbol {Unit}
/* or */
%start_symbol Unit.
/* or */
%start_symbol Unit
花括号允许指定多行值,直到匹配的闭合花括号。支持行和C样式多行注释。