5 lessons
Syntax-directed definitions, attaching meaning to grammar rules
How compilers attach "meaning-computing" actions directly onto grammar rules, and the two flavors of attribute — synthesized and inherited.
Abstract syntax trees: throwing away noise, keeping meaning
Why compilers convert the parser's raw output into a leaner AST, and how to design AST node types in C++ that carry only what later phases need.
Symbol tables: the compiler's phone book for every name
How a compiler remembers what every variable and function name refers to, and why scoping means the same name can mean different things in different places.
Type checking, teaching the compiler what "makes sense"
How a compiler decides whether "1 + true" is nonsense, using type rules walked over the AST with the symbol table from the previous lesson.
Scope and name resolution, the rules behind "which x is this?"
Static vs dynamic scoping, shadowing, and why almost every real language chose static scoping — with a worked C++ example showing exactly how resolution happens at compile time.