Está en la página 1de 10

UNIVERSIDAD NACIONAL JORGE BASADRE GROHMANN

FACULTAD DE INGENIERÍA
ESCUELA PROFESIONAL DE INGENIERÍA DE INFORMÁTICA Y SISTEMAS

“LABORATORIO N°6: INTRODUCCIÓN A BISON”

PRESENTADO POR

ALUMNO:

Juan Pablo Apaza Atencio, 2015-119015

CURSO:
Compiladores y teoría de lenguajes

TACNA-PERÚ
2018
LABORATORIO N° 6: INTRODUCCIÓN A BISON

I. OBJETIVOS

● Conocer e investigar el funcionamiento del analizador sintáctico con Bison.

● Aprender las gramáticas formales, expresiones regulares de Bison

II. MATERIALES

● Computadora que tenga instalado una máquina virtual del sistema operativo Linux.

III. FUNDAMENTO TEÓRICO

3.1. Definición de analizador sintáctico

El análisis sintáctico, conocido en inglés como parser, es un análisis a nivel de sentencias, y


es mucho más complejo que el análisis léxico.

Entre sus funciones principales se consideran las siguientes:

❏ Genera un árbol de análisis sintáctico a partir de los componentes léxicos obtenidos


en la etapa anterior.

❏ 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

3.2. Definición de Bison

Bison es un programa generador de analizadores sintácticos con el propósito convertir una


descripción para una gramática independiente del contexto (en realidad de una subclase de
éstas, las LALR) en un programa en C , C++ o Java que analiza esa gramática.

Es compatible con Yacc, una herramienta clásica de Unix para la generación de


analizadores léxicos, pero es un desarrollo diferente realizado por GNU bajo licencia
GPL.

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.

3.3. Archivos y funciones que genera Bison al ejecutar

Habitualmente Bison se utiliza junto con Flex.

❖ Flex genera un analizador léxico: yylex()


❖ Bison genera un analizador sintáctico: yyparse()

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()

Como se observa en la figura 3 la función main() invoca a la función de análisis sintáctico


yyparse() este retorna un 0 si termina el análisis con éxito (entrada es sintácticamente
correcta) , en caso contrario devuelve un 1.

La función yyparse() solicita a la función yylex() los tokens de la entrada y comprueba si


forman una construcción válida en base a las reglas de la gramática descritas en el fichero de
especificado. Cuando detecta un error sintáctico invoca a la función yyerror() y termina el
proceso de análisis devolviendo un 1.

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

a) Sección de definiciones: Incorpora bloques de código C que se copiará literalmente


en el fichero de salida, definir el tipo de la variable yylval, los símbolos (terminales y
no terminales) de la gramática, el axioma de la gramática, y la asociatividad y
precedencia de los operadores.

b) Sección de reglas: Contiene las reglas de la gramática escritas en un formato


concreto y opcionalmente con acciones asociadas a las reglas.

c) Sección de funciones de usuario: En esta sección se ubican funciones de soporte


como la función yyerror(), el contenido de esta sección se copia literalmente en el
fichero de salida. en aplicaciones grandes, es más conveniente agrupar todas las
funciones de soporte en un fichero o conjunto de ficheros, en lugar de incluirlas en
esta sección.

3.5. Reglas gramaticales en Bison

Una regla gramatical de Bison tiene la siguiente forma general:


resultado: componentes...
;
donde resultado es el símbolo no terminal que describe esta regla y componentes son los
diversos símbolos terminales y no terminales que están reunidos por esta regla. Por ejemplo,
exp: exp ‘+’ exp
;
dice que dos agrupaciones de tipo exp, con un token ‘+’ en medio, puede combinarse en una
agrupación mayor de tipo exp.
Los espacios en blanco en las reglas son significativos únicamente para separar símbolos.
Puede añadir tantos espacios en blanco extra como desee.
Distribuidas en medio de los componentes pueden haber acciones que determinan la
semántica de la regla. Una acción tiene el siguiente aspecto:

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

a) Reconocer una suma de múltiples enteros.

expr: expr OPSUM exp


| CTE
Exp_l: Exp_Calc
| Cal
;
b) Reconocer una frase y enviar mensaje de validación

dialogo : frase
| dialogo frase
;
frase : '\n'
| sujeto predicado '\n' {printf("\n>> Frase correcta\n");}
;

c) Reconocer de una frase las palabras identificadas

frase_preposicional : PREPOSICION frase_nominal


;
predicado : frase_verbal
;
frase_verbal : VERBO
| VERBO frase_nominal
| VERBO frase_preposicional
;
d) Reconocer un signo para realizar una operación aritmética

exp: ENTERO { $$ = $1; }


| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 -$3; }
;

V. CONCLUSIONES

En el presente laboratorio se pudo concluir, lo siguiente:

Se pudo conocer más sobre la herramienta Bison que nos ayudan a escribir analizadores muy
rápidos para formatos de archivo casi arbitrarios.

Es importante conocer sobre Bison en el curso de compiladores debido a que tienen


mecanismos para el manejo de errores y la recuperación, que es algo que definitivamente no
desea intentar incluir en un analizador personalizado.

También podría gustarte