Compiladores e Intérpretes Análisis Semántico IV

Documentos relacionados
Compiladores e Intérpretes Análisis Semántico I

Compiladores e Intérpretes Semántica de MiniJava Segundo Cuatrimestre de 2016

COMPILADORES. Tema 4. Análisis semántico

Análisis semántico Tabla de símbolos, chequeo de tipos y representaciones internas

ANÁLISIS SEMÁNTICO GRAMÁTICAS DE ATRIBUTOS Y TIPOS

Análisis semántico Tabla de símbolos, chequeo de tipos y representaciones internas

Tema 5. Análisis semántico

Introducción. Análisis Semántico. José M. Castaño. Teoría de Lenguajes 2011 Departamento de Computación FCEyN, UBA

Diseño de Compiladores I. Estructura General de un Compilador

Compiladores e Intérpretes

ANÁLISIS SEMÁNTICO LA TABLA DE SÍMBOLOS

GENERACIÓN DE CÓDIGO INTERMEDIO ÁRBOLES DE SINTAXIS ABSTRACTA (ASA)

Compiladores e Intérpretes Generación de Código Máquina e Intérpretes

Diseño de compiladores Recordando la clase anterior

Análisis Semántico y Traducción Dirigida por la Sintaxis. Programación II Margarita Álvarez

Compiladores e Intérpretes Análisis Léxico

PRÁCTICA DE PROCESADORES DE LENGUAJE EVALUACIÓN ORDINARIA CURSO 2009/2010 OBJETIVO DE LA PRÁCTICA

NOMBRE DEL CURSO: Organización de Lenguajes y Compiladores 2

Bison. Introducción. Índice. Introducción Uso de Bison con Flex. Formato del fichero de especificación de Bison

Unidad IV. Este tipo de codificación nos es permitido gracias a la sobrecarga, la cual se aplica a métodos y constructores.

Análisis semántico. Análisis semántico. Índice (I)

INTRODUCCIÓN AL PROCESO DE COMPILACIÓN

Yacc/Bison. Introducción

Unidad I: Análisis semántico

Concepto de compilador Intérprete Fases de un Compilador Herramientas de construcción de Compiladores

Unidad II: Análisis semántico

Práctica 01 - Preprocesamiento básico para un código fuente en lenguaje C Compiladores - Profr. Edgardo Adrián Franco Martínez

FLEX: A FAST LEXICAL ANALYZER GENERATOR

Lenguajes de programación

CÓMO DESARROLLAR Y PROBAR PROGRAMAS?, COMPRUÉBALO!

NOMBRE DEL CURSO: Organización de Lenguajes y Compiladores 2

Tema 5: Traducción dirigida por la sintaxis

Introducción. El proceso de traducción

05 Análisis léxico I Compiladores - Profr. Edgardo Adrián Franco Martínez

Introducción a OOP. Programación Orientada a Objeto

Generación de Código Intermedio

Clases y Objetos en Java. ELO329: Diseño y Programación Orientados a Objetos

NOMBRE DEL CURSO: Organización de Lenguajes y Compiladores 2 CÓDIGO: 781 CRÉDITOS: 5 ÁREA A LA QUE PERTENECE: POST-REQUISITO:

Compiladores e Intérpretes Análisis Sintáctico

ANÁLISIS SEMÁNTICO VERIFICACIÓN DE TIPOS

Una clave Definición informal La clave debe contener una secuencia de una o más letras seguidas por uno o más dígitos

Compiladores: Ambientes para Ejecución. Pontificia Universidad Javeriana Cali Ingeniería de Sistemas y Computación Prof. María Constanza Pabón

Algoritmos y programas. Algoritmos y Estructuras de Datos I

FLEX: A FAST LEXICAL ANALYZER GENERATOR

PROCESADORES DE LENGUAJES I PRÁCTICA DE LABORATORIO 4

Gramáticas de Atributos

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA Escuela Técnica Superior de Ingeniería Informática Procesadores de Lenguajes. Tema 2.

Práctica 2. Reutilización de código Elementos básicos del lenguaje Java Definición de variables, expresiones y asignaciones

Tema 5 Tabla de Símbolos

2.2 Nombres, Ligado y Ámbito

16 Análisis sintáctico I

DOMINIOS COGNITIVOS (Objetos de estudio, temas y subtemas)

Clases y Objetos en C++

Práctica 4 Análisis LALR para milenguaje y construcción de un traductor de milenguaje

Unidad 2: Estructuras de Datos estáticas y dinámicas.

UNIDAD 2 Descripción de un programa

Procesadores de lenguaje Tema 6 La tabla de símbolos

BASES DE DATOS 1. Teórico: Diseño Conceptual

Unidad V Análisis Semántico. M.C. Juan Carlos Olivares Rojas

Tema: Tabla de Símbolos

Bases de datos 1. Teórico: Diseño Conceptual

Comprender las diferencias entre tipos de datos primitivos similares, y aprender a elegir el tipo más conveniente en cada caso.

Herencia en Java. Agustín J. González Diseño y Programación Orientados a Objetos

PROCESADORES DE LENGUAJE EXAMEN FINAL 8-JUNIO-07

Programación Orientada a Objetos en C++

Procesadores de lenguaje Tema 6 La tabla de símbolos

Asignación Dinámica de Memoria. Agustín J. González Versión original de Kip Irvine ELO 326: Seminario II 2do. Sem. 2001

ANÁLISIS LÉXICO Ing. Ronald Rentería Ayquipa

Qué es el análisis semántico?

Lenguaje C, tercer bloque: Funciones

NOMBRE DEL CURSO: Organización de Lenguajes y Compiladores 2 CÓDIGO: 781 CRÉDITOS: 5 ÁREA A LA QUE PERTENECE:

Contenido. Prefacio Orígenes de la programación orientada a objetos... 1

GENERACIÓN DE CÓDIGO INTERMEDIO EJEMPLOS PARA DISTINTAS ESTRUCTURAS DE DATOS

Unidad III: Introducción a la Programación

Tema 1.3. Un lenguaje mínimo y su procesador: Restricciones contextuales

Tema 6: Clases. Índice

Funciones en lenguaje C

TEMA 3: ANÁLISIS SEMÁNTICO

Apuntes de Programación y estructuras de datos. Control de datos

Estructuras de control selectivas

TEMA 6: ANÁLISIS SEMÁNTICO DE EXPRESIONES E INSTRUCCIONES EN L-0

Conceptos básicos sobre gramáticas

Funciones Definición de función

Examen Teórico Convocatoria de Junio de 2012

Elementos de un programa en C

Tema 5: Traducción dirigida por la sintaxis

Seminario de introducción a Bison

Teoría de lenguajes Oscar BRUNO

Tema: Análisis Semántico

Manejo de Punteros y objetos en memoria dinámica en C++ Agustín J. González ELO 329

Procesadores de lenguaje Tema 5 Comprobación de tipos

Analizador Sintáctico RECURSIVO

SOFTWARE Microsoft Visual Studio 2005.NET FrameWork 2.0

Roberto Carlos Abreu Díaz. October 28, 2009

Transcripción:

1 Compiladores e Intérpretes Análisis Semántico IV Sebastian Gottifredi 2018

Repaso 2

Repaso El análisis semántico es el encargado validar y entender el significado del programa Para esto el analizador semántico debe: Recolectar, entender y controlar todas las entidades declaradas Chequeo de Declaraciones Recolectar, entender y controlar todas las sentencias asociadas a las entidades recolectadas Chequeo de Sentencias 3

Repaso Hay dos alternativas para implementar el analizador semántico: Intercalado con el analizador sintáctico (una pasada) Separado del analizador sintáctico (mas de una pasada) En cualquier caso, es necesario realizar acciones especiales dentro del analizador sintáctico Las Gramáticas de Atributos son las herramientas formales utilizadas para diseñar estas acciones en el analizador sintáctico 4

Repaso Los Esquemas de Traducción (EDT) nos dan un orden en el que se ejecutan esas acciones mientras realizamos el análisis sintáctico Para el chequeo de declaraciones, vimos que en el analizador sintáctico se construye la Tabla de Símbolos Sobre la tabla se pueden realizar los controles semánticos referentes a que las entidades estén correctamente declaradas 5

Repaso Para el chequeo de sentencias los ASTs En un AST cada tipo de constructor sintáctico que tiene significado dentro del programa es caracterizado por un tipo de nodo Por ej: bloque, asignación, expresión binaria, while, return, etc. NodoAsignacion NodoAcceso ladoizq NodoExpresion ladoder 6

Repaso Usamos herencia para caracterizar la relación común es un entre los distintos tipos de nodo Es útil para capturar los contextos donde podemos tener distintos tipos de nodos 7

Chequeo de Sentencias 8

Chequeo de Sentencias El Chequeo de Sentencias consiste en chequear que el cuerpo de los métodos y constructores no tiene errores semánticos. Está centrado en el chequeo de tipos y la resolución de nombres en sentencias y expresiones 10

Resolución de Nombres La resolución de nombres se refiere a que cuando se utiliza un Identificador en una expresión o sentencia, se controle que sea el nombre de la entidad adecuada. Por ejemplo en MiniJava, si nos la Clase encontramos Actual con: x( ) y.x( ) x y.x x debe ser el nombre de un método (propio o heredado) en x debe ser el nombre de un método (propio o heredado) de la Clase declarada para y x puede ser una variable local o un parámetro del método actual, o sino una variable de instancia de la clase actual x debe ser el nombre de una variable de Instancia de la Clase declarada para y

Resolución de Nombres La clave del proceso de resolución de nombres es como buscar los nombres en la tabla de símbolos Para eso la tabla de símbolos debe proveer las herramientas de búsqueda adecuadas Por ejemplo, en las expresiones: 4+x 1. Busco a x en la tabla de variables locales y parámetros del método actual. 2. Si no esta en esa tabla, busco x en la tabla de atributos de la clase actual. 3. Sino ERROR! 11

Resolución de Nombres La clave del proceso de resolución de nombres es como buscar los nombres en la tabla de símbolos Para eso la tabla de símbolos debe proveer las herramientas de búsqueda adecuadas Por ejemplo, en las expresiones: 4+x 10*m1(7) 1. Busco a m1 en la tabla de métodos de la clase actual. 2. Sino esta ERROR! 12

Resolución de Nombres Entonces el objetivo de la resolución de nombres es controlar que un nombre en cierto contexto refiere a la entidad adecuada Que sea la entidad adecuada depende de donde busquemos en la tabla de símbolos Si no esta en la tabla que corresponde se produce un error semántico El otro objetivo de la resolución de nombres es obtener la entrada de la entidad para poder efectuar: Chequeo de Tipos Traducción 13

Chequeo de Tipos El chequeo de tipos es el encargado de hacer cumplir las restricciones impuestas por las reglas del sistema de tipos del lenguaje Estas reglas en parte son las que indican como se pueden utilizar las entidades tipadas dentro de las sentencias del lenguaje Es decir, controlar que cuando un elemento tipado (variable, función, expresión) es utilizado en un contexto su tipo es el adecuado Si un elemento tipado no tiene el tipo esperado en el contexto utilizado se produce un error de tipos 14

Chequeo de Tipos En el chequeo de tipos es donde controlamos si los operadores utilizados en una operación son de tipos validos Por lo tanto, donde aplicaremos/consideraremos las reglas de tipos del lenguaje vinculadas a: Sobrecarga Coerción Equivalencia/Compatibilidad Polimorfismo 15

Chequeo de Tipos Como vieron en lenguajes el chequeo de tipos puede realizarse de dos maneras (no necesariamente disjuntas): Chequeos Estáticos: controles que se realizan en tiempo de compilación, durante el análisis semántico Chequeos Dinámicos: controles que se realizan en ejecución, donde el compilador genera código para realizar los cheques En esta clase nos centraremos en los chequeos estáticos. 16

Chequeo de Tipos Para poder realizar sus tareas de manera estática el chequeo de tipos requiere que los tipos de los elementos: Estén declarados, o Sean inferibles estáticamente Por ejemplo, en MiniJava: Por esta razón el chequeo de tipos no solo se encarga de controlar, sino puede llegar a tener que determinar tipos Los tipos estáticos de métodos y variables se declaran Los tipos estáticos de las expresiones se infieren estaticamente 17

Chequeo de Tipos En general el chequeo de tipos, implica chequear que: Los tipos de la expresión usada en una sentencia sean los requeridos Por ejemplo, en MiniJava: El tipo de la expresión de un while sea booleano El tipo la expresión del lado derecho de una asignación sea igual o un subtipo del tipo de la variable correspondiente con el identificador al final de la cadena del lado izquierdo

Chequeo de Tipos En general el chequeo de tipos, implica chequear que: Los tipos de las sub-expresiones en una expresión sean los adecuados. Por ejemplo, en MiniJava: El tipo de las sub-expresiones de una expresión binaria con operador + sea int El tipo de la sub-expresión de una expresión unaria con operador! sea boolean

Chequeo de Tipos y Resolución de Nombres En las expresiones y sentencias donde debemos realizar chequeos de tipos pueden aparecer nombres Al realizar el chequeo de tipos debemos resolver a que entidades hacen referencia eso nombres para obtener su tipo y controlar que se esta usando de forma adecuada Por lo tanto, la resolución de nombres se suele realizar en conjunto con (o como parte de) el chequeo de tipos 20

Chequeo de Sentencias en Analizadores de una Pasada 21

Chequeo Sentencias Una Pasada Cuando el análisis semántico se realiza de manera intercalada con el analizador sintáctico: El chequeo de sentencias se realiza a media que se van reconociendo sintácticamente las sentencias del programa Requiere que no haya referencias hacia adelante NO es el caso de MiniJava 22

Chequeo Sentencias Una Pasada EDT El diseño de los chequeos de tipos y la resolución de nombres se realiza mediante acciones en la EDT Se utiliza a la tabla de símbolos como una estructura global Para determinar los tipos estáticos de la expresiones se utilizan atributos de la gramática La complejidad de esta tarea esta asociada a la estructura de la gramática! 23

Chequeo de Sentencias sobre ASTs 25

Chequeo Sentencias Dos Pasadas Cuando el chequeo de sentencias se realiza de manera separada al sintáctico, se desarrolla sobre una representación alternativa del código fuente Nosotros utilizamos los ASTs como tal representación Este es el caso de MiniJava Por lo cual el modelo que se presentará y los ejemplos a continuación se corresponden con ese lenguaje. 26

Chequeo Sentencias Dos Pasadas ASTs Al diseñar los nodos del AST seguimos la intuición: Cada tipo de nodo se corresponde con un constructor sintáctico que tiene significado Por lo tanto, los controles semánticos van a estar asociados a cada tipo de nodo Intuitivamente entonces el chequeo de sentencias se realizará al visitar adecuadamente los nodos del AST 27

Chequeo Sentencias Dos Pasadas ASTs a = 4*(b+2); a Variable Token Asignación Lado Izq Lado Der 4 Entero Token Expresión Binaria Lado Izq Lado Der TokenOp * Expresión Binaria Lado Izq Lado Der TokenOp + Variable b Token 2 Entero Token

Chequeo Sentencias Dos Pasadas ASTs a = 4*(b+2); a Variable Token Chequear la asignación implica chequear el lado izquierdo y el lado derecho, obtener sus tipos y ver que sean compatibles Asignación Lado Izq Lado Der 4 Entero Token Expresión Binaria Lado Izq Lado Der TokenOp * Expresión Binaria Lado Izq Lado Der TokenOp + Variable b Token 2 Entero Token

Chequeo Sentencias Dos Pasadas ASTs a = 4*(b+2); a Variable Token Asignación Lado Izq Lado Der Chequear una Variable implica ver si está en la tabla de parámetros o variables del método actual, o sino si es una variable 4 de instancia de la clase actual y, en caso de estar, devolver su tipo Entero Token Expresión Binaria Lado Izq Lado Der TokenOp * Expresión Binaria Lado Izq Lado Der TokenOp + Variable b Token 2 Entero Token

Chequeo Sentencias Dos Pasadas ASTs a = 4*(b+2); a Variable Token Chequear una expresión binaria, implica chequear sus dos sub-expresiones y luego ver que sus tipos sean compatibles con el operador Asignación Lado Izq Lado Der 4 Entero Token Expresión Binaria Lado Izq Lado Der TokenOp * Expresión Binaria Lado Izq Lado Der TokenOp + Variable b Token 2 Entero Token

Chequeo Sentencias Dos Pasadas ASTs a = 4*(b+2); Chequear un Entero, implica retornar tipo Entero a Variable Token Asignación Lado Izq Lado Der 4 Entero Token Expresión Binaria Lado Izq Lado Der TokenOp * Expresión Binaria Lado Izq Lado Der TokenOp + Variable b Token 2 Entero Token

Chequeo Sentencias Dos Pasadas ASTs El chequeo de sentencias se realiza mientras que se van recorriendo los AST utilizando la información almacenada en la TS. Aprovechando como diseñamos los AST: Cómo sería una forma conveniente de estructurar la implementación estos controles?

Chequeo Sentencias ASTs Implementación Una implementación posible: Agregamos a cada tipo de nodo del AST un método donde implementaremos los controles asociados al nodo void chequear()* void chequear() void chequear() void chequear()

Chequeo Sentencias ASTs Implementación Una implementación posible: Agregamos a cada tipo de nodo del AST un método donde implementaremos los controles asociados al nodo void chequear()* Tipo chequear()* void chequear() void chequear() void chequear() Tipo chequear() Tipo chequear() Tipo chequear()

Chequeo Sentencias ASTs Implementación Las claves para implementar el chequeo de sentencias recorriendo el AST es que para cada nodo: Realizar los controles que le corresponden según al significado del nodo Delegar el chequeo de sentencias a cada uno de sus hijos 36

Chequeo Sentencias ASTs Implementación Pizarrón! Por Ejemplo (Pseudo codigo) NodoWhile NodoExpresion Condicion NodoSentencia Sentencia void chequear() Si el tipo LadoDer.chequear() no es el mismo o hereda del tipo de LadoIzq.chequear() entonces ERROR! Si Tipo de Condicion.chequear() no es boolean entonces ERROR! sino Sentencia.chequear() NodoAsignacion NodoAcceso LadoIzq NodoExpresion LadoDer token Simbolo void chequear()

Chequeo Sentencias ASTs Implementación El orden en que se realizan los controles y la delegación es importante ya que para los controles unos pueden depender de otros Si el tipo LadoDer.chequear() no es el mismo o hereda del tipo de LadoIzq.chequear() entonces ERROR! NodoAsignacion NodoVar LadoIzq NodoExpresion LadoDer token Simbolo void chequear() El control de la asignación depende de los tipos resultantes de los chequeos de sentencias de su lado derecho y de su lado izquierdo 38

Chequeo Sentencias ASTs Implementación En la asignación el nodo padre (nodoasignacion) depende de los resultados del control de sus hijos (lado izq y lado der) Existen situaciones inversas, donde un nodo hijo necesita información de un nodo padre Por ejemplo: Llamadas o acceso a atributos encadenados v.x Variable Encadenado Token v Variable Encadenada Encadenado Token x 39

Chequeo Sentencias ASTs Implementación En la asignación el nodo padre (nodoasignacion) depende de los resultados del control de sus hijos (lado izq y lado der) Chequear una variable encadenada implica controlar que este en la tabla de atributos de la clase correspondiente al tipo resultante de chequear al nodo ancestro (lo que esta a izquierda del punto). El tipo resultante dependerá de si es el ultimo elemento encadenado. Si lo es será el tipo de la variable, sino será el resultante de chequear lo encadenado Existen situaciones inversas, donde un nodo hijo necesita información de un nodo padre Por ejemplo: Llamadas o acceso a atributos encadenados v.x Variable Encadenado Token v Variable Encadenada Encadenado Token x 40

Chequeo Sentencias ASTs Implementación Cómo podemos resolver esto? Agregando parámetros de entrada en los métodos de chequeos de sentencias de los nodos correspondientes NodoOperando* Encadenado* Pizarrón! Tipo chequear() Tipo chequear(tipo t)* NodoVar Token nombre Encadenado cad Tipo chequear() NodoVarEncadenada Token nombre Encadenado cad Tipo chequear(tipo t) NodoLlamadaEncadenada Token nombre Lista<NodoExpresion> parametros Encadenado cad Tipo chequear(tipo t) 41

Chequeo Sentencias ASTs Implementación Cómo se estructura el chequeo de sentencias de todo el programa en un lenguaje como MiniJava? Debemos controlar el código de todas las unidades (métodos/constructores) del programa fuente Programa esta dividido en clases Básicamente realizar chequeo de sentencias para una clase implica realizar el chequeo de sentencias para todas sus unidades El chequeo de sentencias de un método/constructor implica realizar el chequeo del bloque principal de la unidad 42

Chequeo Sentencias ASTs Implementación El chequeo de sentencias usa las entidades declaradas para: Resolver Nombres Chequear sus tipos Las entidades deben estar correctamente declaradas!!! Por lo tanto debemos realizar primero el chequeo de declaraciones TS + ASTs Chequeo de Declaraciones + Consolidación Analizador Semántico TS* + ASTs Chequeo de Sentencias 43

Chequeo Sentencias ASTs Implementación En los lenguajes como MiniJava donde al herencia se implementa por copia, un método puede aparecer en la tabla de métodos de mas de una clase Qué consideración deberíamos tener en cuenta al realizar el chequeo de sentencias respecto a esto? Solo debemos chequear el cuerpo de un método en la clase donde fue declarado! 44

Chequeo Sentencias Errores Los errores semánticos en el chequeo de sentencias se producen en general cuando: Un nombre utilizado en una sentencia no se corresponde con la entidad adecuada al contexto donde es utilizado Se detecta una incompatibilidad de tipo en el contexto de una expresión o sub-expresion 45

Chequeo Sentencias Errores Para reportar los errores es necesario indicar en que numero de línea se produce el error En la segunda pasada ya no tenemos los tokens Por lo tanto, al diseñar los Nodos del AST se suele almacenar información adicional respecto al numero de línea Usualmente se determina con el token utilizado para caracterizar sintácticamente al nodo 46