Overview
The AnalizadorSemantico (Semantic Analyzer) class performs semantic analysis by traversing the Abstract Syntax Tree (AST) and verifying that the code makes logical sense. It’s the third phase of the compilation process.
Class Definition
class AnalizadorSemantico:
def __init__(self)
Constructor Parameters
No parameters required. The analyzer initializes with an empty state.
Attributes
variables_declaradas (set): Set of variable names that have been declared
errores (List[str]): List of semantic errors found during analysis
Public Methods
analizar()
Analyzes the complete program AST for semantic correctness.
def analizar(self, programa: Programa) -> bool
The AST produced by the Parser
Returns True if no semantic errors were found, False otherwise
Example:
scanner = Scanner("let x = y + 5;")
tokens = scanner.escanear_tokens()
parser = Parser(tokens)
programa = parser.parsear()
analizador = AnalizadorSemantico()
exito = analizador.analizar(programa)
if not exito:
for error in analizador.errores:
print(error)
# Output: Error semántico en línea 1, columna 9: la variable 'y' no ha sido declarada
Semantic Checks
The Semantic Analyzer performs the following validations:
1. Undefined Variable Detection
Verifies that all variables are declared before use.
Error Example:
code = "print x;" # x is not declared
analizador = AnalizadorSemantico()
analizador.analizar(programa)
# Error: la variable 'x' no ha sido declarada
Correct Example:
code = """
let x = 5;
print x;
"""
# ✓ No error: x is declared before use
2. Variable Redeclaration Warning
Warns when a variable is declared multiple times.
Warning Example:
code = """
let x = 5;
let x = 10;
"""
analizador = AnalizadorSemantico()
analizador.analizar(programa)
# Advertencia: la variable 'x' ya fue declarada anteriormente
3. Division by Zero Detection
Detects division by zero when the divisor is a literal number.
Error Example:
code = "let x = 10 / 0;"
analizador = AnalizadorSemantico()
analizador.analizar(programa)
# Error: división entre cero detectada
Note: Only literal divisions are checked:
# This IS detected:
let x = 10 / 0; // Error!
# This is NOT detected (runtime behavior):
let y = 0;
let x = 10 / y; // No compile-time error
4. Self-Reference Detection
Detects variables that reference themselves in their declaration.
Error Example:
code = "let x = x + 1;"
analizador = AnalizadorSemantico()
analizador.analizar(programa)
# Error: la variable 'x' no ha sido declarada
This works because the analyzer:
- Analyzes the right-hand expression first
- Then registers the variable as declared
Implementation Details
Variable Declaration Order
The analyzer processes declarations in the following order:
- Check if the variable already exists (warning if it does)
- Analyze the right-hand side expression
- Register the variable as declared
This order ensures that:
- Self-references are caught as errors
- Variables can reference previously declared variables
let a = 5; // ✓ OK
let b = a + 3; // ✓ OK: 'a' is already declared
let c = c + 1; // ✗ ERROR: 'c' not declared yet
Expression Analysis
The analyzer recursively traverses expressions:
def _analizar_expresion(self, expr: Expresion):
if isinstance(expr, NumeroLiteral):
pass # Numbers are always valid
elif isinstance(expr, Identificador):
# Check if variable exists
if expr.nombre not in self.variables_declaradas:
self.errores.append(...)
elif isinstance(expr, ExpresionBinaria):
# Analyze both sides
self._analizar_expresion(expr.izquierda)
self._analizar_expresion(expr.derecha)
# Check for division by zero
if expr.operador.tipo == TipoToken.DIVISION:
if isinstance(expr.derecha, NumeroLiteral) and expr.derecha.valor == 0:
self.errores.append(...)
elif isinstance(expr, ExpresionAgrupada):
# Analyze inner expression
self._analizar_expresion(expr.expresion)
Error Messages
All error messages include:
- Error type (semantic error or warning)
- Line number
- Column number
- Descriptive message
Format:
Error semántico en línea X, columna Y: [description]
Advertencia en línea X, columna Y: [description]
Usage Example
from compfinal import Scanner, Parser, AnalizadorSemantico
# Complete compilation pipeline
code = """
let x = 5;
let y = x + 10;
let z = y / 0; // Semantic error!
print w; // Semantic error!
"""
# Phase 1: Lexical Analysis
scanner = Scanner(code)
tokens = scanner.escanear_tokens()
if scanner.errores:
print("Lexical errors found!")
exit(1)
# Phase 2: Syntactic Analysis
parser = Parser(tokens)
programa = parser.parsear()
if parser.errores:
print("Syntax errors found!")
exit(1)
# Phase 3: Semantic Analysis
analizador = AnalizadorSemantico()
exito = analizador.analizar(programa)
if not exito:
print(f"Found {len(analizador.errores)} semantic error(s):")
for error in analizador.errores:
print(f" - {error}")
exit(1)
print(f"✓ Semantic analysis passed!")
print(f" Variables declared: {analizador.variables_declaradas}")
Limitations
Runtime Errors Not Detected
The semantic analyzer cannot detect errors that depend on runtime values:
// These are NOT detected:
let divisor = 0;
let result = 10 / divisor; // Runtime error, not compile-time
let x = 5;
let y = -3;
let arr = x + y; // No array support, but no error either
Type Checking Not Implemented
The compiler assumes all values are integers. There’s no type system:
// All treated as integers:
let x = 5; // integer
let y = x + 10; // integer
let z = y * 2; // integer
Error Recovery
The semantic analyzer continues checking even after finding errors:
code = """
let x = a + 5; // Error: 'a' not declared
let y = b + 10; // Error: 'b' not declared
print c; // Error: 'c' not declared
"""
# All three errors will be reported, not just the first one
See Also