Phases of Compilation: Inputs/Outputs at Each Stage (with a Full Example)

Phases of Compilation: Inputs/Outputs at Each Stage (with a Full Example)

Verified Sources
Nov 3, 2026

A compiler translates a program from a source language into an executable form by running multiple phases. The classical compilation pipeline typically includes lexical analysis, syntax analysis, semantic analysis, intermediate code generation, code optimization, and code generation, with optional front-end preprocessing and back-end assembling/linking in toolchains. Each phase takes the output of the previous phase as its input and produces a new, more structured representation of the program. 3

Key terminology used below:

  • Lexical analysis
  • Syntax analysis
  • Semantic analysis
  • Intermediate representation (IR)
  • Code generation

To make the input/output explicit, we will trace one simple statement through all major phases.

Footnotes

  1. Compilation Phases Explained - Analysis and Synthesis - Overview of lexical, syntax, semantic, IR generation, optimization, and code generation; includes an example trace. ↩

  2. 6 Phases Of Compiler | A Detailed Explanation (+Flowcharts) - Describes six compiler phases and their transformation examples. ↩

  3. Compilation, Assembling, Linking and Program Execution (Lecture notes) - Notes describing preprocessing/compilation/assembling/linking stages in the C toolchain. ↩

Six Phases of Compilers (Quick Overview)

Example source program statement

We will track this assignment statement:

position = initial + rate * 60;\texttt{position = initial + rate * 60;}

In a real compilation toolchain, the front end might include a preprocessing step (e.g., #include, macros). Since the question is specifically about the phases of compilation, the core compiler phases start with lexical analysis of the (possibly preprocessed) source. GCC’s documented compilation flow is commonly described as preprocessing → compilation → assembly → linking, where -S, -c, and -E let you stop at different stages.

Footnotes

  1. using-gcc-for-compilation | openEuler documentation - GCC compilation process: preprocessing → compilation → assembly → linking, with -E, -S, -c options. ↩

Phase-by-phase overview (conceptual)

This sequence aligns with standard descriptions of compilation phases and the common pipeline that eventually produces an executable. 3

Footnotes

  1. Compilation Phases Explained - Analysis and Synthesis - Overview of lexical, syntax, semantic, IR generation, optimization, and code generation; includes an example trace. ↩

  2. 6 Phases Of Compiler | A Detailed Explanation (+Flowcharts) - Describes six compiler phases and their transformation examples. ↩

  3. using-gcc-for-compilation | openEuler documentation - GCC compilation process: preprocessing → compilation → assembly → linking, with -E, -S, -c options. ↩

Tracing the example through each compilation phase

  1. 1
    Step 1

    Input is the character stream of the source. Output is a stream of tokens such as identifiers, operators, and literals (e.g., position, =, initial, +, rate, *, 60, ;).

  2. 2
    Step 2

    The parser consumes tokens and checks grammar rules, producing a parse tree/AST reflecting operator precedence (e.g., rate * 60 binds tighter than initial + ...).

  3. 3
    Step 3

    The compiler validates meaning using the symbol table: identifiers must be declared, and type rules must allow the operations (e.g., 60 may be converted to match rate’s type).

  4. 4
    Step 4

    The compiler lowers the checked structure (AST + type info) into a machine-independent IR using temporaries (e.g., t1 = rate * 60.0, then t2 = initial + t1).

  5. 5
    Step 5

    The optimizer transforms the IR without changing observable behavior (e.g., removing redundant temporaries or folding constants).

  6. 6
    Step 6

    The code generator converts optimized IR into target assembly/machine instructions, following calling/ABI and instruction selection conventions.

  7. 7
    Step 7

    The assembler turns assembly into an object file, and the linker combines object files and resolves external references into the final executable (often described as separate stages in GCC-like flows).

Detailed input/output per phase (for the statement)

1) Lexical analysis

Input: source characters, including whitespace/comments removed as needed.
Output: a token stream.

Example token stream for:

position = initial + rate * 60;

Source fragmentToken output (typical)
positionIDENT(id=position)
=ASSIGN
initialIDENT(id=initial)
+PLUS
rateIDENT(id=rate)
*MUL
60INTLIT(value=60)
;SEMICOLON

Lexical analysis is described as converting the source program into meaningful tokens before parsing. 2


2) Syntax analysis (Parsing)

Input: the token stream from lexical analysis.
Output: a parse tree/AST representing grammatical structure.

A precedence-respecting AST for:

position = initial + (rate * 60);

can be sketched as:

Syntax analysis ensures the program structure matches the grammar (e.g., correct placement of operators and precedence). 2


3) Semantic analysis

Input: AST plus symbol table information (declarations/types).
Output: type-checked/annotated representation and validated meaning.

Typical semantic checks here:

  • Symbol table
  • position, initial, and rate must be declared in scope.
  • The multiplication and addition must be valid for their operand types.
  • If types differ (e.g., rate is float/double), 60 may be converted (implicit cast) to a floating literal.

So semantic output might annotate:

  • rate * 60 as double (or float) multiplication after converting 60 to 60.0.

Semantic analysis is commonly described as verifying correct meaning and types. 2


4) Intermediate code generation

Input: semantic-checked AST (with types).
Output: an intermediate representation (IR), often using temporaries.

A common 3-address-code style IR:

Temp/StatementIR meaning
t1 = rate * 60.0compute product
t2 = initial + t1add initial
position = t2store result

Producing machine-independent intermediate code is a standard purpose of this phase. 2


5) Code optimization

Input: IR.
Output: optimized IR (same semantics, improved performance).

For this statement, plausible optimizations include:

  • eliminating unnecessary temporaries if the target allows it
  • constant folding or copy propagation (depending on earlier IR steps)

Example optimized IR (one plausible form):

IR after optimization
position = initial + (rate * 60.0)

Optimization is typically described as improving the IR while preserving behavior. 2


6) Code generation (target code)

Input: optimized IR.
Output: target assembly instructions.

The exact assembly depends on the architecture (x86-64, ARM, RISC-V, etc.). Conceptually, it does:

  • load rate, multiply by constant 60.0
  • load initial, add product
  • store result into position

An example shape (not architecture-specific) looks like:

  • compute multiply into a register/temporary
  • compute add
  • store to memory

Code generation is described as translating optimized IR into final machine code/assembly. 2

Footnotes

  1. Compilation Phases Explained - Analysis and Synthesis - Overview of lexical, syntax, semantic, IR generation, optimization, and code generation; includes an example trace. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  2. 6 Phases Of Compiler | A Detailed Explanation (+Flowcharts) - Describes six compiler phases and their transformation examples. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

Inputs → Outputs at Each Compilation Phase (Example Statement)

A compact mapping of representations across the pipeline.

Common clarifications (and what changes across compilers/toolchains)

Pro Tip: Inspect intermediate artifacts with GCC

Use -E to stop after preprocessing, -S to stop after compilation proper (emit assembly), and -c to stop after assembling (emit object files). This helps you see “input/output” boundaries in practice, not just conceptually.

Footnotes

  1. using-gcc-for-compilation | openEuler documentation - GCC compilation process: preprocessing → compilation → assembly → linking, with -E, -S, -c options. ↩

Warning: Output formats are architecture- and compiler-dependent

Your IR form, AST shape, and the final assembly syntax will vary by compiler (e.g., GCC vs Clang), language standard, and target architecture. However, the phase responsibilities and the idea that each phase consumes the previous phase’s output remain the same. 2

Footnotes

  1. Compilation Phases Explained - Analysis and Synthesis - Overview of lexical, syntax, semantic, IR generation, optimization, and code generation; includes an example trace. ↩

  2. using-gcc-for-compilation | openEuler documentation - GCC compilation process: preprocessing → compilation → assembly → linking, with -E, -S, -c options. ↩

Knowledge Check

Question 1 of 4
Q1Single choice

Which phase converts characters/taken lexemes into a token stream for the parser?