4 lessons
Why compilers bother with intermediate code at all
The N-times-M translation problem every multi-target, multi-source compiler faces, and how one shared middle language solves it.
Three-address code: the compiler's simplest possible sentence
The exact rules of three-address code, why every instruction is limited to one operation, and how it represents control flow with labels and jumps.
Quadruples, triples, indirect triples, and DAGs
The classic ways to actually store three-address code in memory, worked by hand for a real expression, plus DAG construction for spotting shared subexpressions.
A complete TAC generator for a full program, in C++
Wiring up a full three-address code generator across expressions, declarations, assignments, and control flow, tracing a complete real program end to end.