如何在perl6中访问语法的可选部分?

时间:2019-07-11 20:02:33

标签: perl6

作为语法的一部分,我有:

        rule EX1        { <EX2> ( '/' <EX2>)*  }

在我的动作课中,我写了:

    method EX1($/) {
            my @ex2s = map *.made,  $/.<EX2>;
            my $ex1 = @ex2s.join('|');
            #say "EX1 making $ex1";
            $/.make($ex1);
    }

因此,基本上,我只是试图将所有EX2与它们之间的'|'而不是'/'联接在一起。但是我的代码有些不对劲,因为它只选择第一个EX2,而不是后面的。如何找出可选的是什么?

2 个答案:

答案 0 :(得分:10)

TL; DR 如果您的rule创建了该方法所期望的数据结构,则该操作方法将起作用。因此,我们将修复rule并保留该方法。

主要问题

让我们假设EX1规则被放入有效的语法中;字符串已成功解析;子字符串ex2/ex2/ex2EX1规则匹配;并且我们已经显示了解析树的相应部分(通过使用语法仅say.parse的结果):

EX1 => 「ex2/ex2/ex2」
 EX2 => 「ex2」
 0 => 「/ex2」
  EX2 => 「ex2」
 0 => 「/ex2」
  EX2 => 「ex2」

请注意无关的0 =>捕获,以及第二个和第三个EX2在它们下面的缩进以及相对于第一个EX2的缩进。相对于方法的假设,这是错误的嵌套结构。

布拉德对主要问题的解决方案

正如Brad ++在回应此答案的第一个版本的评论中指出的那样,您可以简单地从既分组又捕获((...))的结构切换到仅分组([...]的结构。 )。

    rule EX1        { <EX2> [ '/' <EX2>]*  }

现在,与上述相同的输入字符串对应的解析树片段为:

EX1 => 「ex2/ex2/ex2」
 EX2 => 「ex2」
 EX2 => 「ex2」
 EX2 => 「ex2」

0的捕获已消失,EX2现在都是同级的。有关何时以及为什么P6 <嵌套>嵌套捕获其方式的进一步讨论,请参见jnthn's answer to Why/how ... capture groups?

您的操作方法现在应该可以工作-适用于一些输入...

霍科恩(Håkon)解决了另一个可能的问题

如果布拉德(Brad)的解决方案适用于您希望它能用于某些输入(但不是全部)的问题,则部分问题可能是您的rule<EX2>和{{1 }}字符。

正如Håkon++在他们的答案中指出的那样,您的/的间距可能无法满足您的要求。

如果您不希望图案中的间距很大,请不要使用rule。在ruletoken中,模式中的 all 空间(忽略字符串,例如regex中的空格)只是为了使您的模式更具可读性,而且没有意义。相对于任何匹配的输入字符串。如有疑问,请使用' '(或token)而不是regex

rule

token EX1 { <EX2> ( '/' <EX2>)* } ? ? ? ? ? ? 指示的间距不重要。您可以忽略它或对其进行扩展,这对规则与输入的匹配方式没有影响。这只是出于可读性。

相反,?构造的要点是模式中每个原子和每个量词之后的空白为significant。这样的间距在输入中的相应子字符串之后隐式应用了(用户可重写)边界匹配规则(默认情况下,该规则允许空格和/或“ word”和非“ word”字符之间的过渡)。

在您的rule规则中,为确保清晰起见,我在下面重复使用夸张的空格来重复该规则,其中某些空格有效,就像在{{1}中不一样}或EX1

token

与以前一样,regex表示的间距并不重要-您可以省略或扩展它,并且不会有任何区别。要记住的是,模式(或子模式)的 start 处的空格仅用于可读性。 (使用经验表明,将的任何间距都视为有效间距会更好。)

但是原子或量词的间距或缺少间距很重要:

     rule EX1        {  <EX2>   (  '/'  <EX2>)*   }
                      ?          ?                 ?

通过像编写代码那样编写?来告诉P6仅将输入与边界匹配(默认情况下允许空白)匹配:

  • 之后第一 This spacing is significant: ⮟ ⮟ ⮟ rule EX1 { <EX2> ( '/' <EX2>)* } This LACK of spacing is significant: ⮝⮝ (因此,之前 第一 {{ 1}});

  • rule和后续<EX2>之间的匹配项;

  • 最后 /比赛之后的

因此,您的规则要求P6允许/<EX2>之间的空格匹配当它们以该顺序出现时-<EX2>,然后是{{1 }}。

但是它也告诉P6 允许以其他方式允许空格-在中的/匹配和<EX2>匹配之间订购!除了第一对/之外!! P6可让您声明任意复杂度(包括空格)的匹配模式,但是我怀疑这是您的意思或想要的。

有关“在原子之后”的含义的完整列表(即<EX2>中的空格很重要时),请参见When is white space really important in Perl6 grammars?

此重要的间距功能是:

  • 经典Perl DWIMery旨在简化生活;

  • 惯用语-在大多数语法中使用,因为它确实使生活更轻松;

  • <EX2>声明符存在的唯一原因(这个重要的空白是/<EX2> '/'之间的 only 区别); < / p>

  • 完全可选,因为您可以只使用rule

如果阅读此内容的人认为他们不愿意利用这一重要的空间功能,那么他们可以只使用rule来代替。 (这反过来可能会导致他们了解为什么rule作为一个选项存在,然后,或者也许以后,看看为什么它以这种方式工作,并重新欣赏其DWIMery。:))

您要匹配的模式的内置构造

最后,这是编写您要匹配的模式的惯用方式:

token

这告诉P6匹配由token个字符分隔的一个或多个token。请参见Modified quantifier: %, %%,以获取有关此良好构造的说明。

这仍然是rule,因此其中的大部分间距仍然很大。 The precise details for when it is and isn't显然最适合此构造,因为它最多具有三个重要的间隔,而一个不是:

rule EX1        { <EX2> + % '/' }

<EX2>之后加上之前和之间的间距是多余的:

/

答案 1 :(得分:4)

significant中的空格为rules。因此,我认为您在最后一个<EX2>之后缺少空格:

rule EX1 { <EX2> ( '/' <EX2>)+  }

应该是:

rule EX1 { <EX2> ( '/' <EX2> )+  }

这将留出空间来分隔EX1中的术语。