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 insym
tokens for more than one character? ... The example forsym
shows*
(WhateverCode
) standing in for a single symbol
不是
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的任意字符串即可。原型(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 之间添加了必需的空格。这有两个影响:letter:sym<JJ>
匹配后,“a”和“m”之间缺少空格表示此时整体匹配失败。
sym
, by itself, does work with symbols with more than one character
是的。
token foo:sym<bar> { ... }
所做的全部是添加:foo
的多调度; 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/