настройка возвращаемого значения синтаксического анализа, сохранение безымянных терминалов - PullRequest
0 голосов
/ 25 января 2019

Рассмотрим грамматику:

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 настройка возвращаемого значения довольно ограничена , но вложенные массивы возможны из коробки с опцией конфигурации.

Я продемонстрировал, что желаемая настройка возможна, хотя это не всегда легко или просто.Эти фрагменты кода, прикрепленные к правилам, запускаются при сборке дерева.


Метод parse не возвращает ничего, кроме вложенных объектов Match, которые являются громоздкими.Они не сохраняют безымянные терминалы!(Просто чтобы убедиться, о чем я говорю: это две части данных в RHS правила TOP, значения которых 'x' и 'z'.) Видимо, добавляются только данные, возникающие из именованных деклараторов.к дереву.

Назначение переменной соответствия (аналогично тому, как она работает в Regexp-Grammars), похоже, не имеет никакого эффекта.Поскольку терминалы не попадают в переменную сопоставления, действия тоже не помогают.

В итоге, вот грамматика и обычное значение анализа:

grammar {rule TOP { x <Y> z }; rule Y { y };}.parse('x y z')

Как вы получаете значение ["TOP","x",["Y","y"],"z"] из него?Вы не можете изменять форму правил, потому что это может испортить семантику, присоединенную пользователем, иначе все остальное будет честной игрой.Я все еще думаю, что ключом к решению является переменная соответствия, но я не понимаю, как.

1 Ответ

0 голосов
/ 25 января 2019

Не полный ответ, но метод Match.chunks дает вам несколько входных строк, разбитых на захваченные и не захваченные части.

Это, однако, не дает вам возможности различать не захватывающие литералы в регулярном выражении и неявно сопоставленные пробелы.

Вы можете обойти это, добавив позиционные захваты, и использовать 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, но общая идея должна быть ясной.

...