Compilers and interpreters
Follow source through tokens, syntax, binding, types, intermediate code, optimization, execution, and linking. Inspect a bounded working expression compiler.
Prerequisite: Familiarity with variables, conditionals, and functions. No compiler or assembly experience required. Thirteen lessons follow programs through tokens, syntax trees, name resolution, types, intermediate representations, execution, optimization, native-code concerns, runtimes, and linking. Nine interactive views and 26 illustrated exercises use a bounded working expression compiler plus separate scope, control-flow, and storage models.
Lessons
- 1
Follow a program through its representations
A compiler translates representations; an interpreter executes a representation according to its rules.
- 2
Turn characters into tokens
A lexer recognizes spelling boundaries and records positions without deciding the full syntax.
- 3
Build a syntax tree from a grammar
Precedence and associativity determine which operations become children of others.
- 4
Resolve names to declarations
A name’s spelling is not its identity. Scope determines which declaration a use refers to.
- 5
Check programs against type rules
Types constrain allowed operations; checking and inference do not execute the program.
- 6
Compare tree evaluation with a bytecode machine
The tree and the instruction stream can implement the same language while storing intermediate values differently.
- 7
Choose an intermediate representation for the question
Syntax trees, stack code, and three-address code expose different information.
- 8
Trace control flow through basic blocks
Branches determine which instructions execute and which definitions can reach later uses.
- 9
Optimize only when the semantics permit it
An optimization is a justified change in representation, not merely an algebraic-looking rewrite.
- 10
Map values to instructions and storage
Instruction selection and register allocation must satisfy the target machine, not just preserve an abstract expression tree.
- 11
Connect generated code to runtime services
Calls, closures, objects, and memory management need representations that outlive a single arithmetic instruction.
- 12
Connect compiled pieces and load a program
Object files, symbols, and relocations bridge separate compilation and executable images.
- 13
Investigate a compiler or runtime claim
Use a minimal reproducer, explicit semantics, intermediate evidence, and controlled measurements.