2 个版本
0.1.1 | 2023年2月1日 |
---|---|
0.1.0 | 2023年2月1日 |
#11 in #bnf
25 每月下载
用于 regex-bnf
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];
}
上述宏为每个标记(Value
、Line
、Document
等)创建一个结构体,并为LineEnd
创建一个枚举。每个结构体和枚举都包含一个解析函数,该函数接受一个StringParser并返回一个Result,其中包含(解析值, 剩余字符串)
或错误。
注意
此实现完全是确定的,并且可能受到死锁的影响,包括无限循环和栈溢出。为了调试它,请逐行读取,因为每个结构体都是按照声明顺序解析的。所以,在上面的CSV示例中,LineEnd
将首先尝试解析NewLine
,然后是Eof
。如果解析失败,它将返回一个错误。
性能
解析器性能非常高,因为它没有非确定性行为,并且除了可选的boxed标记之外,不执行任何分配。所有解析的字符串都作为切片及其位置(索引、行号、列号)引用。
语法
有两种类型的声明
- 标签:是一系列标记,包括文字、正则表达式或其他标记类型,它们按顺序解析。
- 枚举:是一系列标签,其中每个都尝试进行解析;如果返回错误,则尝试下一个;如果所有都失败,则返回错误。
在标签声明中,您可以使用label:<标记>
为标记标记以在生成的结构体中给出字段名称,否则它们将被省略。
以下是所有可能的标记类型
- 字符串字面量:
""
- 正则表达式:
r""
- 标签:
<Tag>
(内联),<*Tag>
(boxed,以避免无限大小的结构体) - 可选标签:
<?Tag>
- 重复标签:
<[Tag]*>
(零次或多次),<[Tag]+>
(一次或多次),<[Tag]^>
(直到字符串末尾) - 非标签:
<!Tag>
(如果标签解析成功则失败)
依赖项
~1.5MB
~35K SLoC