Writing a Compiler is Surprisingly Easy (part 1)

Claiming that “writing a compiler is surprisingly easy,” a blog post showcasing a tiny arithmetic-to-assembly compiler sparks debate over what deserves to be called a compiler and how far such simplicity really scales. Commenters generally welcome the demystification of language implementation—arguing that toy compilers are approachable and educational—but contrast this with the complexity of production-grade tools that need robust parsing, type systems, optimization, error reporting, and platform compatibility. Along the way, they trade experiences, reference classic and modern learning resources, and compare approaches such as recursive descent parsing, parser generators, nanopass designs, and emitting C or LLVM IR instead of raw assembly.

Scope: What Counts as a “Compiler”?

  • Several argue the example is “just” a code generator or a compiler backend (AST → assembly, no lexer/parser/symbols/optimizations).
  • Others counter that any pipeline from source to target code is a compiler, and that raising the entry bar with strict definitions is unhelpful.
  • Consensus: it’s a toy / didactic compiler, but still legitimately a compiler.

Toy vs Production Compilers

  • Many agree a simple compiler for a tiny language and single target is “surprisingly easy” and very educational.
  • Multiple commenters share experiences writing small compilers (for C subsets, Scheme-like, Forth-like, fantasy consoles, contest tasks).
  • The jump to production compilers is described as huge: standards compliance, optimizations, register allocation, diagnostics, error recovery, build systems, libraries, tooling.

Parsing, Frontends, and Error Handling

  • Debate: start from grammar (parsers/lexers) vs start from backend and glue a frontend later.
  • Some prefer recursive descent and hand-written parsers as simpler and more controllable than tools like Lex/Yacc/Bison/ANTLR.
  • Others emphasize parser generators help expose grammar ambiguities and reduce bugs.
  • Several note that handling only correct input is easy; robust error messages, type checking, and recovery are the hard parts.

Code Generation, Targets, and Low-Level Details

  • Discussion of emitting assembly text vs opcodes vs targeting LLVM IR or C.
  • Some argue C is a good “portable assembler”; others push back, citing calling conventions, stacks, fibers, and features that don’t map cleanly to C.
  • Register allocation is generally seen as a harder step and out-of-scope for very simple tutorials.
  • There’s a side thread on using push/pop and stack discipline, and on using existing assembler/JIT libraries vs rolling your own.

Learning, Demystification, and Resources

  • Strong support for demystifying compilers to reduce the “wizard” aura and encourage learners.
  • Multiple classic and modern resources are mentioned (older Pascal/Scheme tutorials, “Crafting Interpreters”, nanopass-style books, blog series on compiling to assembly).
  • Concern that many tutorial series never finish; some suggest fully building the compiler first, then writing the series.