Desarrollo del Programa Docente de Procesadores del Lenguaje

Anuncio
Grado en Ingeniería Informática. Procesadores del Lenguaje. Curso 2010-2011
-1-
Desarrollo del Programa Docente de Procesadores del
Lenguaje
Introducción
Se presenta en este texto el programa desarrollado de la asignatura de Procesadores del
Lenguaje del Grado en Ingeniería Informática y del Doble Grado en Informática y
Administración de Empresas. En primer lugar se indica el contexto de la asignatura propuesta
dentro de las materias impartidas en las titulaciones indicadas, y a continuación el programa
detallado de cada tema.
La asignatura Procesadores del Lenguaje está programada para impartirse en tercer
curso. Los alumnos que llegan a estos estudios ya habrán de conocer un conjunto de materias,
tanto de contenido científico de base (matemáticas, física, estadística, etc.), como sobre
fundamentos relativos a las tecnologías de la información (sistemas operativos, programación,
bases de datos, etc.), así como conocimiento de los formalismos de la teoría de autómatas y
lenguajes formales.
Las asignaturas cursadas previamente aportan los conocimientos básicos necesarios y, por
otra parte, es de interés identificar asignaturas en las que serán aplicables los conocimientos
impartidos en éstas. Como otras asignaturas de la Ingeniería Informática, la asignatura de
Procesadores del Lenguaje tiene unos fundamentos teóricos basados en las Matemáticas, cuyos
conocimientos se suponen impartidos en cursos previos. La relación de las Matemáticas con la
Informática se estructura a diversos niveles; desde la descripción abstracta de problemas, hasta
la resolución de funciones complejas mediante procedimientos algebraicos. La teoría de análisis
y traducción de lenguajes, optimización de código, etc, aplica la teoría formal de lenguajes y
autómatas y la teoría de complejidad de algoritmos, además de explotar para problemas
específicos la teoría de grafos.
La relación de Procesadores del Lenguaje con las asignaturas relacionadas con la
programación y estructuras de datos se establece, por un lado, a través de la descripción formal
de los lenguajes de programación y, por otro, en la necesidad de dotar al alumno de la capacidad
de realizar programas y diseñar algoritmos con los que poder aplicar los conocimientos teóricos
de la asignatura. Una de las relaciones más inmediatas de la asignatura de Procesadores del
Lenguaje en la Ingeniería Informática ha de ser con la asignatura cursada previamente que trata
la teoría de Autómatas, Lenguajes y Gramáticas. Esta asignatura va a servir para establecer las
bases y fundamentos de una parte importante de la asignatura de Procesadores del Lenguaje,
proporcionará al alumno las herramientas y conceptos necesarios para entender y aplicar la
teoría de compilación de lenguajes. Por otro lado, también es necesario tener algunas nociones
de Fundamentos de Ordenadores, especialmente en lo que refiere a código máquina, que
permitirán comprender mejor las fases de síntesis en la asignatura.
Programa detallado
TEMA I: Introducción
•
Descripción
El objetivo de este primer tema es centrar al alumno en los conceptos básicos de
Procesadores del Lenguaje. En primer lugar, se lleva a cabo una breve mención histórica de
los antecedentes principales que componen la materia. Posteriormente, se repasan algunas
Grado en Ingeniería Informática. Procesadores del Lenguaje
•
-2-
nociones básicas impartidas en cursos anteriores que son necesarias para la compresión de
la asignatura. Estas nociones incluyen el concepto de autómata, de gramática y de lenguaje
y la equivalencia entre lenguajes, gramáticas y máquinas reconocedoras, mostrándose la
jerarquía de clases de lenguajes abstractos establecida por Chomsky. Una vez centrado el
contenido, se muestran los aspectos teóricos y prácticos más relevantes de los temas que se
verán a lo largo de la asignatura, con el propósito de que el alumno adquiera una visión
global. Se presenta la noción de traductor como programa manipulador de programas,
resaltándose las aplicaciones, conceptos generales, y fases que abarca un compilador.
Contenido
1. Introducción.
1.1. Justificación de la materia.
1.2. Historia de los compiladores y lenguajes.
1.3. Conceptos básicos.
2. Lenguajes y Gramáticas.
2.1. Definición formal de Gramática.
2.2. Derivaciones y Sentencias.
2.3. Definición formal de Lenguaje.
2.4. Jerarquía de los Lenguajes y Gramáticas.
2.5. Expresiones Regulares
3. Autómatas
3.1. Definición Formal y Representación.
3.2. Jerarquía de los Autómatas.
3.2.1. Autómatas finitos
3.2.2. Autómatas a pila. Relación con lenguajes formales
4. Fases y estructura de un compilador
4.1. Análisis léxico
4.2. Análisis sintáctico
4.3. Análisis semántico
4.4. Generación de código
4.5. Diagramas de Tombstone
TEMA II: Análisis Léxico
•
•
Descripción
Los conceptos desarrollados en asignaturas previas relacionadas con la troncalidad de
Teoría de Autómatas y Lenguajes Formales, relativos a la formalización de las gramáticas,
los lenguajes y autómatas, tienen en este tema su continuación natural. El análisis léxico
extiende la definición del autómata, de manera que cuando una cadena es procesada, el
autómata devuelve, no sólo si es reconocida por un lenguaje, si no que además asigna un
determinado atributo asociado al estado final alcanzado (tipo de terminal, “token”). Se
introduce por vez primera el concepto de “error de compilación”, en este caso asociado a los
errores léxicos, mostrándose las posibles acciones que pueden realizarse para manejar este
tipo de error.
Contenido
1. Diseño de un Analizador Léxico.
1.1.
Autómatas Finitos reconocedores de Lenguajes Regulares.
1.2.
Construcción de un Autómata Finito. Ejemplos
2. Generadores Automáticos de Analizadores Léxicos: LEX.
3. Manejo de Errores Léxicos.
Grado en Ingeniería Informática. Procesadores del Lenguaje. Curso 2010-2011
-3-
TEMA III: Análisis Sintáctico
•
Descripción
Este tema puede considerarse como el tema principal del curso, en consonancia con el
hecho de que en un compilador la rutina de análisis sintáctico es la de mayor importancia,
afectando a la ejecución de todas las demás. Este tema partirá del formalismo de las
gramáticas independientes del contexto y de los autómatas a pila, ya revisado en el tema
introductorio y visto en asignaturas de relacionadas con Teoría de Autómatas y Lenguajes
Formales. Ahora se van a mostrar varias técnicas para construir, eficientemente, varios tipos
de analizadores sintácticos que permitirán construir el árbol de derivación correspondiente
al programa analizado. Para ello, se parte de una clasificación de los diferentes tipos de
analizadores sintácticos y posteriormente se introducen varias definiciones de elementos
formales necesarios para la construcción de los analizadores sintácticos, como son los
conjuntos “Primero” y “Siguiente”. Se realizará una descripción detallada de varios tipos de
analizadores sintácticos, estableciendo una clasificación general entre ellos por el tipo de
recorrido (descendente o ascendente) que se efectúa en el árbol sintáctico. Dentro de los
analizadores descendentes, se describirán el análisis sintáctico descendente recursivo y el
análisis predictivo LL(k), observando la existencia de un conjunto de reglas, que si se
verifican, entonces implica que la gramática puede ser evaluada mediante este tipo de
análisis, condición LL(k). Dentro de la clasificación de analizadores ascendentes se
estudiarán los analizadores de gramáticas con precedencia de operador y el análisis LR(k).
Dentro de este último, se describirán las técnicas que permiten la construcción de las tablas
de análisis simple (SLR), canónico (LR) y de símbolo de preanálisis (LALR), ejemplos de
aplicación de la teoría de autómatas en este caso para representar eficazmente la totalidad de
configuraciones posibles de la pila en el proceso de construcción ascendente del árbol. Se
destacan las ventajas de los analizadores SLR y LALR al evitar la explosión de estados del
algoritmo canónico de Knuth, a cambio de reducir su generalidad.
Es interesante resaltar las diferencias de complejidad de los analizadores descendentes y
ascendentes, y la mayor capacidad de reconocer lenguajes de estos últimos (los LL son un
suconjunto propio de los LR), debida a la diferencia de estrategia de análisis. Los
analizadores descendentes han de predecir las derivaciones por la izquierda aplicables desde
la cima del árbol, mientras que los ascendentes deben almacenar las configuraciones
posibles generadas en un proceso de derivación más a la derecha.
A continuación, se presentará la problemática del tratamiento de gramáticas ambiguas, su
efecto sobre el analizador, y estrategias para su utilización provechosa. Finalmente se
mostrarán algunos ejemplos así como una introducción a una de las herramientas más
extendidas para la generación automática de generadores sintácticos, Yacc/Bison de GNU,
que implementa una arquitectura LALR(1) que además enlaza directamente con la
herramienta FLEX presentada anteriormente.
•
Contenido
1. Gramáticas Independientes del Contexto y Autómatas con Pila como Reconocedores de
Lenguajes
2. Introducción al Análisis Sintáctico.
2.1. Clasificación de los métodos de Análisis Sintáctico.
3. Análisis Descendente.
3.1. Con retroceso, Descendente Recursivo.
3.2. Conjuntos PRIMERO y SIGUIENTE.
3.3. Definición de Gramáticas LL.
3.4. Obtención de la tabla LL(1). Ejemplos
4. Análisis Ascendente.
4.1. Análisis Sintáctico con Precedencia de operador.
Grado en Ingeniería Informática. Procesadores del Lenguaje
-4-
4.2.
Construcción de la tabla de precedencia. Conjuntos CABECERA y FINAL.
Implementación de reglas de precedencia
4.3. Análisis Sintáctico LR.
4.4. Obtención de la tabla de análisis SLR(1).
4.5. Obtención de la tabla de análisis canónica LR(1).
4.6. Obtención de la tabla con símbolo de pre-análisis LALR(1).
5. Tratamiento de Gramáticas Ambiguas. Ejemplos.
6. Generadores automáticos de Analizadores Sintácticos: YACC.
TEMA IV: Tratamiento de Errores Sintácticos
•
•
Descripción
Se mostrarán en este tema diferentes técnicas para la detección, análisis y recuperación de
errores sintácticos. Se presenta en primer lugar una clasificación de las estrategias posibles,
y a continuación aspectos de su implementación dentro del contexto del tipo de analizador
específico utilizado. Se trata básicamente de contextualizar el error, con objeto de dar una
información lo más útil posible al programador y por otro lado definir la forma adecuada de
recuperación para seguir con el análisis. Por último se considerará su implementación
práctica dentro de la herramienta de generación de analizadores sintácticos Bison/Yacc.
Contenido
1. Errores. Estrategias de Detección y Recuperación. Ejemplos
2. Recuperación con diferentes analizadores
2.1. Analizador descendente LL
2.2. Analizador ascendente de precedencia de operador
2.3. Analizador ascendente LR
TEMA V: Análisis Semántico
•
Descripción
Este primer tema presenta la problemática de extraer el significado semántico del programa
analizado, lo que requiere introducir elementos adicionales a la gramática independiente del
contexto empleada para representar su estructura sintáctica. Los conceptos principales son
el atributo, valores asociados a cada símbolo de la gramática, terminal o no terminal, y la
acción semántica, como instrumento para propagar información contextual dentro del árbol
sintáctico (a este proceso se le denomina anotación o decoración del árbol). Esta gramática
aumentada es la llamada gramática de atributos. Se introducirá en este punto también la
notación adoptada por la mayoría de los compiladores para representar las acciones
semánticas, el concepto de Traducción Dirigida por Sintaxis. El análisis semántico queda
engarzado dentro del análisis sintáctico, este último como motor que invoca las acciones
semánticas que deben realizarse. Dependiendo de los nodos que son necesarios para poder
evaluar el atributo de un determinado nodo en el árbol sintáctico, se distinguen dos tipos de
atributos; sintetizados y heredados. Las interdependencias entre los atributos de un árbol
sintáctico, independientemente de si estos son sintetizados o heredados, se representan
mediante un grafo dirigido llamado grafo de dependencias. El grafo de dependencias va a
introducir, en este punto, la noción intuitiva de establecer un orden de recorrido en el árbol
sintáctico para realizar adecuadamente la evaluación de los atributos y los controles
semánticos. Algunas fases esenciales del compilador que se tratarán en temas posteriores,
como la verificación de tipos, construcción de la tabla de símbolos y la generación de
código, se introducen aquí como casos particulares de acciones semánticas.
Se trata posteriormente la problemática de la evaluación de los atributos en función de
sus dependencias, abriéndose diferentes opciones en función de su estructura. Se distinguen
aquellos evaluadores que no requieren de una construcción explícita del árbol sintáctico,
Grado en Ingeniería Informática. Procesadores del Lenguaje. Curso 2010-2011
-5-
sino que los atributos pueden propagarse con las acciones en “una pasada”, al tiempo que se
hace el análisis sintáctico, y aquellos que construyen un árbol explícito. Respecto a los
primeros, se presentan las condiciones que deben cumplir las gramáticas para permitir esta
evaluación directa, y su implicación en la implementación de los analizadores LL(1) y
LR(1) presentados en la asignatura Procesadores del Lenguaje I. En los descendentes se
utilizan funciones recursivas que tratan los atributos heredados como argumentos de entrada
y los sintetizados como valores de retorno, mientras que los ascendentes introducen la pila
semántica paralela a la pila sintáctica, para manipular registros semánticos que abarcan
tanto atributos sintetizados como heredados. Finalmente, se presenta brevemente la
alternativa de la construcción explícita de una representación sintáctica de la sentencia a
analizar. Esta representación lleva el nombre de árbol de sintaxis abstracta, que no es más
que la representación del árbol sintáctico en la cual los componentes irrelevantes desde el
punto de vista del análisis semántico se omiten. Este árbol de sintaxis abstracta deberá
contener toda la información necesaria para el posterior tratamiento semántico, es decir, el
árbol sintáctico decorado contiene toda la información para la verificación de tipos y la
generación de código intermedio.
•
Contenido
1. Gramáticas de Atributos
1.1.
Ejemplos
1.2.
Formalización
2. Especificación de un traductor: Traducción Dirigida por Sintaxis y Esquemas de
Traducción
3. Tipos de Atributos.
3.1. Atributos Sintetizados.
3.2. Atributos Heredados.
4. Grafos de Dependencias.
5. Evaluación de gramáticas
5.1. Evaluación ascendente de gramáticas S-Atribuidas
5.2. Evaluación descendente de gramáticas L-Atribuidas
5.3. Evaluación ascendente de gramáticas L-Atribuidas
6. Construcción de árboles de sintaxis abstracta
TEMA VI: Verificación de Tipos
•
Descripción
En el tema anterior se presentó la problemática general de definición y evaluación de
atributos sobre una gramática. Ahora se desarrolla en un tema aparte la etapa del compilador
más representativa de los controles semánticos, la verificación de tipos. Se muestran los
conceptos de expresiones de tipos y sistemas de tipos como elementos que incluyen las
especificaciones del lenguaje a este respecto. Se presentan los mecanismos de construcción
de tipos para representar las estructuras de datos típicamente declaradas en los lenguajes de
alto nivel, y las verificaciones asociadas a los principales tipos de sentencias. La
complejidad de estos controles semánticos será función de la flexibilidad y exigencias del
lenguaje, ilustrando como ejemplo las conversiones automáticas de tipos y los operadores
sobrecargados. Se concluye el tema con una visión de la equivalencia de las expresiones de
tipos.
•
Contenido
1. Comprobación de tipos como manejo de errores semánticos
1.1. Introducción
1.2. Expresiones de tipos
1.3. Sistemas de tipos. Comprobación estática y dinámica
2. Ejemplo de construcción y verificación de tipos sencillo
Grado en Ingeniería Informática. Procesadores del Lenguaje
-6-
Operadores sobrecargados
4. Equivalencia de expresiones de tipos
3.
TEMA VII: Generación de Código Intermedio
•
Descripción
Se presenta el lenguaje intermedio como una opción ventajosa para la portabilidad y
optimización del compilador, a costa de introducir un paso más en la fase de traducción y de
contemplar una representación adecuada que pueda trasladarse después a los detalles de la
máquina final. Se describirán los principales tipos de representaciones intermedias: el
propio árbol sintáctico abstracto visto en el primer tema, la notación postfija y los códigos
de tres direcciones (cuartetos, tercetos y tercetos indirectos), analizando las diferencias de
cada alternativa. Después se presentan las técnicas de generación de código intermedio para
los tipos más representativos de proposiciones de lenguajes de alto nivel: declaraciones,
asignaciones, indexado de arrays, estructuras de flujo de control, etc., empleando de nuevo
una notación de traducción dirigida por la sintaxis.
•
Contenido
1. Tipos de Lenguajes Intermedios.
1.1. Códigos de tres direcciones. Alternativas
1.2. Instrucciones de tres direcciones
2. Generación de código intermedio
2.1. Declaraciones
2.2. Expresiones aritméticas
2.3. Indexado de arrays
2.4. Sentencias de flujo de control
TEMA VIII: Generación de Código Máquina
•
•
Descripción
El problema de la generación de código final se introduce en este tema desligado de
aspectos específicos dependientes de la administración de memoria y entorno de ejecución,
aspectos relegados a un tema posterior, y se presenta suponiendo la existencia de código
intermedio previamente generado. Se presenta una máquina objetivo con un juego simple de
instrucciones y una serie de registros, y diferentes modos de direccionamiento. El código
generado contendrá instrucciones para efectuar asignaciones y para efectuar flujo de
control, posponiendo a un tema posterior las instrucciones de administración de memoria.
Las instrucciones de control de flujo simplemente contienen saltos y saltos condicionales
que trasladan las estructuras de control que ya se tradujeron a un código intermedio
próximo. En el caso de las asignaciones, aparece el problema de la selección del modo de
direccionamiento y utilización de registros para almacenar resultados, presentando la
complejidad de evaluar la mejor opción, no siendo posible enumerar todas las alternativas
para llegar a la solución óptima. Dejando preparado el camino para los temas posteriores de
optimización de código, aquí simplemente se presenta un método simple de generación de
código máquina que administra los registros localmente en los bloques básicos que dividen
el código intermedio a traducir..
Contenido
1. Código máquina y máquina objetivo
1.1. Opciones de código máquina
1.2. Instrucciones y direccionamiento y coste
2. Generación simple de código a partir de lenguaje intermedio
2.1. Bloques básicos y grafos de flujo
2.2. Variables vivas y uso posterior
Grado en Ingeniería Informática. Procesadores del Lenguaje. Curso 2010-2011
2.3.
2.4.
Asignación de registros
Traducción de otras instrucciones
-7-
Grado en Ingeniería Informática. Procesadores del Lenguaje
-8-
TEMA IX: Tabla de Símbolos y Entorno de Ejecución
•
•
Descripción
En este tema se muestran varias estrategias para administrar la memoria en tiempo de
ejecución para algunos tipos de datos básicos y la asignación dinámica de memoria con las
llamadas a funciones, repasando las distintas formas del paso de parámetros. La
administración de memoria puede efectuarse estáticamente, para los casos de lenguajes más
simples, o dinámicamente, complejidad necesaria para tratar los procedimientos recursivos,
o la creación dinámica de datos. Se presentará la gestión de la pila y montículo como
herramientas para administrar la memoria en tiempo de ejecución. En cuanto a la tabla de
símbolos, obviamente no va a ser ésta la primera vez aparezca en el curso, necesariamente
habrá sido referida en los temas anteriores. En este momento se explicita las opciones de
organización, como estructura de datos, así como cuáles y dónde se aplican las funciones
que la manejan.
Contenido
1. Asignación de memoria.
2.1. Asignación estática y dinámica.
2.2. Gestión de pila y montículo. Ejemplos
2. Llamadas a funciones
2.1. Registros de activación
2.2. Paso de parámetros
3. Operaciones y organización de la tabla de símbolos.
TEMA X: Optimización de Código
•
•
Descripción
La fase de optimización es una de las más complejas y menos conocidas de un compilador.
Siguiendo los criterios de generalidad asumidos para este planteamiento de asignaturas, se
requiere la selección de unos contenidos introductorios y generales que sirvan para
presentar esta materia más allá de los detalles específicos de una arquitectura final, detalles
que necesitarían un dimensionamiento y especialización que se saldrían del curso. De esta
forma, de los dos tipos de optimización que se suelen identificar en un compilador, este
tema se centra en las técnicas independientes de la arquitectura final. Definir correctamente
el concepto de optimización de código es fundamental para entender como se aplican las
técnicas involucradas. El término optimización es usado no en el sentido matemático
estricto, lo que se obtiene no es código óptimo, habría que hablar de “código mejorado”.
Siguiendo con el planteamiento del tema 4, se establece la distinción entre optimización de
código en ámbito global y local. Este último se aplica independientemente sobre los bloques
básicos en los que se divide el programa, secuencias lineales de instrucciones que se
ejecutan de principio a fin. Esta optimización local se centra en la mejora de los
direccionamientos y en la búsqueda y eliminación de la redundancia de cálculos dentro de
cada bloque, como expresiones constantes, borrado de operaciones nulas, o simplificación
de operaciones. Esta optimización local se plantea como un proceso posterior e
independiente de la traducción, habitualmente implementado con una técnica de tipo
“mirilla”, que examina las instrucciones en los bloques básicos con una ventana de tres o
cuatro instrucciones para aplicar las modificaciones adecuadas. Finalmente, una vez
presentada la optimización local, se presenta brevemente la optimización global mediante
técnicas de análisis de flujo de datos. Estas técnicas analizan las conexiones entre los
bloques básicos, generalmente considerando todos los caminos posibles, y aplican
algoritmos de grafos para efectuar mejoras que tienen en cuenta estas interdependencias.
Contenido
1. Concepto de Optimización de código.
Grado en Ingeniería Informática. Procesadores del Lenguaje. Curso 2010-2011
-9-
2. Optimización local sobre bloques básicos.
2.3.
Transformaciones que preservan la función.
2.4.
Subexpresiones comunes.
2.5.
Eliminación de código inactivo
2.6.
Optimización de lazos
3. Análisis global del flujo de datos.
3.1.
introducción y definiciones
3.2.
ecuaciones de flujo de datos
3.3.
transformaciones globales
TEMA XI: Aspectos Específicos
•
Descripción
Este último tema presenta algunos elementos relacionados con la teoría de construcción de
traductores y que no se han cubierto en los temas anteriores, como son los intérpretes,
preprocesadores, macroprocesadores y el tratamiento de elementos asociados a tipos
específicos de lenguajes de programación. Así, se contempla la estructura de compiladores
para lenguajes funcionales, lenguajes lógicos y lenguajes orientados a objetos. Finalmente
se ilustran algunos ejemplos de compiladores para lenguajes concretos.
•
Objetivos
(CN14)(CN15)(CM10)(AN9)(CR5)(CR6)
Contenido
1. Otros procesadores de lenguajes
1.1. Intérpretes
1.2. Preprocesadotes y macroprocesadores
2. Diseño de lenguajes
2.1. Estructuras de datos y de control
2.2. Aspectos de compilación para tipos específicos de lenguajes
3. Algunos ejemplos de compiladores
•
Descargar