A compiler is a system software that translates a program written in a high-level programming language into machine code, assembly code, or another target language that can be executed by a computer.
Compiler design consists of several phases. Each phase performs a specific task and passes its output to the next phase.
Phases of Compiler Design
The major phases of a compiler are:
Lexical Analysis
Syntax Analysis
Semantic Analysis
Intermediate Code Generation
Code Optimization
Code Generation
The Symbol Table and Error Handler are supporting components that are used throughout different phases.
1. Lexical Analysis
Lexical analysis is the first phase of a compiler. It is performed by a component called the Lexical Analyzer or Scanner.
The lexical analyzer reads the source program character by character and groups them into meaningful units called tokens.
Example
Consider:
int sum = a + b;
The tokens are:
int→ Keywordsum→ Identifier=→ Assignment Operatora→ Identifier+→ Arithmetic Operatorb→ Identifier;→ Separator
Main Functions
Converts characters into tokens
Removes unnecessary white spaces
Removes comments
Identifies keywords, identifiers, operators and constants
Updates the symbol table
Reports lexical errors
Example of Lexical Error
int @num;
The character @ may be invalid in an identifier depending on the programming language, resulting in a lexical error.
Important Exam Point
Lexical Analyzer → Generates Tokens
2. Syntax Analysis
Syntax analysis is the second phase of a compiler. It is also called parsing.
The component responsible for this phase is called the Parser.
The parser checks whether the sequence of tokens follows the grammar or syntax rules of the programming language.
Example
Consider:
a + b * c
The syntax analyzer constructs a syntax structure according to operator precedence.
The expression is interpreted as:
a + (b * c)
rather than:
(a + b) * c
Main Functions
Checks grammatical structure
Builds a parse tree or syntax tree
Detects syntax errors
Passes the syntactic structure to the next phase
Example of Syntax Error
int = 10;
This statement violates the syntax rules because int is a keyword and cannot normally be used as a variable in this context.
Important Exam Point
Syntax Analyzer → Checks Grammar and Produces Parse Tree
3. Semantic Analysis
Semantic analysis is the third phase of a compiler.
It checks whether the program is logically meaningful according to the rules of the programming language.
The syntax of a statement may be correct, but its meaning may be invalid.
Example
int a;
a = "Hello";
The statements may have a syntactically valid structure, but assigning a string value to an integer variable creates a type mismatch.
Main Functions
Type checking
Checking variable declarations
Checking scope rules
Checking function arguments
Checking compatibility of operands
Detecting semantic errors
Example
int a;
a = 10 + "ABC";
The operands have incompatible types, so semantic analysis can report an error.
Important Exam Point
Semantic Analyzer → Checks Meaning and Type Compatibility
4. Intermediate Code Generation
After semantic analysis, the compiler generates an Intermediate Representation (IR).
The intermediate code is generally independent of the target machine.
One common representation is Three-Address Code (TAC).
Example
Consider:
a + b * c
The compiler may generate:
t1 = b * c
t2 = a + t1
Here, t1 and t2 are temporary variables.
Advantages of Intermediate Code
Makes the compiler more machine-independent
Simplifies code optimization
Makes compiler development easier
Allows the same front end to support multiple target machines
Important Exam Point
Intermediate Code → Machine-Independent Representation
5. Code Optimization
Code optimization improves the intermediate code without changing the program's intended result.
The objective is generally to improve:
Execution speed
Memory usage
Code size
Resource utilization
Example
Original code:
x = 10 * 2;
Optimized code:
x = 20;
Since the result of 10 * 2 is known at compile time, the compiler can calculate it beforehand.
This technique is called constant folding.
Common Optimization Techniques
1. Constant Folding
Calculates constant expressions during compilation.
Example:
x = 5 * 10;
becomes:
x = 50;
2. Constant Propagation
Replaces a variable with its known constant value.
Example:
a = 10;
b = a + 5;
may become:
b = 15;
3. Dead Code Elimination
Removes code that can never affect the result.
4. Common Subexpression Elimination
Avoids calculating the same expression repeatedly.
5. Loop Optimization
Improves frequently executed loops to reduce execution time.
Important Exam Point
Code Optimization → Improves Code Efficiency Without Changing Its Intended Result
6. Code Generation
Code generation is the final major phase of a compiler.
It converts the optimized intermediate code into target code, such as assembly code or machine code.
Example
Intermediate code:
t1 = b * c
t2 = a + t1
A compiler may generate target instructions similar to:
LOAD R1, b
MUL R1, c
ADD R1, a
STORE t2, R1
The exact instructions depend on the target processor or machine.
Main Functions
Instruction selection
Register allocation
Address calculation
Generation of target instructions
Important Exam Point
Code Generator → Produces Target/Machine Code
Symbol Table
The Symbol Table is an important data structure used by different compiler phases.
It stores information about identifiers used in the program.
Typical information includes:
Identifier name
Data type
Scope
Memory location
Storage information
Function parameters
Example
| Identifier | Type | Scope | Address |
|---|---|---|---|
a | int | Local | 1000 |
b | float | Local | 1004 |
sum | int | Local | 1008 |
The symbol table is accessed by several phases, particularly lexical analysis and semantic analysis.
Error Handling in Compiler
A compiler must identify and report errors during compilation.
1. Lexical Error
Occurs when an invalid character or token is encountered.
Example:
int @abc;
2. Syntax Error
Occurs when the program violates grammar rules.
Example:
a = ;
3. Semantic Error
Occurs when the statement is syntactically valid but semantically incorrect.
Example:
int a;
a = "Hello";
Complete Compiler Design Flow
The overall flow can be represented as:
Source Program
↓
Lexical Analysis
↓
Tokens
↓
Syntax Analysis
↓
Parse Tree / Syntax Tree
↓
Semantic Analysis
↓
Intermediate Representation
↓
Code Optimization
↓
Optimized Intermediate Code
↓
Code Generation
↓
Target / Machine Code
Compiler Phases at a Glance
| Phase | Main Component | Main Output |
|---|---|---|
| Lexical Analysis | Lexical Analyzer | Tokens |
| Syntax Analysis | Parser | Parse Tree / Syntax Tree |
| Semantic Analysis | Semantic Analyzer | Annotated/Checked Syntax Structure |
| Intermediate Code Generation | Intermediate Code Generator | Intermediate Code |
| Code Optimization | Optimizer | Optimized Intermediate Code |
| Code Generation | Code Generator | Target Code |
Front End and Back End of Compiler
Compiler phases are also commonly divided into two broad parts.
Front End
The front end mainly deals with analyzing the source program.
It generally includes:
Lexical Analysis
Syntax Analysis
Semantic Analysis
Intermediate Representation generation
The front end is largely machine-independent.
Back End
The back end mainly deals with optimization and target-code generation.
It generally includes:
Code Optimization
Code Generation
The back end is more closely related to the target machine or architecture.
Compiler Phases – Important Points for Exams
Lexical Analysis is the first phase of a compiler.
Lexical analysis converts source characters into tokens.
Syntax Analysis is also called Parsing.
The parser checks the grammar of the programming language.
Semantic analysis performs type checking and other meaning-related checks.
Intermediate code is generally machine-independent.
Three-Address Code (TAC) is a common intermediate representation.
Code optimization improves efficiency without changing the intended program behavior.
Code Generation is the final major phase of a compiler.
The symbol table stores information about identifiers.
Lexical errors are detected during Lexical Analysis.
Syntax errors are detected during Syntax Analysis.
Type mismatch is generally a Semantic Error.
The front end is primarily concerned with program analysis.
The back end is primarily concerned with optimization and target-code generation.
Quick Revision
Source Program → Lexical Analysis → Syntax Analysis → Semantic Analysis → Intermediate Code Generation → Code Optimization → Code Generation → Target Code
Easy Sequence to Remember
L → S → S → I → O → C
Lexical → Syntax → Semantic → Intermediate Code → Optimization → Code Generation
Frequently Asked Questions
What is the first phase of a compiler?
Lexical Analysis is the first phase.
What is the output of lexical analysis?
The output is a sequence of tokens.
Which phase checks grammar?
Syntax Analysis checks the grammar of the source program.
Which phase performs type checking?
Semantic Analysis performs type checking.
What is intermediate code?
Intermediate code is a machine-independent representation generated between source-code analysis and target-code generation.
What is Three-Address Code?
Three-Address Code is an intermediate representation in which instructions generally contain at most three addresses or operands.
Which phase improves the efficiency of code?
Code Optimization.
Which phase generates machine or target code?
Code Generation.
What is the purpose of a symbol table?
It stores information about identifiers, such as their names, types, scopes and locations.
Conclusion
Compiler design is a sequence of systematic phases that transforms a high-level source program into executable target code. Understanding the six major phases—Lexical Analysis, Syntax Analysis, Semantic Analysis, Intermediate Code Generation, Code Optimization, and Code Generation—is essential for Computer Science examinations and technical interviews.