-
Notifications
You must be signed in to change notification settings - Fork 22
Added support for Left Recursive Grammars, using the algorithm from the Ometa paper #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…from the cache. Also update tests to verify this behavior.
|
Wow! This is awesome. Thanks for this work. I'll be reviewing these commits as soon as I get the chance. |
|
Is http://www.vpri.org/pdf/tr2007002_packrat.pdf [1] the Ometa paper? I didn't know what ometa was until I started searching for it. The reason I ask is because I'm reading through http://tratt.net/laurie/research/publications/papers/tratt__direct_left_recursive_parsing_expression_grammars.pdf [2] and the author, Tratt, makes the observation that Warth's Ometa tool, which implements the technique described in [1], incorrectly parses the expression 1-2-3, as (1-(2-(3))), given the grammar: Thanks! |
|
David, Thanks for researching this. As I mentioned above, I'd love to be able to support left recursion in Citrus, but I haven't had the time to thoroughly test the algorithm myself yet. It's an important change, and it deserves careful consideration. |
|
David, yes [1] is the Ometa paper. According to this test I believe left associtivity works as intended https://github.com/joachimm/citrus/blob/master/test/indirect_left_recursion_test.rb |
|
I just tried implementing the special case (a grammar production is both left-recursive and right-recursive) that Tratt documented in his paper [2]. The grammar is: In left_recursion_test.rb, I slightly modified your LR grammar: grammar :LR do
rule :expr do
any(all(label(:expr, 'lhs'), '-', label(:expr, 'rhs')){lhs.value - rhs.value},
:num)
end
rule :num do
ext(/[0-9]+/){to_i}
end
end
def test_lr
match = LR.parse("3-4-5", {:leftrecursive=>true})
assert(match)
assert_equal("3-4-5", match)
assert_equal(-6, match.value)
endUnless I've done something wrong, which is not unlikely, this test fails because 3-4-5 is parsed as (3 - (4 - 5)) and produces the result 4. Can you verify that this is in fact an issue. I'm not 100% sure that I've set up a proper test to verify whether or not Tratt's observation is an issue in this implementation. Thanks. |
|
You are right. Making rules both left-recursive and right-recursive, seems to give unwanted results. Thanks for the link to the Tratt's paper. I will see if I can fit his idea into the algorithm. |
|
Hey @joachimm have you made any progress on this? I'm interested in whether Warth's implementation is correct? |
|
Yesterday I ran across ohmjs/ohm#55, which addresses the same "incorrect parse" in another PEG parser library, and @alexwarth's opinion - ohmjs/ohm#55 (comment) - is that Tratt's conclusion is just one interpretation, but nothing definitive. Something to consider. It may boil down to preference. |
Also added some stuff in the TextMate bundle