#bnf #regex #proc-macro #line #enums #regex-bnf

regex-bnf-macro

regex-bnf的过程宏库

2 个版本

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

#11 in #bnf

25 每月下载
用于 regex-bnf

MIT 许可证

20KB
505

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标记之外,不执行任何分配。所有解析的字符串都作为切片及其位置(索引、行号、列号)引用。

语法

有两种类型的声明

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

在标签声明中,您可以使用label:<标记>为标记标记以在生成的结构体中给出字段名称,否则它们将被省略。

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

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

依赖项

~1.5MB
~35K SLoC