Diseño de Compiladores
Diseño de Compiladores
Diseño de Compiladores
Tipos de compiladores
Un traductor es cualquier programa que toma como entrada un texto escrito en un
lenguaje, llamado fuente, y da como salida otro texto en un lenguaje denominado
objeto.
Por otro lado, algunas de las ventajas de interpretar frente a compilar son:
Análisis sintáctico
A partir de los trabajos de Chomsky ya citados, se produce una sistematizació n de la
sintaxis de los lenguajes de programació n, y con ello un desarrollo de diversos
métodos de aná lisis sintá ctico. Con la aparició n de la notació n BNF { desarrollada en
primer lugar por Backus en 1960 cuando trabajaba en un borrador del ALGOL 60,
modificada en 1963 por Naur y formalizada por Knuth en 1964 { se tiene una guïa
para el desarrollo del aná lisis sintá ctico.
Los diversos métodos de aná lisis sintá ctico (parsing) ascendente y descendente se
desarrollan durante la década de los 60. En 1959 Sheridan describe un método de
aná lisis sintá ctico de FORTRAN que introducía paréntesis adicionales alrededor de los
operandos para ser capaz de analizar las expresiones. Má s adelante, Floyd introduce
la técnica de la precedencia de operador y el uso de las funciones de precedencia. A
mitad de la década de los 60, Knuth define las gramá ticas LR y describe la
construcció n de una tabla canó nica de aná lisis sintá ctico LR.
Por otra parte, el uso por primera vez de un analizador sintá ctico descendente
recursivo tuvo lugar en el añ o 1961. En el añ o 1968 se estudian y definen las
gramá ticas LL así como los analizadores sintá cticos predictivos. También se estudia la
eliminació n de la recursividad por la izquierda de producciones que contienen
acciones semá nticas sin afectar a los valores de los atributos.
En los primeros añ os de la década de los 70, se describen los métodos SLR y LALR de
aná lisis LR. Debido a su sencillez y a su capacidad de aná qlisis para una gran variedad
de lenguajes, la técnica de aná lisis LR va a ser la elegida para los generadores
automá ticos de analizadores sintá cticos. A mediados de los 70, Johnson crea el
generador de analizadores sintá cticos YACC para funcionar bajo un entorno UNIX.
Análisis semántico
Junto al aná lisis sintá ctico, también se fue desarrollando el aná lisis semá ntico. En los
primeros lenguajes (FORTRAN y ALGOL 60) los tipos posibles de los datos eran muy
simples y la comprobació n de tipos muy sencilla. No se permitía la restricció n de tipos
(type coercion), pues ésta era una cuestió n difícil y era má s fá cil no permitirla. Con la
aparició n de ALGOL 68 se permitía que las expresiones de tipo fueran construidas
sistemá ticamente. Má s tarde, de ahí surgió la equivalencia de tipos por nombre y la
equivalencia estructural.
Generación de código y gestión de la memoria
En la generació n de có digo uno de los aspectos má s importantes es la gestió n que va a
hacer el compilador de la memoria de la má quina objeto. En los primeros
compiladores la memoria se gestionaba de forma está tica. Sin embargo, la aparició n
de los subprogramas (y la recursividad) hizo necesario utilizar otro planteamiento
para el manejo de la memoria: la pila.
El manejo de la memoria con una implementació n tipo pila se usó por primera vez en
1958 en el primer proyecto de LISP. La inclusió n en el ALGOL 60 de procedimientos
recursivos potenció el uso de la pila como una forma có moda de manejo de la
memoria. Dijkstra introdujo posteriormente el uso del display para acceso a variables
no locales en un lenguaje de bloques.
También se desarrollaron estrategias para mejorar las rutinas de entrada y de salida
de un procedimiento. Asimismo, y ya desde los añ os 60, se estudió el paso de
pará metros a un procedimiento por nombre, valor y por referencia.
Con la aparició n de lenguajes que permiten la localizació n diná mica de datos, se
desarrolla otra forma de manejo de la memoria, conocida por el nombre
de heap (montículo). Se han desarrollado varias técnicas para el manejo del heap y los
problemas que con él se presentan, como son las referencias perdidas y la recogida de
basura.
Optimización
La necesidad de la optimizació n apareció desde el desarrollo del primer compilador
de FORTRAN. Backus comenta có mo durante el desarrollo del FORTRAN se tenía el
miedo de que el programa resultante de la compilació n fuera má s lento que si se
hubiera escrito a mano. Para evitar esto, se introdujeron algunas optimizaciones en el
cá lculo de los índices dentro de un bucle.
Pronto se sistematizan y se recoge la divisió n de optimizaciones independientes de la
má quina y dependientes de la má quina. Entre las primeras está n la propagació n de
valores, la eliminació n de redundancias, etc. Entre las segundas se podrá encontrar la
localizació n de registros, el uso de instrucciones propias de la má quina y el
reordenamiento de có digo.
A partir de 1970 comienza el estudio sistemá tico de las técnicas del aná lisis de flujo de
datos. Su repercusió n ha sido enorme en las técnicas de optimizació n global de un
programa.
1.2.4 Técnicas actuales para el desarrollo de compiladores
En la actualidad, el proceso de la compilació n está muy asentado. Un compilador es
una herramienta bien conocida, dividida en diversas fases. Algunas de estas fases se
pueden generar automá ticamente (analizador léxico y sintá ctico) y otras requieren
una mayor atenció n por parte del diseñ ador de compiladores (las partes de
traducció n y generació n de có digo).
De todas formas, y en contra de lo que quizá pueda pensarse, todavía se está n
llevando a cabo varias vías de investigació n en este fascinante campo de la
compilació n. Por una parte, se está n mejorando las diversas herramientas disponibles
y por otra, la aparició n de nuevas generaciones de lenguajes ha provocado la revisió n
y optimizació n de cada una de las fases del compilador.
Uno de los ú ltimos lenguajes de programació n de amplia aceptació n que se ha
diseñ ado, el lenguaje Java, establece que el compilador no genera có digo para una
má quina determinada sino para una virtual, la Java Virtual Machine (JVM), que
posteriormente será ejecutado por un intérprete, normalmente incluido en un
navegador de Internet. El gran objetivo de esta exigencia es conseguir la má xima
portabilidad de los programas escritos y compilados en Java, pues es ú nicamente la
segunda fase del proceso la que depende de la má quina concreta en la que se ejecuta
el intérprete.