INTRODUCCIÓN A FLEX Flex es una herramienta que traduce la especificación especificación de un analizador léxico a un programa escrito en C que lo implementa. Para especificarlo usaremos expresiones regulares a las que se puede asociar acciones escritas en C. Cada vez que el analizador encuentra en la cadena de entrada una secuencia que encaja en una de las expresiones regulares especificadas, ejecutará la acción que le hallamos asociado. fichero.l ---> FLEX ---> lex.yy.c lex.yy.c + (ficheros .c) ---> GCC ---> ejecutable Compilación : $flex fichero.l Compila la especificación del analizador y crea el fichero yy.lex.c con el código del autómata. $ gcc lex.yy.c -ll Enlaza con librería de Flex (proporciona yywrap() y main() m ain() por defecto) $ gcc lex.yy.c (ficheros .c) El usuario deberá de proporcinar sus propias main() e yywrap(). Dentro del código se deberá llamar a la función yylex() que tratará un TOKEN por cada llamada. Funcionamiento del analizador. El fichero lex.yy.c contine las tablas de autómata generado y la función int yylex(void) que simula el analizador especificado y sirve de interfaz con el código de usuario. (yylex() deberá de ser llamada en algún punto del código del usuario) En cada llamada, yylex() irá tomando caracteres de la entrada hasta que machee una de las expresiones regulares de la especificación. Entonces, Entonces, se almacenará el texto que ha macheado la expr. reg. en la variable var iable yytext y se ejecutarán las acciones asociadas al patrón.
Las acciones podrán ser simplemente el procesamiento del texto macheado y enviarlo de nuevo a la salida.
En otras ocasiones podrán suponer la alteración de varíables del código de ususario y la devolución a la rutina que llama a yylex() de algún tipo de dato por medio de RETURN (generalmente será un valor numérico que identifique la TOKEN encontrado).
2 .- ESTRUCTURA DE UNA ESPECIFICACIÓN FLEX
Tres partes separadas por el símbolo %%. (Las dos primeras son obligatorias, aunque pueden estar vacías)
%%
%%
Sección de Declaraciones.
En esta sección se puede incluir :
- Código C necesario para las acciones.
Se incluye código C necesario para las acciones asociadas a los patrones. El código C se incluirá entre los símbolos %{ y %}, y será copiado tal cual al fichero lex.yy.c. (Generalmente serán #includes y/o estructuras y variables del código de usuario que se vean afectadas por las acciones)
- Definición de macros.
Se definen "alias" asociados a expresiones regulares que se usarán el la sección de reglas.
Ej. : LETRA_MAYUSCULA [A-Z] (En la sección de reglas se referenciará entre llaves como {LETRA_MAYUSCULA})
- Definición de entornos de reconocimiento (start conditions) Se definen entornos dentro de los cuales se podrán reconocer sub-expresiones. Permite especificar entornos dentro de los cuales se machearán sub-expresiones dependiendo del contexto. (Permite generar mini-analizadores dentro del analizador)
Ej.: (1ra. Conjugacion en español) (en declaración)
%start V1C
... %% (en reglas)
cant {BEGIN V1C;} /* Comienza el entorno V1C */
... o {printf("1ra. Persona presente indicativo");} as {printf("2da. Persona presente indicativo");} a {printf("3ra. Persona presente indicativo");} ...
Sección de reglas.
Esta sección tiene el siguiente formato:
(exp reg 1 ) (acción 1 ) .... .... (exp reg n ) (acción n )
Cada par (exp. reg., acción) recibe el nombre de regla.
NOTA: El primer carácter de la expresión regular debe de comenzar en la primera columna de texto. (de lo contrario se consideraría un trozo de código C)
Cuando la acción involucra varias sentencias C es necesario encerrarlas entre llaves.
Cuando varias expresiones regulares comparten la misma acción se utilizará el símbolo | . Este símbolo indica que se debe tomar como acción para esta regla la misma que se especifique para la siguiente expresión regular.
Si no se especifica ninguna acción se terminará la regla con punto y coma ";". En este caso se considera como una acción vacía y por defecto se copiará directamente el string macheado en la salida.
Ambigüedades.
En el caso de que una misma cadena pueda corresponderse con más de una especificación se elegirá la expresión que machee el mayor número de caracteres. Si el número es el mismo se elige a la que aparezca primero en la especificación.
Sección de rutinas de usuario
Esta sección zona se puede escribir código C adicional, bien funciones llamadas desde las acciones de las reglas o, en el caso de programas pequeños, suelen incluirse las funciones main() y yywrap() propias del usuario. 3.- VARIABLES PREDEFINIDAS POR FLEX
Flex define varias variables estándar que le sirven de interface.
yytext ---> Puntero a una cadena de caracteres que contiene la última cadena de texto que encajó con una expresión regular.
Está declarada como char *yytext (puede modificarse pero no es aconsejable) Su contenido sólo es estable dentro de las reglas y entre llamadas consecutivas a la función yylex().
yyleng ---> Contiene la longitud de la cadena yytext. Tampoco se debe modificar. yyin ---> Variable declarada de tipo FILE *. Contiene un puntero al fichero del que lee caracteres el reconocedor.
Por defecto se corresponde con la entrada estándar. Será necesario cambiarla para que el analizador lea de un fichero distinto.
yyout ---> Variable declarada del tipo FILE *. Contiene un puntero al fichero estándar en el que escribe el analizador léxico al utilizar la acción ECHO. Se puede cambiar libremente