Descargar

Guía básica de Bison y Flex (página 2)


Partes: 1, 2

Declaraciones del Bison

Como se mencionó anteriormente, en esta parte se declaran los símbolos que se utilizan en gramática y además se definen los tipos de los valores semánticos.

Los no terminales se declaran si es necesario asociarle un valor semántico.

Ejemplo de declaración de Tokens:

%token NUM /* Se declara un token que tiene asociado el tipo de datos por defecto*/

Para crear varios tipos se utiliza

%union {

int itype; /* Definimos un tipo entero que se llama itype*/

double dtype; /* Definimos un tipo double que se llama dtype*/

}

Con esta especificación de tipos cuando declaramos un Token tenemos que especificarle el tipo que tiene asociado.

%token <itype> TK_INT /* Se declara un Token literal entero*/

%token <dtype> TK_DOUBLE /* Se declara un token literal real*/

Precedencia de los operadores

Se utiliza %left, %right o %nonassoc para especificar la asociatividad de los operadores, la prioridad se establece por el orden de aparición en la declaración.

Para declarar un Token de esta forma se trabaja con la misma sintaxis que para declarar un Token de la forma %token visto anteriormente.

Ejemplo:

%right '='

%left '-' '+'

%left '*' '/'

%left NEG /* Negación, menos unario */

%right '^' /* Potencia */

En este ejemplo definimos que el de menor precedencia es el operador de asignación y se define que es asociativo por la derecha, le siguen los operadores de adición y substracción que tienen la misma precedencia entre ellos, mayor que la asignación y son asociativos por la izquierda, así sucesivamente, y por último se define que el de mayor precedencia es el operador de potenciación.

Declaración de no terminales

La misma sintaxis que con %token pero utilizando %type

Ejemplo:

%type <itype> exp

Donde itype se tiene que haber creado en %union como vimos anteriormente.

Resumen de las declaraciones del Bison

%skeleton "lalr1.cc": Esta directiva es necesaria para compilar el proyecto para C++, la función es crear los ficheros:

  1. 'position.hh'
  2. 'location.hh' (Estos dos primeros ficheros son utilizados para la localización y posición de los tokens en el fichero fuente)
  3. 'stack.hh' (Pila auxiliar utilizada por el parser)
  4. 'file.hh'
  5. 'file.cc' (Declaración e implementación de la clase parser, 'file' es el nombre del fichero de salida)

%define "parser_class_name" "name": Cambia el nombre por defecto de los ficheros 'output.hh' y 'output.cc' por el definido en "name".

%defines: Se utiliza para especificarle al Bison que cree el fichero "file.hh", por defecto solo se crea "file.cc".

%error-verbose: esta directiva se utiliza para habilitar la muestra de mensajes de error (%debug habilita el traceo durante el proceso de parsing)

%parse-param{argument_declaration}: Declara un parámetro adicional que yylex acepta.

%lex-param {argument_declaration}: Declara un parámetro adicional que yylex acepta.

%locations: Cuando es usada, el parser habilita la búsqueda de localizaciones, dos clases auxiliares definen una posición (un puntero a un archivo) y una localización (un rango compuesto por un par de posiciones).

%initial-action: Corre el código del usuario antes de parsear.

@$: es el conjunto para el rango desde @1 hasta @n, de una regla con n componentes.

%destructor { delete $$; } "identificador": Habilita la liberación de memoria durante el proceso de recuperación de errores.

Introducción al Flex:

El Flex define las reglas de reconocimiento de símbolos (Tokens) a partir de expresiones regulares. Cuando un Token es reconocido por uno de estos patrones de agrupamiento se le define una acción, por lo general esta acción es devolver el Tipo y el valor (lexema).

El Flex cuando se utiliza combinado con el Bison, utiliza las definiciones de los Tokens realizadas en el Bison para la comunicación entre ellos,

Los ficheros del Flex para C++ utilizan por convenio la extensión ‘.ll’. La sintaxis de un fichero en flex es la siguiente:

… definiciones …

%%

… reglas…

%%

… subrutinas …

Expresiones Regulares

Caracteres Especiales

Explicación

.

Reconoce todos los caracteres excepto los cambios de línea

n

Cambio de línea

*

Repite cero o muchas veces

+

Repite una o muchas veces

?

Repite cero o una vez

^

Define el inicio de la expresión

$

Define el final de la expresión

|

Operador OR

""

Define una cadena, dentro se tienen que escapar los caracteres especiales del C para que se puedan reconocer, ejemplo: n t …

[]

Agrupa un rango de caracteres de los cuales se puede seleccionar uno solo en cada momento.

()

Agrupa expresiones regulares.

{}

Expande los tokens o reconoce determinada cadena que se repitan según el rango que se especifique entre las llaves

Ejemplos:

abc abc

abc* ab abc abcc abccc …

abc+ abc abcc abccc …

a(bc)+ abc abcbc abcbcbc …

a(bc)? a abc

[abc] Uno entre: a, b, c

[a-z] Una letra en el rango de la a-z

[a-z] Uno entre: a, -, z (Escaparon el menos porque tiene un significado diferente (El de establecer el rango cuando esta entre dos valores del mismo tipo))

[-az] Uno entre: -, a, z

[A-Za-z0-9]+ Al menos un carácter alfanumérico.

[ tn]+ Espacios en blanco.

[^ab] Cualquier carácter excepto: a, b (Porque ^ está al inicio)

[a^b] Uno entre: a, ^, b

[a|b] Uno entre: a, |, b

a|b Uno entre: a, b

{letra}+ si se definió el Token letra, entonces a partir de esta nueva definición se pueden definir palabras

a{1,5} reconoce las cadenas donde se repita la 'a' de 1 a 5 veces

Partes del Fichero

Se había mostrado las partes de un fichero en Flex:

… definiciones …

%%

… reglas…

%%

… subrutinas …

Las definiciones y las subrutinas no son obligatorias, en las reglas siempre hay que definir al menos una, y siempre después de ‘%%’ aunque no existan definiciones y si no existen subrutinas no es necesario poner el último ‘%%’.

Definiciones

En esta parte si una línea comienza con un espacio en blanco o con un tabulador el contenido de esa línea se copia exactamente en el fichero de código C++ que se genera.

Las directivas que se vayan a utilizar en el programa se colocan entre ‘%{‘ y ‘}%’

Todo lo que se coloque en la primera columna de esta sección y que no este entre ‘%{‘ y ‘}%’ se tomará como una regla de sustitución de cadenas de la forma:

nombre patrón

Esto se utiliza para definir los Tokens que se desean reconocer, por ejemplo:

digito [1-9]

letra [a-zA-Z]

numero {digito}+

palabra {letra}+

blanco [ t]+

rep a{1,5}

Reglas

Las reglas están formadas por un reconocimiento de un Token y una acción asociada a este reconocimiento, si no se define ninguna acción no se hace nada cuando se reconoce dicho Token.

Si aparecen cadenas que no se reconocen por ninguno de los tokens estas se imprimen como aparecen. Una solución para que esto no pase es poner una regla que sea '.' que reconoce cualquier carácter excepto un cambio de línea, pudiéndole asociar otro comportamiento como devolver un Token de error léxico, etc.

Las reglas se pueden realizar a partir de lo que se definió anteriormente, un ejemplo de esto:

{blanco} ;

Esta regla define que no se haga nada al aparecer un espacio en blanco o un tabulador

{rep} printf("%d", yyleng);

Esta regla define que cada vez que se encuentre una cadena compuesta por 'a' entre 1 y 5 repeticiones, imprima la longitud de dicha cadena.

{palabra} printf("%s",yytext);

Cada vez que se encuentre alguna palabra, esta se imprime en pantalla, si entre dos palabras hay un espacio en blanco, este no se imprime (por la primera regla)

{numero} printf("n");

Cada vez que se encuentre algún número imprime en pantalla un cambio de línea.

Cuando las reglas son complejas podemos definirlas entre llaves y escribirlas en varias líneas.

Subrutinas

Se implementan funciones que serán copiadas para el fichero con el código en C++ exactamente como se implementan en esta sección.

 

Datos de los autores:

Daynel Marmol Lacal

Lic. en Ciencias de la Computación

Profesor de programación

Universidad de las Ciencias Informáticas (UCI)

Cuidad de La Habana, Cuba

Leansy Alfonso Pérez

Ing. Informático

Profesor de Programación

Universidad de las Ciencias Informáticas (UCI)

Cuidad de La Habana, Cuba

Categoría del trabajo: Programación

Partes: 1, 2
 Página anterior Volver al principio del trabajoPágina siguiente