24
Universidad de Castilla-La Mancha Escuela Superior de Informática Ciudad Real Procesadores de Lenguajes Diseño de un lenguaje y de un traductor asociado. Curso 2003-2004 Objetivo: El objetivo de las prácticas es el desarrollo de un lenguaje sencillo y elemental y de un traductor asociado a él. Puesto que la realización de un traductor es un tema complejo y la complejidad depende de la estructura gramatical del lenguaje, el lenguaje que se debe diseñar es descrito en el Anexo I. El traductor debe obtener como salida la que se detalla en el Anexo II. Se admiten prácticas propuestas por los alumnos, siempre y cuando estas impliquen el diseño de un lenguaje con unos requerimientos mínimos y de un traductor para analizarlos y realizar alguna acción. Los alumnos interesados deberán ponerse en contacto con el profesor para discutir la práctica que proponen. La realización de la práctica “estándar” se hará en grupos de desarrollo de 2 personas, excepcionalmente 1 o 3. El número de personas permitidas en los grupos de las prácticas propuestas dependerá de su complejidad y deberá ser discutido con el profesor. Documentación a entregar: Cada grupo deberá entregar al finalizar el periodo de prácticas un documento y un disquete con implementaciones. A continuación se detalla los contenidos que deben aparecer en el documento y las implementaciones que se deben realizar: Sesiones dedicadas al lenguaje: 1. Introducción, describiendo el lenguaje diseñado. 2. Descripción de la sintaxis del lenguaje usando notación BNF o EBNF (ver Anexo III) o los diagramas de Conway (ver Anexo IV). 3. Definición de la semántica en lenguaje natural. Consiste en una descripción sencilla pero exacta de cómo se ejecuta cada instrucción del lenguaje y restricciones semánticas que puede tener cada instrucción. Toda esta información debe aparecer en la Documentación del las prácticas realizadas.

Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Universidad de Castilla-La Mancha Escuela Superior de InformáticaCiudad Real

Procesadores de LenguajesDiseño de un lenguaje y de un traductor asociado.Curso 2003-2004

Objetivo:

El objetivo de las prácticas es el desarrollo de un lenguaje sencillo y elemental y de untraductor asociado a él. Puesto que la realización de un traductor es un tema complejo yla complejidad depende de la estructura gramatical del lenguaje, el lenguaje que se debediseñar es descrito en el Anexo I. El traductor debe obtener como salida la que se detallaen el Anexo II.

Se admiten prácticas propuestas por los alumnos, siempre y cuando estas impliquen eldiseño de un lenguaje con unos requerimientos mínimos y de un traductor paraanalizarlos y realizar alguna acción. Los alumnos interesados deberán ponerse encontacto con el profesor para discutir la práctica que proponen.

La realización de la práctica “estándar” se hará en grupos de desarrollo de 2 personas,excepcionalmente 1 o 3. El número de personas permitidas en los grupos de lasprácticas propuestas dependerá de su complejidad y deberá ser discutido con elprofesor.

Documentación a entregar:

Cada grupo deberá entregar al finalizar el periodo de prácticas un documento y undisquete con implementaciones. A continuación se detalla los contenidos que debenaparecer en el documento y las implementaciones que se deben realizar:

Sesiones dedicadas al lenguaje:

1. Introducción, describiendo el lenguaje diseñado.

2. Descripción de la sintaxis del lenguaje usando notación BNF o EBNF (ver Anexo III) o losdiagramas de Conway (ver Anexo IV).

3. Definición de la semántica en lenguaje natural. Consiste en una descripción sencilla peroexacta de cómo se ejecuta cada instrucción del lenguaje y restricciones semánticas quepuede tener cada instrucción.

Toda esta información debe aparecer en la Documentación del las prácticas realizadas.

Page 2: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 2

Sesiones dedicadas al analizador léxico:

4. Identificación de los tokens del lenguaje diseñado. En la documentación debe aparecer unatabla de tokens, en la que para cada token debe registrarse la siguiente información:

• Nombre del token.

• Valores posibles del token.

• Expresión regular asociada al token. Su regla de construcción.

• Identificativo numérico del tipo de token. A partir de este momento éste será el códigopor el cual se identificará el token.

5. Diseñar e implementar el programa analizador léxico desarrollado, que leerá el ficherofuente a analizar y como salida producirá:

• Los tokens encontrados en el fichero fuente, y cuando sea necesario su atributoasociado.

• Eliminar los comentarios y espacios en blanco, caracteres final de línea,...

La información solicitada en el punto 5, debe presentarse en un disquete. Crear un directorio yllamarlo Analizador Léxico. Copiar en él, el fichero en lenguaje lex (*.l), y los ficherosnecesarios para ejecutar el analizador léxico (fuentes y ejecutables). Si hay algún aspecto sobreel diseño del analizador léxico que creas que debe ser resaltado debes introducirla endocumentación.

Para la implementación del analizador léxico se debe usar una herramienta de generaciónautomática de analizadores léxicos. La selección de esta herramienta dependerá del lenguaje deimplementación seleccionado en la Práctica 1. De este modo, se utilizará Flex si el lenguaje deimplementación es C y Jflex si este es Java.

En el Anexo V, se introducen brevemente este tipo de herramientas, para profundizar en ellas serecomienda la lectura de la documentación de la herramienta.

Sesiones dedicadas al análisis sintáctico:

6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada enel punto 2, a producciones de una gramática libre de contexto.

7. Diseño e implementación del programa que realiza el análisis sintáctico. Este programadebe leer un fichero fuente cuyo contenido será un programa escrito según las reglas dellenguaje desarrollado en la sesión dedicada al lenguaje y como salida informará de lacorrección o no de ese fichero. En caso de presencia de errores, el programa analizadorsintáctico debe resolver los errores que se produzcan y no detenerse cada vez que encuentreun error sintáctico, como salida debe informar de los errores encontrados en ese fichero.

La información solicitada en el punto 6, debe aparecer en la documentación de lapráctica. La información solicitada en el punto 7, debe presentarse en el disquete. Crearun directorio y llamarlo Analizador Sintáctico. Copiar en él, el fichero en lenguaje yacc(*.y), y los ficheros necesarios para ejecutar el analizador sintáctico (fuentes yejecutables). Introducir también el fichero en lenguaje lex (*.l) que interactúa con elanalizador sintáctico. Crear además un fichero que contenga un programa escrito segúnlas especificaciones del lenguaje desarrollado con el objeto de verificar su

Page 3: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 3

funcionamiento. Incluir también un programa erróneo para comprobar como secomporta ante los errores.Para la implementación del analizador sintáctico se debe usar una herramienta de generaciónautomática de analizadores sintácticos. La selección de esta herramienta dependerá del lenguajede implementación seleccionado en la Práctica 1. De este modo, se utilizará Bisón si el lenguajede implementación es C y JCup si este es Java.

En el Anexo VI, se introducen brevemente este tipo de herramientas, para profundizar en ellasse recomienda la lectura de la documentación de la herramienta.

Sesiones dedicadas al análisis semántico y tabla de símbolos:

8. Dar una especificación natural de la semántica del lenguaje desarrollado, es decir describirmediante un lenguaje natural las características semánticas, que no sean deducibles de lagramática BNF que describe sintácticamente el lenguaje.

9. Diseñar una estructura de datos para implementar la Tabla de Símbolos o emplear una de lasque se ha estudiado en la clase de teoría, en ambos casos explicar porque se haseleccionado. Estudiar que información es necesaria almacenar en ella.

10. Diseñar e implementar rutinas para el manejo de la tabla de símbolos. Escribir las accionespara crear y manejar la Tabla de símbolos (y donde sea necesario creación y eliminación desubtabla). Escribir una rutina para mostrar por pantalla o a un fichero (*.log) la tabla desímbolos en momentos concretos de la compilación.

11. Diseñar e implementar rutinas para la realización del análisis semántico.

La información solicitada en el punto 8 y 9, debe ser incluida en la documentación. Lainformación solicitada en los puntos 9, 10 y 11 debe ser almacenada en el disquete. Crear undirectorio y llamarlo Análisis Semántico. Copiar en él, el fichero en lenguaje yacc (*.y) en suultima versión y añadirle reglas semánticas para la realización de la comprobación semántica.Introducir los ficheros necesarios para ejecutar el analizador sintáctico (fuentes y ejecutables) yel fichero en lenguaje lex (*.l) que interactúa con el analizador sintáctico (y que utiliza atributospara pasarle información al analizador semántico). Crear además un fichero que contenga unprograma escrito según las especificaciones del lenguaje desarrollado con el objeto de verificarel correcto funcionamiento del analizador semántico.

Para la implementación del analizador semántico se debe usar la herramienta de generaciónautomática de analizadores sintácticos utilizada en la práctica anterior añadiéndole atributos.

En el Anexo VII, se describe brevemente como hacer esto en este tipo de herramientas, paraprofundizar en el tema se recomienda la lectura de la documentación de la herramienta.

Sesiones dedicadas a la generación de código:

12. Establecer que tipo de atributos y acciones semánticas son necesarias para obtener la salidaque se especifica en el Anexo II.

13. Incluir los atributos y acciones semánticas antes determinadas en el código del analizadorsemántico de manera que se obtenga la salida que se espera.

La información solicitada en el punto 12 debe ser incluida en el documento. La informaciónsolicitada en los puntos 13 debe ser almacenada en el disquete. Crear un directorio y llamarloGeneración de Código. Copiar en él, el fichero en lenguaje yacc (*.y) en su ultima versión, con

Page 4: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 4

las reglas semánticas que permiten la generación de código. Introducir los ficheros necesariospara ejecutar el analizador sintáctico (fuentes y ejecutables) y el fichero en lenguaje lex (*.l) queinteractúa con el analizador sintáctico (y que utiliza atributos para pasarle información alanalizador semántico). Crear además varios ficheros que contengan programas correctos eincorrectos según las especificaciones del lenguaje desarrollado con el objeto de verificar elcorrecto funcionamiento del traductor desarrollado.

Page 5: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 5

Sobre el lenguaje de implementación empleado en las prácticas:

Para la realización de las prácticas se puede utilizar cualquier lenguaje de programacióny herramientas de utilidad de libre uso que se considere oportuno (por ejemplo Flex,Jflex para el análisis léxico y Jcup, Bison para el análisis sintáctico). Cuando se utiliceotra herramienta se debe justificar su elección y explicar brevemente su funcionamientoen la documentación de la práctica.

Se valorará positivamente la realización de una práctica novedosa, así como en laimplementación final del traductor, la realización de un buen interfaz de usuario.

Fechas de entrega y evaluación:

La entrega de la primera práctica es obligatoria puesto que las demás prácticasdependerán del lenguaje diseñado. Se deberán tener en cuenta los comentarios ycorrecciones realizadas por el profesor para el desarrollo del resto de prácticas.

Fecha de entrega de la primera práctica: 9 de Diciembre.

Convocatoria de Junio:

Fecha de entrega de las prácticas: 2 de Junio.Listas con los alumnos que han superado el examen de prácticas: 16 de Junio.

Convocatoria de Septiembre:

Fecha de entrega de las prácticas: 1 de Septiembre.Listas con los alumnos que han superado el examen de prácticas: 6 de Septiembre.

Nota:

El profesor podrá citar, cuando considere oportuno, a algún grupo para realizar unadefensa de las prácticas en el laboratorio.

Fdo. José Jesús Castro Sánchez

Page 6: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 6

ANEXO I

Se va diseñar un lenguaje para escribir gramáticas y establecer el tipo de análisis que se

desea realizar sobre ella. El lenguaje diseñado debe tener las siguientes características:

1. Las gramáticas deben ser de tipo 2 o libres de contexto.

2. Permita expresar una o varias gramáticas en un mismo fichero de entrada.

3. El tipo de análisis que se desea realizar puede ser uno o varios de los siguientes

tipos: LL(1) o SLR(1) o LR(1).

4. El tipo de análisis puede establecerse de una manera global, para todas las

gramáticas o particular, para cada gramática.

5. Para una misma gramática pueden hacerse varios tipos de análisis.

6. Los símbolos terminales y no terminales pueden ser cualquier secuencia de letras,

tanto en mayúsculas como en minúsculas o combinación de ambas.

7. Los símbolos terminales y no terminales pueden declararse de manera global, son

válidos para todas las gramáticas del fichero, o de una manera particular, sólo tienen

validez para la gramática en la que han sido declarados.

8. Permitir la declaración de conjuntos de producciones que puedan ser incluidos en la

declaración de una gramática.

Page 7: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 7

ANEXO II

Como salida el traductor diseñado debe dar para cada gramática la tabla de análisis que

se haya indicado:

1. Para el análisis LL(1), la tabla de análisis LL(1)

2. Para el análisis SLR(1), la tabla de análisis SLR(1).

3. Para el análisis LR(1), la tabla de análisis LR(1).

Si existiera algún conflicto en la tabla, el traductor debería indicar cual es el motivo del

conflicto.

Page 8: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 8

ANEXO III

BNF es el acrónimo de Backus-Naur Form, y fue utilizada para describir la sintaxis dellenguaje ALGOL 60. BNF es un ejemplo de un metalenguaje, un lenguaje empleado paradescribir otro lenguaje. Desde sus orígenes ha sido ampliamente empleada por desarrolladoresde lenguajes como mecanismo para especificar sus reglas sintácticas. BNF tiene símbolos,llamados metasímbolos, y reglas propias, las cuales son empleadas para definir la sintaxis dellenguaje en cuestión.

Veamos algunas definiciones para el correcto uso y entendimiento de esta notación:

• TERMINAL. Se dice que un símbolo es terminal cuando tiene entidad propia y sedescribe por si mismo, es decir no requiere ninguna explicación. Se suelen escribiren minúsculas (tokens del lenguaje). Generalmente se escriben en negrita.

• NO TERMINAL. Se dice que un símbolo es no terminal cuando requiere unadefinición mediante una regla o producción. Se suelen escribir en mayúsculas, ysiempre irán encerrados entre paréntesis angulares < y >.

• METASIMBOLOS. Son aquellos símbolos que la notación utiliza para distinguirlos elementos y propiedades de una regla. Los metasímbolos de BNF son:

::= , cuyo significado es “es definido como”

|, cuyo significado es “o”, es empleado para establecer alternativas.

< y >, son empleados para definir categorías de nombres (NO TERMINAL).

En la notación BNF se utilizan una serie de reglas o producciones cuyo objetivo es ladescripción de símbolos NO TERMINAL.

Cada regla tendrá la siguiente estructura:

<NO TERMINAL>::=sucesión de símbolos terminales y no terminales que explican la parte izquierda.

Es decir, una regla consiste en una parte izquierda (dato a explicar), separador (::=) y una partederecha (explicación o descripción).

La parte izquierda es siempre un símbolo no terminal, y en la parte derecha habrá unacombinación cualquiera de símbolos terminales y no terminales, teniendo en cuenta que todo noterminal que aparezca en una descripción debe haber aparecido (o aparecer más adelante) comoparte izquierda de una regla. Por ejemplo, la siguiente regla:

<SENTENCIA_WHILE>::=while <EXPRESION> do <SENTENCIA>

describe la sintaxis de la sentencia while de Pascal.

Una producción o regla para un mini-lenguaje es:

<PROGRAM>::=program <DECLARACIONES> begin <SECUENCIAS> end;

Page 9: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 9

Muchos autores han introducido algunas extensiones a esta notación para facilitar suuso, dando lugar a la Forma Extendida Backus-Naur (EBNF, por sus siglas eninglés):

• Opcionales, son símbolos que pueden o no aparecer. Se emplea los corchetes[ , ] como metasímbolos.

<SENTENCIA_IF>::=if <CONDICION> then <SENTENCIA> [else <SENTENCIA>]

Con BNF esto era realizado por medio de dos reglas:

<SENTENCIA_IF>::=if <CONDICION> then <SENTENCIA><PARTE_ELSE>

<PARTE_ELSE>::=else <SENTENCIA> | ε

• Repeticiones, para indicar un número arbitrario de veces. Se emplean losmetasímbolos llaves { , } para expresar la aparición de cero o varias veces lalista de elementos contenida entre las llaves.

<IDENTIFICADOR>::=<LETRA> {<LETRA> | <DIGITO>}

Con BNF esto era realizado por medio de una regla recursiva:

<IDENTIFICADOR>::=<LETRA> | <IDENTIFICADOR> <RESTO>

<RESTO>::=<LETRA> | <DIGITO>

• Terminales de solo un carácter. Se representan por medio del carácterrodeado por ‘ ’ o “ ”.

<SECUENCIAS>::=<SECUENCIA> {“;” <SECUENCIA>}

• Actualmente, los símbolos no terminales y terminales son distinguidos pormedio del uso o no del formato negrita. Los símbolos terminales estarán ennegrita, mientras que los no terminales serán representados con el formatonormal y sin < , >. Esto facilita la lectura de la sintaxis.

setencia_if::=if expresion_booleana then secuencias [else secuencias ] end if “;”

Veamos como ejemplo, la notación EBNF para expresar la sintaxis de EBNF:

syntax: := {rule}rule ::= identifier “::=” expressionexpression ::= term {“|” term}term ::= factor {factor}factor ::= identifier |

comillas |“(“ expression “)” |“[“ expression “]” |“{“ expression “}”

identifier ::= letra {letra | digito}comillas ::= “ ” ” {letra} “ ” ”

Page 10: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 10

Con la notación EBNF se consigue más claridad en las definiciones, con la recursividadeliminada de la definición BNF.

A continuación puedes ver otro ejemplo, de la notación EBNF aplicable para expresionessimples:

<expresión-simple>::=[signo]<término>{<operador-suma><término>}<término>::=<factor>{<operador-multiplicación><término>}<factor>::=<identificador> | <constante-sin-signo> | <designador-función> | <constructor-conjunto> | <expresiones> | not <factor><constante-sin-signo>::=<número-sin-signo> | <cadena-caracteres> | <identificador-constantes><número-sin-signo>::=<secuencia-dígitos> | <real-sin-signo><secuencia-dígitos>::=dígito{dígito}<operador-suma>::=+ | -<operador-multiplicación>::=* | / | div | mod | and

En Internet tienes multitud de ejemplos sobre la notación BNF y EBNF, y si no pregunta agoogle!!!

Page 11: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 11

ANEXO IV

Puesto que las definiciones BNF o EBNF no siempre son obvias, los diagramas de sintaxis ográficas de ferrocarril han llegado a ser populares, en especial en manuales de lenguajeselementales.

Un diagrama de Conway es un grafo dirigido con un punto de entrada y otro de salida dondelos elementos no terminales aparecen como rectángulos y los terminales como círculos. Conestos diagramas se pueden representar las mismas gramáticas que con la notación BNF o EBNF.Si uno sigue las flechas, se encuentra las mismas restricciones que en la definición BNF.

Concatenación: AB

Alternativa: A|B

Opción: [A]

Repetición: {A}

Cada símbolo no terminal de la gramática lleva asociado un diagrama de Conway que lo define,y se construye siguiendo las reglas antes mencionadas.

Estos diagramas se leen de izquierda a derecha siguiendo el recorrido de las flechas. Cuando seencuentra un elemento no terminal (representado por medio de un rectángulo) se llama a sudiagrama asociado. Si se encuentra un terminal se concatena a lo que ya se ha leído.

Ejemplo:

syntax

A B

A

B

A

A

Rule

Page 12: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 12

rule

expression

term

factor

identifier

::=identifier expression

term

term |

factor

factor

identifier

comillas

identifier

identifier

( )

[ ]

identifier{ }

letra

digito

letra

Page 13: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 13

comillas”

letra

Page 14: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 14

ANEXO V

Los analizadores léxicos se pueden construir automáticamente empleando unasherramientas que se denominan generadores de analizadores léxicos. Un generador deanalizadores léxicos es un programa que tiene como entrada un texto escrito en unlenguaje patrón-acción y como salida produce un programa que implementa el autómatafinito que reconoce los patrones y que ejecuta la acción asociada a cada patrón. En estelenguaje los patrones se especifican por medio de expresiones regulares.

En el campo de la compilación, en el texto de entrada se describen por medio deexpresiones regulares los componentes léxicos del lenguaje fuente, la acción asociada acada patrón será la devolución del identificador numérico del token que reconoce elanalizador sintáctico y si es necesario también puede pasar algún atributo. Como salidada el programa fuente del analizador léxico escrito en un lenguaje determinado, quedependerá de la herramienta empleada (Ver Figura V.1).

Figura V.1. Funcionamiento del generador de analizadores léxicos.

Existen muchos generadores de analizadores léxicos, si bien los más populares son Lex,distribuido gratuitamente con el sistema UNIX, Flex distribuido con el sistemaoperativo Linux (también existe la versión para MS-DOS), y Jflex para MS-DOS. Losdos primeros generan código en C, mientras la última genera código en Java.

El modo de emplear el generador de analizadores léxicos será el que se muestra en laFigura V.2.

Figura V.2. Plan de trabajo a la hora de generar el analizador léxico.

Generador deanalizadores

léxicos

Programaescrito en

lex

Programafuente

analizadorléxico

Generador deanalizadores

léxicos

Programaescrito en

lex *.l

Programafuente

analizadorléxico

Compilador dellenguaje fuente

Programafuente

Programaejecutable

Page 15: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 15

A partir de ahora haremos referencia al generador de analizadores léxicos lex, si bien elresto de herramientas son muy similares en cuanto a la forma de sus programas y a lasnormas de construcción de las expresiones regulares.

El fichero de entrada al programa lex, tiene tres partes, separadas por una línea dondedebe aparecer obligatoriamente un %%, como se muestra a continuación:

definiciones%%reglas%%código del usuario

En la sección de definiciones se pueden incluir definiciones de nombres que seránempleados en la sección de reglas para simplificar la especificación del analizadorléxico, así como condiciones de arranque.

Las definiciones de nombres tienen la siguiente forma:

nombre expresión_regular

donde nombre y expresión_regular deben ir separadas por al menos un espacio en blanco.Posteriormente, se puede hacer uso de este nombre, utilizando {nombre} que se expandiráa expresión regular.

En esta sección también se puede incluir código en lenguaje fuente que figurará tal cualen el programa generado por el analizador léxico, por ejemplo inclusión de libreriasestandar, llamadas al preprocesador, etc...

Para colocar código en lenguaje fuente directamente en el programa generado se deberáponer en la columna 1 de una línea los símbolos %{, a continuación el código enlenguaje fuente que se desea incluir y para finalizar en una línea aparte y también en lacolumna 1, los símbolos }%.

La sección de reglas de lex contienen una serie de reglas de la forma:

expresión_regular acción

donde expresión_regular es un patrón que define un componente léxico, escrito conformea las normas del lenguaje lex y en el que se puede hacer uso, como se ha especificadoantes, de las definiciones de nombres definidas en las sección anterior. El patrón debeaparecer en la columna 1 y la acción debe estar en la misma línea que la acción. Laacción es un fragmento de programa en lenguaje fuente, entre los símbolos { y }, queindica la acción a realizar por el analizador léxico, cuando reconoce el patrón al que estáasociado. Las acciones pueden utilizar variables, funciones y macros definidasexternamente y por defecto en el lex. También se pueden utilizar las funciones definidasen las sección de código de usuario.

La forma de trabajar del programa fuente generado es reconocer patrones y realizar lasacciones que están asociadas a dicho patrón. Existe una acción que se ejecuta pordefecto, siempre que se lee un lexema que no coincide con ningún patrón de los queaparecen en la sección de reglas, esta acción consiste en mostrar por pantalla dicho

Page 16: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 16

lexema. Si se desea, que no se realice esta acción por defecto se escribe la instrucciónnula que generalmente será ; asociada a la expresión regular que denota cualquiercarácter, que es . y que debería escribirse como última regla de la sección de reglas. Sihay varios patrones que tienen asociada la misma acción se puede usar el símbolo dealternativa | para unir los patrones en la misma línea.

El generador lex permite las especificaciones ambiguas, así cuando hay más de unpatrón que empareja un lexema particular, lex elige la regla según el siguiente orden:

1. Prefiere el patrón más largo.

2. En el caso de que tengan la misma longitud, elige el que aparezca antes.

Para más información sobre cómo construir los patrones y las acciones asociadas, serecomienda la lectura de la documentación de la herramienta que se vaya a utilizar.

Finalmente, está la sección código del usuario que está formada exclusivamente porcódigo en lenguaje fuente. Este código pasa sin modificaciones al fichero fuente delanalizador léxico generado. Se utiliza para implementar rutinas de complemento quellaman al escaner o son llamadas por este. La presencia de esta sección es opcional.

Cuando se desea utilizar el analizador léxico como un programa independiente que leaun fichero fuente y genere una determinada salida (Práctica 1), será necesario incluir enesta sección una función principal main que llame a la función yylex() que es la funciónque implementa el autómata que reconoce los patrones de la sección de reglas. Paraconseguir este efecto en Jflex, será necesario incluir la opción %standalone en la secciónde definiciones (Ver manual).

A continuación se muestra un ejemplo de un programa en lex que puede ejecutarseindependientemente:

%{/* Ejemplo de programa escrito en lex para detectar identificadores y numeros.*/ #include <stdio.h>%}letra [a-zA-Z_]digito [0-9]alfanumerico [a-zA-Z_0-9]identificador {letra}{alfanumerico}*numero {digito}+(\.{digito}+)?(E[\+|\-]?{digito}+)?

%%{identificador} printf(“\nIndentificador -> %s\n”, yytext);{numero} printf(“\nNúmero ->%s\n”,yytext);%%

main(argc,argv)int argc;char **argv;{

if (argc>1) { FILE *file;

Page 17: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 17

file= fopen(argv[1],”r”); if (!file) {

fprintf(stderr,”No puedo abrir el fichero %s\n”,argv[1]);exit(1);

} yyin=file; }

yylex();return 0;

}

Page 18: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 18

ANEXO VI

Los analizadores sintácticos se pueden construir automáticamente empleando unasherramientas que se denominan generadores de analizadores sintácticos. Un generadorde analizadores sintácticos es un programa que tiene como entrada una gramática escritaen un lenguaje y como salida produce un programa en un lenguaje fuente queimplementa el analizador sintáctico que reconoce cadenas y detecta si están escritasconforme a las producciones de la gramática. En el problema que nos ocupa, el diseñode un traductor, el generador de analizadores sintácticos partiría de la gramática quedefine el lenguaje fuente descrito en la Práctica 1 y produciría como salida el programafuente del analizador sintáctico para esa gramática, encargado de tomar como entradaprogramas escritos conforme a ese lenguaje fuente y comprobar si son o no correctos.

En la Figura VI.1 se muestra cual es el funcionamiento de esta herramienta, y suinteracción con el analizador léxico.

Figura VI.1. Funcionamiento del generador de analizadores sintácticos.

Existen muchos generadores de analizadores sintácticos, si bien los más populares sonYacc, distribuido gratuitamente con el sistema UNIX, Bison, BYacc, BYacc/J y JCup.Los tres primeros generan código en C, mientras la última genera código en Ja,va.

El modo de emplear el generador de analizadores sintácticos será el que se muestra en laFigura VI.2, en esta explicación nos basamos en las herramientas del tipo Yacc o Bison.Recordad que el analizador sintáctico necesita de un analizador léxico que explore eltexto fuente y que lo divida en tokens, que el analizador sintáctico se encargará deagrupar de una manera lógica. Nosotros utilizaremos una modificación del analizadorléxico generado en la Práctica 2.

Primero se escribe un fichero con extensión *.y que contiene una especificación delanalizador sintáctico que se quiere generar, escrita en el lenguaje del generador deanalizadores sintácticos. Posteriormente, se transforma ese fichero en un programafuente que contiene el analizador sintáctico para la gramática especificada, además segenera un fichero *.h, que contiene la asociación numérica de los tokens de lagramática.

Este fichero *.h se incluirá en la sección de definiciones del analizador léxico encargadode reconocer los tokens de la gramática, además se eliminará la llamada a la funciónmain del analizador léxico de la Práctica 2, y se generará el programa fuente delanalizador léxico.

Por último, se compilan los dos programas fuentes obtenidos en los pasos anteriores, yahemos construido el analizador sintáctico!

Generador deanalizadoressintácticos

Programaescrito enyacc *.y

Programafuente

analizadorsintáctico

Page 19: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 19

Figura VI.2. Plan de trabajo a la hora de generar el analizador sintáctico.

La forma en la que interactúan las herramientas JFlex y JCup, que recordemos generancódigo Java, es distinta ya que ambas herramientas lo que hacen es crear clases. De estemodo la ejecución de JFlex, sobre un fichero que contiene la especificación de lostokens del lenguaje (con la extensión *.flex), crea la clase lexer que contiene los datos ymétodos necesarios para implementar el analizador léxico. La ejecución de JCup, sobreun fichero que contenga la especificación de la sintaxis del lenguaje diseñado (con laextensión *.cup), crea dos clases, una que contiene los datos y métodos necesarios paraimplementar el analizador sintáctico, llamada parser y otra con la definición de lossímbolos de la gramática, denominada sym. Para una descripción más detallada sobre laforma en la que interactúan estas herramientas JFlex y JCup u otras se recomienda lalectura de su documentación.

Generador deanalizadoressintácticos

Programaescrito enyacc *.y

Programafuente

analizadorsintáctico

Fichero *. hque contienela asociaciónnumérica alos tokens

Generador deanalizadores

léxicos

Programaescrito en

lex

Programafuente

analizadorléxico

Compilador dellenguaje fuente

Programaejecutable

Programafuente

analizadorsintáctico

Programafuente

analizadorléxico

Page 20: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 20

A partir de ahora haremos referencia al generador de analizadores sintácticos Yacc, sibien el resto de herramientas son muy similares en cuanto a la forma de sus programas ya las normas de especificación de la gramática.

El fichero de entrada al programa Yacc, tiene tres partes, separadas por una línea dondedebe aparecer obligatoriamente un %%, como se muestra a continuación:

declaraciones%%reglas de producción%%código del usuario o rutinas de apoyo en el lenguaje C

En la sección de declaraciones se puede introducir código en lenguaje fuente, delimitadopor los símbolos %{ y %} que deben aparecer sin tabular. Ejemplo de código fuente quepuede ser incluido aquí son las proposiciones include necesarias y la declaración de lasvariables que sean utilizadas en las secciones segunda y tercera.

Es en esta sección donde se declaran los componentes léxicos de la gramática, pormedio de la directiva %token nombre_del_token (en JCup se hace de una maneradiferente, con la palabra terminal nombre_del_token). Estos componentes léxicos podránser utilizados en la segunda sección de la especificación yacc. También se puedenasignar precedencias a los operadores y asociar atributos semánticos a los símbolos(terminales y no terminales) de la gramática (se explicará como en el Anexo VII).

La siguiente sección reglas de producción contiene un conjunto de reglas que definencomo construir cada símbolo no terminal a partir de sus partes constituyentes. Cadaregla es una producción de la gramática y una acción semántica (se explicará qué es enel Anexo VII). La separación de las reglas en esta sección se realiza por medio delcarácter ; (el punto y coma). Cada regla tendrá una parte izquierda, que consistirá en unno terminal de la gramática y una parte derecha, que consistirá en una combinación desímbolos terminales y no terminales de la gramática, ambas partes estarán separadas porel carácter : (dos puntos). En la herramienta JCup la separación entre las partesizquierda y derecha se hace por medio del símbolo ::=.

Para obtener más información sobre la forma de escribir las reglas de producción de lagramática se recomienda la lectura de la documentación de la herramienta seleccionada.

En la sección código del usuario o rutinas de apoyo en el lenguaje C puede aparecercualquier código en lenguaje fuente que se desee utilizar, así como la definición defunciones que puedan emplearse en las acciones asociadas a las reglas de la secciónreglas de producción. Para ejecutar el análisis sintáctico es necesario incluir en estasección una función principal main que llame a la función yyparse() que es la funciónque llama a la función yylex() para obtener los componentes léxicos y van agrupándoloslógicamente conforme a las reglas de la sección de reglas de producción.

A continuación se muestra un ejemplo de un programa en yacc y de su analizador léxicoasociado:

Page 21: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 21

%token IDENT NUMERO%%sentencia: IDENT ´=´ expresión

| expresionexpresion: expresión ´+´ NUMERO

| expresión ´-´ NUMERO| NUMERO;

%%main(int argc, char **argv){

char *file;extern FILE *yyin;if (argc>1) {

file= fopen(argv[1],”r”); if (!file) {

fprintf(stderr,”No puedo abrir el fichero %s\n”,argv[1]);exit(1);

} yyin=file; }

yyparse();return 0;

}

El analizador léxico asociado podría ser el siguiente:

%{#include “sintactico.h”%}

%%[0-9]+ {return NUMERO;}[a-zA-Z][a-zA-Z_0-9]+ {return IDENT;}. ;%%

Page 22: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 22

ANEXO VII

El analizador semántico se encarga de dos misiones muy importantes en la fase deanálisis de un compilador, primero se encarga de dar significado al programa fuente yen segundo lugar, de realizar las comprobaciones dependientes del contexto que nopueden ser expresadas por medio de una gramática libre de contexto, como por ejemplocomprobar si las variables han sido declaradas antes de ser usadas, si el número deargumentos de la llamada a un procedimiento son los adecuados conforme a ladefinición de la función, si el tipo de esos argumentos es correcto, si las operaciones seaplican a las variables de tipo correcto, etc.

La forma de construir un analizador semántico es empleando las herramientasgeneradoras de analizadores sintácticos que ya han sido comentadas en el Anexo VI. Deeste modo se permite que el análisis semántico se realice a la vez que el análisissintáctico empleando un tipo especial de gramáticas que son las gramáticas conatributos. Estas gramáticas son gramáticas libres de contexto en las que cada símbolo(terminal y no terminal) puede tener asociado un atributo y un valor para ese atributo, lacomplejidad de este atributo dependerá del tipo de acción semántica que vaya a realizar.Si un símbolo representa a un número, el atributo podría ser ese mismo número, si es unidentificador este atributo podría ser la cadena de caracteres que forman eseidentificador o un apuntador al lugar de la tabla se símbolos donde está almacenado. Notodos los símbolos tienen que tener asociado un atributo.

Normalmente, va a ser necesario tratar con atributos de distintos tipos, para permitiresto en herramientas como Yacc o Bison tendremos que definir una union en C llamadaYYSTYPE para contener todos los atributos permitidos. En Yacc y Bison esto se hace deforma automática añadiendo la directiva %union en la zona de declaraciones, en ella seintroducen todos los tipos de los atributos que se van a utilizar. Por ejemplo laintroducción de la siguiente directiva en la sección de declaraciones del programaentrada a la herramienta Yacc:

%union { double dval; int vblno;

}

permitiría utilizar dos tipos de atributos uno de tipo double y el otro de tipo int. Estadirectiva hace que en el fichero *.h que genera la herramienta generadora deanalizadores sintácticos también se introduzca el siguiente trozo de código:

typedef union {double dval;int vblno;

} YYSTYPE;extern YYSTYPE yylval;

La variable yylval será usada por el analizador léxico para pasar los valores asociados acada token. Si no se pone la directiva %union, la variable yyval tomará el tipo pordefecto que es int.

Page 23: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 23

En la herramienta JCup el uso de múltiples tipos de atributos se consigue por medio deluso del objeto Symbol que es el que devuelve el analizador léxico y los que sonalmacenados en la pila del analizador sintáctico. A la hora de trabajar con este objeto setiene que tener en cuenta las asociaciones entre atributos y los símbolos de la gramática.

A continuación veremos cómo y dónde se realiza la asociación de atributos a símbolosde la gramática.

La asociación de atributos a símbolos se hace en la zona de declaraciones del programaentrada al generador del analizador sintáctico, empleando directivas del lenguaje de laherramienta generadora de analizadores léxicos, así en las herramientas Yacc, Bison yBYacc se emplean las directivas %token y %type, con la siguiente sintaxis:

%token <nombre_de_tipo> lista_de_nombres_Terminales%type <nombre_de_tipo> lista_de_nombres_NoTerminales

mientras que en la herramienta JCup se suele utilizar las directivas terminal y non terminalcon la siguiente sintaxis:

terminal nombre_de_tipo lista_de_nombres_Terminalesnon terminal nombre_de_tipo lista_de_nombres_NoTerminales

donde nombre_de_tipo es uno de los tipos que aparecen en la unión ylista_de_nombres_Terminales y _NoTerminales son una secuencia de símbolos terminales yno terminales de la gramática, respectivamente, separados por el carácter ,.

Una vez detallado el mecanismo para asociar atributos a símbolos de la gramática,queda describir cómo emplear estos atributos para la realización del trabajo delanalizador semántico. Como fue explicado en el Anexo VI., la sección reglas deproducción de un programa entrada a una herramienta generadora contiene un conjuntode reglas que definen como construir cada símbolo no terminal a partir de sus partesconstituyentes, donde cada regla era una producción de la gramática que podía tenerasociada una acción semántica. Las acciones semánticas son trozos de código en ellenguaje fuente de la herramienta que se escriben entre los caracteres { y } en lasherramientas Yacc, Bison y BYacc y entre los caracteres {: y :} en la herramienta JCup.En las acciones semánticas se pueden utilizar funciones y procedimientos definidos enla sección código del usuario o rutinas de apoyo en el lenguaje C, así como a los atributosdefinidos en la sección declaraciones.

En las herramientas Yacc, Bison y Byac, en una acción el símbolo $$ se refiere al valordel atributo asociado con el no terminal del lado izquierdo, mientras que $i se refiere alvalor del atributo asociado al i-ésimo símbolo de la producción a la cual está asociada laacción semántica.

En la herramienta JCup, en una acción para referirnos al valor del atributo asociado conel no terminal del lado izquierdo tendremos que utilizar el término RESULT. Paraacceder al valor del atributo de algún símbolo de la producción, será necesariopreviamente etiquetarlo con una etiqueta, esto lo haremos asociando en la regla, alsímbolo que queramos, por medio del carácter :, una etiqueta.

Las acciones semánticas se ejecutan cuando se va a reducir por la producción a la queestán asociadas.

Page 24: Asignatura: Procesadores de Lenguajes · 6. Conversión de la descripción del lenguaje empleando notación BNF o EBNF, realizada en el punto 2, a producciones de una gramática libre

Documentación de las prácticas de Procesadores de lenguajes

Página 24

A continuación se muestra un ejemplo de un programa en yacc con acciones semánticasy de su analizador léxico asociado:

%{#inlcude <stdio.h>%}

%union{int dval;char *cad;

}

%token <dval> NUMERO%token <cad> IDENT

%%sentencia: IDENT ´=´ expresión { printf(“Identificador %s tiene valor %d\n”,$$,$1); }

| expresión { printf(“Valor: %d\n”,$1); }expresion: expresión ´+´ NUMERO { $$ = $1+$2; }

| expresión ´-´ NUMERO { $$ = $1-$2; }| NUMERO { $$ = $1; };

%%main(int argc, char **argv){

char *file;extern FILE *yyin;if (argc>1) {

file= fopen(argv[1],”r”); if (!file) {

fprintf(stderr,”No puedo abrir el fichero %s\n”,argv[1]);exit(1);

} yyin=file; }

yyparse();return 0;

}

El analizador léxico asociado podría ser el siguiente:

%{#include “sintactico.h”#include <string.h>%}

%%[0-9]+ {yylval.dval = atoi(yytext); return NUMERO;}[a-zA-Z][a-zA-Z_0-9]+ {yylval.cad= strdup(yytext); return IDENT;}. ;%%