Search code examples
perlmarpa

What arguments are passed to an Marpa::R2 action?


In the page of Marpa::R2, I understand the BNF (Backus-Naur Form), but I am quite lost with the action callbacks.

In this example below, I understand that the two, left and right members are passed to do_multiply. I have no problem with that. The problem is that I cannot find any documentation of what are these arguments?

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] }   

What are $_[0] or even $_[3]? Where is this documented? Even on the official marpa website I don't see any documentation.

In a different example, here an answer of chobora, we see that pair refers to $_[2] and $_[3]:

Snippet of the BNF:

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

Core code:

$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] }

Solution

  • The Marpe::R2 docs say the following:

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

    The Perl semantic closures are callbacks. They are called as each node in a parse tree is evaluated.

    Each Perl semantic closure is called with one or more arguments. The first argument to a value action is always a per-parse-tree object, which the callbacks can use as a scratchpad. In this example, the per-parse-tree object is not used. The remaining arguments will be the values of the node's "children" -- in other words, the values computed for each of its RHS symbols, in order. If the action is for an empty rule, the per-parse-tree object will be its only argument.

    Every value action is expected to return a value. With one exception, this value is passed up to a parent node as an argument. The exception is the value for the start rule. The return value for the start rule becomes the parse result.

    So those functions are passed an object as the first argument. That's $_[0].

    For your example that text seems to mean that the following arguments, $_[1] and $_[2] are just the values that you use to compute stuff.


    Adding some debug output gave me the following:

    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
    ]