Ivan Godard <ivan@ootbcomp.com> wrote:
+---------------
| Programming languages, even assembler, have always tended to be LL(1)
| to a first approximation. As a result, production compilers intended
| for use by those unfamiliar with the internals have tended to be LL(1)
| too, and usually recursive descent. The advantage of RD is that the
| semantics can be done on the fly, and the semantics can be used to
| guide the parse when the actual language is not a CFG (and most of
| them are not, to at least some degree) without exponential explosion
| of state.
+---------------

Plus, there's a useful trick I learned from the BLISS-10 compiler,
which is that you can very easily embed a simple operator precedence
parser into a recursive descent parser, simply by giving keywords and
flow-control operators [IF, CASE, etc.] very high operator precedences
and "stoppers" [commas, semicolons, right brackets, FI, ESAC, etc.]
very low precedences. This enables a recursive descent parser to
handle complex arithmetic expressions without ending up with long
chains of (otherwise useless) reductions in the parse graph.

I've found this combination to be very convenient, and have used it a
number of times over the years when a small DSL was needed, e.g., for
a user interface or as part of a software build system.

-Rob

p.s. More detail on this construct, including some sample code
[in Scheme], can be found in a couple of previous articles here
from 2010, subject "Re: Is that difficult to write a Shift-Reduce
parser", see: