以下Raku脚本:

#!/usr/bin/env raku
use v6.d;

grammar MyGrammar
{
    rule TOP { <keyword> '=' <value> }
    token keyword { \w+ }
    token value { <strvalue> | <numvalue> }
    token strvalue { '"' <( <-["]>* )> '"' }
    token numvalue { '-'? \d+ [ '.' \d* ]? }
}

say MyGrammar.parse('foo = 42');
say MyGrammar.parse('bar = "Hello, World!"');
具有以下输出:
「foo = 42」
 keyword => 「foo」
 value => 「42」
  numvalue => 「42」
「bar = "Hello, World!"」
 keyword => 「bar」
 value => 「"Hello, World!"」
  strvalue => 「Hello, World!」
对于第二项,请注意strvalue包含不带引号的字符串值,这与捕获市场<( ... )>的意图相同。
但是,令我惊讶的是,引号包含在value中。
有没有解决的办法?

最佳答案

TL; DR 使用“多个调度”。 [1,2] 有关事物为何如此的完整说明,请参见@ user0721090601的答案。如果您希望数字语法与Raku的匹配,请参阅@ p6steve的语法的真正明智的更改。
多调度解决方案

一种方法是切换到显式多调度。
当前,您有一个value token ,该 token 调用专门命名的值变量:

    token value { <strvalue> | <numvalue> }
替换为:
    proto token value {*}
然后根据语法多个调度目标规则重命名被调用的 token ,因此语法变为:
grammar MyGrammar
{
    rule TOP { <keyword> '=' <value> }
    token keyword { \w+ }
    proto token value {*}
    token value:str { '"' <( <-["]>* )> '"' }
    token value:num { '-'? \d+ [ '.' \d* ]? }
}

say MyGrammar.parse('foo = 42');
say MyGrammar.parse('bar = "Hello, World!"');
显示:
「foo = 42」
 keyword => 「foo」
 value => 「42」
「bar = "Hello, World!"」
 keyword => 「bar」
 value => 「Hello, World!」
默认情况下,这不会捕获各个替代项。我们可以坚持“多次 dispatch ”,但重新引入子捕捉的命名:
grammar MyGrammar
{
    rule TOP { <keyword> '=' <value> }
    token keyword { \w+ }
    proto token value { * }
    token value:str { '"' <( $<strvalue>=(<-["]>*) )> '"' }
    token value:num { $<numvalue>=('-'? \d+ [ '.' \d* ]?) }
}

say MyGrammar.parse('foo = 42');
say MyGrammar.parse('bar = "Hello, World!"');
显示:
「foo = 42」
 keyword => 「foo」
 value => 「42」
  numvalue => 「42」
「bar = "Hello, World!"」
 keyword => 「bar」
 value => 「Hello, World!」
  strvalue => 「Hello, World!」
惊喜

一开始我也很惊讶。 [3]
但是当前的行为至少在以下几个方面对我也有意义:
  • 在某些情况下,现有行为值得考虑。
  • 如果期望的话也就不足为奇了,我认为在其他情况下我可能会做得到。
  • 不容易看到一个人如果想要它如何获得当前行为,而是按照您(和我)最初的预期工作。
  • 有一个解决方案,如上所述。

  • 脚注
    [1] 使用多个调度 [2] 是一种解决方案,但鉴于原始问题,它似乎过于复杂。也许有一个更简单的解决方案。也许有人会在您问题的另一个答案中提供它。如果没有,我希望我们有一天至少有一个简单得多的解决方案。但是,如果我们多年都没有,我不会感到惊讶。我们有上述解决方案,还有很多事情要做。
    [2] 虽然可以声明method value:foo { ... }并编写一个方法(假设每个此类方法都返回一个匹配对象),但我认为Rakudo不会使用通常的多方法分派(dispatch)机制来分派(dispatch)给非方法规则更改,但是而是使用NFA
    [3] 如果Raku如我们所愿,它可能会“应该”,“可能”或“将要做到最好”。我发现,如果我一般不回避关于错误/功能的[sh | c | w],除非我愿意考虑其他人提出的任何和所有缺点并愿意帮助完成所需的工作,否则我会认为是最好的想法。做的事情。因此,我只想说我目前将其视为10%错误,90%功能,但“可以”转向100%错误或100%功能,具体取决于在特定情况下我是否想要该行为,并取决于其他人的想法。

    07-24 09:52