Tema: Generación de analizadores con YACC

Anuncio
Compiladores. Guía 5
1
Facultad:
Ingeniería
Escuela:
Computación
Asignatura: Compiladores
Tema: Generación de analizadores con YACC
Contenido
En esta guía se expondrá la forma
analizador
léxico
y
sintáctico
a
herramienta de YACC y LEX.
de generar
través
de
el
la
Objetivos Específicos


Aprender a utilizar la herramienta de YACC para la
generación de analizadores sintácticos.
Conocer la sintaxis de LEX y YACC para la generación de
analizadores léxicos y sintácticos.
Material y Equipo



Guía de Laboratorio Nº 5.
Parser Generator http://www.bumblebeesoftware.com/.
Libro “Construcción de compiladores” de Kenneth
Louden.
C.
Introducción Teórica
YACC: Generación de analizadores sintácticos LR
Guía 3
Un generador de analizadores sintácticos es un programa que
toma
Guíacomo
4 su entrada una especificación de la sintaxis de un
lenguaje en alguna forma, y produce como su salida un
procedimiento de análisis sintáctico para ese lenguaje.
fía
Históricamente los generadores de analizadores sintácticos
fueron llamados compiladores de compilador, debido a que
todos los pasos de compilación eran realizados de manera
tradicional como acciones incluidas dentro del analizador
2
Compiladores. Guía 5
sintáctico. La visión moderna es considerar al analizador
como solo una parte del proceso de compilación, de modo que
este término se volvió obsoleto.
Un
generador
de
analizadores
sintácticos
ampliamente
utilizado que incorpora el algoritmo de análisis sintáctico
LR(1) se conoce como Yacc (Yet Anoter Compiler- Compiler es
decir, “otro compilador de compilador mas” en ingles).
Fundamentos de YACC
YACC toma un archivo de especificación (por lo regular con
sufijo .y) y produce un archivo de salida compuesto del
código fuente en C para el analizador sintáctico (por lo
general con sufijo .tab.c). Un archivo de especificación de
YACC tiene el formato básico
<sección de definiciones>
%%
<sección de reglas>
%%
<sección de rutinas>
De este modo existen tres secciones separadas mediante líneas
que contienen doble signo de porcentaje.
La sección de definiciones contiene información acerca de los
tokens, tipos de datos y reglas gramaticales que YACC
necesita para construir el analizador sintáctico. También
incluye cualquier código en C que debería ir directamente en
el archivo de salida a su inicio (sobre todo directivas
#include de otros archivos de código fuente). Esta sección
del archivo de especificación puede estar vacía.
La sección de reglas contiene reglas gramaticales en una
forma BNF modificada, junto con acciones en código C que se
ejecutaran siempre que se reconozca la regla gramatical
asociada. Las convenciones de meta símbolos utilizadas en
reglas gramaticales son de la manera siguiente. Como es
habitual, la barra vertical se utiliza para las alternativas
(las alternativas también se pueden escribir por separado).
El símbolo flecha “→” que hemos empleado para separar el lado
izquierdo y derecho de una regla gramatical se reemplaza en
YACC por un signo de dos puntos. También un signo de punto y
coma debe finalizar cada regla gramatical.
Compiladores. Guía 5 3
La
tercera
sección,
de
rutinas
auxiliares,
contiene
declaraciones de procedimientos y funciones que de otra
manera pueden no estar disponibles a través de archivos
#include y que son necesarias para completar el analizador
sintáctico y/o el compilador.
Esta sección puede estar vacía, y si este es el caso se puede
omitir el segundo meta símbolo de porcentaje doble del
archivo de especificación. De esta manera, un archivo de
especificación mínimo de YACC consistiría solo de %% seguidos
por reglas gramaticales y acciones (las acciones también se
pueden omitir si solo tratamos de analizar la gramática).
YACC también permite insertar comentarios al estilo de C en
el archivo de especificación en cualquier punto donde no
interfieran con el formato básico.La primera sección que
incluye las directivas #include se encierra entre los
símbolos %{ y %} nótese que los signos de porcentaje se
anteponen a las llaves.
Para definir un token se realiza así: %token nombreToken
Si se desea inicializar como una variable deberá colocarse el
valor numérico a continuación del nombre del token.
En la segunda sección, las reglas gramaticales se colocan
así: expresión: expresión términos
Cuando se reconoce una regla gramatical, cada símbolo en la
regla posee un valor, que se supone es un entero a menos que
sea cambiado por el programador.
Esos valores se conservan en una pila de valor mediante Yacc,
la cual se mantiene paralela a la pila de análisis
sintáctico. Se puede hacer referencia a cada valor de símbolo
en la pila utilizando una pseudo variable que comience con el
signo “$”. $$ representa el valor del no terminal que se
acaba de reconocer, es decir, el símbolo en el lado izquierdo
de la regla gramatical. Las pseudo variables $1, $2, $3 y así
sucesivamente, representan los valores de cada símbolo en
sucesión en el lado derecho de la regla gramatical.
Procedimiento
Yacc no es directamente un analizador sino un generador de
Guía 3
analizadores.
A partir de un fichero fuente en yacc, se
genera un fichero fuente en C que contiene el analizador
sintáctico.
Sin embargo, un analizador sintáctico de yacc no
Guía 4
fía
4
Compiladores. Guía 5
puede funcionar por sí solo, sino que necesita un analizador
léxico externo para funcionar.
Dicho de otra manera, el fuente en C que genera yacc contiene
llamadas a una función yylex() que debe estar definida y debe
devolver el tipo de lexema encontrado. Además, es necesario
incorporar también una función yyerror(), que será invocada
cuando el analizador sintáctico encuentre un símbolo que no
encaja en la gramática.
La estructura general de un programa en YACC es la siguiente:
<sección de definiciones>
%%
<sección de reglas>
%%
<sección de rutinas>
Tabla 1
Ejemplo 1
Construir un analizador sintáctico que reconozca la gramática
para una calculadora simple, con las operaciones suma, resta,
multiplicación y división con la herramienta Yacc.
Abra y ejecute el programa “Parser Generator” y abra un nuevo
texto, luego digite el código de la tabla 2.
Figura 1: Ambiente de Parser Generator.
Compiladores. Guía 5 5
Gramática para la calculadora simple:
exp -> exp opsuma term | term
opsuma -> + | term -> term opmult factor | factor
opmult -> *
factor -> (exp) | numero
Figura 2: Creando un archivo para introducir el texto de la
tabla 2.
/*Sección de definición*/
%token NUMBER
%{
#include <ctype.h>
#include <stdio.h>
#define YYSTYPE double /* double type para pila YACC */
%}
/*La seccion de codigo de c de la definicion debe estar entre
los delimitadores %{ y %}*/
%%
/*Fin de la seccion de definiciones e inicio de la seccion de
reglas de derivacion para el analizador sintactico*/
lines
}
: lines expr '\n'
| lines '\n'
| /* e */
| error '\n'
last line:"); yyerrok(); }
;
expr : expr '+' term
| expr '-' term
| term
;
{ printf("%g\n", $2);
{
yyerror("reenter
{ $$ = $1 + $3; }
{ $$ = $1 - $3; }
6
Compiladores. Guía 5
/*Los símbolos $$ indican el valor introducido en la pila de
valor manejada por YACC, es el no terminal que se ha
reconocido en ese momento del lado izquierdo de la expresión,
y los símbolos $1, $2, etc. indican el valor de las
pseudovariables que vaya encontrando en ese orden hacia la
derecha*/
/*pseudovariables term=$1 '*'=$2 factor=$3 */
term : term '*' factor
{ $$ = $1 * $3; }
| term '/' factor
{ $$ = $1 / $3; }
| factor
;
factor
: '(' expr ')'
| '(' expr error
yyerror("missing ')'"); yyerrok(); }
| '-' factor
| NUMBER
;
{ $$ = $2; }
{
$$
=
$2;
{ $$ = -$2; }
%%
/*Fin de la seccion de reglas y adicion de rutinas auxiliares
en c*/
int main(void)
{
yyparse();
/*Invocacion de la funcion del analizador sintactico*/
return 0;
}
/*Definición del analizador léxico*/
int yylex(void)
{
int c;
while ((c = getchar()) == ' ');
/*Elimina los espacios en blanco*/
if (c == '.' || isdigit(c)) {
/*El character . indica que se termino el programa*/
ungetc(c, stdin);
scanf("%lf", &yylval);
return NUMBER;
}
return c;
}
Tabla 2
Ahora procederemos a guardar nuestro archivo para generar el
analizador sintáctico.
Compiladores. Guía 5 7
Figura 3: De click sobre el icono del disket “Save”,
seleccionar nombre y ubicación y guardamos el archivo como
“calculadora”.
Figura 4: Clic en el menú “Project” y luego “LibBuilder” para
construir el YACC y las librerías de LEX.
8
Compiladores. Guía 5
Figura 5: Se construyeron las librerías, se muestran 0
errores, en la ventana LibBuilder de clic en el botón
“Close”.
Figura 6: Procedemos a través del asistente a convertir el
código YACC, para ello dar clic en el menú “Project” y a
continuación dar clic sobre la opción “ParseWizard”.
Compiladores. Guía 5 9
Figura 7:
ubicación
luego el
escogemos
Microsoft
A continuación colocamos el nombre del proyecto, la
donde se colocarán los archivos de resultado y
lenguaje objetivo en nuestro caso C++, por ultimo
el compilador del lenguaje objetivo y escogemos
Visual C++ de 32 bits.
Figura 8: Escogemos a continuación de los tipos de archivos a
generar de forma intermedia “YACC and Lex file”.
10 Compiladores. Guía 5
Figura 9: Escogemos los nombres de los archivos YACC,
colocamos “calculadora.y” y “calculadora” respectivamente.
Figura 10: Escogemos el nombre de los archivos del analizador
léxico, ingrese “calculadoralex.l” y “calculadoralex” en las
cajas correspondientes.
Compiladores. Guía 5 11
Figura 11: Archivo calculadoralex.l que se utilizara como
analizador léxico escrito en lenguaje Lex aun.
Figura 12: Archivo calculadora que se utilizara
analizador sintáctico escrito en lenguaje YACC.
como
12 Compiladores. Guía 5
Figura 13: Procedemos ahora compilar ambos archivos del
proyecto calculadora, para ello damos clic en el menú
“Project” luego clic sobre la opción “Compile File”.
Figura 14: Ventana de resultados donde nos dice que no hubo
ningún error en la generación de los archivos C++ a partir de
los archivos Lex y YACC.
Al terminar esta operación, en la carpeta que usted ha
escogido como carpeta destino se deben visualizar los
archivos “calculadoralex.h” y “calculadoralex.cpp”, ambos
Compiladores. Guía 5 13
escritos con lenguaje C++ y están listos para ser usados en
un compilador que reconozca el lenguaje de la calculadora
básica.
Figura 15: Archivos generados por Parser Generator para el
proyecto de la calculadora.
Análisis de resultados
Construya
un
analizador
sintáctico
ascendente
con
la
herramienta Parser Generator para la gramática del lenguaje
Micro C.
Investigación complementaria
Responda:
 Que es un analizador semántico
 Cuál es su función principal
 Algoritmo para desarrollarlo
 Cuál es su dependencia con el analizador sintáctico
 Qué es una tabla de símbolos
 Cuáles son los tipos de comprobaciones realizadas por un
analizador semántico.
 Que es un árbol de sintaxis abstracta.
 Que es un AST decorado.
Bibliografía


“Construcción de Compiladores. Principios y practica”,
Kenneth C. Louden.
“Compiladores. Principios técnicas y Herramientas”.
Sethi Ullman. Pearson Education.
14 Compiladores. Guía 5
Hoja de cotejo:
Guía 5: Generación de analizadores
con YACC
Tema: Presentación
del programa
Alumno
:
Docente:
5
1
Máquina No:
Máquina No:
Máquina No:
GL:
Alumno:
Docente:
GL:
Docente:
GL:
Fecha:
a
EVALUACION
%
CONOCIMIENTO
Del 20
al 30%
APLICACIÓN
DEL
CONOCIMIENTO
Del 40%
al 60%
1-4
5-7
8-10
Conocimie
nto
deficient
e de los
fundament
os
teóricos
Conocimiento
y explicación
incompleta de
los
fundamentos
teóricos
Conocimiento
completo y
explicación
clara de los
fundamentos
teóricos
No tiene
actitud
proactiva
.
Actitud
propositiva y
con
propuestas no
aplicables al
contenido de
la guía.
Tiene actitud
proactiva y sus
propuestas son
concretas.
ACTITUD
Del 15%
al 30%
TOTAL
100%
Nota
Descargar