Соответствующие произвольные разделители
У меня был хороший успех при разборе сложных и глупых текстовых форматов с Марпой раньше, и я пытаюсь сделать это снова.
Этот конкретный формат имеет сотни и сотни различных типов блоков "Начало" и "Конец", которые выглядят так:
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;
}