自定义解析 return 值,保留未命名的终端
customising the parse return value, retaining unnamed terminals
考虑语法:
TOP ⩴ 'x' Y 'z'
Y ⩴ 'y'
以下是如何使用各种解析器获取准确值 ["TOP","x",["Y","y"],"z"]
(不是手动编写,而是从语法生成):
xyz__Parse-Eyapp.eyp
%strict
%tree
%%
start:
TOP { shift; use JSON::MaybeXS qw(encode_json); print encode_json $_[0] };
TOP:
'x' Y 'z' { shift; ['TOP', (scalar @_) ? @_ : undef] };
Y:
'y' { shift; ['Y', (scalar @_) ? @_ : undef] };
%%
xyz__Regexp-Grammars.pl
use 5.028;
use strictures;
use Regexp::Grammars;
use JSON::MaybeXS qw(encode_json);
print encode_json $/{TOP} if (do { local $/; readline; }) =~ qr{
<nocontext:>
<TOP>
<rule: TOP>
<[anon=(x)]> <[anon=Y]> <[anon=(z)]>
<MATCH=(?{['TOP', $MATCH{anon} ? $MATCH{anon}->@* : undef]})>
<rule: Y>
<[anon=(y)]>
<MATCH=(?{['Y', $MATCH{anon} ? $MATCH{anon}->@* : undef]})>
}msx;
为接下来的两个解析器省略了代码。使用 Pegex,功能是通过从 Pegex::Receiver. With Marpa-R2, the customisation of the return value is quite limited 继承来实现的,但嵌套数组可以通过配置选项开箱即用。
我已经证明了所需的自定义是可能的,尽管它并不总是那么容易或直接。这些附加到规则的代码片段是 运行 作为树的组装。
parse 方法 returns 除了嵌套的 Match 对象之外别无其他,它们很笨重。他们不保留未命名的终端! (只是为了确定我在说什么:这些是 TOP
规则 RHS 处的两条数据,其值为 'x'
和 'z'
。)显然只有数据出现来自命名声明符的第四个被添加到树中。
分配给匹配变量(类似于它在 Regexp-Grammars 中的工作方式)似乎没有效果。由于终端没有进入匹配变量,actions 也无济于事。
总而言之,这里是语法和普通解析值:
grammar {rule TOP { x <Y> z }; rule Y { y };}.parse('x y z')
如何从中获取值 ["TOP","x",["Y","y"],"z"]
?您不允许更改规则的形状,因为这可能会破坏用户附加的语义,否则其他任何事情都是公平的。我仍然认为解决方案的关键是匹配变量,但我看不出如何。
不是完整的答案,但 Match.chunks method 为您提供了一些输入字符串标记为捕获和非捕获部分。
但是,它确实无法让您区分正则表达式中的非捕获文字和隐式匹配的空格。
您可以通过添加位置捕获来规避它,并使用 Match.caps
my $m = grammar {rule TOP { (x) <Y> (z) }; rule Y { (y) }}.parse('x y z');
sub transform(Pair $p) {
given $p.key {
when Int { $p.value.Str }
when Str { ($p.key, $p.value.caps.map(&transform)).flat }
}
}
say $m.caps.map(&transform);
这会产生
(x (Y y) z)
几乎是您想要的,只是缺少顶级 TOP
(只有硬编码才能进入)。
请注意,这并未涵盖所有边缘情况;例如,当捕获被量化时,$p.value
是一个数组,而不是匹配对象,所以你需要另一个级别的 .map
在那里,但总体思路应该很清楚。
考虑语法:
TOP ⩴ 'x' Y 'z'
Y ⩴ 'y'
以下是如何使用各种解析器获取准确值 ["TOP","x",["Y","y"],"z"]
(不是手动编写,而是从语法生成):
xyz__Parse-Eyapp.eyp
%strict
%tree
%%
start:
TOP { shift; use JSON::MaybeXS qw(encode_json); print encode_json $_[0] };
TOP:
'x' Y 'z' { shift; ['TOP', (scalar @_) ? @_ : undef] };
Y:
'y' { shift; ['Y', (scalar @_) ? @_ : undef] };
%%
xyz__Regexp-Grammars.pl
use 5.028;
use strictures;
use Regexp::Grammars;
use JSON::MaybeXS qw(encode_json);
print encode_json $/{TOP} if (do { local $/; readline; }) =~ qr{
<nocontext:>
<TOP>
<rule: TOP>
<[anon=(x)]> <[anon=Y]> <[anon=(z)]>
<MATCH=(?{['TOP', $MATCH{anon} ? $MATCH{anon}->@* : undef]})>
<rule: Y>
<[anon=(y)]>
<MATCH=(?{['Y', $MATCH{anon} ? $MATCH{anon}->@* : undef]})>
}msx;
为接下来的两个解析器省略了代码。使用 Pegex,功能是通过从 Pegex::Receiver. With Marpa-R2, the customisation of the return value is quite limited 继承来实现的,但嵌套数组可以通过配置选项开箱即用。
我已经证明了所需的自定义是可能的,尽管它并不总是那么容易或直接。这些附加到规则的代码片段是 运行 作为树的组装。
parse 方法 returns 除了嵌套的 Match 对象之外别无其他,它们很笨重。他们不保留未命名的终端! (只是为了确定我在说什么:这些是 TOP
规则 RHS 处的两条数据,其值为 'x'
和 'z'
。)显然只有数据出现来自命名声明符的第四个被添加到树中。
分配给匹配变量(类似于它在 Regexp-Grammars 中的工作方式)似乎没有效果。由于终端没有进入匹配变量,actions 也无济于事。
总而言之,这里是语法和普通解析值:
grammar {rule TOP { x <Y> z }; rule Y { y };}.parse('x y z')
如何从中获取值 ["TOP","x",["Y","y"],"z"]
?您不允许更改规则的形状,因为这可能会破坏用户附加的语义,否则其他任何事情都是公平的。我仍然认为解决方案的关键是匹配变量,但我看不出如何。
不是完整的答案,但 Match.chunks method 为您提供了一些输入字符串标记为捕获和非捕获部分。
但是,它确实无法让您区分正则表达式中的非捕获文字和隐式匹配的空格。
您可以通过添加位置捕获来规避它,并使用 Match.caps
my $m = grammar {rule TOP { (x) <Y> (z) }; rule Y { (y) }}.parse('x y z');
sub transform(Pair $p) {
given $p.key {
when Int { $p.value.Str }
when Str { ($p.key, $p.value.caps.map(&transform)).flat }
}
}
say $m.caps.map(&transform);
这会产生
(x (Y y) z)
几乎是您想要的,只是缺少顶级 TOP
(只有硬编码才能进入)。
请注意,这并未涵盖所有边缘情况;例如,当捕获被量化时,$p.value
是一个数组,而不是匹配对象,所以你需要另一个级别的 .map
在那里,但总体思路应该很清楚。