Actividad 2 Analizador léxico, sintáctico y semántico

46,776 views

Published on

  • Be the first to comment

Actividad 2 Analizador léxico, sintáctico y semántico

  1. 1.  Actividad 2 Programación Tema: Conocer la importancia de unanalizador léxico, sintáctico y semántico apartir de un generador de código.
  2. 2. Análisis Léxico. El analizador léxico es la primera fase de uncompilador, lee caracteres de entrada para formar componentes eidentificarlos o clasificarlos y pasar la información de los componentes alanalizador sintáctico.Realiza además funciones como eliminar espacios en blanco, saltos delínea, tabuladores, ignorar comentarios, detección y recuperación deerrores. Los errores que un analizador léxico reconoce son símbolos noválidos o no reconocidos por el léxico del lenguaje o que no forman partede ningún componente léxico.
  3. 3.  También entre sus funciones están .Manejar el fichero fuente Leer los caracteres de la entrada Generar una secuencia de componentes léxicos (TOKENS) Eliminar comentarios, delimitadores (espacios, símbolos de puntación, fin de línea) Relacionar los mensajes de error con las líneas del programa fuente Introducir los identificadores en la tabla de símbolos Manejar macros Controlar si es de formato libre o no Libre: PASCAL, ALGOL No libre: FORTRAN, BASIC
  4. 4. Análisis Sintáctico. Gramática _ Permite definir un lenguaje mediante reglas que nos permiten generaro producir cadenas de un lenguaje. _ Estas gramáticas son similares a las gramáticas de los lenguajesnaturales, pero mucho más restrictivas y sencillas. _ Un ejemplo de regla de una gramática: Oración _ Sujeto predicado _ Estas reglas se suelen llamar reglas de reescritura: el símbolo Oraciónse puede reescribir por el símbolo Sujeto seguido del símbolo Predicado. Autómata: Al igual que con los lenguajes regulares podemos definir un autómatacomo una máquina reconocedora de cadenas (palabras) de undeterminado lenguaje. Los autómatas con los que trabajaremos en este tema son algo máscomplejos que los AF
  5. 5. Análisis Semántico. La fase de análisis semántico de un procesador de lenguaje esaquélla que computa la información adicional necesaria para elprocesamiento de un lenguaje, una vez que la estructurasintáctica de un programa haya sido obtenida. Es por tanto lafase posterior a la de análisis sintáctico y la última dentro delproceso de síntesis de un lenguaje de programación. Sintaxis de un lenguaje de programación es el conjunto de reglasformales que especifican la estructura de los programaspertenecientes a dicho lenguaje. Semántica de un lenguaje deprogramación es el conjunto de reglas que especifican elsignificado de cualquier sentencia sintácticamente válida.Finalmente, el análisis semántico1 de un procesador de lenguajees la fase encargada de detectar la validez semántica de lassentencias aceptadas por el analizador sintáctico.
  6. 6. 2. Que es el análisis léxico en cuantoa: a) manejo de localidades temporales de memoria (buffers) La forma más fácil de leer un programa es carácter por carácter pero es ineficiente. La forma más eficiente es realizar una copia a la memoria de todo el código fuente. Pero esto en lagran mayoría de las ocasiones es impráctico por las dimensiones de los programas. Para solucionareste problema se sugiere utilizar buffers. Manejo de buffers: Existen muchas formas de dividir el trabajo, pero siempre se deberá llevar dos punteros, uno alcarácter actual y otro al inicial del lexema. El manejo de buffers es esencial para realizar el análisis de grandes programas de mejor manera La diferente de velocidad entre los dos tipos de memoria es muy grande, por lo que resultainteresante definir algún tipo de estrategia que reduzca este diferencial. Un buffer se define como un conjunto de bytes que son leídos o escritos desde un dispositivo dealmacenamiento, en la memoria primaria. Cuando se desea leer una información, se lee un bloquede información en el que aparece. La modificación de un dato se realiza sobre el buffer, queposteriormente debe ser enviado al dispositivo de almacenamiento. La utilización de esta técnicapermite reducir el número de accesos a memoria secundaria.
  7. 7.  Número de Buffers y Velocidad de Acceso: El manejo de buffers por parte del administrador de ficherospermite reducir el número de accesos a memoria secundaria.Pero una cuestión fundamental es el número de buffers a utilizar.Si sólo se utiliza un buffer, un problema que realice lecturas yescrituras de modo alterno, debería leer un bloque en cadaoperación. - Esto se resuelve mediante la utilización de un bufferpara escritura y otro para lectura. Pero la lectura, o escritura,alterna sobre varios ficheros puede provocar el mismo problema.Otra alternativa es la utilización de ambos bloques para lecturas yescrituras de modo alternado. La generalización de esta idea es el caso real, varios buffers quese manejan de modo indistinto para lecturas y escrituras. Lagestión de estos buffers es realizada por el administrador deficheros, aunque el usuario puede controlar el número de buffers. Si todos los buffers están ocupados, se debe vaciar uno de ellospara posibilitar una lectura. Normalmente se utiliza al algoritmoLRU, es decir, se vacía el buffer menos recientemente utilizado.
  8. 8. b) creación de tablas de símbolos Tabla: conjunto de pares clave-valor, llamados elementos de latabla. La tabla de símbolos es una componente necesaria de uncompilador. Al declarar un identificador (normalmente una solavez), éste es insertado en la tabla. Cada vez que se utilice elidentificador se realizará una búsqueda en la tabla para obtenerla información asociada (el valor). Verifican que la semántica seacorrecta y ayuda en la generación apropiada del código. Búsqueda: dada la clave de un elemento, encontrar su valor. Inserción: Dado un par clave-valor, añadir un elemento nuevo a latabla. Cambio de valor: Buscar el elemento y cambiar su valor. Borrado: Eliminar un elemento de la tabla.
  9. 9.  Longitud de búsqueda (o tiempo de acceso): De una clave: Li = número de comparaciones con elementos de la tabla para encontrar esaclave. Máxima: LM = número máximo de comparaciones para encontrar cualquier clave.Media (esperada): Lm = número medio de comparaciones para encontrar un valor. Si lafrecuencia de todas las claves es la misma: Lm = (S Li)/N Si la frecuencia de todas las claves no es la misma: Lm = S pi.Li Grado de ocupación: s = n/N donde n=número de elementos en la tabla y N=capacidad máxima de la tabla. Función debúsqueda: B : K E asocia a cada clave k un elemento B(k).→ Valor asociado a una clave k: v(B(k)). Puede ser múltiple, en cuyo caso normalmente seconvierte en un puntero. Si está en la tabla puede almacenarse consecutivamente o ensubtablas paralelas. Tablas de símbolos (identificadores) La clave es el identificador. El valor está formado por: Atributos del identificador. Puntero a la posición de memoria asignada. La clave puedesustituirse por un puntero. Los identificadores pueden estar empaquetados. La longitud del identificador puede especificarse en la tabla o delante del nombre, o serimplícita. Tablas consecutivas: Todos los elementos ocupan posiciones de memoria adyacentes.Tablas ligadas: cada elemento apunta al siguiente. Tablas doblemente ligadas: cadaelemento apunta al siguiente y al anterior. Tablas no ordenadas Inserción: en el primer lugarvacío.
  10. 10. c) Manejo de erroresléxicos El compilador tiene que reportar clara y exactamente la presencia de errores recuperarse decada error lo suficientemente rápido para poder detectar errores subsecuentes, debe tratarde evitar mensajes falsos de error, Un error produce un token erróneo. Un token o componente léxico es una cadena de caracteres que tiene un significadocoherente en cierto lenguaje de programación. Recuperación en modo pánico: este tipo de estrategia es la más común. Consiste en quecuando se detecta una cadena no reconocible, se siguen leyendo caracteres hasta que sevuelve a detectar un token válido. Borrar un carácter extraño. Insertar un carácter que falta(e.g. reemplazar 2C por 2*C). Reemplazar un carácter incorrecto por otro correcto (e.g.reemplazar INTEJER por INTEGER si el lugar en donde aparece el primer lexema no es elindicado para un identificador) Intercambiar dos caracteres, ó tokens, adyacentes (e.g. IINTEGER por INTEGER I). La recuperación de errores durante el AL puede producir otros en las siguientes fases. varnumero : integer; begin num?ero:=10; end el compilador podría producir los siguientesmensajes de error: ERROR LÉXICO: carácter no reconocido (?) ERROR SEMÁNTICO:identificador no declarado (num) ERROR SINTÁCTICO: falta operador entre identificadoresERROR SEMÁNTICO: identificador no declarado (ero) Otras veces no: var i,j: integer; begin i:=1; ? j:=2; end
  11. 11.  3. Que es el análisis sintáctico en cuanto a: a) Diagramas de sintaxis. Es una forma que los árboles de derivación, su principal característica esque permite ver ls derivaciones al instante de que ocurren Ejemplo 1:Dado el siguiente ejemplo de código en C: superficie = base * altura / 2; La sintaxis del lenguaje C indica que las expresiones se pueden formarcon un conjunto de operadores y un conjunto de elementos básicos.Entre los operadores, con sintaxis binaria infija, se encuentran laasignación, el producto y la división. Entre los elementos básicos de unaexpresión existen los identificadores y las constantes enteras sin signo(entre otros). Su semántica identifica que en el registro asociado al identificadorsuperficie se le va a asociar el valor resultante del producto de losvalores asociados a base y altura, divididos por dos (la superficie de untriángulo).
  12. 12. b) Precedencia de operadores. La precedencia de operadores es de vital importancia en elproceso de análisis sintáctico ya que nos representará laforma en que debe construirse el árbol de derivación. En aritmética existen prioridades, por ejemplo: * y / tienenpreferencia sobre + y -. () indican la máxima prioridad. Prioridad de operadores • La instrucción a = b + c / 2 en la mayoría de los lenguajesno se evalúa de la forma a = (b + c) /2, sino de la forma a = b+ (c/2) • La forma de evaluación depende de cómo se construyanlos operadores, ya sea en infijo, postfijo o prefijo. • Las operaciones se realizan de abajo hacia arriba.
  13. 13. Analizador sintáctico: analizadordescendente (LL), analizadorascendente (LR, LALR). Un analizador sintáctico ( Parser ) es un programa que reconocesi una o varias cadenas de caracteres forman parte de undeterminado lenguaje. Los lenguajes habitualmente reconocidospor los analizadores sintácticos son los lenguajes libres decontexto. Cabe notar que existe una justificación formal queestablece que los lenguajes libres de contexto son aquellosreconocibles por un autómata de pila, de modo que todoanalizador sintáctico que reconozca un lenguaje libre de contextoes equivalente en capacidad computacional a un autómata depila. Los analizadores sintácticos fueron extensivamenteestudiados durante los años 70 del siglo XX, detectándosenumerosos patrones de funcionamiento en ellos, cosa quepermitió la creación de programas generadores de analizadoressintáticos a partir de una especificación de la sintaxis dellenguaje, tales y como yacc, GNU bison y javacc.
  14. 14. Analizador Descendente Ll Análisis Sintáctico Predictivo Recursivo La siguiente fase en la construcción del analizador es la fasede análisis sintáctico. Esta toma como entrada el flujo determinales y construye como salida el árbol de análisissintáctico abstracto. El árbol de análisis sintáctico abstracto es unarepresentación compactada del árbol de análisis sintácticoconcreto que contiene la misma información que éste. Existen diferentes métodos de análisis sintáctico. Lamayoría caen en una de dos categorías: ascendentes ydescendentes. Los ascendentes construyen el árbol desdelas hojas hacia la raíz. Los descendentes lo hacen en modoinverso. El que usaremos aqui es uno de los más sencillos:se denomina método de análisis predictivo descendenterecursivo.
  15. 15. Analizador Ascendente Lr Lalr Analizador Ascendente LR Intenta construir un árbol de análisissintáctico, empezando desde la raíz ydescendiendo hacia las hojas. Lo que es lomismo que intentar obtener una derivaciónpor la izquierda para una cadena de entrada,comenzando desde la raíz y creando losnodos del árbol en orden previo. LL (left to left) leen la cadena de izquierda aderecha y derivan por la izquierda
  16. 16. Administración de tablas desímbolos. Ésta poseerá una entrada por cada identificador declarado en elcontexto que se esté analizando. Con este tipo de estructuras de datosadicionales, los desarrolladores de compiladores acostumbran a suplirlas carencias de las gramáticas libres de contexto. La tabla de símbolos registra información acerca de cada nombre desímbolo en un programa. Históricamente, los nombres se llamaronsímbolos, más que de una tabla de nombres. En este capítulo, la palabrasímbolo significa nombre. La fase de análisis semántico crea la tabla desímbolos, puesto que no es sino hasta este análisis que se tiene lasuficiente información sobre un nombre para describirlo. La generaciónde código usa la tabla de símbolos para extraer las directivas delensamblador, para el tipo y para el tamaño apropiados.” Una tabla de símbolos es una estructura de datos que contiene unregistro por cada identificador. El registro incluye los campos para losatributos del identificador. El administrador de la tabla de símbolos se encarga de manejar losaccesos a la tabla de símbolos, en cada una de las etapas de compilaciónde un programa.
  17. 17.  Análisis sintáctico. Como se muestra en la Figura 1, la entrada del analizadorsemántico es la salida generada por el analizador sintáctico. La estructura empleadapara intercambiar la información entre estas dos fases es lo que se conoce como árbolsintáctico –o una simplificación del mismo, denominada árbol sintáctico abstracto (§2.2). Una vez validada la sintaxis de un programa, el análisis semántico aplicará reglassemánticas para validar dicho árbol. e) Manejador de errores. Si la validación del árbol sintáctico descrita en el párrafoanterior no fuese satisfactoria, es decir, existiese un error semántico, la fase de análisissemántico debería notificar dicho error al manejador de errores para que éste seencargase de su gestión. El proceso de análisis podría seguir ejecutándose o no, enfunción de si el procesador de lenguaje implementa algún mecanismo de recuperaciónde errores. − Generación de código (intermedio). La salida del análisis semántico se sueleemplear como entrada para la generación de código12. La estructura de datosempleada para intercambiar información entre las dos fases mencionadas es un árbolsintáctico decorado (§ 2.2). Este árbol posee información adicional al árbol generadopor el analizador sintáctico, como por ejemplo la información relativa al tipo de cadauna de las expresiones del programa. El empleo de dicha información es útil para llevara cabo el proceso de generación de código (a bajo nivel, el tipo de una expresión esnecesario, por ejemplo, para saber el número de bytes que ocupa su valor). − Tabla de símbolos. Como hemos mencionado previamente, la utilización degramáticas libres de contexto (de tipo 2) no permite expresar característicasrepresentables con gramáticas sensibles al contexto –como la necesidad de que lautilización de una variable en el lenguaje Pascal requiera la declaración previa de lavariable utilizada. Para poder implementar un procesador del lenguaje Pascalempleando gramáticas de tipo 2 e implementaciones de autómatas de pila, esnecesario emplear una estructura de datos auxiliar denominada tabla de símbolos. Estaestructura de datos, a su nivel más básico, es un diccionario (memoria asociativa) queasocia identificadores a la información requerida por el compilador. Sus dosoperaciones básicas son insertar y buscar. En nuestro ejemplo, la declaración de unidentificador en Pascal requerirá una inserción del mismo en la tabla de símbolos; cadavez que se utilice un identificador en una sentencia, el analizador semántico buscaráéste en la tabla de símbolos (llamando al manejador de errores si no existiere).
  18. 18. 4. Que es el análisis semánticoen cuanto a: Se compone de un conjunto de rutinas independientes, llamadas por losanalizadores morfológico y sintáctico. El análisis semántico utiliza como entrada el árbol sintáctico detectadopor el análisis sintáctico para comprobar restricciones de tipo y otraslimitaciones semánticas y preparar la generación de código. En compiladores de un solo paso, las llamadas a las rutinas semánticasse realizan directamente desde el analizador sintáctico y son dichasrutinas las que llaman al generador de código. El instrumento másutilizado para conseguirlo es la gramática de atributos. En compiladores de dos o más pasos, el análisis semántico se realizaindependientemente de la generación de código, pasándoseinformación a través de un archivo intermedio, que normalmentecontiene información sobre el árbol sintáctico en forma linealizada (parafacilitar su manejo y hacer posible su almacenamiento en memoriaauxiliar).
  19. 19.  En cualquier caso, las rutinas semánticas suelen hacer uso de una pila (la pilasemántica) que contiene la información semántica asociada a los operandos(y a veces a los operadores) en forma de registros semánticos. a) Verificación de tipos en expresiones. b) Conversión de tipos. Acciones agregadas en un analizador sintáctico descendente (top-down). Un analizador sintáctico (Parser) es un programa que reconoce si una ovarias cadenas de caracteres forman parte de un determinado lenguaje. Loslenguajes habitualmente reconocidos por los analizadores sintácticos s on los lenguajes libres de contexto. Los analizadores pueden clasificarse dependiendo de la forma en como seconstruyen los nodos del árbol de derivación sintáctico: ascendentes ydescendentes. LL (left to left) leen la cadena de izquierda a derecha y derivan por laizquierda • LR (left to right) • SàaA • AàaBbC • Bàb • Càc
  20. 20. Pila semántica en un analizadorsintáctico ascendente (bottom-up). Los ascendentes construyen el árbol desde las hojas hacia la raíz. Los descendentes lo hacen en modo inverso. • Un analizador ampliamente utilizado se denomina método de análisispredictivo descendente recursivo que es muy sencillo. Derivación izquierda: • SàAaàaaBbCàaabbCàaabbc (1234) • SàaAàaaBbCàaaBbcàaabbc (3421) • LL(k) traductores “top-down” • Un análisis anticipado de k caracteres .SàaS|cA • AàbA|cB|vacia • BàcB|a| vacia Construir cadena acbb • SàaS o SàcA; al anticipar el primer símbolo
  21. 21. Administración de la tabla desímbolos. La tabla de símbolos se crea durante la fase de análisis léxico através de los componentes léxicos, pero en el proceso de análisissintáctico sufren algunas modificaciones. • Generalmente se agregan valores de tipo y significado para elanálisis sintáctico Es una estructura de datos que usa el proceso de traducción deun lenguaje de programación, por un compilador o un intérprete,donde cada símbolo en el código fuente de un programa estáasociado con información tal como la ubicación, el tipo de datos,y el ámbito de cada variable, constante o procedimiento. Los símbolos en la tabla de símbolos pueden referirse aconstantes, a funciones o a tipos de datos en el código fuente deun programa. El administrador de la tabla de símbolos se encarga de manejarlos accesos a l tabla de símbolos, en cada una de las etapas decompilación de un programa.
  22. 22. Manejo de erroressemánticos Los errores semánticos son más sútiles. Un error semántico se produce cuando lasintaxis del código es correcta pero la semántica o significado no es le que sepretendía. La construcción obedece las reglas del lenguaje y por ellos el compilado ointerprete no detectan los errores semánticos, los copiladores o interpretes sólo seocupan de la estructura del código que se escribe, y no de su significado, Un errorsemántic puede hacer que el programa termine de forma anormal, cn o sin unmensaje de error. Si los traductores tuvieran que procesar programas correctas el proceso deimplantación se simplificaría mucho. • ¿Cómo debe de responder un compilador de pascal a un código Fortran? • Ningún método de recuperación de errores resuelve todos los problemas Tipos de errores • Léxicos: como escribir mal un identificador, palabra clave u operador. • Sintácticos: como una expresión aritmética con paréntesis no equilibrados. • Semánticos: como un operador aplicado a un operadorando incompatible. • Lógicos: como una llamada infinitamente recursiva • La mayoría de los errores se centra en la fase de análisis sintáctico.
  23. 23.  El manejador de errores debe: • Informar la presencia de errores con claridad y exactitud., recuperar de cada error con la suficiente rapidez como paradetectar errores posibles., No debe retrasar de manera significativa el procesamiento de programas correctos., Debeindicar la línea del error y algún mensaje informativo, estrategias de recuperación de errores, modo Pánico, nivel deFrase, Producciones de error, Corrección global, recuperación en modo pánico, es el más sencillo de implantar. • El analizador sintáctico desecha componentes léxicos hasta encontrar un carácter de sincronización. Estos caracteresson el punto y como (;) entre otros. Recuperación en modo pánico int a.b,c; struct c { …. } main() { int a; } Recuperación a nivel de frase • Esta técnica utiliza una corrección de caracteres adyacentes, ya sea por inserción, eliminación o intercambio. • Esta técnica permite sustituir , por ;, etc. Son traductores que corrigen errores. Desafortunadamente para muchos casosno aplican por lo que no se utilizan demasiados. Producciones de error • Se pueden generar gramáticas para generar producciones de error y así de esta forma seguir con el proceso. • La dificultad radica en el sentido de encontrar esas reglas gramaticales para generar error. En algunos casos seríainclusiva más extensa que la gramática del propio lenguaje. • Corrección global • Idealmente, sería recomendable que un traductor hiciera el mínimo de cambios para procesar una entrada inválida. Estealgoritmo genera menores costos globales para realizar cambios. • El problema radica en que el implementar estas estrategias son muy costosas en tiempo y espacio.

×