Está en la página 1de 14

GUIA COMPILADORES

¿QUE ES UN COMPILADOR?

Un compilador es simplemente un programa que traduce otros programas. Los


compiladores clásicos traducen código fuente a código máquina ejecutable que tu
ordenador puede entender. (Algunos compiladores traducen código fuente a otro
lenguaje de programación. Estos se denominan traductores fuente-a-fuente o
transpiladores). LLVM es un proyecto de compilador de uso generalizado, consistente
en muchas herramientas de compilación modulares.
PROGRAMAS QUE MANIPULAN FUENTES

¿QUÉ SON?
Son un conjunto de herramientas de software diseñadas para analizar,
simplificar y acelerar el texto del código fuente, así como compilarlo o interpretarlo.
EJEMPLOS Y CÓMO FUNCIONAN
A.- Compilador: es un programa especial que traduce de código fuente de un
programa a lenguaje de máquina. El compilador informa al usuario de la presencia de
errores en el programa fuente.
Un compilador funciona de la siguiente forma:
1. El código fuente se lee en la memoria de la computadora.

2. El código fuente se convierte en código objeto o módulo de objeto. Un

programa puede tener muchos objetos y bibliotecas que necesitan ser unidas

entre sí para crear el ejecutable.

3. Se crean los conectores, para enlazar todos los componentes del programa.

4. Se reasignan los bloques de memoria dentro del programa de modo que una

pieza no sobreponga a otra parte en la memoria.

5. Los archivos compilados se graban en el disco u otro tipo de memoria

permanente.

6. El resultado es un archivo o programa ejecutable.


B.- Intérprete: permite que un programa fuente escrito en un determinado
lenguaje vaya traduciéndose y ejecutándose directamente sentencia a sentencia
por la computadora. Un intérprete capta una sentencia fuente, la analiza y la
interpreta, dando lugar a su ejecución inmediata.
Un intérprete funciona de la siguiente manera:
En lugar de producir un programa objeto como resultado de una traducción, un
intérprete realiza las operaciones que implica el programa fuente. Efectúa las
operaciones de los nodos conforme “recorre” el árbol. En la raíz descubriría que
tiene que realizar una asignación, y llamaría a una rutina para evaluar la expresión
de la derecha y después almacenaría el valor resultante en la localidad de
memoria asociada con el identificador posición.
En el hijo derecho de la raíz, la rutina descubriría que tiene que calcular la
suma de dos expresiones. Se llamaría a sí misma de manera recursiva para
calcular el valor de la expresión velocidad*60. Después sumaría ese valor de la
variable inicial. Muchas veces los intérpretes se usan para ejecutar lenguajes de
órdenes, pues cada operador que se ejecuta en un lenguaje de órdenes suele ser
una invocación de una rutina compleja, como un editor o un compilador. Del mismo
modo algunos lenguajes de “muy alto nivel”, normalmente son interpretados,
porque hay muchas cosas sobre los datos, como el tamaño y la forma de las
matrices, que no se pueden deducir en el momento de la compilación.

C.- Editores de estructuras: Un editor de estructuras toma como entrada una


secuencia de órdenes para construir un programa fuente. Puede comprobar si la
entrada, puede proporcionar palabras clave de manera automática.
Por ejemplo, puede comprobar si la entrada está formada correctamente,
puede proporcionar palabras clave de manera automática (por ejemplo, cuando el
usuario escribe while, el editor proporciona el correspondiente do y le recuerda al
usuario que entre las dos palabras debe ir un condicional) y puede saltar desde un
begin o un paréntesis izquierdo hasta su correspondiente end o paréntesis derecho.
Funcionamiento de un editor de estructuras:
Toma como entrada una secuencia de órdenes para construir un programa
fuente, analiza el texto del programa, imponiendo al programa fuente una estructura
jerárquica apropiada. De esa manera, el editor de estructuras puede realizar tareas
adicionales útiles para la preparación de programas.

D.- Impresoras estéticas: Analiza un programa y lo imprime de forma que la


estructura del programa resulte claramente visible. Por ejemplo, los comentarios
pueden aparecer con un tipo de letra especial, y las proposiciones pueden aparecer
con una indentación proporcional a la profundidad de su anidamiento en la
organización jerárquica de las proposiciones.

Funcionamiento de las impresora estéticas:


Al ser un software, este analiza el texto del código fuente y determina cuál de
todos ellos debe de aplicarle una determinado estilo, color, indentación.
Generalmente el usuario puede escoger el estilo con el que más se sienta a gusto.
E.- Un verificador estático: lee un programa, lo analiza e intenta descubrir
errores potenciales sin ejecutar el programa, puede detectar si hay partes de un
programa que nunca se podrán ejecutar o si cierta variable se usa antes de ser
definida
Funcionamiento de un verificador estático:
La parte de análisis a menudo es similar a la que se encuentra en los
compiladores de optimización. Así, un verificador estático puede detectar si hay partes
de un programa que nunca se podrán ejecutar o si cierta variable se usa antes de ser
definida.
FASES DEL PROCESO DE COMPILACIÓN

A.- El analizador léxico: es la primera fase de un compilador. Su principal


función consiste en leer los caracteres de entrada y elaborar como salida una
secuencia de componentes léxicos que utiliza el analizador sintáctico para hacer
el análisis.
Análisis léxico (Scanner)
Scanner tiene las funciones de leer el programa fuente como un archivo de
caracteres y dividirlo en tokens. Los tokens son las palabras reservadas de un
lenguaje, secuencia de caracteres que representa una unidad de información en
el programa fuente. En cada caso un token representa un cierto patrón de
caracteres que el analizador léxico reconoce, o ajusta desde el inicio de los
caracteres de entrada.
De tal manera es necesario generar un mecanismo computacional que nos
permita identificar el patrón de transición entre los caracteres de entrada,
generando tokens, que posteriormente serán clasificados. Este mecanismo es
posible crearlo a partir de un tipo especifico de maquina de estados llamado
autómata finito.
a) Componentes léxicos:
Un token es un par que consiste en un nombre de token y un valor de atributo
opcional. El nombre del token es un símbolo abstracto que representa un tipo de
unidad léxica; por ejemplo, una palabra clave específica o una secuencia de
caracteres de entrada que denotan un identificador
b) Reconocimiento de los componentes léxicos: Para este fragmento
de lenguaje, el analizador léxico reconocerá las palabras clave if, then,
else, al igual que los lexemas representados por oprel, id y núm. Para
simplificar las cosas, se supone que las palabras clave son reservadas;
es decir, no se pueden usar como identificadores, núm representa los
números enteros y reales sin signo de Pascal.
B.- Análisis sintáctico: Es la fase del analizador que se encarga de chequear el
texto de entrada en base a una gramática dada. Y en caso de que el programa de
entrada sea válido, suministra el árbol sintáctico que lo reconoce. En teoría, se supone
que la salida del analizador sintáctico es alguna representación del árbol sintáctico
que reconoce la secuencia de tokens suministrada por el analizador léxico. En la
práctica, el analizador sintáctico también hace:
• Acceder a la tabla de símbolos (para hacer parte del trabajo del analizador
semántico).
• Chequeo de tipos (del analizador semántico).
• Generar código intermedio.
• Generar errores cuando se producen. En definitiva, realiza casi todas las
operaciones de la compilación. Este método de trabajo da lugar a los métodos de
compilación dirigidos por sintaxis.
a) Gramática independiente del contexto:
Muchas construcciones de los lenguajes de programación tienen una
estructura inherentemente recursiva que se puede definir mediante
gramáticas independientes del contexto. Por ejemplo, se puede tener
una proposición condicional definida por una regla como:
Si S1 y S2 son proposiciones y E es una expresión, entonces
"If E then S1 else S2” es una proposición.
a) Tipos de analizadores sintáctico (ascendiente, descendiente, lr):
DESCENDENTE
Análisis sintáctico por descenso recursivo

Se puede considerar el análisis sintáctico descendente como un

intento de encontrar una derivación por la izquierda para una cadena

de entrada

ANALIZADOS SINTACTICO LR

La técnica se denomina análisis sintáctico LR(k); la "L" es por el

examen de la entrada de izquierda a derecha (en inglés, left-to right),

la "R" por construir una derivación por la derecha (en inglés, rightmost

derivation) en orden inverso, y la k por el número de símbolos de

entrada de examen por anticipado utilizados para tomar las decisiones

del análisis sintáctico.

b) Arboles de análisis sintáctico:


Un árbol de análisis sintáctico se puede considerar como una

representación gráfica de una derivación que no muestra la elección

relativa al orden de sustitución.

C.- Análisis semántico: se encarga de que los tipos que intervienen en las
expresiones sean compatibles o que los parámetros reales de una función sean
coherentes con los parámetros formales.
1- comprobación de tipos):
La fase de análisis semántico revisa el programa fuente para tratar de
encontrar errores semánticos y reúne la información sobre los tipos para la fase
posterior de generación de código. En ella se utiliza la estructura jerárquica
determinada por la fase de análisis sintáctico para identificador los operadores
y operandos de expresiones y proposiciones.
Clasificación:
- Dinámica: Aspectos que solo pueden ser conocidos en tiempos de
ejecución.
- Estática: Aspectos que solo pueden ser controlados en tiempo de
compilación.
- Verificación de Tipos: el compilador verifica si cada operador tiene
operandos permitidos por la especificación del lenguaje fuente.

a) Sistema de tipos:
- Tipos primitivos:

• booleano: un byte, 0 (false), 1


(true)
int i = 2;
...
if (i) ...
• caracter: un byte, ASCII
Java: dos bytes, UNICODE
• entero: dos bytes...
char c;
int i;
short s;
long l; ...
• real: coma fija, coma flotante
• racionales?
• complejos?

- Constructores:
• enumerados: orden total
type dia is (lun, mar, mie, jue, vie, sab, dom);
type fs is (sab, dom);
• subrangos: intervalos
• registros: tuplas
• vectores: secuencias
var s: string[80];
...
write(s);
• conjuntos: selección
• punteros: referencias
• listas: sec. sin indexado
• ficheros: sec. con pos.
• funciones: genera un valor

b) Equivalencia y conversión de expresiones:

- Equivalencia estructural:
Dos tipos son los mismos si y solo si tienen la misma estructura. Dos
expresiones de tipos son estructuralmente equivalentes si son el mismo tipo básico o
se forman aplicando el mismo constructor de tipos sobre expresiones de tipos
estructuralmente equivalentes
Conversión
Debido a que varios operadores están sobrecargados, es decir, que se utiliza el
mismo operador para operaciones diferentes, es por lo que es necesario convertir los
tipos antes de operar.

Funciones principales:
 Identificar cada tipo de instrucción y sus componentes

 Completar la Tabla de Símbolos

 Realizar distintas comprobaciones y validaciones:

 Comprobaciones de tipos.

 Comprobaciones del flujo de control.

 Comprobaciones de unicidad.

El análisis semántico completa las dos fases anteriores de análisis lexicográfico y


sintáctico incorporando ciertas comprobaciones que no pueden asimilarse al mero
reconocimiento de una cadena dentro de un lenguaje.
La fase de análisis semántico revisa el programa fuente para tratar de encontrar
errores semánticos y reúne la información sobre los tipos para la fase posterior de
generación de código. Un componente importante del análisis semántico es la
Verificación de Tipos. Aquí, el compilador verifica si cada operador tiene operandos
permitidos por la especificación del lenguaje fuente.
Ejemplo:

D.- Generación de código Intermedio: Algunos compiladores generan una


representación intermedia explícita del programa fuente, una vez que se han realizado
las fases de análisis. Se puede considerar esta operación intermedia como un
subprograma para una máquina abstracta. Esta representación intermedia debe tener
dos propiedades importantes: debe ser fácil de producir y fácil de traducir al programa
objeto.
Después de haber conducido el análisis semántico el compilador genera un código
intermedio entre el código fuente y el el código de la maquina objetivo (unos y ceros).
Este representa un programa para una máquina abstracta. Esta en medio de un
lenguaje de alto nivel y un lenguaje de máquina. Este código intermedio debe ser
generado de tal manera que es fácilmente traducido a un lenguaje de máquina de
bajo nivel.
Ejemplo:

E.- Generación de Código: Esta constituye la fase final de un compilador. En


ella se genera el código objeto que por lo general consiste en código en lenguaje
máquina (código relocalizable) o código en lenguaje ensamblador.
En la fase de generación de código se toma la versión optimizada del código
intermedio y se mapea a la lenguaje de máquina objetivo. La generación de código
traduce entonces el código intermedio en una secuencia reubicable de código de
máquina, mas tarde el enlazador del sistema operativo tomara estas instrucciones y
les asignara un espacio en la memoria para así poder funcionar.
Ejemplo:
F.-

Optimización de Código: La siguiente fase realiza una optimización del código


intermedio generado. La optimización puede asumirse como algo que quita lineas de
código innecesarias, y ordena una secuencia de declaraciones que aceleran la
ejecución del programa sin desperdiciar recursos de CPU o memoria RAM.
Por ejemplo si tenemos las siguientes líneas en código intermedio.

int valorA = 0;
int valorB = 10;
int temp = valorA + ValorB;

El optmizador lograría que este código se viera reducido así:

1 int temp = 0 + 10;


reduciendo así el espacio reservado para las dos variables iniciales y los ciclos de
reloj que toma asignarlos.

G.- Tabla de símbolos: Las tablas de símbolos (también llamadas tablas de


identificadores y tablas de nombres), realizan dos importantes funciones en el proceso
de traducción: verificar que la semántica sea correcta y ayudar en la generación
apropiada de código. Ambas funciones se realizan insertando o recuperando desde
la tabla de símbolos los atributos de las variables usadas en el programa fuente. Estos
atributos, tales como: el nombre, tipo, dirección de almacenamiento y dimensión de
una variable, usualmente se encuentran explícitamente en las declaraciones o más
implícitamente a través del contexto en que aparecen los nombres de variables en el
programa.
Una de las estructuras de datos que se encuentran relacionadas con las fases
del proceso de compilación es la tabla de símbolos, la cual tiene como propósito
registrar información que se comparte entre varias etapas y que permite administrar
los recursos asociados a las entidades que manipulará el programa. La tabla de
símbolos tiene típicamente la siguiente estructura:

A continuación se
presenta un

ejemplo de una tabla de símbolos típica.

H.- Detección y tratamiento de errores: Aunque es en la etapa de análisis


donde se detectan la mayoría de los errores, cada etapa del proceso puede encontrar
errores. Para tratar adecuadamente un error, interviene el módulo de tratamiento de
errores que comprende generalmente la realización de dos acciones:
• Diagnóstico del error: Trata de buscar su localización exacta y la posible
causa del mismo, para ofrecer al programador un mensaje de diagnóstico, que será
incluido en el listado de compilación.

• Recuperación del error: Después de detectado un error, cada fase debe


tratarlo de alguna forma para poder continuar con la compilación y permitir la
detección de más errores, aunque no se genere código objeto.
Ejemplo:

Unidad II:
1- Preprocesadores:
Un preprocesador es un programa separado que es invocado por el
compilador antes de que comience la traducción real.
El procesador en si es la parte más importante o una parte fundamental del
computador, vendría siendo el cerebro del computador. El procesador es uno
de los componentes más complejos y frecuentemente más caro, pero él no
puede hacer nada solo. Como todo cerebro, necesita de un cuerpo, que es
formado por los otros componentes de la computadora, incluyendo la memoria,
el disco duro, la placa de vídeo y de red, monitor, teclado y mouse, etc.

2- Ensambladores:
El término ensamblador se refiere a un tipo de programa informático que se
encarga de traducir un fichero fuente escrito en un lenguaje ensamblador, a un
fichero objeto que contiene código máquina, ejecutable directamente por el
microprocesador.

3- Cargadores:
Un cargador es un programa que coloca en la memoria para su ejecución, el
programa guardado en algún dispositivo de almacenamiento secundario. Un
cargador es un programa del sistema que realiza la función de carga, pero
muchos cargadores también incluyen relocalización y ligado. Algunos sistemas
tienen un ligador para realizar las operaciones de enlaces y un cargador
separado para manejar la relocalización y la carga. Los procesos de
ensamblado y carga están íntimamente relacionados.

También podría gustarte