&gt; that don&#x27;t use an AST at all but generate machine code directly during parsing<p>It is not any different. A &quot;sufficiently smart&quot; compiler must be capable of fusing the lowering passes straight into a parser. Parsing is not that different from the other kinds of passes.<p>&gt; that becomes harder the more stages you introduce<p>My usual trick is to have a &quot;unit test&quot; simple AST which, when building in a certain mode, is fed into the compilation pipeline and displayed with all the annotations. It helps a lot to understand what exactly each pass is doing. In the next version of my DSL for building compilers (currently a work in progress) it will even be a part of an IDE.<p>&gt; the more language dialects you need to manage to mentally separate when working on the stages<p>Ideally, one pass = one language. Nanopass handles it nicely.<p>I am using this approach for pretty much all kinds of languages, and never had any issues with too many IRs. In my book, the more distinct IRs, the better.