You are on page 1of 8

PROGRAMAS DE SISTEMAS RELACIONADOS CON UN COMPILADOR

La entrada para un compilador puede producirse por uno o varios preprocesadores y puede
necesitarse otro procesamiento de la salida que produce el compilador antes de obtener un
cdigo de mquina ejecutable.
Preprocesadores
Los preprocesadores producen la entrada para un compilador, y pueden realizar las funciones
siguientes:
1. Procesamiento de macros. Un preprocesador puede permitir a un usuario definir macros,
que son abreviaturas de construcciones ms grandes.
2. Inclusin de archivos. Un preprocesador puede insertar archivos de encabezamiento en el
texto del programa. Por ejemplo, el preprocesador de C++ hace que el contenido del
archivo <global.h> remplace a la proposicin #include <global.h> cuando procesa un
archivo que contenga a esa proposicin.
3. Preprocesadores racionales. Estos preprocesadores enriquecen los lenguajes antiguos
con recursos ms modernos de flujo de control y de estructuras de datos. Por ejemplo, un
preprocesador de este tipo podra proporcionar al usuario macros incorporadas para
construcciones, como proposiciones while o if, en un lenguaje de programacin que no las
tenga.
Los procesadores de macros tratan dos clases de proposiciones: definicin de macros y uso de
macros. Las definiciones normalmente se indican con algn carcter exclusivo o palabra clave,
como define o macro. Constan de un nombre para la macro que se est definiendo y de un cuerpo,
que constituye su definicin. A menudo, los procesadores de macros admiten parmetros
formales en su definicin, esto es, smbolos que se remplazarn por valores (en este contexto, un
valor es una cadena de caracteres). El uso de una macro consiste en dar nombre a la macro y
proporcionar parmetros reales, es decir, valores para sus parmetros formales. El procesador de
macros sustituye los parmetros reales por los parmetros formales del cuerpo de la macro;
despus, el cuerpo transformado remplaza el uso de la propia macro.
Ensambladores
Algunos compiladores producen cdigo ensamblador. Otros compiladores realizan el trabajo de
ensamblador, produciendo cdigo de mquina relocalizable que se puede pasar directamente al
editor de carga y enlace. Se supone que el lector tiene cierta familiaridad sobre cmo es un
lenguaje ensamblador y que hace el ensamblador, aqu se revisar la relacin entre el cdigo
ensamblador y el cdigo de mquina.
El cdigo ensamblador es una versin mnemotcnica del cdigo de mquina, donde se usan
nombres en lugar de cdigos binarios para operaciones y tambin se usan nombres para las
direcciones de memoria. Una secuencia tpica de instrucciones en ensamblador puede ser
MOV a,R1
ADD #2,R1
MOV R1, b
Este cdigo pasa el contenido de la direccin a al registro 1; despus le suma la constante 2,
tratando al contenido del registro 1 como un nmero de punto fijo, y por ltimo almacena el
resultado en la posicin de memoria que representa b. De ese modo calculo b = a+2.
Es comn que los lenguajes ensambladores tengan recursos para manejar macros que son
similares a las consideradas antes para los preprocesadores de macros.
Ensamblado de dos pasadas
La forma ms simple de un ensamblador hace dos pasadas sobre la entrada, en donde una pasada
consiste en leer una vez un archivo de entrada. En la primera pasada se encuentran todos los
identificadores que denoten posiciones de memoria y se almacenan en una tabla de smbolos
(distinta de la del compilador). Cuando se encuentran por primera vez los identificadores, se les
asignan posiciones de memoria, de modo que despus de leer (ver figura 1 ) por ejemplo, la tabla
de smbolos contendra las entradas que aparecen en la figura 2. En esa figura, se supone que se
reserva una palabra, que consta de cuatro bytes, para cada identificador, y que las direcciones se
asignan empezando a partir del byte 0.


En la segunda pasada, el ensamblador examina el archivo de entrada de nuevo. Esta vez traduce
cada cdigo de operacin a la secuencia de bits que representa esa operacin en lenguaje de
mquina y traduce cada identificador que representa una posicin de memoria a la direccin dad
por ese identificador en la tabla de smbolos.
El resultado de la segunda pasada normalmente es cdigo de mquina relocalizable, lo que
significa que puede cargarse empezando en cualquier posicin L de la memoria; es decir, si se
suma L a todas las direcciones del cdigo, entonces todas las referencias sern correctas. Por
tanto, la salida del ensamblador debe distinguir aquellas partes de instrucciones que se refieren a
direcciones que se pueden relocalizar.
El siguiente es un cdigo de mquina hipottico al que se pueden traducir las instrucciones en
ensamblador de la figura 1.
FIGURA 1 FIGURA 2


Se concibe una pequea palabra de instruccin, en la que los cuatro primeros bits son el cdigo de
la instruccin, donde 0001, 0010, y 0011 representan las instrucciones LOAD, STORE y ADD,
respectivamente. LOAD y STORE significan trasladar de memoria a un registro y viceversa. Los dos
bits siguientes designan un registro y 01 se refiere al registro 1 de cada una de las tres
instrucciones anteriores. Los dos bits siguientes representan un marcador, donde 00 es el modo de
direccionamiento ordinario, y los ltimos ocho bits se refieren a una direccin de memoria. El
marcador 10 es el modo inmediato, donde los ltimos ocho bits se toman literalmente como el
operando. Este modo aparece en la segunda instruccin de la figura anterior.
En la figura tambin se ve un * asociado con la primera y la tercera instruccin. Este * representa
el bit de relocalizacin que se asocia con cada operando en cdigo de mquina relocalizable.
Supngase que el espacio de direcciones que contiene los datos se va a cargar empezando en la
posicin L. La presencia del * significa que se debe sumar L a la direccin de la instruccin. Por
tanto, si L=000011111, esto es, 15, entonces a y b estaran en las posiciones 15 y 19
respectivamente y las instrucciones de la figura apareceran como


en cdigo de mquina absoluto o no relocalizable. Ntese que no hay ningn * asociado con la
segunda instruccin (Figura 3), de modo que L no se sumo a su direccin en (4), lo cual es correcto,
porque los bits representan la constante 2 y no la posicin 2.
Cargadores y editores de enlace
Por lo general, un programa llamado cargador realiza las dos funciones de carga y edicin de
enlaces. El proceso de carga consiste en tomar el cdigo de mquina relocalizable, modificar las
direcciones relocalizables, como se indica en el ejemplo anteriormente visto, y ubicar las
instrucciones y los datos modificados en las posiciones apropiadas de la memoria.
El editor de enlace permite formar un solo programa a partir de varios archivos de cdigo de
mquina relocalizable. Estos archivos pueden haber sido el resultado de varias compilaciones
FIGURA 4
FIGURA 3
distintas, y uno o varios de ellos pueden ser archivos de biblioteca de rutinas proporcionadas por
el sistema y disponibles para cualquier programa que las necesite.
Si los archivos se van a usar juntos de manera til., puede haber algunas referencias externas, en
las que el cdigo de un archivo hace referencia a una posicin de otro archivo. Esta referencia
puede ser a una posicin de datos definida en un archivo y utilizada en otro, o puede ser el punto
de entrada de un procedimiento que aparece en el cdigo de un archivo y se llama desde otro. El
archivo con el cdigo de mquina relocalizable debe conservar la informacin de la tabla de
smbolos para cada posicin de datos o etiqueta de instruccin a la que se hace referencia
externamente. Si no se sabe por anticipado a qu se va a hacer referencia, es preciso incluir
completa la tabla de smbolos del ensamblador como parte del cdigo de mquina relocalizable.
Por ejemplo el cdigo de la figura 3 ira precedido de
a 0
b 4

Si un archivo cargado con (figura 3) hiciera referencia a b, entonces esa referencia se remplazara
por 4 ms el desplazamiento con el que se localizarn las posiciones del archivo inicial.

EL AGRUPAMIENTO DE LAS FASES
El estudio de las fases (anteriormente visto en el curso de Teora de Lenguajes y compiladores)
trata la organizacin lgica de un compilador. En una implantacin, a menudo se agrupan las
actividades en dos o ms fases.

Etapa inicial y etapa final
Con frecuencia, las fases se agrupan en una etapa inicial y una etapa final. La etapa inicial
comprende aquellas fases, o partes e fases, que dependen principalmente del lenguaje fuente y
que son en gran parte independientes de la mquina objeto. Ah normalmente se incluyen los
anlisis lxico y sintctico, la creacin de la tabla de smbolos, el anlisis semntico y la generacin
de cdigo intermedio. La etapa inicial tambin puede hacer cierta optimacin de cdigo, La etapa
inicial incluye, adems, el manejo de errores correspondiente a cada una de esas fases.
La etapa final incluye aquellas partes del compilador que dependen de la mquina objeto y en
general esas partes no dependen del lenguaje fuente, sino slo del lenguaje intermedio. En la
etapa final, se encuentran aspectos de la fase de optimacin de cdigo, adems de la generacin
de cdigo, junto con el manejo de errores necesario y las operaciones con la tabla de smbolos.
Se ha convertido en rutina el tomar la etapa inicial de un compilador y rehacer su etapa final
asociada para producir un compilador para el mismo lenguaje fuente en una mquina distinta. Si la
etapa final se disea con cuidado, incluso puede no ser necesario redisearla demasiado. Tambin
resulta tentador compilar varios lenguajes distintos en el mismo lenguaje intermedio y usar una
etapa final comn para las distintas etapas iniciales, obtenindose as varios compiladores para
una mquina. Sin embargo, dadas las sutiles diferencias en los puntos de vista de los distintos
lenguajes, slo se ha obtenido un xito limitado en ese aspecto.
Pasadas
Normalmente se aplican varias fases de la compilacin en una sola pasada, que consiste en la
lectura de un archivo de entrada y en la escritura de un archivo de salida.
En la prctica hay muchas formas de agrupar en pasadas las fases de un compilador, as que es
preferible organizar el anlisis de la compilacin por las fases, en lugar de por las pasadas.
Como ya se seal, es comn agrupar varias fases en una pasada, y entrelazar la actividad de estas
fases durante la pasada. Por ejemplo, en anlisis lxico, el anlisis sintctico, el anlisis semntico
y la generacin de cdigo intermedio pueden agruparse en una pasada. En ese caso, la cadena de
componentes lxicos despus del anlisis lxico puede traducirse directamente a cdigo
intermedio. Con ms detalle, el analizador sintctico puede considerarse como el encargado del
control. Este intenta descubrir la estructura gramatical de los componentes lxicos observador;
obtiene los componentes lxicos cuando los necesita, llamando al analizador lxico para que le
proporcione el siguiente componente lxico. A medida que se descubre la estructura gramatical, el
analizador sintctico llama al generador de cdigo intermedio para que se haga el anlisis
semntico y genere una parte del cdigo.
Reduccin del nmero de pasadas
Es deseable tener relativamente pocas pasadas, dado que la lectura y escritura de archivos
intermedios lleva tiempo. Adems, si se agrupan varias fases dentro de una pasada, puede ser
necesario tener que mantener el programa completo en memoria, porque una fase puede
necesitar informacin en un orden distinto al que produce una fase previa. La forma interna del
programa puede ser considerablemente mayor que el programa fuente o el programa objeto, de
modo que este espacio no es un tema trivial.
Para algunas fases, el agrupamiento en una pasada presenta pocos problemas. Por ejemplo. Como
se mencion antes, la interfaz entre los analizadores lxico y sintctico a menudo puede limitarse
a un solo componente lxico. Por otra parte, muchas veces resulta muy difcil generar cdigo hasta
que se haya generado por completo la representacin intermedia. Por ejemplo, lenguajes como
ALGOL 68 permiten usar las variables antes de declararlas. No se puede generar el cdigo objeto
para una construccin si no se conocen los tipos de las variables implicadas en esa construccin.
De manera similar, la mayora de los lenguajes admiten construcciones goto que saltan hacia
adelante en el cdigo. No se puede determinar la direccin objeto de dichos saltos hasta haber
visto el cdigo fuente implicado y haber generado cdigo objeto para l.
En algunos casos, es posible dejar un segmento en blanco para la informacin que falta, y llenar la
ranura cuando la informacin est disponible. En particular, la generacin de cdigo intermedio y
de cdigo objeto a menudo se pueden fusionar en una sola pasada utilizando una tcnica llamada
relleno de retroceso (backpatching). Aunque no se pueden explicar todos los detalles se puede
ilustrar el relleno de retroceso partiendo de un ensamblador. Recordemos que anteriormente se
analiz un ensamblador de dos pasadas, en el que la primera pasada descubra todos los
identificadores que representaban posiciones de memoria y deduca sus direcciones al
descubrirlas. Despus, en una segunda pasada sustitua las direcciones por identificadores.
Se puede combinar la accin de las pasadas como sigue. Al encontrar una proposicin en
ensamblador que sea una referencia hacia adelante, por ejemplo.
GOTO destino
Se genera la estructura de una instruccin, con el cdigo de operacin de mquina para GOTO y se
dejan espacios en blanco para la direccin. Todas las instrucciones, con espacios en blanco para la
direccin de destino se guardan en una lista asociada con la entrada de destino de la tabla de
smbolos. Los espacios se llenan por fin se encuentra una instruccin como.
Destino: MOV algo, R1
Y se determina el valor de destino, es la direccin de la instruccin en curso. Entonces se hace el
relleno de retroceso, recorriendo la lista de destino de todas las instrucciones que necesitan su
direccin, sustituyendo la direccin de destino en los espacios en blanco que aparecen en los
campos de direccin de esas instrucciones. Este enfoque es fcil de implementar si las
instrucciones se pueden guardar en memoria hasta que se hayan determinado todas las
direcciones de destino.
Este enfoque es razonable para un ensamblador que pueda guardar toda una salida en memoria.
Como las representaciones intermedia y final del cdigo para un ensamblador son
aproximadamente iguales, y con seguridad casi de la misma longitud, el relleno de retroceso en
toda la longitud del programa ensamblador no es inviable. Sin embargo, en un compilador, con un
cdigo intermedio que consuma mucho espacio, habr que tener cuidado con la distancia en que
se hace el relleno de retroceso.
HERRAMIENTAS PARA LA CONSTRUCCIN DE COMPILADORES
El escritor del compilador, como cualquier programador, puede usar con provecho herramientas
de software tales como depuradores, administradores de versiones, analizadores, etctera.
Adems de estas herramientas de desarrollo de software, se han creado herramientas para
especializadas para ayudar a implantar varias fases de un compilador. En esta seccin se
mencionan brevemente.
Poco despus de escribirse el primer compilador, aparecieron sistemas para ayudar en el proceso
de escritura de compiladores. A menudo se hace referencia a estos sistemas como compiladores
de compiladores, generadores de compiladores o sistemas generadores de traductores. En gran
parte, se orientan en torno a un modelo particular de lenguaje, y son ms adecuados para generar
compiladores de lenguajes similares al del modelo.
Por ejemplo, es tentador suponer que los analizadores lxicos para todos los lenguajes son en
esencia iguales, excepto por las palabras clave y signos particulares que se reconocen. Muchos
compiladores de compiladores de hecho producen rutinas fijas de anlisis lxico para usar en el
compilador generado. Estas rutinas slo difieren en la lista de palabras clave que reconocen, y esta
lista es todo lo que debe proporcionar el usuario. El planteamiento es vlido, pero puede no ser
funcional si se requiere que reconozca componentes lxicos no estndar, como identificadores
que pueden incluir ciertos caracteres distintos de letras y dgitos.
Se han creado algunas herramientas generales para el diseo automtico de componentes
especficos de compilador. Estas herramientas utilizan lenguajes especializados para especificar e
implantar el componente y pueden utilizar algoritmos bastante complejos. Las herramientas ms
efectivas son las que ocultan los detalles del algoritmo de generacin y producen componentes
que se pueden integrar con facilidad al resto del compilador. La siguiente es una lista de algunas
herramientas tiles para la construccin de compiladores:
1. Generadores de analizadores sintcticos. Estos generadores producen analizadores
sintcticos, normalmente a partir de una entrada fundamentada en una gramtica
independiente del contexto. En los primeros compiladores, el anlisis sintctico consuma
no solo gran parte del tiempo de ejecucin del compilador, sino gran parte del esfuerzo
intelectual de escribirlo. Esta fase se considera ahora una de las ms fciles de aplicar
Muchos de los generadores de analizadores sintcticos utilizan poderosos algoritmos de
anlisis sintctico y son demasiado complejos para realizarlos manualmente.
2. Generadores de analizadores lxicos. Estas herramientas generan automticamente
analizadores lxicos, por lo general a partir de una especificacin basada en expresiones
regulares. La organizacin bsica del analizador lxico resultante es en realidad un
autmata finito.
3. Dispositivos de traduccin dirigida por la sintaxis. Estos producen grupos de rutinas que
recorren el rbol de anlisis sintctico. La idea bsica es que se asocian una o ms
traducciones con cada nodo del rbol de anlisis sintctico, y cada traduccin se define
partiendo de traducciones en sus nodos vecinos en el rbol.
4. Generadores automticos de cdigo. Tales herramientas toman un conjunto de reglas que
definen la traduccin de cada operacin del lenguaje intermedio al lenguaje de mquina
para la mquina objeto. Las reglas deben incluir suficiente detalle para poder manejar los
distintos mtodos de acceso posibles a los datos; por ejemplo, las variables pueden estar
en registros, en un posicin fija (esttica) de memoria o pueden tener asignada una
posicin en una pila. La tcnica fundamental es la de concordancia de plantillas. Las
proposiciones de cdigo intermedio se remplazan por plantillas que representan
secuencias de instrucciones de mquina, de modo que las suposiciones sobre el
almacenamiento de las variables concuerden de plantilla a plantilla. Como suele haber
muchas opciones en relacin con la ubicacin de las variables (por ejemplo, en uno o
varios registros o en memoria), hay muchas formas posibles de cubrir el cdigo
intermedio con un conjunto dado de plantillas, y es necesario seleccionar una buena
cobertura sin una explosin combinatoria en el tiempo de ejecucin del compilador.
5. Dispositivos para anlisis de flujo de datos. Mucha de la informacin necesaria para hacer
una buena optimacin de cdigo implica hacer un anlisis de flujo de datos que consiste
en la recoleccin de informacin sobre la forma en que se transmiten los valores de una
parte de un programa a cada una de las otras partes. Las distintas tareas de esta
naturaleza se pueden efectuar esencialmente con la misma rutina. En la que el usuario
proporciona los detalles relativos a la relacin que hay entre las proposiciones en cdigo
intermedio y la informacin que se est recolectando.

You might also like