Prácticas de Procesadores de Lenguaje

Curso 2007/2008


Práctica 2: Analizador Sintáctico y Tabla de Símbolos

Objetivo de la Práctica

·         Esta práctica tiene como primer objetivo la codificación de un analizador sintáctico mediante el uso del lenguaje de programación C y la herramienta de ayuda a la generación de analizadores sintácticos bison.

·         Este analizador será utilizado por el compilador del lenguaje ALFA que va a desarrollarse durante el curso.

·         El segundo objetivo es la codificación de una tabla de símbolos. El alumno conoce el tipo de datos llamado tabla hash, los algoritmos para su gestión y su rendimiento de la asignatura de segundo Metodología y tecnología de la programación II (MTPII) y su uso como tabla de símbolos de la parte de teoría de la asignatura Procesadores de lenguaje.

 

Desarrollo de la Práctica

Codificación de una Especificación para bison

·         El alumno deberá escribir un fichero de nombre alfa.y que sea una especificación correcta para la entrada de la herramienta bison. Se recomienda al alumno que se familiarice primero con bison mediante las explicaciones que su profesor de prácticas realizará en su laboratorio.

Resolución de Conflictos

·        Cuando se compile el fichero alfa.y pueden aparecer mensajes de conflictos. Estos conflictos se refieren a los que encuentra el autómata a pila generado por la herramienta bison. Para obtener información acerca de ellos, se debe compilar el fichero alfa.y de la siguiente manera:

                    bison -d -y -v alfa.y

      con el flag -v se genera el fichero y.output que contiene la descripción completa del autómata y de los conflictos (si existieran).

      El alumno debe asegurarse de eliminar los conflictos siguiendo las indicaciones de su profesor de prácticas.

Modificación de la Especificación para flex

·         El alumno debe modificar el fichero alfa.l de la práctica 1 para poder ser enlazado con el fichero alfa.y. Para ello, utilizará como guía las explicaciones que su profesor de prácticas realizará en su laboratorio.

Codificación de un Programa de Prueba

·         El alumno también deberá escribir (en C) un programa de prueba del analizador sintáctico generado con bison, con los siguientes requisitos:

o        Nombre del programa fuente:  prueba_sintactico.c

o        Al ejecutable correspondiente, se le invocará de la siguiente manera:

prueba_sintactico [<nombre fichero entrada> [<nombre fichero salida>]]

o        Es decir, el programa se puede ejecutar:

§         Con 0 argumentos, entonces se utilizan la entrada y la salida estándares.

§         Con 1 argumentos, entonces se utiliza la salida estándar y el argumento como nombre del fichero de entrada.

§         Con 2 argumentos, entonces el primero se interpreta como el nombre del fichero de entrada y el segundo como el nombre del fichero de salida.

o        La estructura de los ficheros de entrada/salida se explican a continuación.

Descripción del Fichero de Entrada

·         El fichero de entrada contiene un programa escrito en lenguaje ALFA (no necesariamente correcto).

Descripción del Fichero de Salida

·         El fichero de salida se compone de un conjunto de líneas de dos tipos. En concreto:

o        Una línea por cada Token reconocido (desplazado) por el analizador léxico.

o        Una línea por cada producción reducida en el proceso de análisis sintáctico.

·         Cada línea correspondiente a un Token desplazado debe contener la siguiente información y formato:


D:       <token>

 

donde <token> es el fragmento de entrada reconocido por el analizador léxico y “D:” y “<token>” van separados por un tabulador.

·         Cada línea correspondiente a una regla reducida tendrá el formato siguiente:


R<nº regla>: <regla>

 

donde <nº regla> es el número que identifica la regla que se reduce en la gramática de ALFA especificada en el enunciado de la primera práctica, y <regla> es el texto de la regla reducida según aparece en la gramática. “R<nº regla>” y “<regla>” van separados por un tabulador. Los elementos que forman “<regla>” irán separados por espacios.

Ejemplos

·         Ejemplo 1: Si el fichero de entrada es el siguiente:

 

//

// Programa que eleva un número entero al cuadrado

//

INICIO

   ENTERO x, resultado;

   LEER x;

   resultado=x*x;

   ESCRIBIR resultado

FIN

 

·         El fichero de salida sería el siguiente:

 

D:        INICIO

D:        ENTERO

R8:       <tipo> ::= ENTERO

D:        x

R10:     <clase_escalar> ::= <tipo>

R5:       <clase> ::= <clase_escalar>

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ,

D:        resultado

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ;

R15:     <identificadores> ::= <identificador>

R16:     <identificadores> ::= <identificador> , <identificadores>

R4:       <declaracion> ::= <clase> <identificadores> ;

D:        LEER

R2:       <declaraciones> ::= <declaracion>

R18:     <funciones> ::=

D:        x

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ;

R54:     <lectura_escritura> ::= LEER <identificador>

R32:     <sentencia> ::= <lectura_escritura>

D:        resultado

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        =

D:        x

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        *

R68:     <exp> ::= <identificador>

D:        x

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ;

R68:     <exp> ::= <identificador>

R63:     <exp> ::= <exp> * <exp>

R43:     <asignacion> ::= <identificador> = <exp>

R29:     <sentencia> ::= <asignacion>

D:        ESCRIBIR

D:        resultado

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        FIN

R68:     <exp> ::= <identificador>

R56:     <lectura_escritura> ::= ESCRIBIR <exp>

R32:     <sentencia> ::= <lectura_escritura>

R27:     <sentencias> ::= <sentencia>

R28:     <sentencias> ::= <sentencia> ; <sentencias>

R28:     <sentencias> ::= <sentencia> ; <sentencias>

R1:       <programa> ::= INICIO <declaraciones> <funciones> <sentencias> FIN

 

·         Ejemplo 2: Si el fichero de entrada es el siguiente:

 

//

// Programa que eleva un número x a la potencia y

//

INICIO

   ENTERO x, y;

   ENTERO i, total;

  

   LEER x;

   LEER y;

   i=1;

   total=1;

   MIENTRAS (i<=y) HACER

      total=total*x;

      i=i+1

   FIN;

   ESCRIBIR total

FIN

 

·         El fichero de salida sería el siguiente:

 

D:        INICIO

D:        ENTERO

R8:       <tipo> ::= ENTERO

D:        x

R10:     <clase_escalar> ::= <tipo>

R5:       <clase> ::= <clase_escalar>

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ,

D:        y

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ;

R15:     <identificadores> ::= <identificador>

R16:     <identificadores> ::= <identificador> , <identificadores>

R4:       <declaracion> ::= <clase> <identificadores> ;

D:        ENTERO

R8:       <tipo> ::= ENTERO

D:        i

R10:     <clase_escalar> ::= <tipo>

R5:       <clase> ::= <clase_escalar>

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ,

D:        total

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ;

R15:     <identificadores> ::= <identificador>

R16:     <identificadores> ::= <identificador> , <identificadores>

R4:       <declaracion> ::= <clase> <identificadores> ;

D:        LEER

R2:       <declaraciones> ::= <declaracion>

R3:       <declaraciones> ::= <declaracion> <declaraciones>

R18:     <funciones> ::=

D:        x

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ;

R54:     <lectura_escritura> ::= LEER <identificador>

R32:     <sentencia> ::= <lectura_escritura>

D:        LEER

D:        y

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ;

R54:     <lectura_escritura> ::= LEER <identificador>

R32:     <sentencia> ::= <lectura_escritura>

D:        i

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        =

D:        1

R89:     <constante_entera> ::= TOK_NUMERO

R86:     <constante> ::= <constante_entera>

R69:     <exp> ::= <constante>

D:        ;

R43:     <asignacion> ::= <identificador> = <exp>

R29:     <sentencia> ::= <asignacion>

D:        total

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        =

D:        1

R89:     <constante_entera> ::= TOK_NUMERO

R86:     <constante> ::= <constante_entera>

R69:     <exp> ::= <constante>

D:        ;

R43:     <asignacion> ::= <identificador> = <exp>

R29:     <sentencia> ::= <asignacion>

D:        MIENTRAS

D:        (

D:        i

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        <=

R68:     <exp> ::= <identificador>

D:        y

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        )

R68:     <exp> ::= <identificador>

R81:     <comparacion> ::= <exp> <= <exp>

R71:     <exp> ::= ( <comparacion> )

D:        HACER

D:        total

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        =

D:        total

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        *

R68:     <exp> ::= <identificador>

D:        x

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        ;

R68:     <exp> ::= <identificador>

R63:     <exp> ::= <exp> * <exp>

R43:     <asignacion> ::= <identificador> = <exp>

R29:     <sentencia> ::= <asignacion>

D:        i

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        =

D:        i

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        +

R68:     <exp> ::= <identificador>

D:        1

R89:     <constante_entera> ::= TOK_NUMERO

R86:     <constante> ::= <constante_entera>

R69:     <exp> ::= <constante>

D:        FIN

R60:     <exp> ::= <exp> + <exp>

R43:     <asignacion> ::= <identificador> = <exp>

R29:     <sentencia> ::= <asignacion>

R27:     <sentencias> ::= <sentencia>

R28:     <sentencias> ::= <sentencia> ; <sentencias>

R52:     <bucle> ::= MIENTRAS <exp> HACER <sentencias> FIN

R31:     <sentencia> ::= <bucle>

D:        ;

D:        ESCRIBIR

D:        total

R90:     <identificador> ::= TOK_IDENTIFICADOR

D:        FIN

R68:     <exp> ::= <identificador>

R56:     <lectura_escritura> ::= ESCRIBIR <exp>

R32:     <sentencia> ::= <lectura_escritura>

R27:     <sentencias> ::= <sentencia>

R28:     <sentencias> ::= <sentencia> ; <sentencias>

R28:     <sentencias> ::= <sentencia> ; <sentencias>

R28:     <sentencias> ::= <sentencia> ; <sentencias>

R28:     <sentencias> ::= <sentencia> ; <sentencias>

R28:     <sentencias> ::= <sentencia> ; <sentencias>

R1:       <programa> ::= INICIO <declaraciones> <funciones> <sentencias> FIN

 

 

 Implementación de una tabla de símbolos

·        El alumno debe escribir los ficheros y módulos C que considere necesarios para la definición e implementación de la tabla de símbolos. Para todas sus decisiones de diseño utilizará como referencia las indicaciones que conoce de la parte de teoría y las explicaciones que su profesor de prácticas realizará en su laboratorio.

 

Autocorrección de la práctica

·         En la página web del laboratorio de Procesadores de Lenguaje hay disponible un enlace para que el alumno se descargue el fichero comprimido autocorreccion_sintactico.zip. Este fichero contiene los 15 ficheros de salida a generar por el programa prueba_sintactico desarrollado en esta segunda práctica, tomando como entrada los mismos 15 programas escritos en lenguaje ALFA que se utilizaron en la primera práctica. El alumno deberá comparar las salidas que obtiene de su programa prueba_sintactico con las salidas proporcionadas en el fichero autocorreccion_sintactico.zip. Para realizar la comparación en Linux se puede utilizar el comando diff que compara el contenido de dos ficheros.

 

Evaluación de la práctica

La evaluación de los conocimientos adquiridos por el alumno durante el desarrollo de esta segunda práctica se hará mediante una prueba individual realizada en una sesión de laboratorio en los días que se detallan en la lista adjunta.

La normativa de evaluación que se aplicará está publicada en la página web del laboratorio de Procesadores de Lenguaje.

 

Sugerencia

Se sugiere al alumno que escriba un fichero compatible con la herramienta make y con el nombre makefile que para el objetivo all genere el ejecutable de nombre prueba_sintactico.