1

我想提供一个解析器来解析所谓的 Subversion 配置身份验证文件(请参阅Subversion 红皮书中的基于补丁的授权)。在这里,我想为目录定义规则,例如

[/]
* = r
[/trunk]
@PROJECT = rw

所以我有问题的语法部分是路径定义。我目前在 Parslet 中有以下规则:

rule(:auth_rule_head) { (str('[') >> path >> str(']') >> newline).as(:arh) }
rule(:top)          { (str('/')).as(:top) }
rule(:path)         { (top | ((str('/') >> path_ele).repeat)).as(:path) }
rule(:path_ele)     { ((str('/').absent? >> any).repeat).as(:path_ele) }

所以我想分为两种情况:

  • 仅查找[/](根目录)
  • 在所有其他情况下[/<dir>],可能会重复,但必须在没有结束的情况下结束/

有问题的规则似乎是path定义了一个替代方案,这里/XOR 类似于/trunk

我已经为这些定义了测试用例,并在运行测试用例时收到以下错误:

Failed to match sequence (SPACES '[' PATH ']' NEWLINE) at line 1 char 3.
`- Expected "]", but got "t" at line 1 char 3.

所以问题似乎是,总是选择替代方案(规则:路径)top

这个问题的解决方案(作为语法)是什么?我认为应该有一个解决方案,这看起来像是从这里到那里应该发生的惯用语。我根本不是 PEG 解析器或解析器/编译器生成方面的专家,所以如果这是一个无法解决的基本问题,我也想知道这一点。

4

2 回答 2

1

简而言之:交换 OR 条件。

Parlset 规则使用输入流直到它们得到匹配,然后它们停止。如果您有两个可能的选项(或),则尝试第一个,只有当它不匹配时才尝试第二个。

在您的情况下,由于您的所有路径都以“/”开头,它们都匹配路径规则的第一部分,因此永远不会探索下半部分。

您需要先尝试匹配完整路径,如果失败则仅匹配“顶部”。

# changing this
rule(:path)         { (top | ((str('/') >> path_ele).repeat)).as(:path) }

# to this
rule(:path)         { ((str('/') >> path_ele).repeat) | top).as(:path) }

# fixes your first problem :)

另外......要小心那些不会消耗任何东西的规则。默认情况下重复是重复(0)。通常需要重复(1)。

rule(:path)         { ((str('/') >> path_ele).repeat(1)) | top).as(:path) }

还...

“顶”真的是特例吗?所有路径都以“/”结尾,因此顶部只是零长度路径。

rule(:path)         { (path_ele.repeat(0)  >> str('/')).as(:path) }

或者

rule(:path)         { (str('/') >> path_ele.repeat(0)).as(:path) }
rule(:path_ele)     { ((str('/').absent? >> any).repeat(0)).as(:path_ele) >> str('/') } 
# assuming "//" is valid otherwise repeat(1)
于 2015-12-06T20:41:33.240 回答
0

似乎是我没有正确解决问题。我试图在创建一个包含一些单元测试的小示例语法时重现该问题,但现在,事情正在发挥作用。

如果您对此感兴趣,请查看要点https://gist.github.com/mliebelt/a36ace0641e61f49d78f。您应该能够下载该文件,并直接从命令行运行它。你必须先安装parsletminitest应该已经包含在当前的 Ruby 版本中。

我在那里只添加了(缺失的)规则newline,并添加了 3 个单元测试来测试所有案例:

  • 根:/
  • 只有一个元素的路径:/my
  • 具有多个元素的路径:/my/path

像预期的那样工作,所以我在这里得到两个案例:

  • 仅带有顶部元件的外壳仅顶部元素
  • 具有一个或多个路径元素的案例一个或多个路径元素

也许这可以帮助其他人如何调试这样的情况。

于 2015-12-08T10:59:04.610 回答