English in the Compiler Pipeline
Compiler engineering has a rich and precise vocabulary that has accumulated over decades of research and implementation. For engineers working on compilers — whether writing passes in LLVM, contributing to GCC, or building a language front-end — communicating in this vocabulary with fluency and precision is essential for code reviews, design discussions, and documentation.
This guide walks through the compiler pipeline from front-end to back-end, covering the English terms used at each stage.
Front-End Vocabulary: Lexing and Parsing
The front-end of a compiler transforms source text into a structured representation.
| Term | Definition |
|---|---|
| Lexer (tokeniser) | The component that reads source characters and produces a stream of tokens |
| Token | A categorised unit of source text, such as an identifier, literal, or keyword |
| Lexeme | The actual character sequence that matched a token pattern |
| Parser | The component that reads a token stream and constructs a parse tree or AST |
| Grammar | A formal description of the syntactic rules of a language |
| Production rule | A single rule in a grammar defining how a non-terminal can be expanded |
| Lookahead | The number of tokens the parser examines ahead of the current position to make a decision |
| Ambiguity | A property of a grammar where a single input can be parsed in multiple ways |
| Abstract Syntax Tree (AST) | A tree representation of the syntactic structure of source code, with implementation detail removed |
When reviewing a parser implementation, a common observation is: “This production rule is ambiguous — we need to document the precedence convention or restructure the grammar.”
Middle-End Vocabulary: IR and Optimisation
The middle-end operates on an Intermediate Representation (IR), which is the compiler’s internal language for analysis and optimisation.
| Term | Definition |
|---|---|
| Intermediate Representation (IR) | A language-independent, architecture-independent representation of program semantics |
| Static Single Assignment (SSA) form | An IR property where every variable is assigned exactly once and use-def chains are explicit |
| Phi node (φ-node) | An SSA construct that selects a value based on which predecessor basic block was executed |
| Basic block | A straight-line sequence of instructions with a single entry and single exit |
| Control flow graph (CFG) | A graph where nodes are basic blocks and edges represent possible transfers of control |
| Data flow analysis | A technique for computing properties of values at each program point |
| Dominator | A node D dominates node N if every path to N passes through D |
| Alias analysis | Analysis that determines whether two pointers could refer to the same memory location |
| Inlining | Replacing a function call with a copy of the called function’s body |
| Loop invariant code motion (LICM) | Moving computations out of a loop when their result does not change across iterations |
LLVM-Specific Vocabulary
LLVM has its own set of terms and conventions used in discussions, documentation, and code review.
| Term | Definition |
|---|---|
| Pass | A transformation or analysis that operates on the IR; LLVM programs are optimised by a sequence of passes |
| Analysis pass | A pass that computes information about the IR without modifying it |
| Transform pass | A pass that modifies the IR to improve it in some way |
| Pass manager | The infrastructure that schedules and runs passes efficiently |
| Canonicalise | To transform an IR construct into a standard, normalised form that is easier to reason about |
| Emit | To produce output — either a new IR form or target machine code |
| Legalization | The process of transforming IR operations into forms the target machine supports |
| Instruction selection | The mapping of IR instructions to target machine instructions |
| Register allocation | The assignment of IR virtual registers to physical machine registers |
| Spill | To move a value from a register to memory because there are insufficient registers available |
In LLVM code reviews, “canonicalise” is a frequently used instruction: “Before optimising this pattern, canonicalise it to the form the middle-end expects.”
Back-End Vocabulary: Register Allocation and Code Generation
| Term | Definition |
|---|---|
| Virtual register | An unlimited, abstract register used in IR before register allocation |
| Calling convention | The protocol governing how arguments, return values, and registers are managed across function calls |
| Prologue / Epilogue | The function entry/exit code that sets up and tears down the stack frame |
| Peephole optimisation | A local optimisation that examines a small window of instructions and replaces them with more efficient equivalents |
| Instruction scheduling | Reordering instructions to improve performance, typically to avoid pipeline stalls |
| Relocation | A reference in object code that must be resolved to an address at link time |
| Object file | The output of the assembler, containing machine code and metadata for the linker |
Example Sentences
- “The current lexer does not handle Unicode identifiers correctly — we need to update the token classification rules before the next release.”
- “After SSA construction, all phi nodes in the entry block are trivial and can be eliminated — the mem2reg pass should handle this automatically.”
- “This pass canonicalises all GEP instructions to a normalised form, which makes subsequent alias analysis more precise.”
- “The register allocator is spilling aggressively in this hot loop; we should examine the register pressure and consider splitting the loop into two phases.”
- “The LLVM backend emits a function prologue that is unnecessarily large for leaf functions — we can apply the leaf function optimisation to eliminate the frame pointer setup.”
Communication Tips for Compiler Engineers
When discussing a compiler bug, distinguish between a miscompilation (the compiler generates incorrect code) and a compiler crash (the compiler fails to produce output). These have different debugging approaches and different levels of severity.
When writing pass documentation or code comments, prefer the active voice and imperative mood: “This pass transforms… The analysis computes… Call this pass after…” — not “This pass is used to transform…”
The verb “lower” has a specific meaning in compiler vocabulary: to replace a high-level IR construct with a more concrete one closer to the target machine. “We lower intrinsics to platform-specific builtins in the legalization phase.” Avoid using it in its everyday English sense when writing compiler documentation.
Navigating the Nuances: Practical Application & Common Phrases
Let’s be honest – “lexical analysis” doesn’t roll off the tongue. As a compiler engineer, you’re not just understanding these terms; you need to communicate them effectively, both in documentation and during discussions with colleagues. Often, the biggest hurdle isn’t the technical detail but the phrasing itself. It’s about conveying precision without sounding overly academic or jargon-laden.
A common phrase you’ll hear – particularly when reviewing another engineer’s work – is “the generated code needs more aggressive optimisation.” It’s not simply “bad code.” It’s a specific request tied to the outcome – performance. Similarly, saying “the IR could benefit from loop unrolling” isn’t criticizing the design; it’s suggesting an improvement that aligns with the intermediate representation’s purpose. Focusing on the impact of decisions, rather than just the process itself, is crucial for clear communication. Think about framing changes in terms of measurable results – “reducing memory footprint by X%” or “improving instruction-level parallelism.”
Another area where nuance matters is when discussing errors. Instead of saying “the lexer failed,” a more helpful and professional phrasing would be: “The lexer encountered an unexpected character sequence, leading to a parsing error.” This detail provides context without immediately sounding like a technical problem statement. Similarly, during code reviews, instead of simply stating “this needs fixing,” consider something like, “This section’s performance could be improved by refactoring the data structure.” It’s about offering a constructive suggestion with clear reasoning.
Finally, don’t shy away from using active voice – it makes your explanations clearer and more direct. Instead of “The code was generated…”, say “We generated the code…” This subtly shifts responsibility and emphasizes action.
Here’s an example demonstrating how to use clang-format to enforce a consistent style:
clang-format -i my_source.c
This command will automatically reformat the contents of my_source.c, ensuring that it adheres to the specified formatting rules – a practical application of understanding code generation and its associated tooling. It’s about taking control, not just passively accepting a result.
Keep practising
Turn this article into muscle memory
Five-minute exercises with instant feedback — built from the same kind of real IT language.
What to read next
Frequently asked questions
What will I learn from "Compiler Engineering Vocabulary: From Lexer to Code Generation"?
This is a Advanced-level Vocabulary article covering compilers, vocabulary, systems-programming and LLVM. A comprehensive English vocabulary guide for compiler engineers covering the full pipeline from lexing and parsing through IR, optimisation passes, and code generation.
Is this article free to read?
Yes. Every article on CoderSlingo, including this one, is free to read with no account, sign-up, or paywall.
How is reading this article different from doing an exercise?
Articles like this one explain concepts and vocabulary in context through prose, while exercises are interactive drills — fill-in-the-blank, matching, and multiple-choice — that test and reinforce specific terms. Reading builds understanding; exercises build recall.
Can I practice the vocabulary used in this article?
Yes — this article's topic lines up with our compilers exercises. Use the "Practice this vocabulary" link below to jump straight into a matching drill.
How long does "Compiler Engineering Vocabulary: From Lexer to Code Generation" take to read?
About 9 min. Most CoderSlingo articles, including this one, are written to be read in one sitting, without needing a dictionary open in another tab.
Do I need to create an account to read or save this article?
No account is required to read any article. If you complete exercises elsewhere on the site, your progress is saved locally in your browser — no login needed.
What if I don't understand a technical term used in this article?
Check the site Glossary for plain-English definitions of common IT terms, or browse the #compilers tag page for other Vocabulary articles that use the same vocabulary in different contexts.
Can I share or link to "Compiler Engineering Vocabulary: From Lexer to Code Generation"?
Yes — use the Twitter/X or LinkedIn share buttons at the end of the article, or copy the page URL directly. Attribution back to CoderSlingo is appreciated but the content is free to reference.
When was this Vocabulary article published?
This article was published in 2026. New Vocabulary articles are added regularly — visit the #compilers tag page to see the full, continuously updated list.
Where can I find more articles like this one?
See "English for Nim Language Developers", "English for Ada Developers", "English for D Language Developers" in the Related Articles section below, or browse all Vocabulary articles from the main Blog index.