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
总是将两个产品添加到当前产品集。保持此集合较小有助于提高性能,因为必须在每个令牌之后对其进行迭代以生成新的预测