【问题标题】:Can * be used in sym tokens for more than one character?* 可以在符号标记中用于多个字符吗?
【发布时间】:2019-07-01 07:33:10
【问题描述】:

example for sym 显示 * (WhateverCode) 代表单个符号

grammar Foo {
    token TOP { <letter>+ }
    proto token letter {*}
    token letter:sym<P> { <sym> }
    token letter:sym<e> { <sym> }
    token letter:sym<r> { <sym> }
    token letter:sym<l> { <sym> }
    token letter:sym<*> {   .   }
}.parse("I ♥ Perl", actions => class {
    method TOP($/) { make $<letter>.grep(*.<sym>).join }
}).made.say; # OUTPUT: «Perl␤» 

但是,如果我们用它来代替由几个字母组成的符号,它就会失败:

grammar Foo {
    token TOP { <action>+ % " " }
    proto token action {*}
    token action:sym<come> { <sym> }
    token action:sym<bebe> { <sym> }
    token action:sym<*> { . }
}.parse("come bebe ama").say; # Nil

由于 sym 本身确实可以处理具有多个字符的符号,我们如何定义与一组字符匹配的默认 sym 标记?

【问题讨论】:

    标签: grammar raku


    【解决方案1】:

    * 可以在sym 标记中用于多个字符吗? ...sym 的示例显示 * (WhateverCode) 代表单个符号

    这不是WhateverCodeWhatever1

    foo:sym&lt;...&gt; 中的&lt;...&gt; 是一个引号构造函数,所以... 只是一个文字字符串。

    这就是它起作用的原因:

    grammar g { proto token foo {*}; token foo:sym<*> { <sym> } }
    say g.parse: '*', rule => 'foo'; # matches
    

    就P6而言,foo:sym&lt;*&gt;中的*只是一个随机字符串。可能是abracadabra。我认为作者选择* 来代表“随便”的心理概念,因为它恰好与P6 概念Whatever 匹配。也许他们太可爱了。

    对于这个答案的其余部分,我将写 JJ 而不是 * 就 P6 而言后者只是一个任意字符串。


    原型中的* Whatever。但这与您的问题完全无关:

    grammar g { proto token foo {*}; token foo:sym<JJ> { '*' } }
    say g.parse: '*', rule => 'foo'; # matches
    

    在名称中包含:sym&lt;...&gt; 部分的规则(标记和正则表达式是规则)的主体中,您可以编写&lt;sym&gt;,它将匹配:sym&lt;...&gt; 角度之间的字符串:

    grammar g { proto token foo {*}; token foo:sym<JJ> { <sym> } }
    say g.parse: 'JJ', rule => 'foo'; # matches
    

    但是您可以在规则/令牌/正则表达式正文中编写任何您喜欢的内容。 . 匹配单个字符:

    grammar g { proto token foo {*}; token foo:sym<JJ> { . } }
    say g.parse: '*', rule => 'foo'; # matches
    

    但是,如果我们用它来代替由几个字母组成的符号,它就会失败

    没有。那是因为你改变了语法。

    如果你把语法改回原来的编码(除了更长的letter:sym&lt;...&gt;s)它工作正常:

    grammar Foo {
      token TOP { <letter>+ }
      proto token letter {*}
      token letter:sym<come> { <sym> }
      token letter:sym<bebe> { <sym> }
      token letter:sym<JJ> { . }
    }.parse(
       "come bebe ama",
       actions => class { method TOP($/) { make $<letter>.grep(*.<sym>).join } })
     .made.say; # OUTPUT: «comebebe␤»
    

    请注意,在原始版本中,letter:sym&lt;JJ&gt; 标记正在等待匹配任何单个字符——其中包含一个空格,因此它匹配那些并处理它们。

    但是在您的修改中,您在TOP 标记中的标记之间添加了一个必需 空格。这有两个影响:

    • 匹配“come”后和“bebe”后的空格;

    • “a”与letter:sym&lt;JJ&gt;匹配后,“a”和“m”之间缺少空格意味着此时整体匹配失败。

    sym 本身确实适用于具有多个字符的符号

    是的。 token foo:sym&lt;bar&gt; { ... } 所做的只是添加:

    • foo 的多重分派替代方案;

    • 令牌sym,词法范围为foo 令牌的主体,匹配'bar'

    我们如何定义一个与一组字符匹配的默认sym 令牌?

    您可以编写这样的sym 标记,但需要明确的是,因为您不希望它匹配固定字符串,所以它不能在正文中使用&lt;sym&gt;。(因为&lt;sym&gt; 有是一个固定的字符串。)如果你仍然想capturesym键下,那么你可以在令牌正文中写$&lt;sym&gt;=,正如Håkon在他们的回答下的评论中显示的那样。但它也可以是letter:whatever,正文中带有$&lt;sym&gt;=

    我将把它写成letter:default 标记以强调它是:sym&lt;something&gt; 没有任何区别。 (如上所述,:sym&lt;something&gt; 与其他 :baz&lt;...&gt;s 和 :bar&lt;...&gt;s 一样只是一个替代方案,唯一的补充是如果它是 :sym&lt;something&gt;,那么它也是 使&lt;sym&gt; 子规则在关联规则的主体中可用,如果使用该子规则,则匹配固定字符串'something'。)

    所有rule foo:bar:baz:qux&lt;...&gt;备选方案中的获胜调度是根据LTM logic在以foo开头的规则中选择的。因此,您需要编写一个 not 作为最长令牌前缀但仅在没有其他匹配项时才匹配的令牌。

    要在 LTM 比赛中立即排在最后,请在规则正文的开头插入 {}2

    token letter:default { {} \w+ }
    

    现在,从包的后面看,如果这个规则有机会,它将与\w+ 模式匹配,当它遇到非单词字符时,它将停止标记。

    让它匹配的一点如果没有其他匹配可能意味着最后列出它。所以:

    grammar Foo {
      token TOP { <letter>+ % ' ' }
      proto token letter {*}
      token letter:sym<come> { <sym> }    # matches come
      token letter:sym<bebe> { <sym> }    # matches bebe
      token letter:boo       { {} \w**6 } # match 6 char string except eg comedy
      token letter:default   { {} \w+ }   # matches any other word
    }.parse(
       "come bebe amap",
       actions => class { method TOP($/) { make $<letter>.grep(*.<sym>).join } })
     .made.say; # OUTPUT: «comebebe␤»
    

    这不可能是导致它的原因......“come bebe ama”不应该在你的语法中起作用

    代码有错误,我现在已修复并为此道歉。如果你运行它,你会发现它像宣传的那样工作。

    但是你的评论促使我扩大我的答案。希望它现在可以正确回答您的问题。

    脚注

    1 并不是说​​这与实际发生的事情有任何关系,但是...在 P6 中,* 位于“术语位置”(英文中,名词所属的位置,在一般编程术语,值所属的地方)是Whatever,而不是WhateverCode。即使* 是用运算符编写的,例如。 +** + *,而不是单独使用,*s 仍然只是 Whatevers,但编译器会自动转换一个或多个 *s 的大多数此类组合将一个或多个运算符合并为 Code 的子类,称为 WhateverCode。 (例外情况列于表here。)

    2my answer to SO "perl6 grammar , not sure about some syntax in an example"中的脚注2。

    【讨论】:

    • 现在我完全糊涂了。您唯一更改的是空格分隔符,因此这不可能是导致它的原因。此外,“come bebe ama”不应该在你的语法中起作用,因为你实际上并没有在那里指定任何分隔符。 sym,本身不包含分隔符。
    • 嗨,JJ。在原始语法中,“abracadabra”替代:sym&lt;...&gt; 有一个匹配. 的主体,它是任何字符,包括一个空格。因此:sym&lt;...&gt; 本身 分隔符匹配器(作为默认匹配器的一部分)。但是,虽然这解释了什么不起作用,但它并没有给你一个解决方案。我已经更新了我的答案,以更好地解释问题并提供解决方案。如果您仍然感到困惑,则可以将其放置几天。但是,当您回到这个语法时,当您重读我的答案时,请务必让我知道您仍然感到困惑的任何事情。 TIA。
    • 好的,我现在明白了,并开始了解我在哪里感到困惑。由于 <.whatever> 意味着跳过该捕获,我想 .在这种情况下,意味着跳过角色。此外,这个角色实际上被跳过了。所以我得再检查一次。感谢您的澄清!
    • 啊,有道理。需要明确的是,它仍然在.&lt;letter&gt; 下的解析树中,只是不在.&lt;letter&gt;.grep(*.&lt;sym&gt;) 下。这是因为令牌正文只是 . 而不是 $&lt;sym&gt;=.。 (而其他人只能使用&lt;sym&gt; 而不是$&lt;sym&gt;=come。)Anyhoo,感谢您的耐心等待,而我正在迭代一个好的答案并让我知道我已经取得了进展。 :)
    【解决方案2】:

    :sym&lt;...&gt; 内容供程序的读者使用,而不是供编译器使用,用于区分其他名称相同的多个标记。

    恰好程序员开始写这样的语法:

    token operator:sym<+> { '+' }
    token operator:sym<-> { '-' }
    token operator:sym</> { '/' }
    

    为避免重复符号(此处为 +-/),引入了一个特殊规则 &lt;sym&gt; 匹配 :sym&lt;...&gt; 中的任何内容作为文字,因此您可以编写上述标记作为

    token operator:sym<+> { <sym> }
    token operator:sym<-> { <sym> }
    token operator:sym</> { <sym> }
    

    如果你不在正则表达式中使用&lt;sym&gt;,你可以在:sym&lt;...&gt;中随意写任何你想要的东西,所以你可以写类似的东西

    token operator:sym<fallback> { . }
    

    【讨论】:

      【解决方案3】:

      可能是这样的:

      grammar Foo {
          token TOP { <action>+ % " " }
          proto token action {*}
          token action:sym<come> { <sym> }
          token action:sym<bebe> { <sym> }
          token action:sym<default> { \w+ }
      }.parse("come bebe ama").say;
      

      输出

      「come bebe ama」
       action => 「come」
        sym => 「come」
       action => 「bebe」
        sym => 「bebe」
       action => 「ama」
      

      【讨论】:

      • 感谢您的回答,但这并不是真正的等价物。您不能在令牌中使用&lt;sym&gt;(因为它会失败)或. 如上所述跳过它。必须对其进行特殊处理,因为我们既不能访问 也不能简单地跳过它。
      • @jjmerelo token action:sym&lt;default&gt; { $&lt;sym&gt;=[\w+] } 有帮助吗?
      • 它会更接近,但如果需要,仍然不会通过. 跳过。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-27
      • 2010-12-12
      相关资源
      最近更新 更多