Both GCC and LLVM implement recursive decent parsers for their C compilers.
Parser generators are an abomination inflicted upon us by academia, solving a non problem, and poorly.
A hand-written recursive descent parser (with an embedded Pratt parser to handle expressions/operators) solves all the problems that parser generators struggle with. The big/tricky "issue" mentioned in the article - composing or embedding one parser in another - is a complete non-issue with recursive-descent - it's just a function call. Other basic features of parsing: informative/useful error messages, recovery (i.e. don't just blow up with the first error), seamless integration with the rest of the host language, remain issues with all parser generators but are simply not issues with recursive descent.
And that's before you consider non-functional advantages of recursive-descent: debuggability, no change/additions to the build system, fewer/zero dependencies, no requirement to learn a complex DSL, etc.
I think you cover that with "debuggability" remark.
Here is something else. Yacc/Bison parsing uses its own stack for the symbols. Whereas recursive descent uses the regular run-time stack.
Pop quiz: which stack is visible to your garbage collector, and which isn't?
In TXR Lisp, which uses a Bison/Byacc generated parser, GC is suspended while yyparse() executes. Otherwise it would prematurely collect anything that is only stored in the Yacc stack, and so there would have to be a GC hook to traverse that stack (which would depend on undocumented features of the generated code, and likely have to have some separate coding for Bison versus Byacc.)
Precedence climbing is a natural and efficient way to parse expressions in a recursive decent parser. It's used by Clang in LLVM.
https://eli.thegreenplace.net/2012/08/02/parsing-expressions...
Exactly the recipe I swear by as well!
This is the controversial part, Lisp aficionados to the contrary.
You can parse quite a lot more than Lisp with techniques from 1965.
Like using a hyperlink to code example.
[0]: 1963 operator precedence description: https://dl.acm.org/doi/10.1145/321172.321179
My brain can do it, why can't my computer?
Human language has a pretty clear distinction between syntax and sementics. This is how we recognize that "colorless green ideas sleep furiously" are perfectly well formed, if meaningless. In contrast, "I is happy" is meaningful and unambiguous, but grammatically incorrect.
In terms of syntax, English (like most, if not all) languages is literally ambigous.
Consider the sentence structure:
Subject Verb Object Prepositional-Phrase.
This can be either:
(Subject Verb (Object Prepositional Phrase))
Or
(Subject Verb Object ) Prepositional Phrase.
For instance, consider the sentence "I saw a man with binoculars".
In any sense of the word, this example is structually ambigous.
Exactly! So glad we're on the same page.
Language is created by and intended for big brains with huge amounts of knowledge about each other and about the world. Relying on external knowledge makes it extremely compact and flexible, but also means your parser needs a similar level of knowledge to function.
We're really not. I'm saying you've incorrectly defined the English language. By that definition, no piece of text is English.
My favorite funny phenomenon in this area is when a sentence has two unambiguously different parses that mean exactly the same thing.
Politicians lie.
Cast iron sinks.
Politicians lie in cast iron sinks.
It's not actually ambiguous, but I think it's a lovely illustration of the subtleties of the problem.
An actually ambiguous example: I saw a politician lying in a cast iron sink.
"I couldn't fit the trophy in my suitcase because it was too big."
"I couldn't fit the trophy in my suitcase because it was too small."
Grammar-based parsing for natural language isn't anywhere close to working, sadly, and may never be.
(… I have.)