beginnerPipeline
What happens between source code and machine code?
Whether the candidate carries a staged model of compilation or one opaque box — and, more discriminating, whether they know their model describes one implementation rather than all of them. Almost everyone can list phases; far fewer can say which phases their favourite language actually has.
What a strong answer covers
- Text is scanned into tokens, tokens are parsed into a tree, the tree is checked — names resolved, types assigned — and then lowered into an intermediate representation the optimizer is written against. Passes rewrite the IR, code generation picks target instructions and assigns registers, and a linker resolves the symbols that no single compilation unit could know about.
- The important sentence is the next one: that pipeline is a shape, not a law. CPython stops at bytecode and ships an interpreter. V8 parses, then interprets, then compiles the hot parts with a JIT and can throw that compilation away again. A Rust build runs a borrow checker that has no analogue in the C++ pipeline and lowers through two IRs of its own before it reaches LLVM. TypeScript type-checks and then erases, emitting no checks at all.
- What is common to all of them is not the list of phases but the reason there are phases: each representation exists because the previous one could not answer the next question. Characters cannot say which tokens belong together; tokens cannot say what applies to what; a tree cannot say in what order things happen; and IR cannot say which machine register holds a value.
✓ Green flags
- Names a stage boundary and what is *lost* crossing it — comments and whitespace at lexing, parentheses at AST construction, source line identity through optimization.
- Distinguishes frontend, middle-end and backend by what they depend on: language, nothing, target.
- Volunteers that linking is a separate program with its own failure modes, rather than folding it into "the compiler".
- Mentions that the phases can be interleaved, streamed or repeated — a JIT compiles the same function several times at different tiers.
✗ Red flags
- "The compiler translates the code line by line into assembly." Line-at-a-time translation is what an assembler does; a compiler reorders, merges and deletes across lines, which is precisely why debugging optimized code is hard.
- "Parsing produces machine code." This collapses the entire middle-end and backend, and the candidate then has nowhere to put optimization or register allocation when asked.
- "Optimization happens at the end, on the assembly." Almost all of it happens on IR, before a single target instruction is chosen, because IR is where the analyses are cheap.
- "It goes source, assembly, binary" recited as a fixed law, with no acknowledgment that a language they use every day does not do that.
Follow-up
Pick a language you use daily. Which of those stages does its mainstream implementation actually run, and at what time — build, install, load or run?
Implementation challenge
What to ask them to write or trace on a whiteboard.
On the whiteboard, take x = a + b and write down what it is at each of five stages: characters, tokens, AST, three-address IR, and instructions with physical registers. Then say what each stage made answerable that the one before could not.