I'm working on Ruby bindings for libmarpa. They're coming along quite well. Right now I'm trying to implement prioritized alternatives ('||' in SLIF). I think I'm close, but the following example has me scratching my head. Please be patient as I try to give just enough background. (It's really not that much if you skip the code and dumps.)
First of all, to implement priorities in the Ruby wrapper, I'm using the rule ranking. I'm not modifying the symbol rankings at all. Here is the Perl version. (I know there are plenty of examples on how to do the calculator grammar "right." It's the most straightforward example I could come up with.)
my $grammar_str = "
:default ::= action => [name,values]
:start ::= expr
expr ::= number ||
expr '*' expr ||
expr '+' expr
number ~ [\\d]+
";
my $input = '3+4*5+6*7*8';
my $grammar = Marpa::R2::Scanless::G->new({ source => \$grammar_str });
my $recce = Marpa::R2::Scanless::R->new({ grammar => $grammar});
# check for complete parsing
my $len_read = $recce->read( \$input );
die "Incomplete read" if $len_read != length $input;
# check for ambiguous parse result
if ( my $ambiguous_status = $recce->ambiguous() ) {
chomp $ambiguous_status;
die "Parse is ambiguous\n", $ambiguous_status;
}
I get a single parse result with the '+' before the 6 at the top of the expression tree.
In my Ruby bindings, I'm assigning the ranks so that the "number" rule has the highest rank, the multiply rule has the middle rank, and the addition rule has the lowest rank. Here is the output of the 'show_rules' method for my grammar. (The default rank is 0. If the rank is equal to zero, it is not printed.)
R0: S2 ::= S3
number ::= number.rule
R1: S1 ::= S2 rank 2
expr.rule ::= NUMBER
R2: S4 ::= S0 S5 S0
EXPR /\*/ EXPR ::= EXPR /\*/ EXPR
R3: S1 ::= S4 rank 1
expr.rule ::= EXPR /\*/ EXPR
R4: S6 ::= S0 S7 S0
EXPR /\+/ EXPR ::= EXPR /\+/ EXPR
R5: S1 ::= S6
expr.rule ::= EXPR /\+/ EXPR
R6: S0 ::= S1
expr ::= expr.rule
The DSL gets in the way a little on the LHS of the productions (no, this is not a CSG). Remember, it's a work in progress. :-) The point is that I'm generating the rules with the ranks I expect because the output above reads the rule rank back from libmarpa.
The parsing result I get has five results, with the '*' operators at the top of the tree. In prefix notation, the results are as follows.
"(* (* (* (+ 3 4) (+ 5 6)) 7) 8)"
"(* (* (+ 3 4) (* (+ 5 6) 7)) 8)"
"(* (* (+ 3 4) (+ 5 6)) (* 7 8))"
"(* (+ 3 4) (* (* (+ 5 6) 7) 8))"
"(* (+ 3 4) (* (+ 5 6) (* 7 8)))"
This looks like an equivalent of the 'dangling-else' ambiguity.
I have two questions.
1. Why is my priority backwards? Marpa::R2 gave me the '+' rule at the outer-most level, while my Ruby wrapper gave the '*' rule at the outer-most level every time. In other words, help me understand what 'rank' means in the Marpa context, and how it is applied.
2. Why does Marpa::R2 give an unambiguous result? Even with the '+' rule on the outside, there are two choices for associativity.
Thanks!
- Ryan