考虑语法:
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来实现功能。使用Marpa-R2,customisation of the return value is quite limited(但嵌套数组)可以通过配置选项立即使用。
我已经证明了所需的定制是可能的,尽管它并不总是那么容易或简单。这些规则附加的代码在树组装时运行。
parse方法只返回笨拙的嵌套Match对象,什么也不会返回。它们不保留未命名的端子! (只是为了确保我在说什么:这是TOP
规则的RHS处的两段数据,其值分别为'x'
和'z'
。)显然,只有数据出现了来自命名声明符的第四个元素将添加到树中。
分配给match变量(类似于Regexp-Grammars中的工作方式)似乎无效。由于终端没有将其放入匹配变量,因此actions也无济于事。
总而言之,这是语法和普通解析值:
grammar {rule TOP { x <Y> z }; rule Y { y };}.parse('x y z')
如何从中获得值["TOP","x",["Y","y"],"z"]
?不允许更改规则的形状,因为这可能会破坏用户附加的语义,否则其他任何事情都是公平的。我仍然认为解决方案的关键是match变量,但我看不到如何。
答案 0 :(得分:8)
不是一个完整的答案,但是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
,但总体思路应该很清楚。