The Packrat Parsing and Parsing Expression Grammars Page
bford.info
bford.info
Str = "a" Str "a" / "a"
If you get it right and you understand the logic, by all means use them. If you get it wrong or can't wrap your head around how it works despite knowing the answer, maybe reconsider.EDIT: since my point was too subtle and I have been misunderstood and downvoted as a result of it, allow me to give a hint. If you believe the above grammar matches aaaaa you fall in the latter category. It does not. Yes, aaa matches, aaaaaaa matches, but aaaaa does not. Yes, this is mind-boggling.
a: (a)
aaa: (a(a)a)
aaaaa: (a(a(a)a)a)
etcIt parses this: a a aaa a a But not this: a aaa a
(a(a(a(a)a)
and can't complete the (aXa) parse for the second a, so it backtracks to try the (a) parse (a(a)
The issue is since the parse of the third a as (a(a)a) succeeded, it will never try the (a) parse for the third a. Str = "a" "aa"*
Most languages allow writing tortured and hard to understand logic where simpler alternatives can also be written. I'm not sure why that should make people consider not using them.It is one-line, two-rule PEG grammar. What does it accept, and why? If we can't state this with confidence in such a tiny example, what makes us have any confidence in larger, more complex grammars? We should understand our tools. PEG pretends to be simple and understandable, but it's much less so than it might seem on the surface.
That's a good point. Unfortunately, it's also true not only of PEGs and recursive-descent parsing, but also of essentially every parsing formalism out there. So it doesn't seem to disqualify PEGs in particular.
(It's also true of programming languages generally: For which inputs does Collatz halt, and why?)
CFG semantics is nice and declarative when we specify which strings belong to the language, but a parser is a function from strings to parse results, and then the nice semantics stops working due to ambiguities. The PEG semantics on the other hand naturally expresses such a function, and the function you get with PEG semantics is almost always the function you want.
When we look at character level grammars, the CFG formalism doesn't work well either. They fundamentally rely on greedy lexical token matching.
Extensions such as indentation sensitive parsing and user defined operators quite naturally fit into PEG style semantics, and are more difficult to integrate into CFGs.
CFG based parser generators are way more complicated internally than PEG based parser generators, which are extremely simple.
No, I think you might be misunderstanding my point. For example, if you think the grammar I posted matches aaaaa, you'd be wrong.
Does that mean I'd spot the same gotcha deep in some grammar I was working on? No of course not, that would never happen. It's going to be some other mistake that makes me feel like an idiot after staring at the screen for several hours.
Parsers are designed around data, not conundrums. For structured languages, PEGs are a sharp and simple tool for slicing them up. But they're not great at solving the Liar's Paradox.
I'll concede that this appears counterintuitive, but I feel that cases like this most often just pop up because people have been "overexposed" to EBNF/CFGs before and write PEG grammars with wrong preconceptions (also often ending in "left recursion" confusion, but that at least gives early errors).
But I still think that it is much preferable to debug/rewrite a questionable PEG grammar than e.g. a cobbled-together mess of conditionals and regular expressions...
But now I'm really interested in what you're advocating for instead? CFG parser frameworks? Or learning how to write the parser by hand? Or learning about PEGs until your example is understood?
LR(1) gets a bad rap for impossible to understand conflicts while writing a grammar. I strongly believe this is due to most tools advertising LR(1) actually using LALR(1). LALR(1) is deservedly awful, and introduces mysterious conflicts. But modern parser generators can support minimal LR(1), which generates parse tables almost as small (or often exactly ad small) as LALR(1) without the mysterious conflicts.
Finally LR(1) gets a bad rap for screaming at you at all during parser writing, but I see this as a feature, like the type checker in a programming language, preventing you from writing ambiguous or expensive to parse constructs.
Is there a mechanism that works well for improving errors in PEGs (i.e. something like a non-returnable node), and how does one practically implement that?
Yes, it's called the "cut operator".
> how does one practically implement that?
Pick a parser generator that supports it natively. ;-) If you're talking about implementing the parser generator yourself then you probably already know more about it than I do.
EDIT: Even making it easier to annotate the parser specifications to improve error reporting would be an improvement for many parser generators. In the past I've experimented with parser generators that included a prolog-inspired "cut" like operator that stops further backtracking, and that'd take an error message to output if nothing further can be matched without backtracking. It'd prevent the parser from "escaping" out of a likely human error and end up reporting a failure to match productions much higher up. It worked fairly well, and mimics what human parser writers tends to do in recursive descent parsers - we'll often guess at the likely error based on context deep down and bail out.
It's literally impossible to write a PEG with an ambiguity. So I don't know what you mean?
Not sure how that's saying anything useful though? If you write the wrong grammar with any parsing system it's also not going to work.
S := A '+' A | A '*' A
A := ...
If you do that in most PEG systems I've tried, you're just going to get the wrong result with no indication of what might have gone wrong, unless you know where to look.