在 Perl 6 中传递数据以形成语法规则
Passing data to form grammar rules in Perl 6
不确定 grammars
是否打算做这样的事情:我希望 tokens
在运行时定义(将来 — 使用文件中的数据)。所以我写了一个简单的测试代码,不出所料,它甚至无法编译。
grammar Verb {
token TOP {
<root>
<ending>
}
token root {
(\w+) <?{ ~[=10=] (elem) @root }>
}
token ending {
(\w+) <?{ ~[=10=] (elem) @ending }>
}
}
my @root = <go jump play>;
my @ending = <ing es s ed>;
my $string = "going";
my $match = Verb.parse($string);
.Str.say for $match<root>;
在 Perl 6 中执行此类操作的最佳方法是什么?
要匹配数组的任何元素,只需在正则表达式中写入数组变量的名称(以 @
符号开头):
my @root = <go jump play>;
say "jumping" ~~ / @root /; # Matches 「jump」
say "jumping" ~~ / @root 'ing' /; # Matches 「jumping」
因此在您的用例中,唯一棘手的部分是将数组从创建它们的代码(例如通过解析数据文件)传递到需要它们的语法标记。
最简单的方法可能是使它们成为动态变量(由 *
twigil 表示):
grammar Verb {
token TOP {
<root>
<ending>
}
token root {
@*root
}
token ending {
@*ending
}
}
my @*root = <go jump play>;
my @*ending = <ing es s ed>;
my $string = "going";
my $match = Verb.parse($string);
say $match<root>.Str;
另一种方法是传递 Capture
with the arrays to the args
adverb of method .parse
,这会将它们传递给 token TOP
,从那里您可以使用 [=19= 将它们传递给子规则] 或 <foo: ...>
语法:
grammar Verb {
token TOP (@known-roots, @known-endings) {
<root: @known-roots>
<ending: @known-endings>
}
token root (@known) {
@known
}
token ending (@known) {
@known
}
}
my @root = <go jump play>;
my @ending = <ing es s ed>;
my $string = "going";
my $match = Verb.parse($string, args => \(@root, @ending));
say $match<root>.Str; # go
您采用的方法本可以奏效,但您犯了三个错误。
范围界定
词法变量声明需要在编译器遇到它们的使用之前以文本形式出现:
my $foo = 42; say $foo; # works
say $bar; my $bar = 42; # compile time error
回溯
say .parse: 'going' for
grammar using-token {token TOP { \w+ ing}}, # Nil
grammar using-regex-with-ratchet {regex TOP {:ratchet \w+ ing}}, # Nil
grammar using-regex {regex TOP { \w+ ing}}; # 「going」
regex
声明符与 token
声明符具有完全相同的效果,只是它默认执行 backtracking.
您在 root
标记中首次使用 \w+
匹配整个输入 'going'
,然后无法匹配 @root
的任何元素。然后,因为没有回溯,整个解析立即失败。
(不要认为这意味着您应该默认使用 regex
。依赖回溯会大大减慢解析速度,通常不需要它。)
调试
见
这个有效:
my @root = <go jump play>;
my @ending = <ing es s ed>;
grammar Verb {
token TOP {
<root>
<ending>
}
regex root {
(\w+) <?{ ~[=12=] (elem) @root }>
}
token ending {
(\w+) <?{ ~[=12=] (elem) @ending }>
}
}
my $string = "going";
my $match = Verb.parse($string);
.Str.say for $match<root>;
输出:
go
不确定 grammars
是否打算做这样的事情:我希望 tokens
在运行时定义(将来 — 使用文件中的数据)。所以我写了一个简单的测试代码,不出所料,它甚至无法编译。
grammar Verb {
token TOP {
<root>
<ending>
}
token root {
(\w+) <?{ ~[=10=] (elem) @root }>
}
token ending {
(\w+) <?{ ~[=10=] (elem) @ending }>
}
}
my @root = <go jump play>;
my @ending = <ing es s ed>;
my $string = "going";
my $match = Verb.parse($string);
.Str.say for $match<root>;
在 Perl 6 中执行此类操作的最佳方法是什么?
要匹配数组的任何元素,只需在正则表达式中写入数组变量的名称(以 @
符号开头):
my @root = <go jump play>;
say "jumping" ~~ / @root /; # Matches 「jump」
say "jumping" ~~ / @root 'ing' /; # Matches 「jumping」
因此在您的用例中,唯一棘手的部分是将数组从创建它们的代码(例如通过解析数据文件)传递到需要它们的语法标记。
最简单的方法可能是使它们成为动态变量(由 *
twigil 表示):
grammar Verb {
token TOP {
<root>
<ending>
}
token root {
@*root
}
token ending {
@*ending
}
}
my @*root = <go jump play>;
my @*ending = <ing es s ed>;
my $string = "going";
my $match = Verb.parse($string);
say $match<root>.Str;
另一种方法是传递 Capture
with the arrays to the args
adverb of method .parse
,这会将它们传递给 token TOP
,从那里您可以使用 [=19= 将它们传递给子规则] 或 <foo: ...>
语法:
grammar Verb {
token TOP (@known-roots, @known-endings) {
<root: @known-roots>
<ending: @known-endings>
}
token root (@known) {
@known
}
token ending (@known) {
@known
}
}
my @root = <go jump play>;
my @ending = <ing es s ed>;
my $string = "going";
my $match = Verb.parse($string, args => \(@root, @ending));
say $match<root>.Str; # go
您采用的方法本可以奏效,但您犯了三个错误。
范围界定
词法变量声明需要在编译器遇到它们的使用之前以文本形式出现:
my $foo = 42; say $foo; # works
say $bar; my $bar = 42; # compile time error
回溯
say .parse: 'going' for
grammar using-token {token TOP { \w+ ing}}, # Nil
grammar using-regex-with-ratchet {regex TOP {:ratchet \w+ ing}}, # Nil
grammar using-regex {regex TOP { \w+ ing}}; # 「going」
regex
声明符与 token
声明符具有完全相同的效果,只是它默认执行 backtracking.
您在 root
标记中首次使用 \w+
匹配整个输入 'going'
,然后无法匹配 @root
的任何元素。然后,因为没有回溯,整个解析立即失败。
(不要认为这意味着您应该默认使用 regex
。依赖回溯会大大减慢解析速度,通常不需要它。)
调试
见
这个有效:
my @root = <go jump play>;
my @ending = <ing es s ed>;
grammar Verb {
token TOP {
<root>
<ending>
}
regex root {
(\w+) <?{ ~[=12=] (elem) @root }>
}
token ending {
(\w+) <?{ ~[=12=] (elem) @ending }>
}
}
my $string = "going";
my $match = Verb.parse($string);
.Str.say for $match<root>;
输出:
go