规则开始相同的Parslet语法

时间:2015-12-06 17:56:38

标签: ruby parsing peg parslet

我想提供一个解析器来解析所谓的Subversion配置auth文件(参见patch based authorization in the Subversion red book)。在这里,我想为目录定义规则,如

[/]
* = 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解析器或解析器/编译器生成的专家,所以如果这是一个不可解决的基本问题,我也想知道。

2 个答案:

答案 0 :(得分:1)

简而言之:交换OR条件。

Parlset规则消耗输入流直到它们匹配,然后它们停止。 如果您有两个可能的选项(OR),则尝试第一个选项,并且只有当它没有匹配时才尝试第二个选项。

在您的情况下,因为您的所有路径都以&#39; /&#39;开头。它们都与路径规则的第一部分相匹配,因此从未探索过后半部分。

您需要首先尝试匹配完整路径,并且只匹配&#39; top&#39;如果失败了

# 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) }

也...

&#34; top&#34;真的是一个特例吗?所有路径都以&#34; /&#34;结尾,因此top只是零长度路径。

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)

答案 1 :(得分:0)

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

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

我只为newline添加了(缺失)规则,并添加了3个单元测试来测试所有情况:

  • 根:/
  • 只包含一个元素的路径:/my
  • 包含多个元素的路径:/my/path

按预期工作,所以我在这里得到两个案例:

  • Case with the top elemment only仅限顶部元素
  • Case with one or more path elements一个或多个路径元素

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