Compiladores. Guía 7 1 Facultad: Ingeniería Escuela: Computación Asignatura: Compiladores Tema: Análisis Sintáctico LR Contenido En esta guía se abordarán los conceptos pertenecientes al componente de análisis sintáctico ascendente de un compilador. Además se utilizaran herramientas para la generación del analizador sintáctico LR a partir de la herramienta de YACC. Objetivos Específicos Conocer las características y algoritmo del analizador sintáctico ascendente. Analizar y descubrir las diferencias entre una analizador sintáctico ascendente y el analizador sintáctico descendente. Aprender a utilizar la herramienta de YACC para la generación de analizadores sintácticos. Material y Equipo Guía de Laboratorio Nº 7. Computadora con programa Parser Generator. Introducción Teórica Analizados Sintáctico LR La técnica se denomina análisis sintáctico LR(k); la “L” es por el examen de la entrada de izquierda a derecha (en inglés, left-to-right), la “R” por construir una derivación por la derecha (en inglés, rightmost derivation) en orden inverso, y la k por el número de símbolos de entrada de examen por anticipado utilizados para tomar las decisiones del análisis sintáctico. Cuando se omite, se asume que k, es 1. El análisis LR es atractivo por varias razones. 2 Compiladores. Guía 7 • Pueden reconocer la inmensa mayoría de los lenguajes de programación que puedan ser generados mediantes gramáticas de contexto-libre. • El método de funcionamiento de estos analizadores posee la ventaja de localizar un error sintáctico en el mismo instante que se produce con lo que se adquiere una gran eficiencia de tiempo de compilación frente a procedimientos menos adecuados como pueden ser los de retroceso. El principal inconveniente del método es que supone demasiado trabajo para construir un analizador sintáctico LR a mano para una gramática de un lenguaje de programación típico. Se necesita una herramienta especializada – un generador de analizador sintáctico LR-. Por fortuna, existen disponibles varios de estos generadores. Existen tres técnicas para construir una tabla de análisis sintáctico LR para una gramática. El primer método, llamado LR sencillo (SLR, en ingles) es el más fácil de implantar, pero el menos poderoso de los tres. Puede que no consiga producir una tabla de análisis sintáctico para algunas gramáticas que otros métodos si consiguen. El segundo método, llamado LR con examen por anticipado (LALR, en ingles), está entre los otros dos en cuanto a poder y costo. El método LALR funciona con las gramáticas de la mayoría de los lenguajes de programación y, con un poco de esfuerzo, se puede implantar en forma eficiente. Funcionalmente hablando, un analizador LR consta de dos partes diferenciadas, un programa de proceso y una tabla del análisis. El programa de proceso posee como veremos seguidamente un funcionamiento muy simple y permanece invariable de analizador a analizador. Según sea la gramática a procesar deberá variarse el contenido de la tabla de análisis que es la que identifica plenamente el analizador. La la siguiente estructura figura muestra un esquema general de un analizador LR. sinóptico de Compiladores. Guía 1 3 Como puede apreciarse en la figura, el analizador consta de una tira de entrada donde se encuentra la cadena a reconocer finalizada con el símbolo $ que representa el delimitador. Esta tira lee de izquierda a derecha un símbolo cada vez en el proceso de reconocimiento. El contenido de la pila tiene la forma s0 X1 s1 X2 s2... Xm sm Donde el símbolo sm se encuentra en la cabeza tal y como se muestra en la figura. Cada uno de los Xi son símbolos de la gramática y a los si vamos a denominarlos estados del analizador. Los estados se utilizan para representar toda la información contenida en la pila y situada antes del propio estado. Es mediante el estado en cabeza de la pila por el que se decide qué reducción ha de efectuarse o bien que desplazamiento. Tradicionalmente, una tabla de análisis para reconocedor LR consta de dos partes claramente diferenciadas entre sí que representan dos funciones, la función GOTO y la función ACCION. El funcionamiento del analizador LR es el siguiente: 1. Se determina el estado Sm en cabeza de la pila y el símbolo actual ai en el instante de la cadena de entrada. 2. Se consulta en la tabla de análisis la función acción con los parámetros anteriores y que pueden dar como resultado. 4 Compiladores. Guía 7 Acción (sm,ai)= { Desplazar S Reducir Aβ Aceptar Rechazar Por su parte la función GOTO actúa igualmente con un estado y un símbolo de la gramática produciendo un nuevo estado. Análogamente puede definirse una configuración analizador LR como un par de la forma. de un (s0 X1 s1 X2 s2 ... Xm sm , ai ai+1 ... an $) es decir, el primer componente es el contenido actual de la pila, y el segundo la substituirá de entrada que resta por reconocer, ai es el símbolo de entrada actual de análisis. El movimiento del analizador se realiza teniendo en cuenta: 1. 2. El símbolo leído. El símbolo en cabeza de la pila. Actuando con la función acción y dependiendo de las cuatro posibles alternativas pueden obtenerse las configuraciones que seguidamente se detalla. 1. Si acción (sm, ai) = desplazar s. Entonces se introducen en la pila el símbolo actual analizado de la cadena de entrada y en la cabeza de la pila el nuevo estado obtenido mediante la función GOTO(sm, ai)= S. La configuración así obtenida es la mostrada seguidamente. (s0 X1 s1 X2 s2 ... Xm sm ai s , ai+1 ... an $) Pasando s a estar situado en cabeza de la pila y ai+1 el siguiente símbolo a explorar en la cinta de entrada. 2. Si acción (sm, ai) = reducir Aβ Entonces el analizador ejecuta la reducción oportuna donde el nuevo estado en cabeza de la pila se obtiene mediante la función GOTO (sm-r, ai) = s donde r es precisamente la longitud de la β cadena reducida. Compiladores. Guía 1 5 Aquí el analizador extrajo primero 2r símbolos de la pila (2 símbolos de estados y r símbolos de la gramática), exponiendo el estado sm-r. Luego introdujo A, el lado izquierdo de la regla de producción, y s, la entrada de GOTO (sm-r,A), en la pila La configuración así obtenida es la mostrada seguidamente. (s0 X1 s1 X2 s2 ... Xm-r sm-r A s , ai ai+1 ... an $) Donde s es el nuevo estado en cabeza de la pila y no se ha producido variación en la tira de entrada que aún queda por analizar. 3. Si acción (sm, ai)= aceptar Entonces se ha llegado a la finalización en el proceso de reconocimiento y el análisis termina reconociendo la tira de entrada. 4. Si acción (sm, ai)= error Entonces es muestra de que el analizador LR ha descubierto un error sintáctico y procederá en consecuencias activando las rutinas de corrección de errores… Una de las ventajas de este tipo de análisis es que, cuando se produce una acción de error, el token erróneo suele estar al final de (α) o al principio de (β), lo que permite depurar con ciertas facilidades las cadenas de entrada (programas). La configuración inicial del analizador es: (s0, a1 a2... an $) Donde s0 es el estado inicial del reconocedor. Los sucesivos movimientos se realizan en base a los cuatro puntos anteriores hasta que se acepta la cadena de entrada o bien hasta la aparición de un error. Procedimiento Yacc no es directamente un analizador sino un generador de analizadores. A partir de un fichero fuente en yacc, se genera un fichero fuente en C que contiene el analizador sintáctico. Sin embargo, un analizador sintáctico de yacc no 6 Compiladores. Guía 7 puede funcionar por sí solo, sino que necesita un analizador léxico externo para funcionar. Dicho de otra manera, el fuente en C que genera yacc contiene llamadas a una función yylex() que debe estar definida y debe devolver el tipo de lexema encontrado. Además, es necesario incorporar también una función yyerror(), que será invocada cuando el analizador sintáctico encuentre un símbolo que no encaja en la gramática. La estructura general de un programa en YACC es la siguiente: <sección de definiciones> %% <sección de reglas> %% <sección de rutinas> Tabla 1 El procedimiento inicia con la verificación de la existencia de “Parse Generator” en su máquina. Caso contrario descargue la herramienta Parser Generator desde el enlace siguiente: http://www.bumblebeesoftware.com/ Proceda a instalar la aplicación utilizando el usuario Wamp con la clave wamp. Ejemplo 1 Construir un analizador sintáctico que reconozca la palabra „Hola‟, en mayúsculas o minúsculas, y con un número arbitrario de letras „o‟. Primero crear una carpeta con el nombre sintactico, dentro del “Escritorio”. En esta dirección almacenaremos los archivos generados en esta práctica. Abra y ejecute el programa “Parser Generator” y abra un nuevo texto, luego digite el código de la tabla 2. Compiladores. Guía 1 7 Figura 1: Ambiente de Parser Generator. /*Seccion de definicion*/ %token H,O,L,A %{ #define H 257 #define O 258 #define L 259 #define A 260 /*Definicion del Analizador lexico*/ int yylex() { char carac=getchar(); switch(carac) { case 'H': case 'h': return H; case 'O': case 'o': return O; case 'L': case 'l': return L; case 'A': case 'a': return A; } return -1; } 8 Compiladores. Guía 7 int yyerror() { printf("La expresión de la entrada NO forma parte del lenguaje reconocido\n"); return 0; } %} /*La seccion de codigo de c de la definicion debe estar entre los delimitadores %{ y %}*/ %% /*Fin de la seccion de definiciones e inicio de la seccion de reglas de derivacion para el analizador sintactico*/ hola: H letra_o L A {printf("La expresión introducida es parte del lenguaje reconocido\n");}; letra_o: O | letra_o O ; %% /*Fin de la seccion de reglas y adicion de rutinas auxiliares en c*/ int main() { yyparse(); /*Invocacion de la funcion del analizador sintactico*/ return 0; } Tabla 2 Ahora procederemos a guardar nuestro archivo en la carpeta “sintactico” creada anteriormente en el Escritorio. Compiladores. Guía 1 9 Figura 2: Menú “File” y luego “Save”, seleccionar nombre y ubicación y guardamos el archivo como “hola”. Figura 3: Clic en el menú “Project” y luego “Compile File” para generar el código analizador sintáctico de nuestro proyecto. 10 Compiladores. Guía 7 Figura 4: Salida de compilación correcta. Figura 5: Archivos generados por Parser Generator: Definición de analizador sintáctico en C, archivo de cabecera header para C y un archivo de Verbose File que utiliza la herramienta de Parser. Compiladores. Guía 1 11 Análisis de resultados Construir un analizador sintáctico que reconozca la gramática para una calculadora simple, con las operaciones suma, resta, multiplicación y división con la herramienta Yacc. (Consultar “Construcción de compiladores” de Kenneth C. Louden pag 228). Investigación complementaria 1. Investigar sobre el uso de FLEX, YACC y BISON. Responda: Que es un analizador semántico Cuál es su función principal Algoritmo para desarrollarlo Cuál es su dependencia con el analizador sintáctico Bibliografía “Construcción de Compiladores. Principios y practica”, Kenneth C. Louden. “Compiladores. Principios técnicas y Herramientas”. Sethi Ullman. Pearson Education. Generador de analizador sintáctico de la palabra “HOLA”, http://www.infor.uva.es/~mluisa/talf/docs/labo/L8.pdf 12 Compiladores. Guía 7 Hoja de cotejo: Guía 7: Analizador sintáctico LR Alumno: Máquina No: Docente: GL: 1 1 Fecha: EVALUACION % CONOCIMIENTO Del 20 al 30% APLICACIÓN DEL CONOCIMIENTO Del 40% al 60% 1-4 5-7 8-10 Conocimie nto deficient e de los fundament os teóricos Conocimiento y explicación incompleta de los fundamentos teóricos Conocimiento completo y explicación clara de los fundamentos teóricos No tiene actitud proactiva . Actitud propositiva y con propuestas no aplicables al contenido de la guía. Tiene actitud proactiva y sus propuestas son concretas. ACTITUD Del 15% al 30% TOTAL 100% Nota