Phases of a Compiler for GATE: One Statement Traced Through Every Phase

Follow position = initial + rate * 60 through all six compiler phases. Each step shows the exact artifact, error class and hand-off that GATE can test.

KnowledgeGate Team

Exam prep & CS education

Updated 29 Jul 20266 min read

GATE often asks which compiler phase performs a task or which artifact a phase produces. Reciting six names in order will not settle those questions. The reliable method is to watch one statement change form from source text to target instructions and notice exactly what each phase hands over.

The two halves of a compiler

A compiler is usually explained as an analysis half and a synthesis half.

The analysis phase, or front end, breaks the source program into meaningful parts and checks them. Its three main stages are lexical analysis, syntax analysis and semantic analysis. By the end of analysis, the compiler has an annotated internal representation that says both what the program means and whether its use of names and types is valid.

The synthesis phase, or back end, turns that checked representation into a target program. Its stages are intermediate code generation, code optimization and target code generation. The target may be assembly or machine code for a particular architecture.

Two services run across this pipeline:

  • The symbol table stores information about identifiers, such as their names, types and storage details. Lexical analysis starts entries, and later phases add or use information.

  • The error handler receives different error classes from different phases. There is not one final error check after all compilation work is complete.

This front-end and back-end split is useful, but GATE usually tests the finer phase-to-artifact mapping.

The running assignment statement

One assignment statement is enough to exercise all six phases:

position = initial + rate * 60

Assume position, initial and rate are floating-point variables. The literal 60 is an integer. That difference matters because the semantic phase must reconcile the types before floating-point multiplication can be generated.

For compact internal names, let the symbol table assign position -> 1, initial -> 2 and rate -> 3. Every later form preserves the multiplication before addition that operator precedence requires.

Analysis phases traced step by step

Lexical analysis reads characters and groups them into tokens. It also removes layout details such as spaces when they carry no meaning. For this statement, the token stream is:

<id,1> <=> <id,2> <+> <id,3> <*> <60>

The three identifier tokens point to symbol-table entries rather than repeating full names. An illegal character or an invalid token pattern is a lexical error. The deeper token and lexeme distinction is covered in Lexical Analysis in Compiler Design: Tokens, Patterns and Lexemes Explained.

Syntax analysis takes the tokens and checks whether their order follows the grammar. Its tree has assignment = at the root. The left child is id1. The right child is +, with id2 on the left and a multiplication node on the right. That multiplication has children id3 and 60.

In compact form, the tree is =(id1, +(id2, *(id3, 60))). A misplaced operator, an unbalanced parenthesis or another grammar violation belongs here. If you need to connect this tree to parser mechanics, read Parsing in Compiler Design: Top-Down and Bottom-Up Explained.

Semantic analysis checks meaning that grammar alone cannot establish. The compiler confirms that the identifiers are declared and that the operand types are compatible. Here rate is a float but 60 is an integer, so the phase inserts a coercion:

=(id1, +(id2, *(id3, inttofloat(60))))

The result is an annotated syntax tree. An undeclared identifier or an invalid type combination is a semantic error, not a syntax error.

Synthesis phases traced step by step

Intermediate code generation converts the annotated tree into a machine-neutral form. One possible three-address sequence has exactly four instructions:

t1 = inttofloat(60)
t2 = id3 * t1
t3 = id2 + t2
id1 = t3

There is one operation on the right of each instruction. The order also makes the data dependency visible: t2 needs t1, and t3 needs t2.

Code optimization improves the intermediate code without changing its result. A machine-independent optimizer can write the known converted constant as 60.0, eliminate the conversion instruction and store the addition directly into id1:

t1 = id3 * 60.0
id1 = id2 + t1

The count has fallen from four instructions to two. This is still intermediate code, not target assembly.

Code generation selects machine instructions and registers. For an illustrative floating-point target, the two optimized operations could become five instructions:

MOVF  R1, id3
MULF  R1, #60.0
MOVF  R2, id2
ADDF  R2, R1
MOVF  id1, R2

Read the two-operand form as destination first. MOVF R1, id3 loads rate into R1, MULF R1, #60.0 multiplies R1 in place, and the final MOVF id1, R2 stores the sum into position. This is one illustrative target sequence, not a universal instruction set: register choices and instruction names are what make this phase machine-dependent.

Vertical flowchart tracing position = initial + rate * 60 down six numbered compiler phases: lexical analysis emitting the token stream, syntax analysis showing = over id1 and +(id2, *(id3, 60)), semantic analysis wrapping the 60 in inttofloat, intermediate code generation producing four three-address instructions, optimization cutting them to two, and code generation emitting five floating-point machine instructions, with a symbol table alongside mapping position, initial and rate to 1, 2 and 3.

Artifact-per-phase table for match-the-phase questions

Input

Phase

Output

Source character stream

Lexical analysis

Tokens and initial symbol-table entries

Token stream

Syntax analysis

Parse tree or abstract syntax tree

Syntax tree

Semantic analysis

Annotated tree with types and coercions

Annotated tree

Intermediate code generation

Three-address code

Intermediate code

Code optimization

Improved intermediate code

Improved intermediate code

Code generation

Target assembly or machine code

Read the table in both directions. The examiner may name an output and ask for its producer, or name a phase and ask what it emits.

Traps GATE plants in compiler-phase questions

The most common error is assigning a fault to the wrong phase. An illegal character is lexical. A missing operand or unbalanced parenthesis is syntactic. An undeclared variable or incompatible type is semantic. An array index going out of bounds while the program runs is a runtime error, unless a specific compile-time check can prove it.

Do not treat the symbol table as the private output of one phase. It is created and maintained across phases. Also keep machine-independent optimization separate from machine-dependent target generation. Optimization may transform three-address code without knowing the final register set.

Finally, do not confuse a parse tree with a token stream. Tokens have already discarded irrelevant character-level detail; a tree adds grammatical structure and precedence.

How GATE tests the six phases

Typical stems ask where inttofloat is inserted, which phase catches an undeclared identifier, what syntax analysis produces or how many stages belong to analysis.

Take a stem in the common form. Given the declarations int a; float b; and the assignment b = a * 2.5;, which phase inserts the type conversion? Lexical analysis returns <id,1> <=> <id,2> <*> <2.5> and never looks at a declaration. Syntax analysis builds =(id1, *(id2, 2.5)) and accepts it, because no grammar rule for an assignment mentions int against float. Semantic analysis is the first phase that reads the declared types out of the symbol table, finds an integer operand inside a floating-point multiplication, and rewrites it as inttofloat(a). The answer is semantic analysis, reached by the same route the running example took.

For wording tied to a particular year or paper pattern, verify the paper and answer key on the official GATE portal of the organising IIT. The compiler concepts themselves remain stable.

Short version and next step

Lexical analysis produces tokens, syntax analysis produces a tree, and semantic analysis annotates that tree. Intermediate code generation then produces TAC, optimization improves it, and code generation emits target instructions. The symbol table and error handling support the complete route.

Trace one arithmetic statement and one conditional statement on paper. Then use GATE Guidance by Sanchit Sir for the full Compiler Design sequence, or move through the wider GATE preparation category when you are building a subject plan.