The Compiler Pipeline
Every compiler — GCC, V8, rustc, even the TypeScript checker — is the same assembly line: characters to tokens to tree to checked tree to optimized form to output code. Learn the stations once, recognize them everywhere.
The front/back split is the field's great economy: LLVM is a shared back end, so Rust, Swift, Clang, and Julia each wrote only a front end and got world-class optimization for every CPU free. Same trick in reverse: one front end can target many back ends — that's how the same C code compiles for x86, ARM, and WebAssembly.
This pipeline isn't just for 'real' compilers. A linter is a front end that reports patterns instead of generating code. A formatter parses and prints the tree back prettily. TypeScript's compiler type-checks and then emits JavaScript — a compiler whose target language is another high-level language (a 'transpiler'). Syntax highlighting in your editor is a lexer running on every keystroke.
Interpreters share the front half: Python lexes, parses, and compiles your file to bytecode, then executes the bytecode in a loop instead of translating it to machine code. JIT engines like V8 do both — interpret first, compile hot paths natively while running. 'Compiled vs interpreted' is a spectrum, not a binary.