For example I work with a parser definition that's supposedly shared between C and Java, but it's a massive nightmare because it's 50% imperative actions.
Yes... but most practical languages do not have simple LL or LR grammars. Hence this blog post and discussion and these problems.
Java hasn't ever been able to be parsed with one token look ahead, the earlier versions had a section on how to modify the grammar to be LALR(1)[0] but it was dropped in later versions of the specification -- probably due to added features which made it unfeasible like generic classes.
It's actually quite a good resource since they explain the reasons why the parser needs to have more than one token to figure out what's going on.
[0] http://titanium.cs.berkeley.edu/doc/java-langspec-1.0/19.doc...
I said ‘most’ not ‘all’, and nobody here said the only reason to hand-write a parser was context sensitivity.
Last but not least, what you actually end up wanting to build is an ast, as at some point you want to do something with the input, for most parsers you then have to implement even more code to build up the ast.
It is much easier to hand write it. In the end its faster to write and usually faster to run.
Every few years I evaluate the new options for the languages I use (c#, pascal), every time so far I am disappointed with the tooling. Maybe one year.