3

我以前用 Marpa 解析复杂而愚蠢的旧文本格式取得了很好的成功,我正在尝试再做一次。

这种特殊格式有成百上千种不同的“开始”和“结束”块,如下所示:

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”)到其内容的键值映射作为字符串。

4

1 回答 1

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;
}
于 2016-02-12T18:16:08.077 回答