Skip to content

Análisis Semántico. Comprobación de Tipos

Objetivo

El análisis semántico se ha dividido en dos etapas (identificación y comprobación de tipos). En el capítulo anterior ya se implementó la primera de ellas, por lo que en el capítulo actual se tratará la segunda. Se diseñará e implementará la etapa de comprobación de tipos, es decir, la parte del semántico que pretende detectar errores en las operaciones sin necesidad de tener que ejecutarlas y sin necesidad de conocer sobre qué valores concretos operarán. Esto lo hace observando el tipo de cada expresión y comprobando si es apto en el contexto en el que se quiere usar dicha expresión.

Por ejemplo, ante una entrada como:

DATA
	float f;
	int i;

CODE
	i = 2.0;	// Error
	f = 2;		// Error

	print 1 + 2.5;	// Error
	2 = i;			// Error (but not a type error)

Debería notificar los siguientes errores:

bash
Compiler starts...

Error in Type Checking: [6:2] The expression types don't match
Error in Type Checking: [7:2] The expression types don't match
Error in Type Checking: [9:8] The expression types don't match
Error in Type Checking: [10:2] The expression on the left is not modifiable

4 errors detected.

Para poder comprobar si el tipo de cada expresión es válido se necesita previamente haber calculado el tipo de todas ellas. Este proceso es el que se conoce como inferencia de tipos.

Además, aunque el objetivo de esta fase sería únicamente comprobar los tipos, como se adelantó en el capítulo anterior, en esta fase se suelen incluir comprobaciones adicionales que no se corresponden con las tareas propias de un comprobador de tipos. Un ejemplo de estas validaciones es el último error del ejemplo anterior, en el que la causa del mismo no es que los tipos de ambos operandos de la asignación no sean compatibles (de hecho, son del mismo tipo); la causa es que no se puede modificar una constante (no es modificable).

Otro ejemplo de una validación que no pertenezca a las dos fases principales (aunque no se presenta en el lenguaje de este tutorial) sería la regla semántica de Java de que todo camino de un método con valor de retorno debe acabar en un return. Este sería un ejemplo de reglas de control de flujo, que, aunque podrían tener su propia etapa aparte en el semántico, a menudo se suele incorporar en la comprobación de tipos.