grammar - *可以在符号 token 中使用多个字符吗?

标签 grammar raku

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 token ?

最佳答案

Can * be used in sym tokens for more than one character? ... The example for sym shows * (WhateverCode) standing in for a single symbol



不是WhateverCodeWhatever .1
<...>中的foo:sym<...>是一个引号构造函数,因此...只是一个文字字符串。

这就是为什么这样工作:
grammar g { proto token foo {*}; token foo:sym<*> { <sym> } }
say g.parse: '*', rule => 'foo'; # matches

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

对于此答案的其余部分,我将编写JJ而不是*,只要后者只是P6的任意字符串即可。

原型(prototype)中的*Whatever。但这与您的问题完全无关:
grammar g { proto token foo {*}; token foo:sym<JJ> { '*' } }
say g.parse: '*', rule => 'foo'; # matches

在名称包括:sym<...>部分的规则( token 和正则表达式为规则)的主体中,您可以编写<sym>,它将与:sym<...>的角度之间的字符串匹配:
grammar g { proto token foo {*}; token foo:sym<JJ> { <sym> } }
say g.parse: 'JJ', rule => 'foo'; # matches

但是您可以在rule/token/regex正文中编写任何您喜欢的内容。 .与单个字符匹配:
grammar g { proto token foo {*}; token foo:sym<JJ> { . } }
say g.parse: '*', rule => 'foo'; # matches

It will, however, fail if we use it to stand in for a symbol composed of several letters



不。那是因为您更改了语法。

如果将语法改回原始编码(除了较长的letter:sym<...>之外),则可以正常工作:
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<JJ> token 在机翼中等待以匹配任何单个字符-并且该字符包含单个空格,因此它与那些匹配并且被处理。

但是在修改中,您在TOP token 中的 token 之间添加了必需的空格。这有两个影响:
  • 它匹配“come”之后和“bebe”之后的空间;
  • 在将“a”与letter:sym<JJ>匹配后,“a”和“m”之间缺少空格表示此时整体匹配失败。

  • sym, by itself, does work with symbols with more than one character



    是的。 token foo:sym<bar> { ... }所做的全部是添加:
  • 替代foo的多调度;
  • 一个 token sym,在词法上作用域为foo token 的主体,与'bar'相匹配。

  • how can we define a default sym token that matches a set of characters?



    您可以编写这样的sym token ,但是要明确一点,因为您不希望它与固定字符串匹配,所以不能使用主体中的<sym>。(因为<sym>必须是固定字符串。)仍要在键sym下捕获,则可以在 token 正文中写$<sym>=,如Håkon在其答案下方的注释中所示。但也可以是letter:whatever,体内带有$<sym>=

    我将其编写为letter:default token ,以强调它是:sym<something>并没有任何区别。 (如上所述,:sym<something>可以与其他:baz<...>:bar<...>一起作为替代,唯一的补充是,如果它是:sym<something>,那么它也会使<sym>子规则在关联规则的主体中可用, (如果使用的话)与固定字符串'something'匹配。)

    rule foo:bar:baz:qux<...>开头的规则中,根据LTM logic在所有foo备选方案中选择获胜调度。因此,您需要编写这样的 token ,该 token 不会作为最长的 token 前缀赢,而只有在没有其他匹配的情况下才匹配。

    要立即在LTM竞赛中返回背包,请在规则body2的开头插入{}:
    token letter:default { {} \w+ }
    

    现在,从背包的背面,如果此规则有机会,它将与\w+模式匹配,该模式将在遇到非单词字符时停止 token 。

    如果没有其他匹配项,则使其匹配可能意味着最后将其列出。所以:
    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␤»
    

    that just can't be the thing causing it ... "come bebe ama" shouldn't work in your grammar



    该代码中有错误,现在我已修复并对此表示歉意。如果您运行它,您会发现它可以像宣传的那样工作。

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

    脚注

    1并非所有这些都与实际发生的事情有关,而是...在P6中,“词条位置”中的*(英语中,名词所属,在通用编程术语中,值所属)是 Whatever ,而不是 WhateverCode 。即使使用操作符编写了*,例如+** + *而不是单独使用*,但仍然只是Whatever,但是编译器会自动将一个或多个*的大多数此类组合与一个或多个运算符转换为 Code 的子类,称为WhateverCode。 (异常在表here中列出。)

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

    关于grammar - *可以在符号 token 中使用多个字符吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56831631/

    相关文章:

    compiler-construction - 使用自适应语法

    raku - 终端 ANSI 颜色不适用于 Inline::Perl5 (Data::Printer)

    regex - Raku 有没有一种快速的方法来查找和删除/替换非 ASCII 或格式错误的 utf8 字符?

    raku - Perl6的Perlbrew

    raku - 类中的私有(private)属性使类型化的公共(public)属性未定义

    regex - 在正则表达式或语法标记中捕获嵌套结构中的内容

    powershell - 什么是 PowerShell 中的可扩展字符串

    C++ 如何使用 vector<T> 专门化模板?

    sql - SQL 有有限状态机定义吗?

    raku - 需要在 Raku 中的每 n 行读取文本文件的建议