#parser-generator #lalr-parser #parser #lemon #lalr #generator

lemon-mint

著名的柠檬解析器生成器,作为库实现并提供API。

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

MIT 许可证

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个子模块:coderules。在 code 模块中只有两个有趣的东西:ParserToken。请参见上面的示例,了解它们的用法。在 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样式多行注释。

无运行时依赖

功能