* 可以在sym 标记中用于多个字符吗? ...sym 的示例显示 * (WhateverCode) 代表单个符号
这不是WhateverCode 或Whatever。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 而言后者只是一个任意字符串。
原型中的* 是Whatever。但这与您的问题完全无关:
grammar g { proto token foo {*}; token foo:sym<JJ> { '*' } }
say g.parse: '*', rule => 'foo'; # matches
在名称中包含:sym<...> 部分的规则(标记和正则表达式是规则)的主体中,您可以编写<sym>,它将匹配:sym<...> 角度之间的字符串:
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<...>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<JJ> 标记正在等待匹配任何单个字符——其中包含一个空格,因此它匹配那些并处理它们。
但是在您的修改中,您在TOP 标记中的标记之间添加了一个必需 空格。这有两个影响:
sym 本身确实适用于具有多个字符的符号
是的。 token foo:sym<bar> { ... } 所做的只是添加:
我们如何定义一个与一组字符匹配的默认sym 令牌?
您可以编写这样的sym 标记,但需要明确的是,因为您不希望它匹配固定字符串,所以它不能在正文中使用<sym>。(因为<sym> 有是一个固定的字符串。)如果你仍然想capture在sym键下,那么你可以在令牌正文中写$<sym>=,正如Håkon在他们的回答下的评论中显示的那样。但它也可以是letter:whatever,正文中带有$<sym>=。
我将把它写成letter:default 标记以强调它是:sym<something> 没有任何区别。 (如上所述,:sym<something> 与其他 :baz<...>s 和 :bar<...>s 一样只是一个替代方案,唯一的补充是如果它是 :sym<something>,那么它也是 使<sym> 子规则在关联规则的主体中可用,如果使用该子规则,则匹配固定字符串'something'。)
所有rule foo:bar:baz:qux<...>备选方案中的获胜调度是根据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。)
2见my answer to SO "perl6 grammar , not sure about some syntax in an example"中的脚注2。