Jeremy,

So, I just hacked up your suggestion in Rats! --- thankfully, almost all the necessary code was already written, so it was easy.

Problem is, your idea does NOT work for mutually left-recursive productions, only directly left-recursive productions.

To illustrate, here's my example input grammar:


module xtc.parser.Foo;

option main(Top), verbose;

public Node Top = Choice !_ ;

generic Choice = One / Two ;

generic One = Choice "one" / Base ;
generic Two = Choice "two" / Base ;

String Base = "base" ;


And here is the execution trace on input "baseonetwo", indented for readability:

enter Top @ 0 : ""
   enter Choice @ 0 : ""
      enter One @ 0 : ""
         lookup Choice @ 0 : "" -> error
         enter Base @ 0 : ""
         exit Base @ 0 with match
         lookup Base @ 0 : "base" -> match
      exit One @ 0 with match
      enter One @ 0 : "base"
         lookup Choice @ 0 : "base" -> error  *****
         lookup Base @ 0 : "base" -> match
      exit One @ 0 with match
      lookup One @ 0 : "base" -> match
   exit Choice @ 0 with match
   enter Choice @ 0 : "base"
      lookup One @ 0 : "base" -> match
   exit Choice @ 0 with match
   lookup Choice @ 0 : "base" -> match
exit Top @ 0 with error

bar:1:0: top expected

The problem occurs in the line marked with *****. At this point, the Choice production should produce a match on the One production matching the Base production. However, the memoized result is the error marker from the first iteration of your do/while loop. Hence, there's only a look-up, which fails. Everything afterwards doesn't really matter anymore.

Now, if Choice would simply ignore the memoized result and try again, it would pull up the match from One and the parser would progress correctly. In other words, all productions that are mutually left- recursive need to share some state for the same input position, which complicates your scheme considerably.

Robert

On Sep 3, 2007, at 2:45 PM, Jeremy Bruestle wrote:

I'm missing something: the first iteration forces a base case, in my
example no characters with null as the semantic value. With Bryan's
condition, that's it; no more recursion. But my point is that I need
to try the recursive case now.

Robert

Actually, my bad again, the return should be "return prev", but given
that, the logic is as follows:

On the first entry into the loop body, cur = -1

Now:
    memory[key] = cur;  // Memorized version is now -1, no match
    prev = cur;  // Prev is also -1
    cur = do_pase(rule, position);

The do_parse calls the actual matcher, none of the recursive calls
work (since memorized version is currently -1), but the null match
does work, resulting in a return of 0 (since null match has length 0).
 Now, cur = 0, prev = -1, thus cur != -1 && cur > prev thus we go
around the loop again.

Now:
    memory[key] = cur;  // Memorized version is null match
    prev = cur;  // Prev is now 0
    cur = do_pase(rule, position);

This time, the recursive calls work (the memorized version is the
empty match), and since all of your cases do actually match real
values the new match that results is cur > 0, thus once again cur !=
-1 && cur > prev, and so on.  When at some point there is no
additional left recursive matches, so we fall though to the lowest
rule, the null rule, which of course matches (since it always does).
At this point, we return cur = 0 again, which will fail the loop
condition, exiting, and the return to the original caller will the the
*previous* match, which was the longest recursive match.

I checked the 'only null' case and the 'non-recursive' case and they
seem to work fine as well.

I think that's all correct now.

-Jeremy

_______________________________________________
PEG mailing list
PEG@lists.csail.mit.edu
https://lists.csail.mit.edu/mailman/listinfo/peg


_______________________________________________
PEG mailing list
PEG@lists.csail.mit.edu
https://lists.csail.mit.edu/mailman/listinfo/peg

Reply via email to