Sie sind auf Seite 1von 7

Octubre de 2004 -Jorge Jorquera M.

jojorque@udec.cl

APRENDA “BISEX” (BISON-FLEX) COMO SI ESTUVIERA EN


PRIMERO

PREPARADO POR:
Jorge Jorquera M. (jojorque@udec.cl)
DIICC
Universidad de Concepción

INTRO
Hola, muxax@s. Espero que este pequeño manual logre sacarlos del pánico en que
han entrado al oír las palabras “Flex” y “Bison”, ya que no es nada muy complicado o del
otro mundo.

I.- Un Poco De Conceptos Previos.

Las herramientas Flex y Bison permiten realizar análisis léxico y sintáctico,


respectivamente, sobre una entrada de texto plano. Mediante ambos análisis se pueden
realizar sondeos para determinar el reconocimiento de sentencias independientes del
contexto, lo cual constituye la base para el procesamiento sintáctico de los lenguajes de
programación que ustedes ya conocen.

Cada una por separado:


Flex permite generar plantillas de análisis léxico basadas en expresiones regulares.
Para cada expresión regular se puede definir una sentencia ejecutable. Cuando se
detecta un patrón que calza con una expresión regular, se ejecuta la acción
correspondiente definida.
Bison permite generar análisis sintáctico a través de la definición de una gramática
independiente del contexto. Para cada producción de la gramática es posible definir
una regla de procesamiento que permite realizar acciones semánticas en fase de
parsing.
¿Cómo se relacionan el uno con el otro? Muy sencillo: simplemente, los tokens
reconocidos por el analizador lexico basado en Flex pueden emplearse sin problemas
como símbolos terminales de la gramática definida en el analizador sintáctico basado
en Bison.

Lenguajes Formales y Teoría de Compiladores – Semestre II 2004 1


Octubre de 2004 -Jorge Jorquera M.
jojorque@udec.cl

II.- FLEX: A Fast Lexical Analyzer Generator


La idea de Flex es construir un archivo que contenga las reglas de procesamiento
en forma simplificada. A partir de este conjunto de reglas, se genera “automágicamente”
un programa en C que implementa el DFA correspondiente.

Esquema de un archivo de especificación léxica


(Consta de 3 secciones que van separadas por %%):

Declaraciones y Definiciones
%%
Patrones y Acciones
%%
Código Auxiliar

Sección de Declaraciones

En esta parte se incluyen las declaraciones de variables, constantes, includes ...


(en general código C que necesitemos para ejecutar las acciones). Se coloca entre los
símbolos %{ %}. En esta sección también se definen las expresiones regulares básicas
que se utilizarán más tarde para la definición de los patrones. Por ejemplo:
%{
#include <stdio.h>

int nlines=0;
%}

DIGITO [0-9]
LETRA [a-zA-Z]

Sección de Patrones y Acciones

Patrón 1 {Acción 1}
Patrón 2 {Acción 2}
...
Patrón n {Acción n}

Los patrones determinan los componentes léxicos a reconocer; pueden a su vez ser
definidos como expresiones regulares. Las acciones son el código a ejecutar cuando se
reconoce un determinado componente léxico. Si la acción a ejecutar ocupa más de una
línea, debe obligatoriamente ponerse entre llaves, si no, las llaves no son necesarias.

Sección de Código Auxiliar

En esta parte va el código C de las funciones que se utilizan en las acciones. Se


puede colocar también la función main.
Ej:

main(){
yylex();//funcion de análisis léxico
}

Lenguajes Formales y Teoría de Compiladores – Semestre II 2004 2


Octubre de 2004 -Jorge Jorquera M.
jojorque@udec.cl

Operadores que se pueden utilizar al definir ER’s

Operador Descripción
[] Rango de valores
* Cero o más repeticiones
+ Al menos una vez
? Opcionalidad
. Cualquier otra cosa diferente a las ER anteriores
| Alternativa
^ Negación

Para utilizar estos caracteres como tales y no como metasímbolos de definición de


expresiones regulares, se debe colocar el carácter \ delante de ellos o ponerlos entre “ ”.
Se debe colocar { } para hacer referencia a las abreviaturas que se definen en la sección
de declaraciones.
Ejemplo:

{DIGITO}+”.”{DIGITO}+ {printf(“Encontrado NUMERO REAL”);}

Variables internas de Flex

Variables Descripción
char * yytext Texto del patrón reconocido
int yyleng Longitud del patrón reconocido
FILE * yyin Archivo de entrada (por defecto stdin)
FILE * yyout Archivo de salida (por defecto stdout)
int yylex() Llamada al analizador léxico
int yyparse() Llamada al analizador sintáctico

Ambigüedades de las reglas

Si una entrada calza con más de un patrón se sigue el siguiente criterio: se elige la
opción que calza con un mayor número de caracteres. Al igual número de caracteres se
elige la regla que se encuentra en primer lugar (de aquí que sea más convenienteponer la
definición de las palabras clave antes que los identificadores).
Por ejemplo para la entrada ende, la reconoceríamos como un identificador

“end” {return TKN_END;}


{LETRA}+ {return TKN_ID;}

Interacción con Bison

El analizador sintáctico pide al analizador léxico que le proporcione un nuevo token


cada vez que durante el proceso de análisis sintáctico encuentra un token en la gramática.
El analizador léxico lee de la entrada e intenta reconocer algún patrón, entonces ejecuta la
acción y devuelve al analizador sintáctico el token reconocido (si como acción léxica se ha
puesto un return TIPO_TKN;) y el control del programa.

Lenguajes Formales y Teoría de Compiladores – Semestre II 2004 3


Octubre de 2004 -Jorge Jorquera M.
jojorque@udec.cl

III.-BISON: Generador De Analizadores Sintácticos

Bison es una herramienta que traduce la especificación de una gramática de


contexto libre a un programa en C implementando un analizador LL(1) que reconoce
frases de esa gramática. El analizador LL(1) generado es un parser bottom-up de
desplazamiento-reducción (shift-reduce). Además de reconocer frases se puede asociar
código C a las reglas de la gramática, lo que permite especificar acciones semánticas, que
se ejecutarán cada vez que se aplique la regla correspondiente. Bison es compatible con
Yacc (el generador de analizador clásico de los sistemas UNIX), además añade una seríe
de características no disponibles en Yacc.

La generación de una analiz ador Bison tiene lugar de la siguiente forma: la entrada
es un archivo con la extensión ‘.y’ que contiene la definición de los terminales, no-
terminales y la gramática. La salida es un programa en C que realiza el análisis sintáctico.
Al igual que Flex, consta de tres secciones:

Declaraciones y Definiciones
%%
Reglas de la gramática
%%
Código Auxiliar

Ejemplo de analizador léxico:


DIGITO [0-9]
...
%%
{DIGITO}+ {yylval.entero=atoi( yytex);
return TKN_NUM;}
...
%%

Ejemplo de analizador sintáctico:


...
%union{
int entero;
}
...
%token <entero> TKN_NUM
...
%%
inicio : TKN_NUM TKN_RESTA TKN_NUM {
$$ = $1-$3; printf(“%d - %d = %d”,$1,$3,$$); };
%%
...

Lenguajes Formales y Teoría de Compiladores – Semestre II 2004 4


Octubre de 2004 -Jorge Jorquera M.
jojorque@udec.cl

Declaraciones y Definiciones

En esta sección se puede incluir :


Código C necesario para las acciones semánticas. Se incluye código C
necesario para las acciones asociadas a las reglas. El código C se incluirá entre los
símbolos %{ y %}, y será copiado tal cual al archivo XXXX.tab.c. (Generalmente serán
#includes y/o estructuras y variables del código de usuario que se vean afectadas por
las acciones).

Definiciones de BISON:

a) Especificación del tipo de datos asociado a los tokens y a los no terminales.


Se utiliza la directiva %union
Ej.:
%union {
int entero;
double real;
char * texto;
}
b) Especificación de TOKENs y no terminales.
Directivas de BISON para declarar los TOKEN de la gramática y especificar sus
propiedades (asociatividad, precedencia).

Directiva %token: Declara un TOKEN indicado su nombre y opcionalmente su


tipo (el tipo deberá ser uno de los identificadores declarados en la directiva %union).
Formato : %token <tipo> nombre
Ej. : %token BEGIN END IF THEN ELSE
%token <entero> CONSTANTE_ENTERA
%token <real> CONSTANTE_REAL
%token <texto> NOMBRE_VARIABLE NOMBRE_FUNCION
NOTA: No es necesario declarar los TOKENS compuestos por único caracter. Cada caracter
que se usa como TOKEN se identifica por el valor numérico de su código ASCII. (Para los
demás TOKENS se asignan constantes numéricas empezando en 256).

Directivas %left %right %nonasoc: Declaran un TOKEN especificando su


asociatividad (izquierda, derecha o no asociativo) y determina como actuará el
analizador sintáctico cuando se encuentre con una expresión con varios TOKENs de
ese tipo. Normalmente esos TOKENs serán operadores de algún tipo. Mismo formato
que %token
Formato: %left <tipo> nombre
Ej. : %left '-' '+' '*' '/'
%right '^' '='

Directiva %type: Especifica el tipo de un no terminal. No es necesario declarar


previamente los no terminales (se diferencian por que aparecen en el lado izq. de las
reglas), pero si es necesario especificar su tipo en el caso de que tengan asociado
valores semánticos.
Formato : %type <tipo> nombre_no_terminal
Ej. : %type <entero> expresion_entera
%type <real> expresion_real

Lenguajes Formales y Teoría de Compiladores – Semestre II 2004 5


Octubre de 2004 -Jorge Jorquera M.
jojorque@udec.cl

Directiva %start : Identifica el no terminal que sirve como axioma de la


gramática
Formato : %start no_terminal
Por defecto, Bison utiliza como axioma de la gramática el no_terminal en el lado izquierdo
de la primera regla.

Reglas de la gramática

Formato de las reglas :


no_terminal : componente1 componenete2 ... componenteN
;

Cuando varias reglas tienen el mismo no terminal a la derecha, se puede abreviar la


notación en la forma :
no_terminal : lado_derecho_1
| lado_derecho_2
| lado_derecho_3
;
Las reglas epsilon son la que tienen el lado derecho vacio (suele incluirse un comentario
indicándolo).

Acciones: Las acciones contienen código C que se ejecutará cada vez que se
reconozca una instancia de la regla asociada. Las acciones se componen de sentencias
C incluidas entre llaves. Se suelen situar al final de la regla y se ejecutan cuando se
reconoce completamente la parte derecha de la regla. También se admiten acciones
en cualquier posición dentro de las reglas, que se ejecutarán en cuanto se reconozca
la fracción de regla asociada.

Pseudo-variables: Las pseudo-variables $$, $1, $2,.... permiten que dentro de


las acciones se pueda acceder a los valores semánticos a asociados a los símbolos de
la regla. $$ -> contiene el valor semántico asociado al no terminal del lado izquierdo
de la regla. $1, $2, ....$N -> contiene los valores semánticos asociados a los símbolos
(TOKENs y no terminales) del lado derecho de la regla. El tipo de esas pseudo-
variables será el tipo que se le haya asociado al símbolo correspondiente en la sección
de declaraciones (directivas %token, %type, %left, etc....). Cuando no se indica
ninguna acción en una regla, BISON añade por defecto la acción $$=$1, en caso de
que concuerden los tipos.

Código Auxiliar 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(), yyerror() e yylex() propias
del usuario (yyparse() deberá de ser llamada en algún punto del código del usuario
para comenzar el proceso de análisis típicamente dentro de main()).Cada vez que
yyparse() necesite un nuevo TOKEN, llamará a la función yylex(), que le devolverá un
entero que identifica al siguiente token en el archivo de entrada (esos enteros se
especifican en el archivo XXXX.tab.h). Si ha alcanzado el final del archivo, yylex()
devuelve el TOKEN EOF (end of file).

Lenguajes Formales y Teoría de Compiladores – Semestre II 2004 6


Octubre de 2004 -Jorge Jorquera M.
jojorque@udec.cl

IV.- Integración FLEX - BISON.

Para utilizar el analizador generado con FLEX, es necesario :


Generar el archivo XXXX.tab.h en incluir en la sección de declaraciones C de la
expecificación FLEX.
%{
#include "XXXX.tab.h"
%}
%%
....

En la acción asociada al patrón del TOKEN se debe cargar en la variable yylval los
atributos léxicos que se vayan a utilizar en el análisis sintáctico (opcional) y devolver el
tipo del TOKEN encontrado mediante una orden return (obligatorio).

%%
[0-9]+ { yylval.entero = atoi(yytext[0]);
return CONSTANTE_ENTERA; }
"+" { return yytext[0]; }
. . . .
%%

(Para los caracteres simples, basta devolver su valor en ASCII.)

Para compilar
bison –d sintactico.y
flex lexico.l
gcc lex.yy.c sintactico.tab.c –o mianalizador –lfl

Al compilar el archivo ‘.bison’ con la opción –d se crea un archivo sintactico.tab.h con la


definición de los tokens, que hay que incluir en la parte léxica y un archivo sintactico.tab.c
con la implementación del analizador. El archivo ‘.flex’ genera un archivo ‘.c’ llamado
siempre lex.yy.c que será el que se compile con el compilador de C junto con el
sintactico.tab.c. La opción -v envía la tabla del analizador LL(1) y otra información a un
archivo de texto con extensión .ouput.

PALABRAS AL CIERRE

Espero que este tutorial les sea de provecho, cualquier sugerencia para mejorarlo es
bienvenida.

Saludos a todos!!!

Koke.

Lenguajes Formales y Teoría de Compiladores – Semestre II 2004 7

Das könnte Ihnen auch gefallen