Análisis semántico: Comprobación de tipos Introducción

Anuncio
Análisis semántico:
Comprobación de tipos
Expresiones de tipos, sistemas de comprobación de
tipos, equivalencia, resolución de sobrecargas y
unificación.
Introducción
Objetivo de comprobación estática:
„
Establecer en tiempo de compilación si el programa fuente sigue
las convenciones sintácticas y semánticas del lenguaje.
Ejemplos de comprobación estática:
„
„
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
„
Comprobaciones
Comprobaciones
Comprobaciones
Comprobaciones
de tipos
del flujo de control
de unicidad
relacionadas con nombres
Sistemas de tipos
Cada construcción de un lenguaje tiene asociado un tipo:
Expresiones.
Funciones.
Sentencias.
„
„
„
El problema básico:
Decidir un tipo único para cada uno de los elementos
„
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Estrategia:
Reglas de tipos:
„
“Si ambos operandos de los operadores aritméticos de suma,
sustracción y multiplicación son de tipo entero, entonces el resultado
es de tipo entero”.
“El resultado del operador unario & es un apuntador hacia el objeto al
que se refiere el operando. Si el tipo del operando es ‘…’, el tipo del
resultado es ‘puntero a …’”.
„
„
Construir expresiones de tipos, separando:
„
Tipos básicos.
Tipos construidos.
„
„
Expresiones de tipos
El tipo de una construcción del lenguaje se denotará mediante
expresiones de tipo
Definición de expresión de tipo:
„
Un tipo básico es una expresión de tipo.
„
„
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
„
boolean, char, integer, real, error_tipo, vacío.
El nombre de un tipo es una expresión de tipo
Un constructor de tipos aplicado a una expresión de tipo es una
expresión de tipo
Las expresiones de tipo pueden contener variables cuyos valores
son expresiones de tipo
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Constructores de tipos
Matrices: Si T es una expresión de tipo, array(I,T) es una expresión
de tipo, donde I es un conjunto de índices, y T el tipo de los
elementos
Productos: Si T1 y T2 son expresiones de tipo, su producto
cartesiano, T1×T2 es una expresión de tipo
Registros: el constructor record se aplicará a una tupla formada
con nombres de campos y tipos de campos.
Punteros: Si T es una expresión de tipo, entonces pointer(T) es una
expresión de tipo
Funciones: transformaciones de un dominio de tipo D a un rango
de tipo R. La expresión de tipo D→R indicará el tipo de la función
Sistemas de tipos: Reglas
Definición Sistema de Tipos: Serie de reglas para asignar
expresiones de tipo a las distintas partes de un programa.
Un comprobador de tipos implanta un sistema de tipos
Comprobación estática vs. Dinámica:
„
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
„
Cualquier verificación puede realizarse dinámicamente
Un sistema de tipos seguro elimina la necesidad de comprobar
dinámicamente errores de tipo
Un lenguaje es fuertemente tipado si su compilador puede
garantizar que los programas que acepte se ejecutarán sin
errores de tipo
Errores de tipos:
„
„
El compilador debe informar de la naturaleza y posición del error
Es conveniente que se recupere de los errores para comprobar el
resto de la entrada
Comprobador de tipos sencillo
Un lenguaje simple y prototípico para representar el problema
de especificación de tipos:
P→D ; E
D→D ; D | id : T
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
T→char | integer | array [ num ] of T | ↑T
E→literal | num | id | E mod E | E [ E ] | E↑
Comprobador de tipos sencillo
Parte de un esquema de traducción que guarda el tipo de un
identificador:
P→D ; E
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
D→D ; D
D→id : T
{añadetipo(id.entrada, T.tipo)}
T→char
{T.tipo:=char}
T→integer
{T.tipo:=integer}
T→↑T1
{T.tipo:=pointer(T1.tipo)}
T→array [ num ] of T1
{T.tipo:=array(1..num.val, T1.tipo)}
Comprobador de tipos sencillo
Comprobación de tipos en las expresiones
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
E→literal
E→num
E→id
E→E1 mod E2
{E.tipo:=char}
{E.tipo:=integer}
{E.tipo:=busca(id.entrada)}
{E.tipo:=if E1.tipo = integer and
E2.tipo = integer then integer
else error_tipo}
{E.tipo:=if E2.tipo = integer and
E1.tipo = array(s,t) then t
else error_tipo}
{E.tipo:=if E1.tipo = pointer(t) then t
else error_tipo}
E→E1 [ E2 ]
E→E1↑
Comprobador de tipos sencillo
Comprobación de tipos en las proposiciones
T→boolean (gramática aumentada)
S→id := E
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
S→if E then S1
{S.tipo := if id.tipo = E.tipo then vacío
else error_tipo}
{S.tipo:=if E.tipo = boolean then S1.tipo
else error_tipo}
S→while E do S1 {S.tipo:=if E.tipo = boolean then S1.tipo
else error_tipo}
S→S1 ; S2
{S.tipo:= if S1.tipo = vacío and
S2.tipo = vacío then vacío else error_tipo}
Comprobador de tipos sencillo
Comprobación de tipos de funciones
E→E ( E ) (gramática aumentada)
E→E1 ( E2 )
{E.tipo:= if E2.tipo = s and
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
E1.tipo = s → t then t
else error_tipo}
Equivalencia de expresiones de tipos
Equivalencia:
„
„
„
Identidad (estructural sin constructores)
Estructural
De nombre (nombres para tipos)
Equivalencia estructural en las expresiones de tipos:
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
„
Dos expresiones son, o bien el mismo tipo básico, o están
formadas aplicando el mismo constructor a tipos estructuralmente
equivalentes
Dos expresiones de tipos son estructuralmente equivalentes, si y
sólo si, son idénticas
Equivalencia de expresiones de tipos
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Comprobación de la equivalencia estructural de dos
expresiones de tipos s y t.
function equivest(s,t): boolean;
begin
if s y t son el mismo tipo básico then return true
else if s=array(s1, s2) and t=array(t1, t2) then return equivest(s1,t1)
and equivest(s2,t2)
else if s=s1×s2 and t=t1×t2 then return equivest(s1,t1)
and equivest(s2,t2)
else if s=pointer(s1) and t=pointer(t1) then return equivest(s1,t1)
else if s=s1→s2 and t=t1→t2 then return equivest(s1,t1)
and equivest(s2,t2)
else
return false
end
Equivalencia de expresiones de tipos
Nombres en expresiones de tipos:
„
„
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
Se permite dar nombres a las expresiones de tipo y que estos
nombres aparezcan en expresiones de tipos donde previamente
sólo existían tipos básicos
Equivalencia de nombre: dos expresiones de tipo tienen
equivalencia de nombre, si y sólo si, son idénticas
Equivalencia estructural: dos expresiones de tipos son
estructuralmente equivalentes si representan dos expresiones de
tipos estructuralmente equivalentes cuando todos los nombres
han sido sustituidos
Equivalencia de expresiones de tipos
Ciclos en las representaciones de tipos
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
Los nombres de tipo definidos recursivamente se pueden sustituir
si se quieren introducir ciclos en el grafo de tipos
Ejemplo:
type enlace = ↑nodo
nodo = record
info:integer
siguiente:enlace
end;
Equivalencia de expresiones de tipos
Ciclos en las representaciones de tipos
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
nodo=record
×
×
info
×
integer
siguiente
pointer
nodo
Equivalencia de expresiones de tipos
Ciclos en las representaciones de tipos
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
nodo=record
×
×
info
×
integer
siguiente
pointer
Conversiones de tipos
Coerciones:
„
„
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
La conversión de un tipo a otro es implícita si el compilador la va
a realizar automáticamente. Estas conversiones se llaman
coerciones
La conversión es explícita si el programador debe escribir algo
para motivar la conversión (operador).
Para un comprobador de tipos, las conversiones explícitas se
tratan como aplicaciones de función, por lo que no presentan
problemas nuevos.
Sobrecarga de funciones y operadores
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Símbolo sobrecargado: es aquél que tiene distintos
significados dependiendo de su contexto
La sobrecarga se resuelve cuando se determina un significado
único para un caso de símbolo sobrecargado
La solución de sobrecarga se denomina identificación de
operadores
Sobrecarga de funciones y operadores
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
La sobrecarga “implícita” (operadores aritméticos,
generalmente) es posible resolverla mirando a los operandos
La sobrecarga “explícita” se resolverá (si se puede) al
observar el contexto en el que se encuentra
Sobrecarga de funciones y operadores
Ejemplo de sobrecarga (operador de multiplicación):
integer × integer → integer
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
integer × integer → complex
complex × complex → complex
• La expresión 3*5 podrá tener tipo integer o complex
• En 2*(3*5), 3*5 sólo podrá tener tipo integer
• En z*(3*5), 3*5 sólo podrá tener tipo complex
Sobrecarga de funciones y operadores
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Cada subexpresión de una expresión tendrá un conjunto
posible de tipos (cada uno de los tipos se denomina tipo
factible)
Se resuelve la sobrecarga (en una expresión) si puede
determinarse un tipo único para la expresión y cada una de
sus subexpresiones
Sobrecarga de funciones y operadores
Solución de la sobrecarga (2 pasos):
„
Se determina un tipo único para la expresión completa
Se comprueba cada subexpresión comprobando si a partir del tipo
único, el tipo de la subexpresión es o no único
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
Sobrecarga de funciones y operadores
Sobrecarga de operadores no resuelta
2*(3*5) con la sobrecarga anterior en la multiplicación
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
E {i,c}
E{i}
*:{i×i→i,
E{i,c}
i×i→c,
2{i}
c×c→c}
E{i}
*:{i×i→i,
E{i}
i×i→c,
3{i}
c×c→c}
5{i}
Sobrecarga de funciones y operadores
Sobrecarga de operadores resuelta
2+(3*5) con la sobrecarga anterior en la multiplicación
E {i}
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
{i}
E{i}
2{i}
+:{i×i→i}
E{i,c}
E{i}
*:{i×i→i,
E{i}
i×i→c,
3{i}
c×c→c}
5{i}
Funciones polimórficas
Una función polimórfica es aquella que puede ejecutarse con
argumentos de tipos distintos
fun longitud(aplista)=
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
if null(aplista) then 0
else longitud(tl(aplista))+1;
longitud([“dom”, “lun”, “mar”])=3
longitud([10, 9, 8])=3
Funciones polimórficas
Las variables que representan expresiones de tipos permiten
considerar tipos desconocidos en:
„
funciones polimórficas
comprobación del uso consistente de identificadores en un
lenguaje que no exija que se declaren antes de ser utilizados (si
siempre se usa igual, se garantiza un uso consistente y puede
inferirse su tipo).
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
Funciones polimórficas
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Inferencia de tipos: problema de determinar el tipo de una
construcción del lenguaje a partir del modo en que se usa
Las técnicas para inferencia de tipos pueden aplicarse a
programas en lenguajes como C y Pascal para completar
información sobre los tipos que faltan en el momento de la
compilación
Funciones polimórficas
Notación para tipos polimórficos
function desref(p);
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
begin
return p↑
end;
• El tipo de la función es ∀α.pointer(α) →α
• Una expresión de tipo que contenga un símbolo ∀ se
considerará un “tipo polimórfico”
Funciones polimórficas
Un lenguaje con funciones polimórficas
P→D;E
D → D ; D | id : Q
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Q → ∀ variable_de_tipo.Q | T
T→
T ‘→’ T
|T×T
| constructor_unario ( T )
| tipo_basico
| variable_de_tipo
|(T)
E → E ( E ) | E , E | id
Funciones polimórficas
‘Programa’ generado por la gramática
desref: ∀α.pointer(α) →α
q: pointer(pointer(integer)
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
desref(desref(q))
¿Es correcta la expresión a partir de la
declaración de tipos?
Funciones polimórficas
Diferencias para comprobación de tipos entre funciones
polimórficas y ordinarias:
„
„
Casos diferentes de una función polimórfica en la misma
expresión no deben tener necesariamente argumentos del mismo
tipo
Ejemplo:
„
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
desrefe y desrefi en
desrefe(desrefi(q))
Funciones polimórficas
Diferencias para comprobación de tipos entre funciones
polimórficas y ordinarias :
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
Reconsideración de la equivalencia de tipos (unificación: de
manera informal, determinación de si s y t pueden ser
estructuralmente equivalentes sustituyendo las variables en s y t
por expresiones de tipo)
Ejemplo:
pointer(ai)=pointer(pointer(integer)), si
ai se sustituye por pointer(integer)
Funciones polimórficas
Diferencias para comprobación de tipos entre funciones
polimórficas y ordinarias:
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
„
Se necesita un mecanismo para registrar el efecto de la
unificación de dos expresiones. Si una variable a representa al
tipo t, entonces a debe continuar representando a t durante toda
la comprobación de tipos
Funciones polimórficas
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Sustitución: transfomación de variables de tipo a
expresiones de tipo
Unificación: Dos expresiones de tipo t1 y t2 se unifican si
existe alguna sustitución S tal que S(t1)=S(t2). En la práctica,
interesa el unificador más general, que es la sustitución que
menos limitaciones exige a las variables dentro de las
expresiones
Funciones polimórficas
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Ejemplo de comprobación de tipos para desref(desref(q))
Expresión
Tipo
q
pointer(pointer(integer))
desrefi
pointer(αi)Æαi
desrefi(q)
pointer(integer)
desrefe
pointer(αe)Æαe
desrefe(desrefi(q))
integer
Sustitución
αi=pointer(integer)
αe=integer
Funciones polimórficas
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Relación entre comprobación e inferencia de tipos
function desref(p)
begin
return p↑
end;
• Inferir el tipo de desref a partir del cuerpo de la función
• Unificación de desref(p) con return p↑
Funciones polimórficas
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Relación entre comprobación e inferencia de tipos
Conocimiento previo:
EXPRESIÓN
TIPO
↑
pointer( χ )Æχ
return
δÆδ
Método: Evaluación ascendente de declaración y expresión
(de las subexpresiones a la expresión)
Funciones polimórficas
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Relación entre la comprobación y la inferencia de tipos
Expresión
Tipo
p
α
desref
β
desref(p)
χ
p
α
↑
pointer(δ)Æδ
p↑
δ
Sustitución
β=αÆχ
α=pointer(δ)
Funciones polimórficas
© Valentín Cardeñoso Payo. Departamento de Informática
UNIVERSIDAD DE VALLADOLID
Relación entre la comprobación y la inferencia de tipos
Expresión
Tipo
Sustitución
return
σÆσ
return p↑
σ
δ=σ
desref (p) con return p↑
χ
σ=χ
Realizando las sustituciones tenemos que el tipo inferido es:
∀χ.pointer(χ)→χ
Descargar