PEG.js - parser generator for JavaScript
pegjs.majda.cz
pegjs.majda.cz
* http://zaa.ch/2k - Jison
* http://inimino.org/~inimino/blog/peg_first_release - another Packrat (has an es5 parser as an example)
Plus a few more that work but produce generated code that's too slow to be useful.
Grammar ambiguities are resolved by ordered choice. If there are two ways to parse something, the first way will be tried first. If it succeeds, the ordered choice short-circuits and the second way is ignored. So you can resolve, say, the classic dangling else problem by ordering your choices correctly.
While the backtracking behavior is different, choice order affects PEG rules similarly to Prolog.
http://compilers.iecc.com/comparch/article/05-09-114
In particular:
"Yes, this is "the" problem with PEG's. / implies ordering of the search (parsing) space. You need to order your / operators so that special cases (e.g. longer matches), so that they appear first. Unfortunately, if you don't do this, nothing will tell you you have a problem with your grammar, it will simply not parse some inputs. To me this implies that if one wants to use a PEG to parse some input, then one must exhaustively test the parser."
Hopefully the thread therein will describe my issue better than I have thus far.
It's for Lua, but there isn't anything in the VM design that requires Lua per se - porting it to another language's C API wouldn't be difficult. In my experience, LPEG has been quite easy to use for the sort of tasks one would normally apply regular expressions to (and then some, as it handles recursive structures far better), it's quite fast, and it's easy to tune incrementally. In my (not yet ready for release) Lua/LPEG webserver, I'm handling 1000+ requests per second in about 2MB ram total* , so LPEG's design has tamed the usual space issues caused by PEG memoization.
* Only a tiny amount of that time is due to request parsing, it's mostly because I'm still working the kinks out of the event loop.
One strike against it is that there isn't a whole lot of casual documentation, though the documentation that does exist (the research paper and a library reference) is quite thorough. Also, it takes advantage of Lua's operator overloading to make the grammars concise, which takes getting used to. Still, having it so thoroughly integrated into the language is extremely convenient, and it's quite a bit more expressive than regular expressions.
Also, here's a link to the PEG paper on the author's site, rather than behind the ACM's paywall: http://www.bford.info/pub/lang/peg.pdf . Gotta love the ACM.
Now seeing this for javascript makes me think if I should actually do more work with js.
http://www.bluishcoder.co.nz/2007/10/javascript-parser-combi...
I did the same thing in ActionScript. It's easy and fun.
Update: Thanks for the links! That being said, I didn't mean parsers written in Javascript or Ruby, I mean PEGs or CFGs that parse Javascript and/or Ruby programs :-)
Im writing a programming language in Ruby at the moment - and after playing with that for a few days I've gone back to "hand coded lexer plus Racc for grammar". It's probably personal preference but I find that a little more tunable.
OMeta is based upon PEGs and is worth a look because it has some great meta-meta ideas from the 60's that were ignored.
(Also, there are several ports of OMeta to other languages)
Also peg/leg for C is intended (iirc) as a direct competitor to flex/bison et al.
(Hmm, I must definitely try to port it to PEG.js :-)
As for Ruby, I am not sure if it is even possible to create a PEG grammar. Its lexer and parser are heavily interconnected and there is a lot of state involved. If the grammar will be created, I don't think it would be pretty.
How does: multiplicative : primary "* " multiplicative { return $1 * $3; }
return the product of two integers?
multiplicative : primary "*" multiplicative { return $1 * $3; }
/ primary
"primary" refers to another rule in the grammar, which is defined as integer or a parenthesized expression. This snippet defines "multiplicative", which is either a primary, or a primary followed by an asterisk followed by another multiplicative. (This recursively expands to allow any number of primaries, separated by asterisks.)The value of the multiplicative expression is the value of the first term times the value of the third term. (The second term is just the literal string "*".)
I will probably implement support for left recursion in PEG.js - it is possible (see e.g. http://www.vpri.org/pdf/tr2007002_packrat.pdf). After that, the grammar could be rewritten to evaluate in the correct order.
(Another alternative - which works right now - is to change the parsing expressions to something like "additive ([+-] additive)*" and deal with the whole chain of operations with the same priority at once. I didn't use this in the example as I wanted it to be as simple as possible.)
First, you'll note the algorithm is extremely complicated--nothing like the simple top-down algorithm that makes PEGs so attractive. Not only is it complicated, it misses basic refactoring issues--some logic is duplicated across functions, and the functions interact in ugly ways.
Second, it doesn't even handle left recursion correctly. Throw a ruleset like this at their parser
A -> B "a"
B -> C "b"
C -> B / A / "c"
and it will explode into a million little pieces, because the authors did not account for any recursive rule having multiple recursion points. Don't even try something like
S -> A / B
A -> A "a" / B / a
B -> B "b" / A / "b"
What was your final result? Did you implement the left recursion in the way the paper describes, invented/found some other way or abandoned the whole idea?
It involves the memo entries being able to remember which left-recursive results they are dependent on. This way, when a left-recursive rule produces a result that is dependent on itself, it knows that this match can possibly be "grown" through repeated iterations. That's a basic sketch of the idea. Performance properties remain the same in the case of left-recursive rules that are not interdependent. I don't really know what they are like for large numbers of interdependent left-recursive rules--but if you have a language like that, better to use an Earley or GLR parser.
I'm still working on it. It passes a battery of test cases, two of which I posted above, but I'm not 100% confident in it just yet. Also, as posted above, I'm trying to get permission from the higher-ups to release the code into the wild.
The issue is that a top-down grammar cannot handle left-recursion, since it naturally leads to infinite recursion when being parsed from the top down.
I actually had to handle the left-recursion problem for a PEG I wrote in-house--right now I'm trying to convince my boss to let me open-source it :)
term ::= factor ( ('*' | '/') factor )* ;
If you introduce regex-like closure operators to model loops, life gets much easier, and you can build your trees the right way around.How applicable this is to PEGs is another matter though. I generally write my parsers by hand, and I parse expressions with operator precedence.
And for stuff that LL(1) can't handle, I think GLR is a better approach.
In the simplest version, each rule can be seen as a function that calls other rules, passing along a memo table as it goes. It's entirely stateless and functional, except for the memo table. In addition, each function is only a few lines.
Backtracking isn't a hack--it's the natural result of statelessness. There's no cursor that needs to be backtracked.
Asking the user to have to worry about this stuff, when he doesn't have to, is not good software design. Not all of us are writing high performance parsers for complicated languages.
a: b / c
(The asterisks in my post were escaped because they were in a code block, or because there were not two of them in the same line.)