UNIDAD V. Analisis Semantico. 5.1 Introduccion. Analizador Semántico. Verifica que el significado de las construcciones del lenguaje tengan sentido.

Documentos relacionados
Generación de Código Intermedio

Compiladores: Análisis Semántico. Pontificia Universidad Javeriana Cali Ingenieria de Sistemas y Computación Prof. Gloria Inès Alvarez V.

Qué es el análisis semántico?

ANÁLISIS SEMÁNTICO. Especificación formal: Semántica Operacional, semántica denotacional, semántica Axiomática, Gramáticas con Atributos.

Tema 5. Análisis semántico

Definición de la sintaxis (1) Definición de la sintaxis (2) Definición de la sintaxis (3)

Tema 5: Traducción dirigida por la sintaxis

Controla el flujo de tokens reconocidos por parte del analizador léxico. 4.2 Introduccion a las gramaticas libres de contexto y arboles de derivacion

Análisis semántico I Traducción dirigida por la sintaxis

Apunte Laboratorio ALPI - El lenguaje de programación Pascal

Analizador De léxico. V A R i : I N T E G E R ; \n...

Unidad Didáctica 2. Elementos básicos del lenguaje Java Tipos, declaraciones, expresiones y asignaciones

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

16 Análisis sintáctico I

Analizador Léxico. Programación II Margarita Álvarez. Analizador Léxico - Funciones

8.1.- FUNCIONES Y PROCEDIMIENTOS DEFINIDOS POR EL USUARIO EN TURBO PASCAL.

Procesadores de lenguaje Tema 5 Comprobación de tipos

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

Unidad II: Análisis semántico

ANÁLISIS DESCENDENTE. Compruébese que la siguiente gramática es LL(1) sin modificarla.

Objetivos Que el estudiante logre conocer, comprender y manejar conceptos y técnicas vinculados con el Analizador Léxico, para lo cual debe:

TEMA 3: ANÁLISIS SEMÁNTICO

Java. Introducción a la Programación Orientada a Objetos

ÁRBOLES DE SINTAXIS. Los nodos no terminales (nodos interiores) están rotulados por los símbolos no terminales.

Tema: Análisis Semántico

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

Capítulo 5: Traducción Dirigida por Sintaxis

Conceptos básicos sobre gramáticas

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

Unidad 2. Introducción Lenguajes y Compiladores

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

Módulo. = Asignación = = Comp. de igualdad!= Com. de desigualdad <= Comp. menor o igual >= Comp. mayor o igual AND lógico OR lógica.

Curso de Java Introducción a la Programación II

PROCESADORES DE LENGUAJE EXAMEN FINAL 8-JUNIO-07

PROCESADORES DE LENGUAJES I PRÁCTICA DE LABORATORIO 4

Elementos de un programa en C

UNIDAD IV Programación Funcional. Lic. Jesús Germán Andrés PAUTSCH - FCEQyN - UNaM

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

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

Introducción al lenguaje C

Arboles. Definiciones formales: 1) un árbol es un grafo acíclico finito T (P, E) tal que. P = E + 1 => todo arco es desconectante.

Manual de turbo pascal

Lenguajes y Compiladores Análisis Sintáctico Parte I. Teoría Lenguajes 1

Lenguaje de programación C. Introducción

Estatutos de Control C# Estatutos de Decisión (Selección)

FUNDAMENTOS DE INFORMÁTICA

Compiladores: Sesión 15. Análisis semántico, traducción dirigida por sintaxis

DEFINICIONES BÁSICAS DE LAS ESTRUCTURAS DE DATOS

4. Operadores Operador asignación

Tema 2: Análisis léxico

FUNDAMENTOS DE OBJECT PASCAL

ALGORÍTMICA. Dpto. Ingeniería de Sistemas y Automática Facultad de Ciencias Universidad de Valladolid.

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

Informática PRÀCTICA 3 Curs Práctica Nº 3: Tipos de datos simples. Constantes y variables. Operadores aritméticos. Formato de salida.

Principios de Computadoras II

JavaScript Básico. Elementos Básicos: Comentarios: Literales: Valores que puede tomar una variable o una constante.

2.2 Nombres, Ligado y Ámbito

Componentes Básicos. InCo. InCo Componentes Básicos 1 / 28

Todo programa en 'C' consta de una o más funciones, una de las cuales se llama main.

LABORATORIO DE PROCESADORES DE LENGUAJE Curso: Práctica 2: Analizador léxico/sintáctico/semántico con Flex y Bison

Tema 1.2. Un lenguaje mínimo y su procesador: Gramáticas de atributos y tabla de símbolos

Programación en Lenguaje C

Un. VI. Generador de código intermedio.

Docente: Juan Carlos Pérez P. Alumno : Fecha : Nota:

Tema 8: Tipos de datos. Sesión 24: Tipos de datos (1)

Java para programadores

COMPILADORES E INTERPRETES

Lenguaje C. República Bolivariana de Venezuela Fundación Misión Sucre Aldea Fray Pedro de Agreda Introducción a la Programación III

Lenguajes de Programación Programación funcional

Elementos léxicos del lenguaje de programación Java

Tipos Recursivos de Datos

CUP. Diseño de compiladores. Estructura del archivo CUP. Estructura del archivo CUP. Estructura del archivo CUP. Estructura del archivo CUP 20/04/2014

Unidad I: Análisis semántico

EJERCICIO 2 (3 PUNTOS) A) Sea el árbol binario AVL de la figura siguiente: B) Dada la estructura de la figura siguiente:

Algoritmos y programas. Algoritmos y Estructuras de Datos I

Introducción a Java. Introducción a Java. Programación I

Introducción a PL/SQL

PROGRAMACIÓN ORIENTADA A OBJETOS (L40629) Sabino Miranda-Jiménez

El lenguaje C. 1. Identificadores, constantes y variables

YACC. Los símbolos terminales que la gramática empleará. El axioma o símbolo inicial de la gramática. %token. %start

Estructura de datos Tema 2: Tipos Abstractos de Datos (TADs)

Análisis semántico. Análisis semántico. Índice

Desde los programas más simples escritos en un lenguaje de programación suelen realizar tres tareas en forma secuencial.

INTRODUCCIóN A LA PROGRAMACIóN APUNTES DE JAVA APUNTES DE JAVA

FUNCIONES. Identificador valido. Tipo-Funcion Identificador_de_la_funcion (Tipo par1,tipo par2 )

Unidad II. Fundamentos de programación en Java. Ing. José Luis Llamas Cárdenas

Funciones Definición de función

Compiladores: Sesión 16. Análisis semántico, traducción dirigida por sintaxis

FASES DE UN COMPILADOR

TUTORIAL PSEINT. Ing. Ronald Rentería Ayquipa. Fundamentos de Programación

Lenguajes de Programación. Capítulo 4. Expresiones.

Examen de Procesadores de Lenguaje

Tema 3. Tipos de datos simples

Centro Asociado Palma de Mallorca. Antonio Rivero Cuesta

U nidad 6: A rreglos: U nidim ensionales y m ultidim ensionales

Código Intermedio. Compiladores II 1

Modelos de Desarrollo de Programas Y Programación Concurrente Clase N 3

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

Tema 7. Generación de código

Tema 2. El lenguaje JAVA

Transcripción:

UNIDAD V Analisis Semantico 5.1 Introduccion Analizador Semántico. Ejemplo: Verifica que el significado de las construcciones del lenguaje tengan sentido. Tareas del analizador semántico: 1) Comprobación de Tipos. 2) Comprobación de parámetros. 3) Generación de código intermedio. A : float ; B : string ;... A := B + 5 ; Analizador Léxico id 1 : float ; id 2 : string ;... id 1 := id 2 op num ; TABLA DE SÍMBOLOS Lexema Complex Tipo... 1 A id? 2 B id? 3 5 num?

Analizador Sintáctico := A + Analizador Semántico B 5 Hasta aquí la entrada es lexica y sintacticamente valida, ahora se analiza desde el punto de vista semantico: := id 1.entrada + real id 2.entrada cadena num entero (1) ERROR_TIPO ERROR_TIPO = No hay compatibilidad de tipos cadena + entero = ERROR_TIPO Un compilador puede necesitar tener en cuenta muchas características además del código generado para la construcción de entrada. Para realizar un análisis semántico a cada construcción del lenguaje se le asocia una serie de atributos así como de acciones o reglas semánticas. Un atributo es información asociada a un terminal o a un no-terminal, y puede representar una cadena o una posición de memoria. Regla Semántica: Acción o conjunto de acciones(algoritmo) para calcular el valor de los atributos.

Los analizadores semánticos se construyen asociando una serie de atributos y acciones o reglas semánticas a cada construcción del lenguaje. Dos formas de asociarlo: 1) Definición dirigida por la sintáxis. 2) Esquema de traducción. En ambos casos es útil definir un conjunto de atributos a los símbolos gramaticales del lenguaje. Dos tipos de atributos: 1) Sintetizados. 2) Heredados. 5.2 Definiciones dirigidas por la sintaxis Definición dirigida por la sintáxis = Gramática + Reglas Semánticas El concepto Definición dirigida por la sintáxis se utiliza para especificar las traducciones para las construcciones del lenguaje(sentencias) en función de atributos asociados con sus componentes sintácticos. Una definición dirigida por la sintáxis usa una gramática para especificar la estructura sintáctica de la entrada. A cada símbolo de la gramática se le asocia un conjunto de atributos y a cada producción un conjunto de reglas semánticas, para calcular los valores de los atributos asociados con los símbolos que aparecen en esa producción. Las definiciones dirigidas por la sintáxis no solo se utilizan para la comprobación de tipos, se puede usar para transformar una sentencia o cadena de entrada a cualquier forma de salida. Ejemplo: Definición dirigida por la sintáxis para traducir expresiones infijas a postfijas: PRODUCCION Expr expr1 + término expr expr1 - término Expr término termino 0 termino 1 Termino 9 REGLA SEMÁNTICA expr.t := expr 1.t término.t + expr.t := expr 1.t término.t - expr.t := término.t termino.t := 0 termino.t := 1 termino.t := 9

Infija 9 5 + 2 Postfija 9 5 2 + operando operando operador expr.t="95-2" expr.t="95-" + termino.t="2" expr.t="9" - termino.t="5" '2' termino.t="9" '5' '9' Tipos de atributos. Tipos sintetizados heredados Sintetizados. Su valor esta en función de los atributos en nodos hijos. B.b A.a C.c Donde: son atributos si... es sintetizado

Heredados. Su valor esta en función de los atributos en nodos padres y/o hermanos. A.a Donde: A, b, c son atributos si c := f(b,a)... es heredado B.b C.c Definición dirigida por la sintáxis para la declaración de identificadores integer y real PRODUCCION D T L L.h := T.tipo REGLA SEMÁNTICA T int T.tipo := integer T real L L 1, id T.tipo := real L 1.h := L.h anadetipo(id.entrada,l.h) L id anadetipo(id.entrada,l.h) Tipo de Atributo Atributo L.h T.tipo heredado sintetizado Ejemplo: Analizar la siguiente sentencia de entrada: int num Analizador Léxico int id

Analizador Sintáctico D T int L id Analizador Semántico D.tipo = integer T.tipo = integer L.h = integer int id.entrada = 1 Ejercicios: 1. Similar al ejemplo anterior, evaluar la siguiente sentencia de entrada: real a, b, c 2. La siguiente gramática genera expresiones separadas mediante el operador aritmético + a constantes enteras y reales. Cuando se suman 2 enteros el tipo obtenido es un entero de lo contrario es real: E E + T T T num.num num

5.3 Esquemas de traducción. ENFOQUE DEL DISEÑO DEL ANALIZADOR Definición dirigida por la sintáxis Esquema de traducción Gramática + Reglas Semánticas. No aplican un orden estricto de evaluación. Gramática + Acciones Semánticas. Indican el punto preciso en que se debe evaluar la acción. Un esquema de traducción es una gramática independiente de contexto en la que se asocian atributos con los símbolos gramaticales y se insertan acciones semánticas encerradas entre llaves dentro de los lados derechos de las producciones. Los esquemas de traducción son una notación útil para especificar la traducción durante el análisis sintáctico. Ejemplo: El siguiente esquema de traducción transforma expresiones infijas con suma y resta en expresiones postfijas : Acciones Semánticas E T R R oparit T { printf(oparit.lexema) } R 1 ε T num { printf(num.lexema) } Equivalente a un símbolo gramatical

E T R num {printf(num.lexema)} oparit {printf(oparit.lexema)} Las acciones encerradas entre llaves se consideran como símbolos terminales, lo cual es conveniente para establecer cuando se deben ejecutar las acciones. Es decir, los esquemas de traducción establecen el orden preciso en que de deban evaluar las acciones semánticas. 5.4 Comprobación de tipos. Un Comprobador de Tipos se asegura de que el tipo de una construcción coincida con el previsto en su contexto. Por ejemplo, el operador mod en Pascal exige operándoos de tipo entero, de igual manera debe asegurarse de que la indización que se haga sobre una matriz sea con un índice entero, y de que a una función definida por el usuario se aplique el número y tipo correcto de argumentos. Cadena de componentes léxicos Analizador Sintáctico Árbol Sintáctico Comprobador de tipos Ubicación de un comprobador de tipos. Generador de código intermedio Árbol Sintáctico Representación intermedia Un compilador debe comprobar si el programa fuente sigue las convenciones sintácticas y semánticas del lenguaje fuente. Dicha comprobación puede ser de dos tipos:

1. Estática. La comprobación ocurre al compilador. 2. Dinámica. La comprobación se realiza al ejecutar el programa En la comprobación Estática existen las siguientes ventajas: i. Facilita la depuración de programas ya que verifica los errores posibles. ii. No requiere guardar toda la información acerca de los objetos de datos. En la comprobación Dinámica su ventaja principal es la flexibilidad que permite en el diseño de lenguaje ya que: a) No requiere una definición previa del tipo de dato para las variables. b) El tipo de dato asociado al nombre de la variable puede cambiar durante su ejecución. Comprobación Estática Lenguajes orientados a los tipos ( ej. Pascal ) Comprobación Dinámica FoxPro al momento de la ejecución... store 100 to vcalif [ vcalif toma el tipo int] store reprobados to vcalif [vcalif toma el tipo cadena] vprom = vcalif / 100 [Error_tipo] 5.5 Expresiones de tipo. Es o bien un tipo básico (booleano,char,integer,real) o una expresión que se forma aplicando un operador llamado constructor de tipos a otras expresiones de tipo 1. Tipo Básico. Un tipo básico es por si solo una expresión de tipo; al conjunto de tipos básicos se agregan el tipo básico especial error_tipo, el cual señala el error durante la comprobación de tipos. Además un tipo básico vacío que indica la ausencia de valor y permite que se compruebe las proposiciones que no requieren un tipo de dato específico. id := x * a real := real * char S if E then S 1 S.tipo <------- {ERROR_TIPO} vacio ERROR_TIPO if E.tipo then S 1.tipo BOOLEAN VACIO ERROR_TIPO

2. Constructor de tipos. Un constructor de tipos aplicado a expresiones de tipo es también una expresión de tipos. Los constructores de tipos incluyen: i. MATRICES: Si T es una expresión de tipo, entonces: array ( I, T ) es una expresión de tipo que indica el tipo de una matriz con elementos de tipo T y un conjunto de índices I, donde I es un rango de enteros. Ejemplo: var A : array [ 1...10 ] of integer Cuál es la expresión de tipo para A? array ( 1...10, integer ) ii. PRODUCTOS: Si T 1 y T 2 son expresiones de tipo entonces su producto cartesiano: T 1 x T 2 es también una expresión de tipo. Este tipo de constructor se utiliza para definir los tipos de elementos individuales de un tipo del mayor nivel. Ejemplo: var A : array [ 1...10 ] of integer su expresión de tipo como producto seria: int x int... x int ( hasta 10 veces )

iii. REGISTROS: El constructor de tipos record se aplicará a una tabla formada con nombres de compras y tipos de datos. Ejemplo: type fila = record direccion : integer; lexema : array[1...15] of char; end; La expresión de tipo para la declaración del tipo fila es: record (int x array ( 1...15, char ) iv. APUNTADORES Si T es una expresión de tipo, entonces: pointer ( T ) es una expresión de tipo que indica el tipo " apuntador a un objeto de tipo T ". Ejemplo: var i : integer La expresión de tipo para i sería: pointer ( int ) v. FUNCIONES. Indica el tipo de una función que transforma un dominio de tipo D a un rango tipo R. La expresión de tipo: D R indicará el tipo de función. Por ejemplo, la función predefinida "mod" de pascal tiene un dominio de tipo: int x int es decir, un par de enteros y rango de tipo: int entonces la expresión de tipo completa es: int x int int

Ejemplo: function ( a, b : char ) : integer char x char pointer ( int ) Ejercicio. Dar la expresión de tipo para: a) int *miarreglo [10] b) void func ( char *c, int i, flota f ) c) byte tridi [5][10][15] d) class miclase { int i; bool b; double d [20]; void m1 ( ); bool m2 ( double d ); }

5.6 Comprobador de tipos de ejemplo. Este esta diseñado como un esquema de traducción que sintetiza el tipo de cada expresión: P D ; S D D ; D D id : T {anadetipo(id.entrada),t.tipo);} T char {T.tipo:=char;} T integer {T.tipo:=integer;} T T 1 {T.tipo:=pointer(T 1.tipo);} T array[num] of T 1 {T.tipo:=array(num.entrada,T 1.tipo);} S id:=e {S.tipo:=if buscatipo(id.entrada)==e.tipo then VACIO; el se ERROR_TIPO;} S if B then S 1 {S.tipo:=if B.tipo==BOOLEAN AND S 1.tipo==VACIO then VACIO; else ERROR_TIPO;} S while B do S 1 {S.tipo:=if B.tipo==BOOLEAN AND S 1.tipo==VACIO then VACIO; else ERROR_TIPO;} S S 1 ; S 2 {S.tipo:=if S 1.tipo== VACIO AND S 2.tipo==VACIO then VACIO; else ERROR_TIPO;} E literal {E.tipo:=char;} E num {E.tipo:=integer;} E id {E.tipo:= buscatipo(id.entrada);} E E 1 mod E 2 {E.tipo:=if E 1.tipo==integer AND E 2.tipo==integer then integer ; else ERROR_TIPO;} E T {E.tipo := T.tipo } E 1 E 2 + T {E 1.tipo := if E 2.tipo = integer AND T.tipo = integer then Integer Else ERROR_TIPO } T F {T.tipo := F.tipo } T 1 T 2 * F {T.tipo := if T 2.tipo = integer AND F.tipo = integer then Integer Else ERROR_TIPO } F (E) {F.tipo := E.tipo } F id {F.tipo := buscatipo ( id.entrada ) } F num {F.tipo := integer } B E 1 oprel E 2 {B.tipo := if E 1.tipo == E 2.tipo then BOLEAN else ERROR_TIPO }

Ejemplo: Hacer la comprobación de tipo del siguiente programa x : char ; y : integer ; x : = Hola muchachos ; if y > 5 then y : = x ; Analizador Léxico id 1 : char; id 2 : integer; id 1 := literal 3 ; if id 2 oprel num 4 id 2 :=id 1 ; then Analizador Sintáctico Semántico P D 1 ; S 1 D 2 ; D 3 S 2 ; S 3 id 1 : T 1 id 2 : T 2 id 1 := E 1 if B then S 4 char integer literal 4 id 2 := E 2 id 1

Recorrido del árbol (Comprobador de Tipos) ATRIBUTOS Símbolo p D 1 D 2 D 1 T 1 T 2 S 1 S 2 S 3 E 1 S 4 E 2 B Tipo char integer ERROR_TIPO VACIO ERROR_TIPO char ERROR_TIPO char BOOLEAN... ERROR_TIPO (No hay compatibilidad de tipos) 5.7 Diseño de un traductor predictivo Esquema de traducción con una gramática adecuada para él analisis predictivo Traductor predictivo Algoritmo Algoritmo : 1. Para cada no-terminal A 1 constrúyase una función que tenga un parámetro formal para cada atributo heredado de A y que devuelva los atributos sintetizados de A. La función para A tiene una variable local para cada atributo de cada símbolo gramatical que aparezca en una producción para A. 2. El código para el no-terminal A decide que producción utiliza basándose en el símbolo en curso de entrada. 3. El código asociado con cada producción hace lo siguiente: a) Para el símbolo terminal X con atributos sintetizados x, guardese el valor de x en la variable declarada X.x después emparéjese X. b) Para el no-terminal B genérese una asignación

c := B ( b 1, b 2,... b n ) Donde: b 1,b 2,...b n son las variables para los atributos heredados de B. c es la variable para el atributo sintetizado de B. c) Para el caso de una acción semántica cópiese el código de la acción dentro del analizador sintáctico, sustituyendo cada referencia a un atributo por la variable correspondiente a dicho atributo. Ejemplo: Implementar la siguiente producción que sirve para declarar un identificador y su correspondiente tipo de dato. La accion semántica 4 sirve para registrar el tipo de dato del identificador en la tabla de símbolos. V -> id : T {4} {4} = { anadetipo ( id.entrada, T.tipo ) V.tipo := VACIO } El pseudocodigo que implementa el procedimiento del símbolo V seria: void V ( TAtributos _V ) { TAtributos _T; // Atributos del símbolo T TAtributos id; // Atributos del símbolo id String complex; // Símbolo de preanalisis complex = be.preanalisis.complex; // Obtiene una copia del simbolo de preanalisis if ( PRIMEROS ( complex, V ) ) { id = be.preanalisis; // Salva los atributos del símbolo id emparejar ( id ); emparejar ( : ); T ( _T ); // Accion semántica 4 ------------------------------- ts.anadetipo ( id.entrada, _T.tipo ); _V.tipo = VACIO; } } else // fin de la accion semántica 4 ------------------------ error ( ); // error sintactico Ejemplo: Considere la siguiente producción que genera la sentencia SQL

S -> DELETE FROM id WHERE C { 1 } {1} = { S.tipo := if buscatipo ( id.entrada ) = TABLA AND C.tipo = bolean then vacio else error_tipo } El pseudocodigo que implementa el procedimiento del símbolo S seria: procedure S ( TAtributosSS _S ) begin TAtributosSS _C // Atributos del simbolo C ( tanto heredados como sintetizados ) TAtributosSS id // Atributos del simbolo id ( ) If preanalisis = DELETE then Begin emparejar ( DELETE ) emparejar ( FROM ) // Salvamos los atributos de id antes de emparejarlo. Solo salvamos el atributo entrada // porque es el unico que se utiliza de id en las acciones semánticas de esta producción. id.entrada := preanalisis.entrada emparejar ( id ) emparejar ( WHERE ) // Invocamos el procedimiento de C pasandole sus atributos heredados y // después de la llamada nos devolvera sus atributos sintetizados C ( _C ) end; End Else // Accion semántica 1 If buscatipo ( id.entrada ) = TABLA AND _C.tipo = boolean then begin end else begin _S.tipo := VACIO _S.tipo := ERROR_TIPO error ( ) // Error Semantico end //Fin de la Accion semántica 1 error ( ) // Error Sintactico

5.8 Manejo de errores semanticos Libro: Compiladores. Conceptos fundamentales Capitulo: 6 Tema: 6.5 Errores semanticos, pag. 126