【问题标题】:How do I access the optional parts of a grammar in perl6?如何在 perl6 中访问语法的可选部分?
【发布时间】:2019-07-11 20:02:33
【问题描述】:

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

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

在我的行动课上我写过:

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

所以基本上我只是想将所有EX2 与它们之间的'|' 连接在一起,而不是'/'。但是,我的代码有些问题,因为它只获取第一个 EX2,而不是后续的。如何找出可选的选项是什么?

【问题讨论】:

    标签: raku


    【解决方案1】:

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

    主要问题

    让我们假设EX1 规则被插入到一个工作语法中;一个字符串被成功解析;子字符串ex2/ex2/ex2 匹配EX1 规则;我们已经显示了解析树的相应部分(只需saying 使用语法.parse 的结果):

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

    注意无关的0 =&gt; 捕获以及第二个和第三个EX2s 如何在它们下面缩进并且相对于第一个EX2 缩进。相对于您的方法假设,这是错误的嵌套结构。

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

    正如 Brad++ 在他们对本答案第一个版本的评论中指出的那样,您可以简单地从组合和捕获的构造 ((...)) 切换到仅组合的构造 ([...])。

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

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

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

    0 捕获消失了,EX2s 现在都是兄弟姐妹。有关 P6 nests 何时以及为何采用这种方式的进一步讨论,请参阅 jnthn's answer to Why/how ... capture groups?

    您的操作方法现在应该可以工作了——对于一些输入...

    Håkon 对另一个可能问题的解决方案

    如果 Brad 的解决方案适用于您希望它适用的某些输入(但不是全部),则部分问题可能是您的 rule&lt;EX2&gt;/ 字符之间的匹配方式。

    正如 Håkon++ 在他们的回答中指出的那样,您的 rule 的间距可能不符合您的要求。

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

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

    ? 指示的间距并不重要。您可以省略或扩展它,它不会影响规则如何匹配输入。这只是为了便于阅读。

    相比之下,rule 构造的全部要点是模式中每个原子和每个量词后面的空格是significant。这种间距在输入中的相应子字符串之后隐式应用(用户可覆盖的)边界匹配规则(默认情况下,允许空格和/或“单词”和非“单词”字符之间的转换的规则)。

    在您的 EX1 规则中,我在下面重复夸大间距以确保清晰,一些间距显着,就像它不在 token 或 @987654360 中一样@:

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

    和以前一样,? 表示不重要的间距——您可以省略或扩展它,它不会有任何区别。要记住的是,模式(或子模式)的 start 处的空格只是为了便于阅读。 (使用经验表明,如果将任何间距视为显着,则效果会更好。)

    但间隔或缺少间隔原子或量词之后很重要:

    This spacing is significant: ⮟      ⮟        ⮟
         rule EX1        { <EX2>   ( '/'  <EX2>)*   }
    This LACK of spacing is significant:      ⮝⮝
    

    通过写你的 rule 你告诉 P6 只匹配输入与边界匹配(默认情况下允许空白):

    • 之后第一个&lt;EX2&gt;(因此之前第一个/) ;

    • / 和随后的&lt;EX2&gt; 匹配之间;

    • 最后&lt;EX2&gt;匹配之后。

    所以你的规则告诉 P6 允许 /&lt;EX2&gt; 之间的空格匹配当它们以该顺序出现时 -- /,然后是&lt;EX2&gt;

    但它也告诉 P6 允许相反的空格 - 在&lt;EX2&gt; 匹配和/ 匹配之间那个顺序!除了第一对&lt;EX2&gt; '/'!! P6 将允许您声明任意复杂的匹配模式,包括间距,但我怀疑这是您的意思或想要的。

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

    这个重要的间距特征是:

    • 经典 Perl DWIMery 旨在让生活更轻松;

    • 惯用语——用于大多数语法,因为它确实确实让生活更轻松;

    • rule 声明符存在的唯一原因(这一重要的空白方面是唯一ruletoken 之间的区别);

    • 完全可选,因为您可以改用token

    如果阅读本文的人认为他们不想利用这一重要的空间功能,那么他们可以改用tokens。 (这反过来可能会引导他们了解为什么 rule 存在作为一个选项,然后,或者可能稍后,了解它为什么会这样工作,并重新欣赏它的 DWIMery。:)

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

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

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

    这告诉 P6 匹配一个或多个由/ 字符分隔的&lt;EX2&gt;s。请参阅 Modified quantifier: %, %% 了解有关这个不错的构造的说明。

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

    NOT significant:  ⮟                 ⮟
         rule EX1   {   <EX2>    +    %    '/'   }
    Significant:              ⮝    ⮝          ⮝
    

    + 之后的 之前都包含空格是多余的:

         rule EX1   {   <EX2>    +    %    '/'   }
         rule EX1   {   <EX2>    +%        '/'   } # same match result
         rule EX1   {   <EX2>+        %    '/'   } # same match result
    

    【讨论】:

    • 我想我也应该指出可以通过使用[] 而不是() 来改进它。
    • @BradGilbert Duh。你说的太对了。答案改写。谢谢。
    【解决方案2】:

    rules 中的空格是 significant。所以我认为你在最后一个&lt;EX2&gt; 之后缺少一个空格:

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

    应该是:

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

    这允许空格分隔EX1 中的术语。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-18
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-26
      • 2013-06-05
      相关资源
      最近更新 更多