Title: Herramientas de software: Lex/Flex.

Herramientas de software:

Sin título Text

Un compilador puede tener hasta varios millones de líneas de código. Entonces, dada la importancia de su desarrollo y su gran complejidad, en los años 70 se empezaron a desarrollar herramientas para automatizar algunas partes del compilador. Esas herramientas originalmente fueron llamadas compiladores de compiladores. Sin embargo, se les puede llamar de manera adecuada como generadores de analizadores léxicos o sintácticos. Hay dos herramientas en particular: Lex y Yacc.

Herramienta Lex:

Sin título Text

La herramienta Lex fue creada por Lesk y Schmidt en 1975, en lenguaje C, como un comando para el sistema operativo UNIX. Lex puede leer de la entrada estándar o de un archivo la especificación de un analizador léxico y genera el código fuente en lenguaje C del analizador léxico. Lex es patentado, pero existen versiones de código abierto. Una de esas versiones, flex (“fast lexical analyzer”), fue creada por Paxson. Bajo Windows existe una versión llamada Win flex-bison que se puede integrar con Visual Studio.

Formato Lex:

Sin título Text

El formato de la especificación de Lex/flex consta de tres secciones: definiciones, reglas y código de usuario. Cada sección está separada por una línea que inicia con doble carácter %. Sección definiciones. Contiene código en C delimitado por %{ y %}, definiciones de nombres de patrones y directivas de Lex/flex. Sección reglas. Contiene reglas que constan de un patrón y una acción a ejecutar cuando se detecta el patrón. Sección código de usuario. Contiene código en C que requiera el analizador léxico.

Sección definiciones:

Sin título Text

- Bloque de código en C. Contiene código en C entre los símbolos %{ y %}
- Definiciones de patrones. Cada definición incluye un nombre de patrón seguido de espacio(s) en blanco y una expresión regular
- Directivas de Lex/flex:
%x: Definir estado(s) inicial(es) exclusivo(s).
%s: Definir estado(s) inicial(es) inclusivo(s).
%option: Definir opción(es) de flex.
%top{}: Incluir código en C en la parte superior.

Sección de reglas:

Sin título Text

Cada regla está formada por un patrón o expresión regular y una acción separados por espacio en blanco. La acción es código en C y puede omitirse. Cuando la acción ocupa varias líneas se usan { y }. En la acción se puede usar | para indicar que la acción es la misma que la de la siguiente regla. En la parte superior de la sección puede colocarse una acción inicial, pero ésta debe ser indentada con espacios en blanco. Puede haber comentarios con /* y */. Pero éstos deben ser indentados ya que flex espera una expresión regular al inicio de la línea.

Sección código de usuario:

Sin título Text

Puede incluir código en C que sea necesario para la aplicación. Cuando se está implementando una aplicación independiente, se debe incluir una función main. La función main debe abrir el archivo de entrada, inicializar la variable yyin y llamar a la función yylex(). También se debe incluir la función yywrap(), pero ésta no es necesaria cuando se usa la directiva %option noyywrap. Si no se incluye la función yywrap() y no se especifica la directiva mencionada, entonces se deberá agregar la opción –lfl al compilar con gcc.

Patrones:

Sin título Text

Un patrón es una expresión regular o secuencia de caracteres que especifica el conjunto de cadenas a buscar. Las expresiones regulares vienen implementadas en las herramientas de procesamiento de texto de UNIX tales como ed, awk y grep. Una expresión regular puede ser simplemente una cadena de texto como “float”, “for”, “int”.

Expresiones regulares:

Sin título Text

Flex soporta las operaciones regulares siguientes:

- Concatenación.
- Cerradura de Kleene.
- Cerradura positiva.
- Opcional.
- Unión.
- Clase de caracteres.
- Complemento de clase.
- Agrupamiento.
- Repetición.
- Resta o unión de clases.
- Cualquier carácter excepto \n.
- Clase de caracteres.
- Expansión de patrón.
- Búsqueda restringida: Al inicio de línea o fin de línea.
- Búsqueda sólo en estado inicial.
- Búsqueda en cualquier estado inicial.
- Búsqueda de fin de archivo.
- Carácter con código octal.
- Carácter con código hexadecimal.
- Carácter nulo.
- Secuencias de escape.

Estados iniciales:

Sin título Text

Flex tiene un mecanismo para activar o desactivar reglas. Cualquier regla que empiece con <sc> estará activa sólo cuando el analizador esté en el estado sc. Los estados son declarados con las directivas %s y %x. La primera declara estados inclusivos y la segunda estados exclusivos. Un estado es activado con la acción BEGIN.

Valores disponibles al usuario:

Sin título Text

Flex pone a disposición del usuario lo siguiente para usarse en las acciones:

- char *yytext. Texto del patrón actual.
- int yyleng. La longitud de yytext.
- FILE *yyin, Archivo que lee yylex().
- FILE *yyout. Archivo donde envía datos la acción ECHO.
- YY_START. El estado inicial activo.
- YY_CURRENT_BUFFER. El buffer actual.
- ECHO. Escribir yytext en la salida.
- REJECT. Proceder con la segunda mejor regla.

Acciones:

Sin título Text

Una acción puede incluir instrucciones return para retornar un valor a la rutina que llamó a yylex(). Una acción que inicia con el carácter ‘{‘, termina hasta su correspondiente carácter ‘}’. Una acción que consista sólo de ‘|’ indica que es la misma acción que la siguiente regla. Una acción en blanco, significa que el texto encontrado es descartado o ignorado. Caracteres no detectados como parte de ningún patrón son enviados a la salida en la regla por default.

Tokenización:

Sin título Text

Como habíamos mencionado, la función yylex() generada por lex/flex retorna un valor entero. Ese valor entero representa un token o símbolo. Los tokens son usualmente definidos como constantes enteras usando una enumeración. A cada token corresponden una o más reglas. Algunas de estas reglas deben retornar el token cuando éste sea detectado. Además, debe haber reglas que no retornan ningún token. Por ejemplo, las que detectan comentarios o espacios en blanco.

Algunos tokens pueden tener información adicional (atributos) útil para el análisis semántico. Por ejemplo, las constantes numéricas, las cadenas y los identificadores. Flex proporciona un mecanismo para el paso de esos atributos que consiste en usar la unión yylval. Cuando se usa flex con Bison, se debe definir yylval y los nombres de los tokens en la especificación de la gramática. Los atributos de cada token son simplemente asignados a alguna variable de la unión yylval.