#bnf #regex #parser #deterministic #syntax #error #line

regex-bnf

基于正则表达式的BNF启发式语法的确定性解析器

3个版本

0.1.2 2023年2月1日
0.1.1 2023年2月1日
0.1.0 2023年2月1日

2443Rust模式

26 每月下载次数

MIT 许可证

12KB
239

regex-bnf

一种基于宏的BNF风格解析器,用于简化语法定义。

这种方法在您需要解析复杂语法而无需先进行标记化时很有用,例如,当标记可能包含空格和新行,并且周围有复杂规则时。

以下是一个简单的CSV解析器示例

use regex_bnf::*;

bnf! {
    Value = <!Eof> <!NewLine> val:r"([^,\r\n]|\\,)*" <?Comma>;

    Line = <!Eof> values:<[Value]> <LineEnd>;
    Document = lines:<[Line]^>;

    Comma = ",";
    NewLine = r"[\r\n]+";
    Eof = ^;
    enum LineEnd = [NewLine | Eof];
}

上述宏为每个标记创建一个结构体(ValueLineDocument等)和一个枚举类型为LineEnd。每个结构和枚举都包含一个解析函数,该函数接受一个StringParser并返回一个包含(解析值, 剩余字符串)或错误的Result。

注意

此实现完全确定,可能存在死锁,包括无限循环和栈溢出。为了调试它,请按声明顺序线性读取每个结构。因此,在上面的CSV示例中,LineEnd将首先尝试解析NewLine,然后是Eof。如果解析失败,则返回错误。

性能

解析器性能非常高,因为它具有零非确定性行为,并且除了可选的boxed标记之外,不执行任何其他分配。所有解析的字符串都作为切片引用,包括其位置(索引、行号、列号)。

语法

有两种类型的声明

  • 标签:是一系列标记,包括文字、正则表达式或其他标记类型,它们线性解析。
  • 枚举:是一系列标签,每个标签都尝试解析。如果返回错误,则尝试下一个。如果所有标签都失败,则返回错误。

在标签声明中,您可以使用<标记>为标记添加标签,以便在生成的结构体中为其提供字段名,否则将省略。

以下是所有可能的标记类型

  • 字符串文字:""
  • 正则表达式:r""
  • 标签:<Tag>(内联),<*Tag>(boxed,以避免无限大小的结构体)
  • 可选标签:<?标签>
  • 重复标签:<[标签]*>(零次或多次),<[标签]+>(一次或多次),<[标签]^>(直到字符串结束)
  • 非标签:<!标签>(如果标签解析成功则失败)

依赖项

约3-4.5MB
约88K SLoC