Compiladores: Análisis Semántico Pontificia Universidad Javeriana Cali Ingenieria de Sistemas y Computación Prof. Gloria Inès Alvarez V. Verificaciòn de tipos Se puede hacer en forma Estàtica: en tiempo de compilaciòn Dinàmica: en tiempo de ejecuciòn Verifica: Compatibilidad entre un operador y sus operandos Flujo de control sea correcto Duplicidad de nombres cuando esto sea prohibido Verificaciòn de tipos Puede hacerse durante el anàlisis sintàctico Puede requerir una pasada sobre el àrbol de anàlisis sintàctico entre el anàlisis sintàctico y la generaciòn de còdigo Verificaciòn de tipos Sobrecarga de operadores: el operador cambia su significado dependiendo del contexto Coacciòn de tipos: el lenguaje brinda un operador que modifica el tipo de su operando Funciones polimòrficas: realizan un mismo procesamiento sobre elementos de distintos tipos Sistema de Tipos Es una colecciòn de reglas para asignar expresiones de tipo a diferentes partes de un programa Para construirlo se necesita conocer: Las construcciones sintàcticas del lenguaje La nociòn de tipos Normalmente hay tipos bàsicos y tipos construidos Expresiones de tipo Sirven para tipar construcciones del lenguaje que tienen tipo construido Definiciòn: Un tipo bàsico es una expresiòn de tipo Un nombre de tipo es una expresiòn de tipo Un constructor de tipo aplicado a una expresiòn de tipo, es una expresiòn de tipo Una expresiòn de tipo se puede representar mediante un grafo Expresiones de tipo Tipos básicos Arreglos Productos Registros Punteros Funciones Verificaciòn estàtica y dinàmica En principio, la verificaciòn puede hacerse dinàmica si todo elemento mantiene su tipo asì como mantiene su valor Un sistema de tipos sensato elimina la necesidad de hacer verificaciòn dinàmica Un lenguaje es fuertemente tipado si garantiza en compilaciòn la ausencia de errores de tipo en ejecuciòn Recuperaciòn de errores de tipo Lo mìnimo que se espera es establecer la naturaleza y localizaciòn del error Es deseable poder continuar revizando la entrada Un verificador de tipos simple Es un esquema de traducciòn Ejemplo: P -> D ; E D -> D ; D | id : T T -> char | integer | array [num] of T | ^T E -> literal | num | id | E mod E | E^ Expresiones de tipo Esquema de traducción D -> id : T T-> char T-> integer T -> ^T1 {addtype(id.entry,T.type)} {T.type = char} {T.type = integer} {T.type = pointer(T1.type)} T -> array[num] of T1 {T.type =array(1..num.val,T1.type) } Verificación de tipos Tipos básicos Expresiones entero E -> num {E.type = integer} caracter E-> literal {E.type = char} E -> id {E.type = buscar(id.entry)} E -> E1 mod E2 {E.type = if E1.type = integer and E2.type = integer then integer else type_error} Tipos construidos E -> E1[E2] {E.type = if E2.type = integer and E1.type = array(s,t) then t else type_error} E -> E1^ {E.type = if E1.type = pointer(t) then t ...} Equivalencia de Expresiones de Tipo La equivalencia depende de si un nombre de un tipo en una expresión se representa a si mismo, o a una expresion de tipo: Equivalencia Estructural: dos expresiones de tipo son equivalentes si son del mismo tipo básico, o si están formadas aplicando el mismo constructor de tipo a dos tipos estructuralmente equivalentes. Ejemplo: “entero” es equivalente a “entero” “registro((c1xentero)x(c2xreal))” es equivalente a “registro((c1xentero)x(c2xreal))” Equivalencia de Nombres: cada nombre de tipo es una expresión de tipo distinta, por lo tanto, dos expresiones de tipo son equivalentes si y solo si son identicas. Pontificia U. Javeriana Cali - Ingenieria de Sistemas y Computación – Compiladores – Prof. Ma. Constanza Pabón Equivalencia de Expresiones de Tipo La estructura de una expresión de tipo se puede representar construyendo un grafo dirigido Ejemplo: TYPE t1 = ARRAY [1..10] OF INTEGER; VAR v1 : t1; v2 : ARRAY [1..10] OF INTEGER; ARREGLO 1..10 ENTERO Pontificia U. Javeriana Cali - Ingenieria de Sistemas y Computación – Compiladores – Prof. Ma. Constanza Pabón Ejemplo de un Algoritmo para Comprobar Equivalencia Estructural Eq_Est (s, t) : Si s y t son del mismo tipo básico Retorne Verdadero Sino Si s = arreglo(s1, s2) y t = arreglo(t1, t2) Retorne Eq_Est(s1, t1) y Eq_Est(s2, t2) Sino Si s = apuntador(s1) y t = apuntador(t1) Retorne Eq_Est(s1, t1) ...... Sino Retorne Falso Pontificia U. Javeriana Cali - Ingenieria de Sistemas y Computación – Compiladores – Prof. Ma. Constanza Pabón Conversiones de Tipos Las reglas del lenguaje definen que conversiones son necesarias Al generar código intermedio se pueden introducir las conversiones de tipo necesarias Coacciones: conversiones de tipo implicitas (realizadas por el compilador). Generalmente se realizan en los casos en que no se pierde información. Conversiones Explicitas: cuando el programador causa la conversión escribiendo una instrucción. Las coacciones se deben tener en cuenta al escribir las reglas semánticas para comprobación de tipos del compilador. Pontificia U. Javeriana Cali - Ingenieria de Sistemas y Computación – Compiladores – Prof. Ma. Constanza Pabón Sobrecarga de Funciones y Operadores Un símbolo sobrecargado es aquel que tiene diferentes significado dependiendo del contexto. Ejemplo: el operador + El significado es diferente cuando se suman enteros, o reales, o complejos, o matrices. La sobrecarga se resuelve cuando se define un significado unico para una ocurrencia del símbolo sobrecargado Si la sobrecarga no se resuelve, una expresión puede tener un conjunto de tipos posibles Ejemplo: si para el operador + se tienen los siguientes tipos posibles: entero x entero → entero entero x entero → complejo complejo x complejo → complejo Pontificia U. Javeriana Cali - Ingenieria de Sistemas y Computación – Compiladores – Prof. Ma. Constanza Pabón Funciones Polimorficas Una función polimorfica permite ser ejecutada con argumentos de tipos diferentes cada vez (pero siempre ejecuta el mismo cuerpo de instrucciones). Ejemplo: los operadores definidos por el lenguaje para indexar arreglos, llamar funciones y manejar punteros. Las funciones polimorficas facilitan la implementación de algoritmos que manipulan estructuras de datos, sin importar el tipo de dato de los elementos de la estructura. Ejemplo: longitud de una lista, altura de un arbol. Pontificia U. Javeriana Cali - Ingenieria de Sistemas y Computación – Compiladores – Prof. Ma. Constanza Pabón Variables de Tipo Variables de Tipo: Permiten representar tipos desconocidos en una expresión de tipo. Se usan para comprobación de tipos de lenguajes que no exigen declarar los identificadores antes de su uso. Inferencia del Tipo: es el problema de determinar el tipo de una contrucción del lenguaje de acuerdo con la forma en que es usado. Type list ↑celda; Procedure x (l : list; procedure p) Begin ...... p(l); ..... End; p es tipo α → void p es tipo list → void Pontificia U. Javeriana Cali - Ingenieria de Sistemas y Computación – Compiladores – Prof. Ma. Constanza Pabón Variables de Tipo y Funciones Polimorficas La expresión de tipo de una función polimorfica se define usando el cuantificador universal ∀ (para todo) Para la función que retorna la longitud de una lista: ∀ α . List(α ) → integer La equivalencia de tipos se determina haciendo unificación de tipos. Pontificia U. Javeriana Cali - Ingenieria de Sistemas y Computación – Compiladores – Prof. Ma. Constanza Pabón