自定义解析返回值,保留未命名的终端

时间:2019-01-25 19:53:48

标签: parsing grammar perl6

考虑语法:

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变量,但我看不到如何。

1 个答案:

答案 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,但总体思路应该很清楚。