CD Notes
Overview of semantic analysis, type checking, scope validation, and semantic rules
Introduction: Beyond Syntax
Imagine a sentence in English that is grammatically perfect but meaningless: "The colorless green ideas sleep furiously." The grammar is correct — it has a subject, verb, and adverb — but the meaning makes no sense. Compilers face the same challenge. The parser ensures that code follows grammar rules (syntax), but that alone does not guarantee the code is meaningful. Semantic analysis is the phase that checks whether syntactically correct code actually makes sense.
Consider this C code: int x = "hello";. The syntax is perfect — it follows the pattern type identifier = expression;. But semantically, it is nonsense: you cannot store a string in an integer variable. The parser would accept it happily; only semantic analysis catches this error. This is why semantic analysis exists as a separate, essential phase.
What Semantic Analysis Checks
Semantic analysis performs several categories of validation, all of which go beyond what grammar rules can express:
Type Checking
The most prominent task — verifying that operations are applied to compatible types:
The semantic analyzer walks the parse tree bottom-up, computing the type of each expression from the types of its subexpressions. When an operator is applied, it checks whether the operand types are compatible with that operator.
Scope Validation
Ensuring that every identifier is declared before use and used within its valid scope:
void process() {
y = x + 5; // ERROR: 'x' not declared in this scope
int x = 10; // (Even though x is declared later, C requires declaration first)
{
int temp = x;
// temp is valid here
}
temp = 20; // ERROR: 'temp' not in scope (block ended)
}Declaration Checking
Verifying that identifiers are declared exactly once in their scope (no duplicates) and that they are used consistently with their declarations:
int count = 0;
float count = 1.0; // ERROR: 'count' already declared in this scope
void display(int n);
display(1, 2, 3); // ERROR: too many arguments (expected 1, got 3)
int max(int a, int b);
float result = max(3.14, 2.71); // OK but arguments truncated to intOther Semantic Checks
- Return type consistency: Every return statement must return a value compatible with the function's declared return type
- Break/continue validity: These statements must appear inside a loop
- Array index type: Array indices must be integers, not floats or strings
- Assignment target: The left side of an assignment must be an lvalue (a modifiable memory location)
The Symbol Table: Heart of Semantic Analysis
The symbol table is the central data structure that makes semantic analysis possible. It stores information about every declared identifier:
The symbol table supports nested scopes using a stack structure:
| Entering function | push new scope |
| Entering block | push new scope |
| int x; | insert into current (top) scope |
| x + 5 | lookup: search from top scope downward until found |
| Exiting block | pop scope (x disappears) |
| Exiting function | pop scope |
How Semantic Analysis Works: An Algorithm
The semantic analyzer performs a depth-first traversal of the AST. At each node, it performs checks appropriate to that node type:
Worked Example: Tracing Semantic Analysis
Consider analyzing this program:
int add(int a, int b) {
return a + b;
}
void main() {
float x = 3.14;
int result = add(x, "hello"); // Multiple errors here!
}The semantic analyzer processes this as follows:
| - Insert add(int, int) | int into global symbol table |
| - Insert parameter 'a' | int |
| - Insert parameter 'b' | int |
| - Analyze return statement | a + b |
| - a is int, b is int | int + int = int ✓ |
| - Process declaration | float x = 3.14 |
| - 3.14 is float, x is float | compatible ✓ |
| - Process declaration | int result = add(x, "hello") |
| - Lookup 'add': found, expects (int, int) | int |
| - Check argument 1 | x is float, parameter expects int |
| - Check argument 2 | "hello" is char*, parameter expects int |
| - Return type of add is int, result is int | compatible ✓ |
Semantic Errors vs Syntax Errors
Understanding the boundary between syntax and semantics is a common exam question:
| Code | Error Type | Phase Detected | Reason |
|---|---|---|---|
int x = ; | Syntax | Parser | Violates grammar rule |
int 5 = x; | Syntax | Parser | Number cannot be lvalue |
int x = "hi"; | Semantic | Semantic analyzer | Type mismatch |
y = x + 1; (x undeclared) | Semantic | Semantic analyzer | Undeclared variable |
int x; int x; | Semantic | Semantic analyzer | Duplicate declaration |
break; (outside loop) | Semantic | Semantic analyzer | Invalid context |
Attribute Grammars: Formalizing Semantics
Attribute grammars provide a rigorous mathematical framework for specifying semantic analysis. Each grammar symbol gets attributes, and semantic rules define how to compute them:
| Production: E | E₁ + E₂ |
| Semantic Rule | E.type = |
| Production: D | type id |
| Semantic Rule | id.entry = insert(symtab, id.name, type.value) |
This formalism separates the "what" (semantic rules) from the "how" (tree traversal algorithm), making it easier to reason about correctness and to automatically generate semantic analyzers from specifications.
Key Takeaways
Semantic analysis bridges the gap between syntactic correctness and meaningful computation. It validates that programs obey the rules that grammars cannot express — type compatibility, scope restrictions, declaration requirements, and usage constraints. The symbol table is its essential data structure, tracking what has been declared and what properties each identifier has. Without semantic analysis, a compiler would happily generate code for nonsensical programs, producing mysterious runtime failures instead of clear compile-time error messages.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Semantic Analysis Introduction.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Compiler Design topic.
Search Terms
compiler-design, compiler design, compiler, design, semantic, analysis, introduction, semantic analysis introduction
Related Compiler Design Topics