I write mine all by hand. It's the easiest part of a compiler to write, by far. It's also the least troublesome.
One advantage of doing them by hand is better, more targeted error messages are easier to fold in.
I write mine all by hand. It's the easiest part of a compiler to write, by far. It's also the least troublesome.
One advantage of doing them by hand is better, more targeted error messages are easier to fold in.
Recursive descent is surprisingly ergonomic and clean if one gets the heuristics right. Personally I find it way easier than writing BNF and its derivatives as you quickly get into tricky edge cases, slow performance and opaque errors.
Same with parser combinators. Not until a bunch of trial and error do you build up the intuitions you need to use them in production, I think.
Despite two decades of using those, I've found it much simpler to write my own scanning or RD parser.
Much of the parser code, if you compare the code with the BNF grammar, is a 1:1 correspondence. Super easy to do.
It's also the most annoying if you're writing a new language. You want to iterate on its ideas, but can't do so until you have a parser done.
I've been designing a few language concepts over the past year, and it feels 80% of this time has been writing and debugging parsers; by the time I get to the meat of language design - the shape of its AST, the semantics of it - any small syntactic change means going back to update the lexer and parser stage. Doesn't help that I can't settle on a syntax.
BTW I first started with PEG, which are nice in theory, but I feel the separation of lexing and parsing stage to very helpful to reduce boilerplate (handling whitespace in PEG is obnoxious). Later, I hand-wrote my parsers (in C), but it's gotten so repetitive I've dedicated a weekend to just learning lex/yacc (actually flex/bison). Even if parsers are easy to write, it's good to have higher level tools to reduce the tedium of it.
> You want to iterate on its ideas, but can't do so until you have a parser done.
Embed your language into host language. It is simple to do even in C++.Iterate on ideas till your heart content, then add syntax.
1. having to learn lex and yacc
2. running into limitations with lex and yacc
3. having a foreign program (i.e. lex and yacc) integrated into your build process
4. requiring a particular version of lex and yacc that may be awkward on multiple platforms
5. optimizing the code. (Once you start doing that, you cannot use lex/yacc to generate a new version.)
And so on.
At one point, we decided to write a D program that built the D compiler, instead of using make. Well, that turned out to be a greater time sink than just using make.
Yacc/lex tend to produce generic error messages and do very poorly with error recovery.
I suspect you might spend more time trying to specify what you want to the AI than just writing it.