Documentos de Académico
Documentos de Profesional
Documentos de Cultura
FACULTAD DE INGENIERÍA
ESCUELA PROFESIONAL DE INGENIERÍA DE INFORMÁTICA Y SISTEMAS
PRESENTADO POR
ALUMNO:
CURSO:
Compiladores y teoría de lenguajes
TACNA-PERÚ
2018
LABORATORIO N° 6: INTRODUCCIÓN A BISON
I. OBJETIVOS
II. MATERIALES
● Computadora que tenga instalado una máquina virtual del sistema operativo Linux.
❏ Toma el programa fuente en forma de tokens, que recibe del analizador léxico y
determinar la estructura de las sentencias del programa.
El análisis sintáctico finalmente, lo que hace es agrupar a los tokens en clases sintácticas
(denominadas no terminales en la definición de la gramática), tales como expresiones,
procedimientos, etc., obteniendo un árbol sintáctico (u otra estructura equivalente) en la cual
las hojas son los tokens y cualquier nodo, que no sea una hoja, representa un tipo de clase
sintáctica. (Como se observa en la figura 1).
Figura 1. Árbol Sintáctico
Todas las gramáticas escritas apropiadamente para Yacc deberían funcionar con
Bison sin ningún cambio. Usándolo junto a Flex esta herramienta permite construir
compiladores de lenguajes
Figura 2. Flex y Bison.
Bison construye la función yyparse() de análisis sintáctico a partir del fichero al que
corresponde. La función yyparse() se ubica en el fichero y.tab.c.
Las funciones de usuario incluyen funciones de soporte como por ejemplo funciones para
generar código, funciones invocadas por Flex y Bison como por ejemplo yywrap() o
yyerror(), y también la función principal que invoca al analizador sintáctico para realizar la
compilación, todas estas funciones se pueden organizar en varios ficheros.
Las librerías del sistema proporcionan versiones sencillas de las funciones que son invocadas
por Flex y Bison así como una versión mínima de la función principal que invoca al
analizador léxico o al sintáctico. Si el usuario proporciona estas funciones no es necesario
utilizar las librerías. Dependiendo del sistema operativo, las librerías existen o no, por lo
tanto para facilitar la portabilidad del código, es recomendable que el usuario aporte sus
propias versiones de las funciones, o bien establezca de manera correcta las opciones de las
herramientas Flex y Bison.
Para obtener el programa objetivo alfa, se compilan y enlazan los ficheros descritos
anteriormente.
Figura 3. Comunicación entre las funciones main(), yylex() e yyparse()
La función yylex() lee el fichero de entrada para identificar los tokens descritos en el fichero
de especificación correspondiente. Cada vez que la función yylex() devuelve un token al
analizador sintáctico, si el token tiene un valor asociado, yylex() guarda ese valor en la
variable yylval antes de terminar.
Por ejemplo, un identificador de una variable, además de tener un número de token que lo
identifica y distingue de otros tipos de tokens, también tiene asociado como valor o atributo,
el lexema del identificador. Sin embargo, un paréntesis no tiene asociado ningún valor
o atributo. La función yyparse() utiliza el valor de la variable yylval en las acciones de
las reglas de la gramática.
3.4. Estructura de fichero Bison
Sentencias en C
Normalmente hay una única acción que sigue a los componentes.
Se pueden escribir por separado varias reglas para el mismo resultado o pueden unirse con el
caracter de barra vertical ‘|’ así:
resultado: componentes-regla1...
| componentes-regla2...
...
;
Estas aún se consideran reglas distintas incluso cuando se unen de esa manera. Si los
componentes en una regla están vacíos, significa que resultado puede concordar con la
cadena vacía (en notación formal sería e). Por ejemplo, aquí aparece cómo definir una
secuencia separada por comas de cero o más agrupaciones exp:
expseq: /* vacío */
| expseq1
;
expseq1: exp
| expseq1 ‘,’ exp
;
Es habitual escribir el comentario ‘/* vacío */’ en cada regla sin componentes.
Una regla se dice recursiva cuando su no-terminal resultado aparezca también en su lado
derecho. Casi todas las gramáticas de Bison hacen uso de la recursión, ya que es la única
manera de definir una secuencia de cualquier número de cosas. Considere esta definición
recursiva de una secuencia de una o más expresiones:
expseq1: exp
| expseq1 ‘,’ exp
;
Puesto que en el uso recursivo de expseq1 este es el símbolo situado más a la izquierda del
lado derecho, llamaremos a esto recursión por la izquierda. Por contraste, aquí se define la
misma construcción utilizando recursión por la derecha:
expseq1: exp
| exp ‘,’ expseq1
;
Cualquier tipo de secuencia se puede definir utilizando ya sea la recursión por la izquierda o
recursión por la derecha, pero debería utilizar siempre recursión por la izquierda, porque
puede analizar una secuencia de elementos sin ocupar espacio de pila (es decir, de forma
mucho más eficiente en memoria). La recursión indirecta o mutua sucede cuando el
resultado de la regla no aparece directamente en su lado derecho, pero aparece en las reglas
de otros no terminales que aparecen en su lado derecho.
Por ejemplo:
expr: primario
| primario ‘+’ primario
;
primario: constante
| ‘(‘ expr ‘)’
;
define dos no-terminales recursivos mutuamente, ya que cada uno hace referencia al otro.
IV. DESARROLLO
4. Ejemplos en Bison
dialogo : frase
| dialogo frase
;
frase : '\n'
| sujeto predicado '\n' {printf("\n>> Frase correcta\n");}
;
V. CONCLUSIONES
Se pudo conocer más sobre la herramienta Bison que nos ayudan a escribir analizadores muy
rápidos para formatos de archivo casi arbitrarios.