Соответствующие произвольные разделители

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

Этот конкретный формат имеет сотни и сотни различных типов блоков "Начало" и "Конец", которые выглядят так:

Begin BlahBlah
    asdf qwer 123
    987 xxxx
End BlahBlah

Begin FooFoo
    Begin BarBar
        some stuff (1,2,3)
    End BarBar
    whatever x
End FooFoo

Как мне создать одно правило, которое будет соответствовать всем BlahBlah, BarBar и FooFoo из вышеприведенного материала? Ни в каких примерах я не вижу, как динамически перехватить токен и использовать его для прекращения действия правила, по крайней мере, в случае со стандартными грамматическими примерами без сканирования. Я не хочу перечислять все различные типы блоков, потому что новые типы будут ломать вещи, и я не думаю, что это необходимо.

Содержимое блоков Begin/End несущественно для вопроса. На самом деле эти вещи - сложный беспорядок, но я не знаю, как это можно сделать. Я отмахиваюсь руками от других усложняющих деталей, которые делают Marpa хорошим инструментом для этого, так что я не хочу прибегать к регулярным выражениям.

Как минимум, все, что я пытаюсь достичь - это отображение значения ключа типа блока (то есть "BlahBlah") с его содержимым в виде строки.

1 ответ

Это не совсем отвечает на мой первоначальный вопрос, потому что я в конечном итоге пришел к тому, что просто проигнорировал повторяющуюся строку, следующую за токеном "Конец". Я, вероятно, последую предложению комментария выше просто проверить, совпадают ли имена начала / конца на этапе постобработки. Работая в предположении, что токен является избыточным, это, похоже, работает нормально, как грубое первое сокращение. Критика приветствуется:

#!/usr/bin/perl
use warnings;
use strict;
use v5.18;
use utf8;
use feature 'unicode_strings';
use autodie;

use Marpa::R2;
use Data::Dumper;

my $g = Marpa::R2::Scanless::G->new({
        source         => \(<<'END_OF_SOURCE'),
lexeme default = latm => 1
:default ::= action => ::array
:start ::= beginend_blocks
:discard ~ <ws>

beginend_blocks ::= beginend_block+

beginend_block ::= beginend_block_header beginend_block_contents

beginend_block_header ::= ('Begin') beginend_block_name action => ::first

beginend_block_name ::= <word> 

beginend_block_contents ::= beginend_block_content_elems (beginend_block_terminator) (<word>)

beginend_block_content_elems ::= beginend_block_content_elem+
beginend_block_content_elem ::= word            action => ::first
                              | beginend_block  action => ::first

beginend_block_terminator ::= ('End')

<word> ~ <wordchar>+
<wordchar> ~ [\S]

<ws> ~ [\s]+

END_OF_SOURCE
});


my $test_str = <<THEDATA;
Begin BlahBlah
    asdf qwer 123
    987 xxxx
End BlahBlah

Begin FooFoo
    something else
    Begin BazBaz
        some stuff (1,2,3)
    End BazBaz
    whatever x
    Begin BarBar
        some stuff (1,2,3)
    End BarBar
    whatever y 
End FooFoo
THEDATA

MAIN: {
    my $re = Marpa::R2::Scanless::R->new({ grammar => $g, trace_terminals => 0 });

    for (my $pos = $re->read(\$test_str); $pos < length $test_str; $pos = $re->resume) {
        my ($pause_start, undef) = $re->pause_span;
    }

    say Dumper $re->value;
}
Другие вопросы по тегам