4

Marpa::R2的页面中,我了解 BNF(Backus-Naur 形式),但我对动作回调非常迷茫。

在下面的这个例子中,我知道左右两个成员被传递给do_multiply. 对于那件事我没有任何疑问。问题是我找不到任何关于这些论点的文档?

my $dsl = <<'END_OF_DSL';
:default ::= action => [name,values]
lexeme default = latm => 1    
Calculator ::= Expression action => ::first
...
    Term '*' Factor action => do_multiply
...
END_OF_DSL

my $grammar = Marpa::R2::Scanless::G->new( { source => \$dsl } );

sub do_multiply    { $_[1] * $_[2] }   

$_[0]甚至是什么$_[3]?这是在哪里记录的?即使在官方 marpa 网站上,我也看不到任何文档。

在另一个示例中,这里是chobora的答案,我们看到它pair指的是$_[2]and $_[3]

BNF 的片段:

Hash  ::= '(' Pairs ')'     action => hash
Pairs ::= Pair+             action => pairs
Pair  ::= '(' Key Value ')' action => pair
Key   ::= String

核心代码:

$recce->read(\$input);
print Dumper $recce->value;

sub hash   { $_[2] }
sub pairs  { shift; +{ map @$_, @_ } }
sub pair   { [ @_[2, 3] ] }               # What is 2 and 3?
sub itself { $_[1] }
4

1 回答 1

4

Marpe ::R2 文档说以下内容:

sub My_Actions::do_add {
    my ( undef, $t1, undef, $t2 ) = @_;
    return $t1 + $t2;
}

Perl 语义闭包是回调。它们在解析树中的每个节点被评估时被调用。

每个 Perl 语义闭包都用一个或多个参数调用。值操作的第一个参数始终是每个解析树对象,回调可以将其用作暂存器。在此示例中,不使用 per-parse-tree 对象。剩下的参数将是节点的“子节点”的值——换句话说,按顺序为每个 RHS 符号计算的值。如果操作是针对空规则的,则 per-parse-tree 对象将是它的唯一参数。

每个值操作都应该返回一个值。除了一个例外,这个值作为参数传递给父节点。例外是开始规则的值。开始规则的返回值成为解析结果。

所以这些函数被传递一个对象作为第一个参数。那就是$_[0]

对于您的示例,该文本似乎意味着以下参数,$_[1]并且$_[2]只是您用于计算内容的值。


添加一些调试输出给了我以下信息:

use Data::Printer;

sub My_Actions::do_add {
    my ( undef, $t1, undef, $t2 ) = @_;
say 'do_add';
p @_;

    return $t1 + $t2;
}

sub My_Actions::do_multiply {
    my ( undef, $t1, undef, $t2 ) = @_;
say 'do_multiply';
p @_;
   return $t1 * $t2;
}

__END__

do_multiply
[
    [0] {},
    [1] 42,
    [2] "*",
    [3] 1
]
do_add
[
    [0] {},
    [1] 42,
    [2] "+",
    [3] 7
]
于 2015-07-03T07:05:03.843 回答