Diagrama a bloques de la operación de un buen compilador.Un
compilador es un programa informático que traduce un programa escrito en un
lenguaje de programación a otro lenguaje de programación, generando un programa
equivalente que la máquina será capaz de interpretar. Usualmente el segundo
lenguaje es lenguaje de máquina, pero también puede ser simplemente texto. Este
proceso de traducción se conoce como compilación.
Un compilador es un programa que permite traducir el código fuente de un
programa en lenguaje de alto nivel, a otro lenguaje de nivel inferior
(típicamente lenguaje de máquina). De esta manera un programador puede diseñar
un programa en un lenguaje mucho más cercano a como piensa un ser humano, para
luego compilarlo a un programa más manejable por una computadora.
Partes de un compilador
La construcción de un compilador involucra la división del
proceso en una serie de fases que variará con su complejidad. Generalmente
estas fases se agrupan en dos tareas: el análisis del programa fuente y la
síntesis del programa objeto.
Análisis: Se trata de la comprobación de la corrección
del programa fuente, e incluye las fases correspondientes al Análisis Léxico
(que consiste en la descomposición del programa fuente en componentes léxicos),
Análisis Sintáctico (agrupación de los componentes léxicos en frases
gramaticales ) y Análisis Semántico (comprobación de la validez semántica de
las sentencias aceptadas en la fase de Análisis Sintáctico).
Síntesis: Su objetivo es la generación de la salida expresada en el
lenguaje objeto y suele estar formado por una o varias combinaciones de fases
de Generación de Código (normalmente se trata de código intermedio o de código
objeto) y de Optimización de Código (en las que se busca obtener un código lo
más eficiente posible).
Alternativamente, las fases descritas para las tareas de análisis y síntesis se
pueden agrupar en Front-end y Back-end:
Front-end: es la parte que analiza el código fuente,
comprueba su validez, genera el árbol de derivación y rellena los valores de la
tabla de símbolos. Esta parte suele ser independiente de la plataforma o
sistema para el cual se vaya a compilar, y está compuesta por las fases
comprendidas entre el Análisis Léxico y la Generación de Código Intermedio.
Back-end: es la parte que genera el código máquina, específico de una
plataforma, a partir de los resultados de la fase de análisis, realizada por el
Front End.
Esta división permite que el mismo Back End se utilice para
generar el código máquina de varios lenguajes de programación distintos y que
el mismo Front End que sirve para analizar el código fuente de un lenguaje de
programación concreto sirva para generar código máquina en varias plataformas
distintas. Suele incluir la generación y optimización del código dependiente de
la máquina.
El código que genera el Back End normalmente no se puede ejecutar directamente,
sino que necesita ser enlazado por un programa enlazador (linker)
Tipos de compiladores
Esta taxonomía de los tipos de compiladores no es
excluyente, por lo que puede haber compiladores que se adscriban a varias
categorías:
• Compiladores cruzados: generan código para un sistema
distinto del que están funcionando.
• Compiladores optimizadores: realizan cambios en el código para mejorar su
eficiencia, pero manteniendo la funcionalidad del programa original.
• Compiladores de una sola pasada: generan el código máquina a partir de una
única lectura del código fuente.
• Compiladores de varias pasadas: necesitan leer el código fuente varias veces
antes de poder producir el código máquina.
• Compiladores JIT (Just In Time): forman parte de un intérprete y compilan
partes del código según se necesitan.
Pauta de creación de un compilador: En las primeras épocas
de la informática, el software de los compiladores era considerado como uno de
los más complejos existentes.
Los primeros compiladores se realizaron programándolos
directamente en lenguaje máquina o en ensamblador. Una vez que se dispone de un
compilador, se pueden escribir nuevas versiones del compilador (u otros
compiladores distintos) en el lenguaje que compila ese compilador.
Actualmente existen herramientas que facilitan la tarea de
escribir compiladores ó intérpretes informáticos. Estas herramientas permiten
generar el esqueleto del analizador sintáctico a partir de una definición
formal del lenguaje de partida, especificada normalmente mediante una gramática
formal y barata, dejando únicamente al programador del compilador la tarea de
programar las acciones semánticas asociadas.
Proceso de compilación
Es el proceso por el cual se traducen las instrucciones
escritas en un determinado lenguaje de programación a lenguaje máquina. Además
de un traductor, se pueden necesitar otros programas para crear un programa
objeto ejecutable. Un programa fuente se puede dividir en módulos almacenados
en archivos distintos. La tarea de reunir el programa fuente a menudo se confía
a un programa distinto, llamado preprocesador. El preprocesador también puede expandir
abreviaturas, llamadas a macros, a proposiciones del lenguaje fuente.
Normalmente la creación de un programa ejecutable (un
típico.exe para Microsoft Windows o DOS) conlleva dos pasos. El primer paso se
llama compilación (propiamente dicho) y traduce el código fuente escrito en un
lenguaje de programación almacenado en un archivo a código en bajo nivel
(normalmente en código objeto, no directamente a lenguaje máquina). El segundo
paso se llama enlazado en el cual se enlaza el código de bajo nivel generado de
todos los ficheros y subprogramas que se han mandado compilar y se añade el
código de las funciones que hay en las bibliotecas del compilador para que el
ejecutable pueda comunicarse directamente con el sistema operativo, traduciendo
así finalmente el código objeto a código máquina, y generando un módulo
ejecutable.
Estos dos pasos se pueden hacer por separado, almacenando el
resultado de la fase de compilación en archivos objetos (un típico.obj para
Microsoft Windows, DOS o para Unix); para enlazarlos en fases posteriores, o
crear directamente el ejecutable; con lo que la fase de compilación se almacena
sólo temporalmente. Un programa podría tener partes escritas en varios
lenguajes (por ejemplo C, C++ y Asm), que se podrían compilar de forma independiente
y luego enlazar juntas para formar un único módulo ejecutable.