Herramienta lex y yacc Compiladores Instituto Politécnico Nacional (IPN) 16 pag. Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) INSTITUTO POLITÉCNICO NACIONAL ESCUELA SUPERIOR DE INGENIERIA MECÁNICA Y ELECTRICA UNIDAD CULHUACÁN LA HERRAMIENTA LEX ASIGNATURA: COMPILADORES PROFESORA: RESENDIZ COLÍN PILAR. GRUPO: 5CV24 EQUIPO: 5 INTEGRANTES: NºLISTA – NOMBRE 1 ALVAREZ RODEA CARLOS GERARDO. 3 CARRASCO VAZQUEZ LEONARDO. 11 IRIARTE HERNANDEZ JESUS EMMANUEL 16 MERINO MARTINEZ ROBERTO EDUARDO 26 VERA OROZCO MARÍA DE LOS ÁNGELES Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) Índice • Introducción • La herramienta Lex • Esquema de una fuente en Lex • Zona de definiciones • Zona de reglas • Zona de rutinas del usuario • Archivo de salida (lex.yy.c) • Copilar una fuente de Lex • Opciones estándar • Depuración de una fuente de Lex • Prueba rápida de una fuente • Expresiones regulares en Lex • Caracteres • Clases de caracteres • Reconocer cualquier caracter • Unión • Clausuras • Repetición acotada • Opción • Paréntesis 1 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) Introducción La herramienta Lex es un generador de analizadores léxicos utilizado en el campo de la informática. También se conoce como un "analizador de escáner" o "analizador léxico". Lex se utiliza comúnmente para procesar y analizar texto estructurado en lenguajes de programación, sistemas de compilación y otros entornos relacionados. El propósito principal de Lex es reconocer y dividir el texto de entrada en unidades léxicas más pequeñas llamadas "tokens". Estos tokens pueden representar palabras clave, identificadores, números, símbolos y otros elementos del lenguaje de programación o del sistema que se está analizando. Lex utiliza un enfoque basado en reglas para generar analizadores léxicos. El usuario define un conjunto de reglas en un archivo de especificación de Lex que describe cómo se deben reconocer los tokens en el texto de entrada. Cada regla consta de un patrón de búsqueda y una acción asociada. Cuando Lex encuentra una coincidencia entre un patrón y una parte del texto de entrada, ejecuta la acción correspondiente, que puede ser una función o un fragmento de código. Una vez que se ha generado el analizador léxico con Lex, se puede utilizar en conjunción con otros componentes del sistema para realizar tareas más complejas, como el análisis sintáctico o la generación de código. Lex se ha utilizado ampliamente en la implementación de compiladores, intérpretes y otras herramientas de procesamiento de lenguajes de programación. En resumen, Lex es una herramienta eficiente y flexible que simplifica el proceso de análisis léxico en informática. Proporciona una forma estructurada de definir y reconocer tokens en el texto de entrada, lo que facilita el desarrollo de sistemas de procesamiento de lenguajes de programación y otros entornos relacionados. Herramienta Lex Lex es una herramienta que traduce la especificación de un analizador léxico a un programa escrito en C que lo implementa. Para especificarlo usaremos en esencia, expresiones regulares a las que se puede asociar acciones escritas en C. Cada vez que el analizador encuentra en la cadena 2 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) de entrada un prefijo que encaja con una de las expresiones regulares especificadas, ejecutará la acción que le hallamos asociado. El principal problema que se le suele achacar a Lex es el hecho de que genera programas poco eficientes, por lo que su aplicación en entornos de producción industrial se ve claramente menguada. En la actualidad, se ha desarrollado una versión que genera un código final más eficiente, pero mantiene una completa compatibilidad con la herramienta original. Se trata de Flex, un producto GNU de dominio público del que existen versiones para UNIX y MS-DOS. Esquema de una fuente en Lex %{ // Declaraciones del encabezado, incluyendo bibliotecas y definiciones #include <stdio.h> %} // Reglas %% patrón1 acción1 patrón2 acción2 // ... // Código C adicional %% // Función principal int main() { // Inicialización y llamada al analizador léxico generado por Lex yylex(); // Código adicional, si es necesario return 0; } Declaraciones del encabezado (%{ y %}): Esta sección contiene las declaraciones del encabezado, que incluyen bibliotecas y definiciones que se utilizarán en el código C generado por Lex. 3 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) Reglas (%%): Esta sección contiene las reglas del analizador léxico. Cada regla tiene un patrón y una acción asociada. Cuando el analizador léxico encuentra un patrón que coincide con la entrada, ejecuta la acción correspondiente. Código C adicional: Esta sección contiene cualquier código C adicional que desees incluir en el programa. Puede contener funciones o variables que se utilizarán en las acciones de las reglas. Función principal: La función main() inicializa el analizador léxico y llama a la función yylex(), que es generada automáticamente por Lex. Puedes incluir código adicional después de la llamada a yylex() si es necesario. Reglas: Reconocer números enteros: %% [0-9]+ { printf("Entero: %s\n", yytext); } Reconocer identificadores (variables): %% [a-zA-Z_][a-zA-Z0-9_]* { printf("Identificador: %s\n", yytext); } Reconocer palabras clave: %% if else { printf("Palabra clave IF\n"); } { printf("Palabra clave ELSE\n"); } Ignorar espacios en blanco y saltos de línea: %% [ \t\n] ; // Ignorar espacios en blanco y saltos de línea 4 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) Manejar errores: %% . { printf("Carácter no reconocido: %s\n", yytext); } Estos son ejemplos muy simples y puedes expandirlos según las necesidades de tu lenguaje o aplicación específica. Cada regla consta de un patrón y una acción. Cuando la entrada coincide con el patrón, se ejecuta la acción asociada. Puedes tener tantas reglas como sea necesario para manejar diferentes partes de tu lenguaje fuente. Archivo de salida (lex.yy.c) Generalmente está asociado con el uso de herramientas como Flex (Fast Lexical Analyzer Generator). lex.yy.c es el nombre predeterminado del archivo de salida generado por Flex cuando se crea un analizador léxico. Cuando utilizas Flex para generar un analizador léxico, creas un archivo de entrada con extensión .l que contiene reglas de análisis léxico. Luego, ejecutas Flex en este archivo de entrada para generar el código fuente del analizador léxico en C, y el resultado se guarda en un archivo llamado lex.yy.c por defecto. Este archivo contiene el código C para el analizador léxico. Aquí hay un ejemplo básico del proceso: Crear un archivo de entrada Flex (por ejemplo, mi_analizador_lexico.l): %{ #include <stdio.h> %} %% 5 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) palabra_clave printf|scanf identificador [a-zA-Z][a-zA-Z0-9]* numero [0-9]+ %% int main() { yylex(); return 0; } Ejecutar Flex: flex mi_analizador_lexico.l Esto generará el archivo lex.yy.c. Compilar el código C generado: gcc lex.yy.c -o mi_analizador_lexico Esto compilará el código generado por Flex y creará un ejecutable llamado mi_analizador_lexico. Ejecutar el analizador léxico: ./mi_analizador_lexico Estos pasos son un ejemplo básico, y el contenido real del archivo .l y cómo se utiliza el analizador léxico dependerá de tus necesidades específicas. Ten en cuenta que el nombre del archivo de salida (lex.yy.c) y del ejecutable (a.out por defecto) pueden variar según la configuración o opciones utilizadas. 6 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) Copilar una fuente de Lex Escribe el Código en Lex: Utiliza un editor de texto para escribir tu código en Lex. Los archivos suelen tener la extensión .l o .lex. Por ejemplo, si estás trabajando en un archivo llamado mi_analizador.lex, puedes usar un editor de texto para escribir el código fuente. Ejecuta el Compilador Lex: Utiliza el compilador de Lex para generar el código en C correspondiente. El comando puede variar según tu sistema operativo. En muchos sistemas basados en Unix/Linux, puedes usar el comando lex. Por ejemplo: lex mi_analizador.lex Compila el Código Generado: El paso anterior generará un archivo en C, generalmente con el nombre lex.yy.c. Ahora necesitas compilar ese código C. Puedes usar un compilador como gcc. Por ejemplo: gcc lex.yy.c -o mi_analizador -ll En algunos sistemas, el flag -ll es necesario para vincular la biblioteca de Lex. Ejecuta el Programa Compilado: Una vez que hayas compilado tu programa, puedes ejecutarlo: ./mi_analizador Estos son pasos generales y pueden variar según el sistema operativo y las herramientas específicas que estés utilizando. Asegúrate de consultar la 7 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) documentación de Lex y las herramientas asociadas en tu entorno de desarrollo específico para obtener detalles precisos. Opciones estándar Generar un Archivo de Salida Específico: Puedes utilizar la opción -o para especificar el nombre del archivo de salida generado por Lex. Por ejemplo: lex -o mi_analizador.c mi_analizador.lex Mostrar Información Detallada: La opción -t o --t suele utilizarse para que Lex muestre información detallada sobre el análisis léxico durante el proceso de generación. Esto puede ser útil para depurar tu código en Lex. lex -t mi_analizador.lex No Generar Funciones de Entrada/Salida por Defecto: A veces, puede que no desees que Lex genere sus funciones de entrada/salida estándar (yyin, yyout). Puedes usar la opción -p para especificar un prefijo personalizado para estas funciones. Si no quieres que se generen, puedes usar P seguido de un nombre no existente para deshabilitarlas. lex -Pnoyyin mi_analizador.lex 8 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) Generar un Analizador Silencioso: Puedes usar la opción -q para hacer que Lex genere un analizador sin imprimir mensajes sobre el análisis léxico. lex -q mi_analizador.lex Depuración de una fuente de Lex Mensajes de Depuración: Agrega mensajes de depuración en tu código para imprimir información relevante durante la ejecución. Puedes usar la función printf en C para imprimir mensajes en la salida estándar. Esto puede ayudarte a entender en qué parte del código se produce un problema. Habilita la Impresión de Información Detallada: Usa la opción -t al ejecutar Lex para que genere información detallada sobre el análisis léxico. Esto puede ayudarte a identificar problemas relacionados con el reconocimiento de tokens. lex -t mi_analizador.lex Visualización de Automatas: Algunas implementaciones de Lex te permiten generar diagramas de estados finitos para visualizar el autómata finito que representa tu analizador léxico. Esto 9 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) puede ser útil para comprender el flujo del programa y detectar posibles problemas. Revisa las Expresiones Regulares: Asegúrate de que las expresiones regulares utilizadas para definir patrones de tokens sean correctas. Verifica si alguna expresión regular está generando conflictos o no está coincidiendo correctamente con la entrada. Revisa las Acciones asociadas a los Patrones: Verifica las acciones asociadas a tus reglas. Asegúrate de que estén correctamente escritas y que estén manejando adecuadamente los datos. Errores en las acciones pueden causar comportamientos inesperados. Manejo de Errores: Implementa un manejo adecuado de errores en tu código. Asegúrate de que tu programa pueda manejar entradas inesperadas o incorrectas y proporcionar mensajes de error claros. Divide y Conquista: Si tu programa es grande, trata de dividirlo en partes más pequeñas y verifica cada parte por separado. Esto puede ayudarte a identificar rápidamente la sección del código que está causando el problema. 10 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) Utiliza Herramientas de Depuración: Si estás trabajando en un entorno de desarrollo que admite la depuración de programas en C, aprovecha las herramientas de depuración disponibles, como gdb. Esto te permitirá realizar un seguimiento paso a paso del programa y examinar variables en tiempo de ejecución. Al seguir estos consejos y realizar un enfoque sistemático para la depuración, deberías poder identificar y corregir los problemas en tu programa Lex de manera efectiva. Prueba rápida de una fuente Lex Lexicografía: Es la disciplina que se ocupa de la elaboración de diccionarios, la descripción de las palabras y su clasificación de acuerdo con criterios como el significado, la etimología, la pronunciación, etc. Léxico: Es el conjunto de palabras que pertenecen a una lengua o que se utilizan en un área específica. En términos más simples, el léxico se refiere al vocabulario de una lengua. Ejemplo: Supongamos que tenemos el siguiente código fuente en un lenguaje de programación imaginario: # Código fuente de ejemplo suma = 10 + 20 * 5 resultado = suma / 2 11 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) La prueba léxica para este código podría generar una secuencia de tokens, donde cada token representa una unidad léxica reconocida por el analizador léxico. Aquí hay una posible salida: <Token: IDENTIFICADOR, Lexema: 'suma'> <Token: OPERADOR_ASIGNACION, Lexema: '='> <Token: ENTERO, Lexema: '10'> <Token: OPERADOR_SUMA, Lexema: '+'> <Token: ENTERO, Lexema: '20'> <Token: OPERADOR_MULTIPLICACION, Lexema: '*'> <Token: ENTERO, Lexema: '5'> <Token: FIN_DE_LINEA, Lexema: '\n'> <Token: IDENTIFICADOR, Lexema: 'resultado'> <Token: OPERADOR_ASIGNACION, Lexema: '='> <Token: IDENTIFICADOR, Lexema: 'suma'> <Token: OPERADOR_DIVISION, Lexema: '/'> <Token: ENTERO, Lexema: '2'> <Token: FIN_DE_LINEA, Lexema: '\n'> En este ejemplo: IDENTIFICADOR: Representa nombres de variables como "suma" y "resultado". OPERADOR_ASIGNACION: Indica la asignación de un valor a una variable. ENTERO: Representa números enteros como '10', '20', y '5'. 12 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) OPERADOR_SUMA, OPERADOR_MULTIPLICACION, OPERADOR_DIVISION: Representan operadores aritméticos. FIN_DE_LINEA: Indica el final de una línea en el código fuente. Esta sería una salida simplificada; en un compilador real, también podrían aparecer otros tokens, como tokens de palabras clave, operadores lógicos, delimitadores, etc. La idea es que el analizador léxico descomponga el código fuente en unidades léxicas significativas para que el compilador pueda procesarlo de manera más estructurada. Expresiones regulares en Lex Supongamos que estamos escribiendo un analizador léxico para un lenguaje simple que incluye números enteros, identificadores y operadores aritméticos. Aquí estaría un fragmento de código Lex con expresiones regulares: %{ // Encabezado: Código en C que se copiará directamente al analizador léxico generado #include <stdio.h> %} // Definición de tokens y expresiones regulares %% [0-9]+ { printf("TOKEN_ENTERO: %s\n", yytext); } [a-zA-Z][a-zA-Z0-9]* { printf("TOKEN_IDENTIFICADOR: %s\n", yytext); } "+" { printf("TOKEN_SUMA\n"); } "-" { printf("TOKEN_RESTA\n"); } "*" { printf("TOKEN_MULTIPLICACION\n"); } 13 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) "/" { printf("TOKEN_DIVISION\n"); } "=" { printf("TOKEN_ASIGNACION\n"); } \n { /* Ignorar caracteres de nueva línea */ } [ \t] { /* Ignorar espacios y tabulaciones */ } . { printf("ERROR: Caracter no reconocido\n"); } %% // Código adicional después de la sección de reglas int main() { yylex(); // Llamada al analizador léxico generado return 0; } En este ejemplo: [0-9]+: Coincide con uno o más dígitos, representando un número entero. [a-zA-Z][a-zA-Z0-9]*: Coincide con un identificador, que comienza con una letra y puede estar seguido por letras o dígitos. +, -, *, /, =: Coinciden con los operadores aritméticos y de asignación respectivamente. \n: Coincide con un salto de línea. [ \t]: Coincide con espacios y tabulaciones, que se ignorarán. .: Coincide con cualquier otro carácter, y en este caso, se utiliza para manejar errores cuando se encuentra un carácter no reconocido. 14 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com) Estas expresiones regulares son utilizadas por Lex para generar un analizador léxico que identificará y clasificará los tokens en el código fuente según los patrones definidos. Referencias • Componentes léxicos, patrones y lexemas http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro32/22_compon entes_lxicos_patrones_y_lexemas.html • • • • Análisis léxico, Universidad Europea de Madrid https://www.cartagena99.com/recursos/alumnos/apuntes/ININF2_M4_U2_T 1.pdf Análisis léxico, Procesamiento de lenguajes, Isis https://lc.fie.umich.mx/~rochoa/MATERIAL_MATERIAS/ANA_LEXICO.pdf Token. Wikipedia, The Free Encyclopedia. https://es.wikipedia.org/w/index.php?title=Token_(inform%C3%A1tica)&oldi d=153790078 Tokens. (s/f). Zator.com. https://www.zator.com/Cpp/E3_2.htm 15 Document shared on https://www.docsity.com/es/herramienta-lex-y-yacc/10546596/ Downloaded by: luis-guillermo-cordoba (934.260a@gmail.com)