Perl 我如何制作Marpa';s序列规则贪婪?
我正在研究一种语法,它将文本中的项目分组。每个组只能包含特定类型的项,但不显式分隔。这会导致问题,因为Perl 我如何制作Marpa';s序列规则贪婪?,perl,parsing,ambiguous-grammar,marpa,Perl,Parsing,Ambiguous Grammar,Marpa,我正在研究一种语法,它将文本中的项目分组。每个组只能包含特定类型的项,但不显式分隔。这会导致问题,因为x…x(其中表示可以作为组的一部分的项目)可以分组为x(…)x,x(…)x,x(…)x,x(…)x。换句话说,语法是高度模糊的 如果我只需要x(…)x解析,也就是说,如果我想强制+量词只表现为“贪婪”(就像在Perl正则表达式中那样),如何消除这种歧义 在下面的语法中,我尝试将rank副词添加到序列规则中,以便将Group置于sequence之上,但这似乎不起作用 下面是练习这种行为的测试用例
x…x
(其中
表示可以作为组的一部分的项目)可以分组为x(…)x
,x(…)x
,x(…)x
,x(…)x
。换句话说,语法是高度模糊的
如果我只需要x(…)x
解析,也就是说,如果我想强制+
量词只表现为“贪婪”(就像在Perl正则表达式中那样),如何消除这种歧义
在下面的语法中,我尝试将rank
副词添加到序列规则中,以便将Group
置于sequence
之上,但这似乎不起作用
下面是练习这种行为的测试用例
使用严格;
使用警告;
使用Marpa::R2;
使用测试::更多;
my$grammar_source=::first
|组操作=>::第一个
团体
:=GroupItem+action=>[名称、值]
分组项目
::=('[')序列(']')操作=>::首先
单词~[a-z]+
空间[\s]+
尾声语法
my$input=“foo[a][b]bar”;
diag“perl$^V”;
诊断“Marpa::R2”。R2->VERSION;
my$grammar=Marpa::R2::Scanless::G->new({source=>\$grammar\u source});
我的$recce=Marpa::R2::Scanless::R->new({grammar=>$grammar});
$recce->read(\$input);
我的$parse_count=0;
而(我的$value=$recce->value){
是$$value、['foo'、[Group=>['a']、['b']]、'bar']、'expected structure'
或diag explain$$值;
$parse_count++;
}
是$parse_count,1,'预期的解析数';
完成测试;
测试用例的输出(失败):
#perl v5.18.2
#Marpa::R2 2.09
ok 1-预期结构
不正常2-预期结构
#测试“预期结构”失败
#第38行。
#结构开始于:
#$got->[1][2]=不存在
#$expected->[1][2]=数组(0x981bd68)
# [
#"福",,
# [
#"集团",,
# [
#“a”
# ]
# ],
# [
#${\$VAR1->[1][0]},
# [
#“b”
# ]
# ],
#“酒吧”
# ]
不正常3-预期的分析次数
#测试“预期的分析次数”失败
#第41行。
#得到:“2”
#预期:“1”
1..3
#看起来你3次考试中有2次没通过。
序列规则是为非棘手的情况而设计的。当事情变得棘手时,序列规则总是可以重写为BNF规则,这就是我在这里的建议。以下内容使您的测试工作正常:
use strict;
use warnings;
use Marpa::R2;
use Test::More;
my $grammar_source = <<'END_GRAMMAR';
inaccessible is fatal by default
:discard ~ space
# Three cases
# 1.) Just one group.
# 2.) Group follows by alternating words and groups.
# 3.) Alternating words and groups, starting with words
Sequence ::= Group action => ::first
Sequence ::= Group Subsequence action => [values]
Sequence ::= Subsequence action => ::first
Subsequence ::= Words action => ::first
# "action => [values]" makes the test work unchanged.
# The action for the next rule probably should be
# action => [name, values] in order to handle the general case.
Subsequence ::= Subsequence Group Words action => [values]
Words ::= WORD+ action => ::first
Group
::= GroupItem+ action => [name, values]
GroupItem
::= ('[') Sequence (']') action => [value]
WORD ~ [a-z]+
space ~ [\s]+
END_GRAMMAR
my $input = "foo [a] [b] bar";
diag "perl $^V";
diag "Marpa::R2 " . Marpa::R2->VERSION;
my $grammar = Marpa::R2::Scanless::G->new( { source => \$grammar_source } );
my $recce = Marpa::R2::Scanless::R->new( { grammar => $grammar } );
$recce->read( \$input );
my $parse_count = 0;
while ( my $value = $recce->value ) {
is_deeply $$value, [ 'foo', [ Group => ['a'], ['b'] ], 'bar' ],
'expected structure'
or diag explain $$value;
$parse_count++;
} ## end while ( my $value = $recce->value )
is $parse_count, 1, 'expected number of parses';
done_testing;
使用严格;
使用警告;
使用Marpa::R2;
使用测试::更多;
my$grammar\u source=[值]
序列::=子序列操作=>::第一个
子序列::=单词操作=>::第一个
#“action=>[values]”使测试工作不变。
#下一个规则的操作可能应该是
#操作=>[name,values]以处理一般情况。
子序列::=子序列组字操作=>[值]
单词::=单词+动作=>::第一
团体
:=GroupItem+action=>[名称、值]
分组项目
::=('[')序列(']')操作=>[值]
单词~[a-z]+
空间[\s]+
尾声语法
my$input=“foo[a][b]bar”;
diag“perl$^V”;
诊断“Marpa::R2”。R2->VERSION;
my$grammar=Marpa::R2::Scanless::G->new({source=>\$grammar\u source});
我的$recce=Marpa::R2::Scanless::R->new({grammar=>$grammar});
$recce->read(\$input);
我的$parse_count=0;
而(我的$value=$recce->value){
是$$value、['foo'、[Group=>['a']、['b']]、'bar'],
“预期结构”
或diag explain$$值;
$parse_count++;
}##结束时(我的$value=$recce->value)
是$parse_count,1,'预期的解析数';
完成测试;
无歧义语法:
Sequence : WORD+ SequenceAfterWords
| Group SequenceAfterGroup
SequenceAfterWords : Group SequenceAfterGroup
|
SequenceAfterGroup : WORD+ SequenceAfterWords
|
Jeffrey Kegler说,在Marpa中,使用递归进行引导的处理效率更高。上面采用的相同方法也可以回到前面来实现这一点
Sequence : SequenceBeforeWords WORD+
| SequenceBeforeGroup Group
SequenceBeforeWords : SequenceBeforeGroup Group
|
SequenceBeforeGroup : SequenceBeforeWords WORD+
|
在这两种情况下
Group : GroupItem+
GroupItem : '[' Sequence ']'
非常感谢。我想接下来我将编写递归规则,并通过自定义操作展平解析树。我只是想首先确定没有一种更有效的方法是我忽略的。仅供参考,我在尝试用类似标记的语言解析列表时遇到了这个问题,即进行缩进敏感解析。这并不是Marpa擅长的事情,但是对于一些事件(尽管事件系统中可能存在关于零L0长度外部读取词素的错误,我必须对此进行一些研究),这是一种非常优雅的方法。我的是左递归,因为左递归对于Marpa内部来说比右递归稍微好一点——两者都是线性的,如果没有歧义的话,但是右递归需要更多的簿记。@Jeffrey Kegler,你有相同规则的产品,它们有一个共同的开始,这个事实怎么样。Marpa能有效地处理这些问题吗?@Jeffrey Kegler,Argh,no.在
A的A
两部作品中B
是共同的开始吗?@ikegami是的,像Marpa这样的早期解析器能有效地处理这样一个共同的开始。当预测A
时,这将预测产品A→ · B C
和A→ · bd
(·
是当前位置)。所以这两个产品都预测了B
。在B
完成后,我们将进入A→ B·C
和A→ B·D
,它预测C
和D
。如果两者均未找到,A
将从当前产品中删除。如果找到其中一个,则完成生产和A
。如果两个都找到了,那么两个产品都完成了,我们有一个不明确的解析。这种基于预测的表解析意味着没有回溯。但是,该规则A
总是将两个产品添加到当前产品集。保持此集合较小有助于提高性能,因为必须在每个令牌之后对其进行迭代以生成新的预测