This is a collection of lecture notes on compiler construction, based on the graduate and undergraduate compiler classes I teach at Purdue.

There are many excellent books about compilers but I have never been satisfied with any single one as textbook for my classes. Existing books that are deep are great as a reference for someone who already knows how to build compilers, but they are less ideal for learning. Others simplify too much or in the wrong way, treating uninteresting toy languages, or only idealized target platforms instead of real hardware.

The worst books do both: they skip the most interesting parts “in the interest of simplicity” and still make everything look complicated by introducing lots of accidential complexity. The present notes and the courses they are based on were designed to do the exact opposite: radically simplify the implementation to cover more ground and tackle “difficult” aspects head-on.

Interpreters and compilers are among the most powerful tools computer science has to offer but at their core, they are doing something relatively simple. The goal of these notes is to show that given the right techniques, this simplicity can be carried through into realistic implementations.

The overarching principles are the following:

  • Explain how sophisticated language features are expressed using simpler ones.
  • Eliminate magic and black-box components, implement and understand everything end-to-end.
  • Radically simplify the implementation to cover more ground and tackle difficult aspects head-on.