You are on page 1of 8

UAA Sistemas Electrnicos

Compiladores

Eduardo Serna-Prez

1
1.1

Introduccin a los compiladores


Compiladores

Los compiladores son programas de computadora que traducen de un lenguaje a otro. Un compilador toma como su entrada un programa escrito en lenguaje fuente y produce un programa equivalente escrito en lenguaje objeto.

Lenguaje Fuente

Traductor

Lenguaje Destino

Mensajes de error

Generalmente al lenguaje fuente se le asocia como lenguaje de alto nivel, mientras al lenguaje objeto se el conoce como cdigo objeto (cdigo de maquina) escrito especficamente para una maquina objeto. A lo largo del proceso de traduccin el compilador debe informar la presencia de errores en el lenguaje fuente. Disear y desarrollar un compilador, no es tarea fcil, y quizs pocos profesionales de la computacin se vean involucrados en esta tarea. No obstante, los compiladores se utilizan en casi todas las formas de la computacin y cualquiera involucrado en esta rea debera conocer la organizacin y el funcionamiento bsico de un compilador.

1.2

Historia de los compiladores

A finales de la dcada de 1940, comenzaron a construirse las primeras computadoras digitales y fue necesario implementar un lenguaje capas de realizar los clculos, es aqu donde aparece el lenguaje de maquina que representaba secuencias de cdigos numricos: C7 06 0000 0002 (instruccin que mueve el nmero dos a la ubicacin 0000) Desafortunadamente este lenguaje era tedioso de seguir y complicado de mantener, por lo que esta forma de codificacin fue reemplazada por el lenguaje ensamblador, en el cual las instrucciones y las localidades de memoria son formas simblicas. Un ensamblador traduce de los cdigos simblicos a lenguaje de maquina. Aun con esta mejora, el lenguaje ensamblador sigue siendo demasiado difcil de mantener: MOV X, 2 (instruccin en ensamblador equivalente a la anterior) En este punto se presenta la necesidad de lenguajes que permitan escribir los programas de forma concisa, similar a una notacin matemtica, y que se pudieran traducir a cdigo ejecutable para una mquina dada: X = 2 En la dcada de 1950, G. M. Hooper acua el termino compilador y aparecen los primeros trabajos sobre compiladores relacionados con la traduccin de formulas aritmticas a cdigo de mquina. John Backus lider un grupo de trabajo en IBM para realizar de un traductor de cdigo mquina a frmulas matemticas. Resultando con gran xito: la especificacin de un lenguaje de alto nivel (FORTRAN, FORmule TRANslation) y la realizacin de un traductor para una mquina (IBM 704). Trabajaron 18 personas durante mas de un ao en el proyecto. Fe un compilador hecho ad-hoc (a puro corazn), pues no exista una teora formal, sino que se iban resolviendo las construcciones una a una, para cada situacin particular.

UAA Sistemas Electrnicos

Compiladores

Eduardo Serna-Prez

Mas o menos al mismo tiempo Noam Chomsky comienza sus estudios sobre la estructura del lenguaje natural. Sus estudios lo condujeron a la clasificacin de los lenguajes de acuerdo a una jerarqua de sus gramticas, sus estudios sobre los algoritmos de reconocimiento derivaron en una automatizacin del proceso de traduccin mas eficiente. Durante la dcada de 1960, se disea el lenguaje LISP. En un principio, el cdigo LISP se traduca manualmente a cdigo mquina (tambin para el IBM 704). Se escribi en LISP un programa capaz de interpretar programas LISP, que se tradujo manualmente a cdigo de mquina, construyendo de este modo un intrprete ejecutable de LISP. Adems se desarrollan la mayora de las tcnicas de anlisis sintctico (Knuth). En la dcada de 1970, se presentan los mayores avances en el rea de lenguajes de programacin y compiladores. Aparecen los primeros programas que automatizan los procesos de anlisis lxico y sintctico. Surge la llamada Torre de Babel debido a la proliferacin de la teora para la construccin de compiladores. Niklaus Wirth, del Instituto Politcnico de Zurich disea Pascal, pensado para la enseanza. Wirth propone el concepto de representacin intermedia de cdigo, separando el proceso de traduccin en dos fases: el front-end encargada de analizar el programa fuente (operaciones dependientes slo del lenguaje fuente) y el back-end encargada de generar el cdigo para la mquina objeto (operaciones dependientes slo del lenguaje fuente). Adems surge el concepto de memoria dinmica. Ya para la dcada de 1980, comienzan a proliferar las tcnicas de mejoramiento de cdigo (optimizacin), se consolida y prolifera el concepto de asignacin y liberacin de memoria dinmica. La programacin orientada a objetos es extensamente utilizada y madura. A partir de la dcada de 1990, los lenguajes de programacin y compiladores son muy similares a lo que tenemos actualmente, surgen los ambientes de desarrollo, los lenguajes interpretados comienza a ganar terreno en aplicaciones de Internet y el cdigo intermedio se vuelve a poner de moda.

1.3

Tipos de traductores

Un traductor es un programa que convierte un archivo de lenguaje de programacin a su correspondiente en lenguaje objeto. As pues apreciaremos que un compilador en realidad es un tipo especifico de traductor. Existen diversos traductores y solo hablaremos de los mas significativos para consolidar la idea de traductor. Ensamblador: Programa que convierte de lenguaje ensamblador a lenguaje mquina, generando un archivo con el cdigo objeto equivalente al cdigo fuente completo, junto con informacin necesaria para el montaje. Formadores de texto: toma como entrada una cadena de caracteres que incluye el texto a componer y rdenes para indicar captulos, secciones, prrafos, enumeraciones, figuras, formulas, tablas, etc. (Latex, Html). Interpretes: Ejecutan las instrucciones del programa fuente inmediatamente en vez de esperar a que est traducido por completo el cdigo fuente a cdigo mquina. Necesitan menos memoria, pero son ms lentos que los compiladores. LISP y BASIC Histricamente, se pusieron de moda en los primeros aos porque los recursos de memoria eran escasos. Permiten aadir cdigo dinmicamente durante la ejecucin. Ventajas de compilador frente a un intrprete Se compila una vez, se ejecuta n-veces En bucles, la compilacin genera cdigo equivalente al bucle pero un interprete se traduce tantas veces una lnea como veces se repite el bucle El compilador tiene una visin global del programa, por lo que la informacin de mensajes de errores es ms detallada.

UAA Sistemas Electrnicos

Compiladores

Eduardo Serna-Prez

Ventajas de un intrprete frente a compilador Un interprete necesita menos memoria que un compilador Permite una mayor interactividad con el cdigo en tiempo de desarrollo.

1.4

Fases de un compilador

Un compilador se compone internamente de varias etapas, o fases, que realizan operaciones lgicas. Es til pensar en estas fases como piezas separadas dentro del compilador, y pueden en realidad escribirse como operaciones codificadas separadamente aunque en la practica a menudo se integran juntas. A continuacin describiremos brevemente cada un de ellas.
Cdigo fuente Anlisis Lxico Componentes lxicos / Tokens Anlisis Sintctico rbol sintctico Anlisis Semntico rbol sintctico con anotaciones Generacin / Optimizacin de cdigo intermedio Cdigo intermedio Generacin / Optimizacin de cdigo objeto Fase de sntesis Cdigo objeto Tabla de smbolos Fase de anlisis

Gestor de errores

Analizador lxico: lee la secuencia de caracteres de izquierda a derecha del programa fuente y los agrupa las secuencias de caracteres en unidades con significado propio (componentes lxicos o tokens en ingles), por ejemplo: palabras clave, identificadores, operadores, constantes numricas, signos de puntuacin como separadores de sentencias, llaves, parntesis, etc. Adems de eliminacin de comentarios, procesamiento de macros o inclusin de archivos. La estructura lxica la modelaremos mediante expresiones regulares. Tomemos como ejemplo la siguiente instruccin en cdigo C: a[indice] = 4 + 2; Componentes lxicos: a [ indice ] = 4 + 2 ; identificador corchete de apertura identificador corchete de cierre operador de asignacin numero operador suma numero punto y coma

UAA Sistemas Electrnicos

Compiladores

Eduardo Serna-Prez

Anlisis sintctico: determina si la secuencia de componentes lxicos sigue la sintaxis del lenguaje y obtiene la estructura jerrquica del programa en forma de rbol, donde los nodos son las construcciones de alto nivel del lenguaje. Se determinan las relaciones estructurales entre los componentes lxicos, esto es semejante a realizar el anlisis gramatical sobre una frase en lenguaje natural. La estructura sintctica la definiremos mediante las gramticas independientes del contexto. Como ejemplo consideremos la lnea de cdigo C anterior. Representa un elemento estructural denominado expresin, la cual es una expresin de asignacin compuesta de una expresin de subndice a la izquierda y una expresin aritmtica a la derecha (rbol de anlisis gramatical).
expresin expresin asignacin expresin expresin subndice = expresin expresin aditiva

expresin identificador a

expresin identificador indice

expresin numero 4

expresin numero 2

Los nodos internos del rbol de anlisis gramatical estn etiquetados con los nombres de las estructuras que representan y las hojas del rbol representan la secuencia de tokens. Los rboles de anlisis gramatical son tiles para visualizar la sintaxis de un programa pero no es eficaz en la representacin de esa estructura. Los analizadores sintcticos tienden a generar un rbol sintctico (una simplificacin de la informacin contenida en un rbol de anlisis gramatical).
expresin asignacin expresin subndice expresin aditiva

identificador a

identificador indice

numero 4

numero 2

Para nuestro ejemplo observamos que en el rbol sintctico se han eliminado nodos, esto debido a que sabiendo la naturaleza de la expresin, ya no es necesario contar con ciertos tokens. Anlisis semntico: realiza las comprobaciones necesarias sobre el rbol sintctico para determinar el correcto significado del programa, por ejemplo: verificacin e inferencia de tipos en asignaciones y expresiones, declaracin antes de uso (variables, funciones, tipos), correcto uso de operadores, mbito de variables, correcta llamada a funciones. Nos limitaremos al anlisis semntico esttico (en tiempo de compilacin), donde es necesario hacer uso de la Tabla de smbolos, como estructura de datos para almacenar informacin sobre los identificadores que van surgiendo a lo largo del programa. El anlisis semntico suele agregar atributos (como tipos de datos) a la estructura del rbol semntico. Siguiendo con el ejemplo de la expresin en C, el analizador semntico extrae la informacin de que a es una arreglo de valores enteros y que indice es una variable entera.

UAA Sistemas Electrnicos

Compiladores

Eduardo Serna-Prez

El analizador semntico registrara el rbol sintctico con los tipos de datos de las subexpresiones y verificara que la asignacin tiene sentido para los tipos, en caso contrario mandara un mensaje de error en correspondencia de tipos. De esta forma se obtiene un rbol sintctico con anotaciones.
expresin asignacin expresin subndice entero identificador a arreglo de enteros identificador indice entero numero 4 entero expresin aditiva entero numero 2 entero

Generacin y optimizacin de cdigo intermedio: la optimizacin consiste en la calibracin del rbol sintctico donde ya no aparecen construcciones de alto nivel. Generando un cdigo mejorado, ya no estructurado, ms fcil de traducir directamente a cdigo ensamblador o mquina, compuesto de un cdigo de tres direcciones (cada instruccin tiene un operador, y la direccin de dos operndoos y un lugar donde guardar el resultado), tambin conocida como cdigo intermedio. La etapa de optimizacin slo dependen del lenguaje fuente (y no de la mquina), se busca principalmente: eliminar subexpresiones comunes, identificar cdigo muerto, sustituir operaciones aritmticas, clculo previo de constantes, variables de induccin, propagacin de copias o cdigo inalcanzable. Suele ser una fase lenta y compleja. Siguiendo con el ejemplo de la expresin de asignacin, el generador/optimizador, colapsara la expresin aditiva generando una constante 6. En ocasiones estas adecuaciones pueden realizarse en el rbol directamente, pero generalmente resulta mas fcil hacerlo de manera lineal en cdigo de tres direcciones (cdigo intermedio). cdigo no optimizado t = 4 + 2 a[indice] = t cdigo optimizado a[indice] = 6

Generacin y optimizacin de cdigo objeto: toma como entrada la representacin intermedia y genera el cdigo ensamblador o mquina (objeto). La optimizacin depende de la mquina, es necesario conocer el conjunto de instrucciones, la representacin de los datos (nmero de bytes), modos de direccionamiento, nmero y propsito de registros, jerarqua de memoria, encauzamientos, etc. Suelen implementarse a mano, y son complejos porque la generacin de un buen cdigo objeto (mquina) requiere la consideracin de muchos casos particulares. Tambin se est investigando la creacin de generadores de cdigo automticos. La idea es automticamente hacer corresponder una representacin intermedia a plantillas de instrucciones objeto. Permitiendo generar fcilmente el cdigo objeto para una nueva mquina objeto, cambiando el conjunto de plantillas. Por ejemplo GNU GCC posee plantillas para mas de 10 arquitecturas ms habituales de ordenadores. Finalmente para nuestro ejemplo debemos decidir ahora cuantos enteros se almacenarn para generar el cdigo del arreglo, para este ejemplo emplearemos modos de direccionamiento propios de C, generando el cdigo objeto en un lenguaje ensamblador hipottico.
MOV MUL MOV ADD MOV R0, indice R0, 2 R1, &a R1, R0 *R1, 6 ;; ;; ;; ;; ;; valor de index doble valor en direccin de a sumar R0 a R1 constante 6 -> -> R0 -> R1 direccin en R1

UAA Sistemas Electrnicos

Compiladores

Eduardo Serna-Prez

Tabla de Smbolos: es una estructura tipo diccionario con operaciones de insercin, borrado y bsqueda, que almacena informacin sobre los smbolos que van apareciendo a lo largo del programa como son: los identificadores (variables y funciones), etiquetas, tipos definidos por el usuario (arreglos, registros, etc.). Adems almacena el tipo de dato, mtodo de paso de parmetros, tipo de retorno y de argumentos de una funcin, el mbito de referencia de identificadores y la direccin de memoria. Interacciona tanto con el analizador lxico, sintctico y semntico que introducen informacin conforme se procesa la entrada. La fase de generacin de cdigo y optimizacin tambin la usan. Gestor de errores: detecta e informa de errores de cada fase que se produzcan durante el anlisis. Debe generar mensajes significativos y reanudar la traduccin. Encuentra errores: En tiempo de compilacin: errores lxicos (ortogrficos), sintcticos (construcciones incorrectas) y semnticos (p. ej. uso de variables no declaradas, errores de tipo, etc.). En tiempo de ejecucin: direccionamiento de vectores fuera de rango, divisiones por cero, etc. De especificacin/diseo: compilan correctamente pero no realizan lo que el programador desea.

Se trataran slo errores estticos (en tiempo de compilacin). Respecto a los errores en tiempo de ejecucin, es necesario que el traductor genere cdigo para la comprobacin de errores especficos, su adecuado tratamiento y los mecanismos de tratamiento de excepciones para que el programa se contine ejecutando. La mayora de los compiladores son dirigidos por la sintxis, es decir, el proceso de traduccin es dirigido por el analizador sintctico. El anlisis sintctico genera la estructura del programa fuente a travs de tokens. El anlisis semntico proporcionan el significado del programa basndose de la estructura del rbol de anlisis sintctico. Las fases de anlisis lxico y anlisis sintctico se pueden automatizar de manera relativamente fcil, las verdaderas dificultades en la construccin de compiladores son el anlisis semntico, la generacin y la optimizacin de cdigo. El nmero de pasadas, es decir, el nmero de veces que hay que analizar el cdigo fuente, esta en funcin del grado de optimizacin. Tpicamente se realiza una pasada para realizar el anlisis lxico y sintctico, otra pasada para el anlisis semntico y optimizacin del lenguaje intermedio y una tercera pasada para generacin de cdigo y optimizaciones dependientes de la mquina.

1.4.1 Estructuras de datos empleadas en un compilador Las principales estructuras de datos que se necesitan en el proceso de traduccin y que sirven para comunicarse entre las fases son: Componentes lxicos: estructura tipo registro con dos campos, el tipo de componente lxico que se representa por un tipo enumerado y el lexema como una cadena de caracteres. rbol sintctico: se genera de forma dinmica como una estructura estndar basada en punteros conforme se avanza en el proceso de anlisis sintctico. Cada nodo es un registro con informacin obtenida por el analizador lxico (lexema), sintctico (tipo) y semntico (por ej. valor de una expresin, tipo de una expresin). Esta informacin depende del tipo de construccin del lenguaje que ese nodo represente. Tabla de Smbolos: contiene informacin sobre los identificadores, funciones, variables, mbito de referencia de identificadores, constantes numricas y literales, tipos de datos, o incluso la direccin de memoria. Es importante que las operaciones de insercin, bsqueda y eliminacin sean de costo casi constante (tabla Hash).

UAA Sistemas Electrnicos

Compiladores

Eduardo Serna-Prez

Cdigo intermedio: se implementa como una lista de registros, donde cada registro tiene cuatro campos (operador, la direccin de los operndoos y del resultado). Es eficiente para mover cdigo para el proceso de optimizacin posterior. Se puede usar tambin un archivo de texto.

1.5

Agrupamiento de fases

La estructura de un compilador se puede ver desde varias perspectivas, en la seccin anterior vimos las fases que representan su estructura lgica. Los constructores de compiladores deben estar familiarizados con los diversos tipos estructurales de compilador, ya que de esto depende su buen mantenimiento, eficiencia y confiabilidad. En el modelo de anlisis y sntesis las operaciones del compilador que analizan el programa fuente y calculan sus propiedades se clasifican como anlisis del compilador, mientras que las operaciones involucradas con la traduccin a cdigo objeto se conoce como sntesis del compilador. Etapa de anlisis: Anlisis lxico Anlisis sintctico Anlisis semntica Etapa de sntesis: Optimizacin y generacin de cdigo intermedio Optimizacin y generacin de cdigo objeto La intencin de separa las etapas de anlisis y sntesis, es principalmente para realizar mantenimientos y actualizaciones eficientes.

1.6

Compilador cruzado

Es un compilador que genera cdigo para una maquina diferente de la que utiliza para ejecutarse. Es perfectamente normal construir un compilador de Pascal que genere cdigo para MS-DOS y que el compilador funcione en Linux y se haya escrito en C++. Existe tambin la variante que implica un compilador para maquina abstracta, que facilita la transportabilidad de compiladores de un lenguaje fuente a varias maquina objeto. La construccin de este tipo de compiladores se realiza en dos etapas: front-end o etapa inicial: Las operaciones dependen slo del lenguaje fuente. Incluye: anlisis lxico, sintctico y semntico, la creacin de la Tabla de Smbolos, generacin de cdigo intermedio y algunas optimizaciones. Adems, del manejo de errores de cada fase. back-end o etapa final: Las operaciones dependen slo de la mquina objeto. Incluye: generacin de cdigo objeto y optimizaciones dependientes de la mquina. Depende de los modos de direccionamiento, conjunto de instrucciones de la mquina, nmero de registros, arquitectura de la mquina, sistema operativo, etc.
Front-End Back-End

Cdigo fuente

Cdigo intermedio

Cdigo objeto

Si se cambia de lenguaje fuente, entonces se reescribe el front-end. Si se cambia la mquina objeto, entonces se reescribe el back-end. Si aparece una nueva arquitectura, basta con desarrollar un traductor del lenguaje intermedio a esa nueva mquina.

UAA Sistemas Electrnicos

Compiladores

Eduardo Serna-Prez

1.7

Herramientas de construccin de compiladores

Son programas de ayuda en el proceso de escritura de compiladores: sistemas generadores de traductores. Tambin se les conoce como compiler writing tools, compiler generators, compilercompilers. A continuacin mencionaremos los mas conocidos. Generadores de analizadores lxicos: a partir de una especificacin basada en expresiones regulares. Lex / Flex. Generadores de analizadores sintcticos: a partir de una entrada que es la gramtica independiente del contexto que representa la estructura sintctica del lenguaje. Yacc / Bison. Generadores de cdigo: con rutinas para la generacin del rbol de anlisis sintctico y para su recorrido. En cada nodo se especifican las acciones para su traduccin a cdigo objeto correspondiente. Dispositivos para el anlisis de flujo de datos y de control: analizan la forma en que se transmiten los valores de un bloque a otro del programa, tiles en la optimizacin, prediccin de ramificaciones, eliminacin de cdigo muerto, eliminacin de redundancias, etc. Incluyen la generacin de la Tabla de Smbolos e incluso paquetes para la reparacin de errores. Bibliografa Aho, A.V., Sethi, R., Ullman, J.D. (1990), Compiladores: principios, tcnicas y herramientas, capitulo 1, pginas: 1- 25, 743-747. Louden, K.C. (1997), Construccin de Compiladores: Principios y prctica, capitulo 1, pginas: 1- 27. http://en.wikipedia.org/wiki/Compiler