CD Notes
Comprehensive treatment of semantic errors: error classification, detection strategies, error recovery, reporting mechanisms, parser integration, practical error handling in modern compilers.
Error Classification
Categories of Semantic Errors
| - Type mismatch | int x = "hello" |
| - Undefined operator for type | string & integer |
| - Undefined variable | use y before declaration |
| - Redefinition | declare x twice in same scope |
| - Ambiguous names | overload resolution fails |
| - Access violation | use private member |
| - Scope mismatch | goto into block scope (in C) |
| - Unreachable code | after return statement |
| - Missing return | function doesn't return value |
| - Incomplete type | use struct before definition |
| - Invalid storage class | thread_local on global |
| - Conflicting attributes | const and volatile |
Error Detection Strategies
Type Checking
def check_assignment(lhs_type, rhs_type):
if lhs_type == rhs_type:
return OK
elif can_promote(rhs_type, lhs_type):
insert_conversion_code()
return OK
else:
report_error(f"Cannot assign {rhs_type} to {lhs_type}")
return ERROR
def check_binary_operation(lhs_type, op, rhs_type):
result_type = infer_type(lhs_type, op, rhs_type)
if result_type is None:
report_error(f"Cannot apply {op} to {lhs_type}, {rhs_type}")
return result_typeName Resolution
def resolve_name(identifier):
symbol = symbol_table.lookup(identifier)
if symbol is None:
report_error(f"Undefined: {identifier}")
# Create dummy symbol to continue checking
return dummy_type
else:
return symbol.typeError Recovery
Panic Mode Recovery
On error
1. Report error with location
2. Skip tokens until reaching synchronization point
3. Continue semantic analysis
Synchronization points
- ;, }, newline (end of statement)
- if, while, for (start of statement)
- else (between statement blocks)
Error Node Propagation
class ErrorNode:
def __init__(self, message):
self.is_error = True
self.message = message
def combine_with(self, other):
if other.is_error:
return ErrorNode(self.message + "; " + other.message)
else:
return self # Propagate error upward
# Usage:
type1 = check_expression(expr1)
if type1.is_error:
type1 = ErrorNode("error in expr1")
type2 = check_expression(expr2)
result = combine_types(type1, type2)Error Reporting
Helpful Error Messages
BAD
Error on line 10
BETTER
Type error on line 10, column 5:
Cannot assign float to int
int x = 3.14;
^^^^
BEST
Type error on line 10, column 5:
Cannot assign float to int
Expected: int, Got: float
Suggestion: cast to int: (int) 3.14
int x = 3.14;
^^^^
Error Message Components
Required
1. Error type (Type error, Undefined variable, etc.)
2. Location (file, line, column)
3. Description (what's wrong)
Optional but helpful
4. Source code excerpt
5. Pointer to problem
6. Suggestions/fixes
7. Related errors
Error Handling Patterns
Error Attribute Pattern
Add error flag to all types:
class Type:
def __init__(self, name, is_error=False):
self.name = name
self.is_error = is_error
# Usage:
if expr.type.is_error:
# Don't perform further checking
return ErrorType()
else:
# Continue type checking
...Defensive Check Pattern
def check_function_call(func_name, args):
# Defensive: check each argument type
arg_types = []
for arg in args:
arg_type = check_expression(arg)
if arg_type.is_error:
arg_types.append(ErrorType())
else:
arg_types.append(arg_type)
# Verify against function signature
func = symbol_table.lookup(func_name)
if func is None:
report_error(f"Undefined function: {func_name}")
return ErrorType()
# Check argument count
if len(args) != len(func.parameters):
report_error(f"Function {func_name} expects {len(func.parameters)} args, got {len(args)}")Quick Revision Notes
- Semantic error: Violates language semantics (compiles but illegal)
- Type error: Type mismatch or undefined operation
- Name error: Undefined or redefined identifier
- Error recovery: Skip to synchronization point, continue
- Error attribute: Add error flag to propagate errors upward
- Defensive checking: Assume any subexpression could be erroneous
- Helpful messages: Include location, description, suggestions
Interview Q&A
Q1: How do you prevent error cascades in semantic analysis?
A: Use error types/flags to mark problematic expressions. Subsequent checking skips detailed analysis on error nodes, preventing multiple error messages from same mistake. Continue analysis to find independent errors.
Q2: What's the difference between error detection and error recovery?
A: Detection identifies the problem; recovery lets compilation continue despite errors. Recovery is essential for reporting multiple errors instead of stopping at first error.
Q3: When should errors be fatal vs non-fatal?
A: Non-fatal: semantic errors (type mismatch, undefined variable)—collect all, report at end. Fatal: I/O errors (can't read file), syntax errors (parser cannot continue)—stop immediately.
Q4: How do you handle cascading type errors?
A: Mark expressions with error type; propagate error upward. Skip detailed checking for error-typed expressions to avoid repeated error messages for same root cause.
Q5: What makes a good error message?
A: Precise location (file:line:column), clear description, source code context with pointer, suggested fix if possible. Avoid jargon; assume user isn't compiler expert.
Q6: Can semantic errors be detected at parse-time or must they wait until semantic analysis?
A: Most semantic errors require semantic analysis (type info, symbol lookup). Some can be caught at parse-time (undefined syntax, but syntax and semantics are intertwined in practice).
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Semantic Errors: Detection and Reporting in Compiler Construction.
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, errors, semantic errors: detection and reporting in compiler construction
Related Compiler Design Topics