martes, 31 de mayo de 2016

Portada

               UNIVERSIDAD GENERAL GERARDO BARRIOS
FACULTAD DE CIENCIA Y TECNOLOGÍA
INGENIERÍA EN SISTEMAS Y REDES INFORMÁTICAS




CATEDRÁTICO:
Ing. Marvin Osmaro Parada Benites

CÁTEDRA:
Compiladores e Interpretes.
  RESPONSABLE:
José Gonzalo Estrada López       usis019013
Actividad:
E-Portafolio de clases de compiladores e interpretes

Unidad Nº 5 Generación de código intermedio


  • Lenguajes intermedios, definición y tipos
  • Optimización dependiente e independiente de la maquina Generador de código


INDEPENDENCIA DE LA MÁQUINA
Según el modelo de arquitectura de un compilador en el que éste se divide en frontend y backend, la etapa inicial traduce el programa fuente a una representación intermedia a partir de la cual la etapa final genera el código objeto, ya sea en forma de código máquina o ensamblador.

La construcción del lenguaje objeto en la etapa final, facilita la reutilización del frontend para crear otros compiladores del mismo lenguaje pero que generan código para otras plataformas.

La división en etapas se realiza utilizando un código intermedio independiente de la máquina destino.

El programa en código intermedio resultante es la salida de la etapa frontend y la entrada al backend.


¿A QUÉ LE LLAMAMOS CÓDIGO INTERMEDIO?
El código intermedio es una simplificación de los lenguajes de alto nivel en la que se elimina las estructuras y las declaraciones y con sentencias cercanas al ensamblador.

Los lenguajes intermedios son representaciones abstractas de un leguaje fuente. Algunas representaciones obsoletas o en desuso son los árboles sintácticos. 
Actualmente se utilizan como código intermedio las cuádruplas.



¿PARA QUE LO UTILIZAMOS?
El código intermedio se utiliza en un compilador por las siguientes razones:
1. Es mas fácil hacer la conversión en dos fases. 
2. Independiza el analizador sintáctico del resto del compilador.
Es mas sencillo aplicar la optimización sobre instrucciones independientes del hardware que sobre instrucciones dependientes.



¿A QUE SE REFIERE EL USO DE CUÁDRUPLAS?
Tipos de cuádruplas:
Cuartetos o código de tres direcciones (OPERADOR, operando1, operando2, resultado)
Tercetos o código de dos direcciones. (OPERADOR, operando1, operando2)










Unidad 4 Análisis semántico

¿Que es la semántica?

Se refiere a los aspectos del significado, sentido o interpretación del significado de un determinado elemento, símbolo, palabra, expresión o representación formal.


Análisis semántico
Se trata de determinar el tipo de los resultados
intermedios, comprobar que los argumentos
que tiene un operador pertenecen al conjunto
de los operadores posibles, y si son compatibles
entre sí, etc. En definitiva, comprobará que el

significado de lo que se va leyendo es válido.

  • El análisis semántico se realiza posteriormente al sintáctico y mucho más difícil de formalizar que éste.
  • La salida “teórica” de la fase de análisis semántico sería un árbol semántico.






  • Que es un árbol semántico?
    Es una estructura jerárquica en la cual se registran las operaciones que implica u operan dentro del programa fuente 

    En cada una de las ramas del  árbol semántico se registra el valor o significado que este debe tener, y el análisis semántico se encarga de terminar cual de los valores registrados en las ramas es aplicable.





    Tabla de símbolos en esta fase
    Un compilador necesita guardar y usar la información de los objetos que se va encontrando en el texto fuente, como variables, etiquetas, declaraciones de tipos, etc.

    Esta información se almacena en una estructura de datos interna conocida como tabla de símbolos.



    •  El compilador debe desarrollar una serie de funciones relativas a la manipulación de esta tabla como consultar un elemento en ella, y consultar la información relacionada con un símbolo, etc. 
    • Como se tiene que acceder mucho a la tabla de símbolos los accesos deben ser lo más rápidos posible para que la compilación sea eficiente.




    Sistemas de tipo: 
    Es el conjunto de reglas que determinan el criterio para asignar expresiones de tipo a las diferentes partes del código fuente.



    • Tipo básico: entero, carácter, real, lógico  
    • Nombres de tipo 
    • Constructores de tipo: estructuras, uniones, objetos 
    •  Apuntadores: referencias a tipos 
    • Funciones a=suma();


    Chequeo de tipos (y otros)
    Un compilador debe realizar una serie de chequeo estáticos, como chequeo de tipos:

    Consistencia: unicidad, existencia, no-ciclicidad, ... Equivalencia y compatibilidad de tipos Inferencia de tipos (en valores) Sobrecarga de funciones y operadores


    COMPROBACIONES SEMÁNTICAS TIPOS


    • Comprobaciones ESTÁTICAS. Las comprobaciones sintácticas y semánticas. Comprobaciones DINÁMICAS. Realizadas en tiempo de ejecución.
    • Comprobaciones SEMÁNTICAS 
    • De TIPO.
    • Verificación del tipo de los operando en las expresiones.

    • De FLUJO de CONTROL.
    • Verifica los puntos del programa de salida y entrada del control.


    COMPROBACIONES SEMÁNTICAS

    De UNICIDAD. Verifica la presencia de símbolos de forma única. (ejemplo: declarar un símbolo una sólo vez). Relación de NOMBRES. Un mismo nombre puede aparecer más de una vez.


    Unidad 03: Análisis Sintáctico
    •  Determina  la  sintaxis,  o  estructura  de  un programa.
    •  Es un análisis a nivel de sentencias, y es mucho más complejo que el análisis léxico.
    •  Su función es tomar  el  programa  fuente  en  forma  de  tokens,  que  recibe  del analizador
    • léxico,  y  determinar  la  estructura  de  las sentencias del programa.
    • Este proceso es similar a determinar la estructura de una frase

    Análisis Sintáctico – Proceso 




    Código fuente 


    Analizador léxico o rasterador 


    Tokens 


    Analizador Sintáctico 


    Árbol sintáctico 


    Analizador Semántico 


    Árbol con anotaciones 


    Optimizador de código fuente 


    Código intermedio 


    Generador de código 


    Código objetivo 


    Optimizador de código objetivo 


    Código Objetivo 






    La tarea del AS es determinar la estructura sintáctica de un programa a partir de los tokens producidos por el AL.
    En resumen una función que toma como entrada la secuencia de tokens y salida el AS.
    Secuencia de tokens <> árbol sintáctico
    El árbol se define como estructura de datos dinámica, nodos, atributos, campos del atributo.
    Manejo de errores, no solo mostrar mensaje sino recuperarse (inferir código corregido) y continuar el análisis, para encontrar tantos errores como sea posible.
    Al proceso de reconocer la estructura del lenguaje fuente se conoce con el nombre de análisis sintáctico (parsing).
    Hay distintas clases de analizadores o reconocedores sintácticos, pero en general se clasifican en 2 grandes grupos:


    A.S. Ascendentes y A.S. Descendentes.

    Tipos de Análisis Sintácticos
     Análisis descendente:

    Partimos de la raíz del árbol (donde estará situado el símbolo inicial de la gramática) y se van aplicando reglas por la izquierda de forma que se obtiene una derivación por la izquierda de la cadena de entrada.
    Para decidir qué regla aplicar, se lee un token de la entrada.

     Análisis ascendente:

    Partiendo de la cadena de entrada, se construye el árbol de análisis sintáctico empezando por las hojas (donde están los tokens) y se van creando nodos intermedios hasta llegar a la raíz (hasta el símbolo inicial), construyendo así el árbol de abajo a arriba.


    El recorrido del árbol se hará desde las hojas hasta la raíz.
    La principal tarea del analizador sintáctico no es comprobar que la sintaxis del programa fuente sea correcta, sino construir una representación interna de ese programa y en el caso en que sea un programa incorrecto, dar un mensaje de error.


    Función principal
    Comprueba que el orden en que el analizador léxico le va entregando los tokens es válido. Si esto es así significará que la sucesión de símbolos que representan dichos tokens puede ser generada por la gramática correspondiente al lenguaje del código fuente






    • Está constituido por todas las palabras y símbolos que lo componen.Para un lenguaje de programación la definición también es válida.
    •  Lo constituyen todos los elementos individuales del lenguaje, denominados frecuentemente en inglés tokens
    Token 
     Así son tokens: las palabras reservadas del lenguaje, los símbolos que denotan los distintos tipos de operadores, identificadores (de variables, de funciones, de procedimientos, de tipos, etc.), separadores de sentencias y otros.


    Elemento léxico del lenguaje 
    Símbolo No Terminal de las fases siguientes

    Patrón 
    Expresión regular que define el lenguaje 
    Letra (Letra | Digito)

    Lexema 
    ◦ Secuencia de caracteres que concuerda con un patrón 
    ◦ Numero, caracter.
    Atributos 
    • Estructura de datos de cada token para almacenarse en la TS 
    • Depende del tipo de token 
    • [ID, Lexema, Tipo, Valor, línea]
    •  Un programa fuente es una serie de símbolos que representan las construcciones del lenguaje tales como variables, etiquetas, palabras reservadas, constantes, operadores, entre otros. 
    •  El programa fuente se trata inicialmente con el analizador léxico
    •  Identificar la colección de tokens  
    • Estructurar la colección de tokens  
    • Describir el lenguaje como expresiones regulares
    •  Así, para la siguiente sentencia de Pascal: IF cuenta = sueldo THEN jefe:= justo;
    • El analizador léxico la separa en la siguiente secuencia de tokens:

    Y les asigna su atributo, habitualmente por medio de un código numérico cuyo significado se ha definido previamente.






    El análisis léxico es un análisis a nivel de caracteres, su misión es reconocer los componentes léxicos o tokens, enviando al analizador sintáctico

     Analizador léxico que reconozca los siguientes elementos: 

    •  Números enteros 
    • Operadores aritméticos suma, resta, producto, división, incremento y decremento (+, - *, /, ++,--)  
    • Identificadores 
    • WHILE


    Especificación formal 

    • Gramáticas Lineales 
    • Recursivas a izquierdas 
    • Recursivas a derechas 
    • expresiones regulares 
    • Autómatas Finitos (Diagramas de Transición)
    • Tratar con la tabla de símbolos 
    • Generar tokens bajo demanda del analizador sintáctico  
    • Manejar el fichero fuente 
    • Ignorar comentarios 
    • Contabilizar posición de tokens 
    • Preprocesar macros, constantes, includes



    Tabla de Símbolos.

    Almacena todos los nombres declarados en el programa y sus atributos (tipo, valor, dirección, parámetros, etc).

    Se usa en las distintas fases del compilador.

    Estructura de datos.

    Almacena información sobre:
    • Los identificadores.
    • Las palabras reservadas.
    • Las constantes.
    Contiene una entrada para cada uno de los símbolos definidos en el programa fuente.

    Sobre los identificadores, y opcionalmente sobre las palabras reservadas y las constantes.

    Información sobre el lexema, tipo de datos, ámbito y dirección en memoria.

    Por cada entrada en la tabla de símbolos habrá que guardar:
    • Lexema correspondiente.
    • Tipo.(depende de la implementación).
    • Ámbito.(depende de la implementación).
    • Dirección de memoria asignada.
    • Forma.(depende de la implementación).
    ¿Utilidad de la tabla de símbolos?

    • Analizador Léxico: Pasa en el token y la entrada de la TS creada.
    • Analizador Sintáctico y Semántico: busca el token y si no la encuentra crea una nueva entrada.

    Datos que se almacenan:
    Para un array:
    • Tipo de los elementos.
    • Número de elementos.
    • Limites inferior y superior.
    Para una función:
    • Número de parámetros.
    • Tipo de los parámetros.
    • Forma de paso de parámetros.
    • Tipo de retorno.
    Operaciones Principales.
    • Insertar: introduce un símbolo tras una declaración.
    • Buscar: recupera información asociada a un símbolo.
    • Eliminar: borra la información.
    Ejemplo de Uso I.

    Declaración previa al uso de variables:
    • En las declaraciones, inserción en la TS.
    Aparición de una variable en una sentencia, búsqueda en la TS:
    • Si se encuentra Fue declarada.
    • Si no se encuentra Error de compilación.
    Ejemplos de Uso II.

    Acceso a una posición de un array:
    • Declaración > Inserción en la TS.
    • Acceso a un array > Búsqueda en la TS.
    1. Comprobación de tipo array.
    2. Comprobación acceso a una posición válida.
    Tabla de Símbolos.


    Ejemplo:



    • Analizador Lexicográfico: Inserta en TS cada id que detecta y si corresponde da error si ya existe.
    • Analizador Sintáctico: Inserta el tipo de id.
    • Analizador Semántico: Verifica que cada id sea declarado antes de usarlo y recupera el tipo de id.
    • Generación de Código Intermedio: recupera tipo y dirección del id.
    • Generación de Código: Inserta y recupera información sobre la memoria asignada.
    Estructuras usadas para implementar una tabla de símbolos.
    Lista
    1. Simple de implementar.
    2. Lenta cuando se trabaja con muchos identificadores.
    Árbol
    1. Rápida.
    2. Consume más memoria.
    3. Es útil cuando hay muchas declaraciones.
    Tabla de Hashing

    1. Rápida.
    2. Difícil de implementar.
    3. Se debe definir una función de hashing apropiada para evitar colisiones.

    Operaciones sobre TS.
    • Búsqueda (lexema): entero;
    • Inserción (lexema, descriptor): boolean;
    • Obt_atributo (lexema, atributo): valor;
    • Eliminación (lexema): entero.
    Manejo de palabra

    Si el scanner diferencia entre un identificador y una palabra reservada, entonces devuelve al parser el código correspondiente. Aquí no se requiere el ingreso de la palabra clave en la TS.

    Si el scanner no las diferencia de los identificadores:
    • Pueden almacenarse en una tabla separada.
    • Estar inicializadas al principio de la TS.
    • Una entrada, en TS para una palabra reservada.
    Entrada en la TS.

    Una primera desagregación de una entrada de la tabla de símbolos.

    No todos los atributos se introducen a la vez, estos se completan conforme avanzan las etapas de compilación.

    Parte Fija.


    Parte Variante.

    • Depende del objeto computacional asociado con el identificador.
    • Variable Simple: la parte variante es vacía excepto cuando se admitan valores de inicialización.
    • Variable Estructurada (Arreglo).





    Procedimiento o Función.


    Operaciones sobre TS: Lenguajes estructurados a bloques.

    Crean un ámbito, una visibilidad y un tiempo de vida para los identificadores.


    Tareas que se deben realizar cuando se ingresa a un nuevo bloque:
    • Dar de alta un nuevo bloque.
    • Insertar cada identificador encontrado en dicho bloque.

    Tareas realizadas cuando se finaliza el análisis de un bloque:
    • Eliminar cada identificador en el bloque.
    • Eliminar el bloque.
    Operaciones sobre TS: Lenguajes Estructurados a Bloques.

    Cuando se busque un identificador en la TS se debe retornar el último identificador insertado, es decir, el identificador declarado en el bloque actual, si en tal bloque no existe el identificador buscarlo en el bloque que lo contenga, y así sigue hasta encontrarlo. Si el identificador no se encuentra en ninguno de los bloques anidados entonces no existe.

    Ejemplo:

    Clasificación de los Interpretes

    ¿Que es un Interprete?

    •  En lugar de producir un programa objeto como resultado de una traducción, un intérprete realiza las operaciones que implica el programa fuente. 
    •  Un intérprete no genera un programa equivalente, sino que toma una sentencia del programa fuente en un lenguaje de alto nivel, la traduce al código equivalente y al mismo tiempo la ejecuta.
    • Un intérprete es un programa que analiza y ejecuta simultáneamente el programa fuente, es decir no producen un código objeto, siendo su ejecución simultánea a la del programa fuente.
    Comportamiento de un Interprete

    • Un intérprete es como un compilador, solo que la salida es una ejecución. El programa de entrada se reconoce y ejecuta a la vez. No se produce un resultado físico (código máquina) sino lógico (una ejecución).
    • Además de que la traducción optimiza el programa acercándolo a la máquina, los lenguajes interpretados tienen la característica de que permiten construir programas que se pueden modificar a sí mismos.

    Resultado del Interprete




    Ventajas de los Interpretes
    •  Su principal ventaja es que permiten una fácil depuración. Permiten una mayor interactividad con el código en tiempo de desarrollo. 
    •  En algunos lenguajes (Smalltalk, Prolog, LISP) está permitido y es frecuente añadir código según se ejecuta otro código, y esta característica solamente es posible implementarla en un intérprete. 
    •  Puede ser interrumpido con facilidad. 
    •  Puede ser rápidamente modificado y ejecutado nuevamente.
    • Un Intérprete necesita menos memoria que un compilador. 
    • Facilita la búsqueda de errores. 
    • En algunos lenguajes está permitido añadir código según se ejecuta otro código. 
    • Menor consumo de memoria.

    Desventajas de los Interpretes
    •  Lentitud de ejecución, ya que al ejecutar a la vez que se traduce no puede aplicarse un alto grado de optimización. Cada instrucción debe ser traducida a código máquina tantas veces como sea ejecutada
    • Durante la ejecución, el intérprete debe residir en memoria ya que no genera código objeto.
    • Tamaño del programa objeto, que exige añadir el intérprete al programa propiamente dicho.

    Clasificación de Intérpretes
    • Intérpretes Puros
    • Interpretes Avanzados
    • Interpretes Incrementales


    Intérpretes Puros
    •  Los intérpretes puros son los que analizan una sentencia y la ejecutan, y así sucesivamente todo el programa fuente. Fueron los intérpretes desarrollados en la primera generación de ordenadores, pues permitían la ejecución de largos programas con ordenadores de memoria muy reducida, ya que sólo debían contener en memoria el intérprete y la sentencia a analizar y ejecutar. 
    • El principal problema de este tipo de intérpretes es que si a mitad del programa fuente se producen errores, se debe de reiniciar el proceso.

    Funcionamiento del Intérprete Puro


    Explicación del Interprete Puro
    • En la figura se representa el esquema general de un intérprete puro, donde se puede observar que el lenguaje fuente se traduce a una representación interna (texto o binaria) que puede ser almacenada en memoria o en disco. 
    •  Esta representación interna tiene todas las instrucciones numeradas o colocadas consecutivamente en estructuras de tamaño fijo (por ejemplo un array o posiciones consecutivas de memoria, o un fichero binario de estructuras de tamaño fijo)
    •  Mientras se realiza este paso se puede construir la tabla de etiquetas, que es una tablas que contiene una estructura donde están todas las etiquetas y su posición en el programa fuente (las etiquetas se utilizan tanto en las instrucciones de salto como en las llamadas a procedimientos y funciones). 
    •  Una vez que este proceso ha finalizado, comienza la ejecución por la primera instrucción del código, que se envía al evaluador de instrucciones, éste la ejecuta (recibiendo datos si es necesario o enviando un mensaje de error).
    • El evaluador de instrucciones también determina la instrucción siguiente a ejecutar, en algunos casos previa consulta a la tabla de etiquetas. En el caso de que no haya saltos (GOTO) o llamadas a procedimientos o funciones se ejecuta la siguiente instrucción a la instrucción en curso. 
    •  El evaluador de instrucciones puede utilizar dos métodos de evaluación. El método clásico es la evaluación voraz o ansiosa, donde se evalúan las expresiones completamente. Otro método es la evaluación perezosa, evaluándose sólo la parte necesaria de la expresión (el resto no se evalúa).


    Interpretes Avanzados

    •  Los intérpretes avanzados o normales incorporan un paso previo de análisis de todo el programa fuente. Generando posteriormente un lenguaje intermedio que es ejecutado por ellos mismos.
    • De esta forma en caso de errores sintácticos no pasan de la fase de análisis.

    Funcionamiento del Intérprete Avanzado



    Explicación del Interprete Avanzado

    • Un ejemplo de intérprete avanzado es el que utiliza el lenguaje Java. Así un programa en lenguaje java (con la extensión .java) se compila y produce uno o varios ficheros con la extensión .class, estos ficheros están en un formato binario denominado bytecode independiente de plataforma, que se interpreta posteriormente.
    • Esto permite que el bytecode se ejecute en cualquier sistema operativo que disponga de un intérprete de bytecode. Dado que la mayor parte de los navegadores de Internet llevan inmerso un intérprete de bytecode, esto ha permitido al lenguaje Java ser uno de los más utilizados en aplicaciones que usen Internet.

    Interpretes Incrementales
    • Algunos lenguajes no se pueden compilar, debido a que entre sus características pueden manejar objetos o funciones que no son conocidos en tiempo de compilación, ya que son creados en ejecución. Para este tipo de lenguajes existen los intérpretes incrementales, que permiten compilar los módulos completamente definidos, y recompilar en tiempo de ejecución los nuevos módulos.
    •  Los intérpretes incrementales tienen gran interés en los lenguajes que permiten no definir los problemas completamente en tiempo de compilación. En estos casos se utilizan evaluadores parciales que toman como entrada el programa fuente junto con algunos datos (pero no todos), realizándose los cálculos que se pueden hacer con dicho subconjunto de datos, y produciendo una salida que contiene un residuo del programa fuente que se ha introducido.

    Clase 2.1
    Un traductor es un programa que toma como entrada un texto escrito en un lenguaje y da como salida otro texto en un lenguaje diferente.



    Forma de el proceso de compilación


    Compilador: es un traductor que convierte un texto escrito en un lenguaje de alto nivel a un lenguaje de bajo nivel(código objeto o maquina).

    Ensamblador: es un lenguaje de bajo nivel, donde cada sentencia del lenguaje fuente se traduce a una instrucción en código maquina.

    Interprete: no genera código objeto, analiza y ejecuta directamente cada proposición del codigo fuente.

    Pre-procesador: procesan un texto fuente modificandolo en cierta forma previamente a la compilación.



    Como saber si estamos ante un compilador
    Cuando el lenguaje fuente esta en un lenguaje de programación de alto nivel y el objeto generado sea de bajo nivel.






    Ventajas de los compiladores.
    • Producen un código optimizado.
    • La ejecución del programa objeto es mucho mas rápida que si se interpreta el programa fuente
    • El compilador tiene una visión global del programa, por lo que la información de mensajes de error es más detallada.

    Desventajas de los compiladores.
    • Se debe de ejecutar muchas veces el código fuente para ver los cambios en el resultado.
    • Mayor consumo de memoria.
    Interprete: 

    Es un programa que analiza y ejecuta simultáneamente el programa fuente, es decir no producen un código objeto, siendo su ejecución simultánea a la del programa fuente.

    Comportamiento del Interprete:

    Un interprete es como un compilador, solo que la salida es una ejecución. El programa de entrada se reconoce y ejecuta a la vez. No se produce un resultado físico (código máquina) sino lógico (una ejecución).

    Resultado del interprete




    Contexto del compilador.


    Etapas de compilación.


    Token: es una cadena de caracteres que tiene un significado coherente un lenguaje de programación.

    En la etapa de análisis se divide el programa fuente en sus piezas constituyentes y crea una representación intermedia del mismo.

    En la etapa de síntesis se construye el programa destino deseado a partir de una descripción en un lenguaje de representación intermedia.


    Análisis Léxico.
    El analizador léxico o scanner, transforma el texto fuente en una secuencia ordenada de elementos léxicamente válidos (tokens).






    Funciones del Análisis Léxico.

    El analizador léxico debe reconocer y presentar los caracteres Tokens en una representación más útil para el analizador sintáctico.

    Además de:
    • Eliminar espacios.
    • Ignorar comentarios.
    • Tratar con la tabla de símbolos.
    • Reconocer identificadores y palabra reservada.
    • Manejar el fichero fuente.
    • Contabilizar posición de tokens.
    • Procesar macros, constantes, includes..
    • Generar tokens bajo demanda del analizador sintáctico.
    • Estructurar la colección de tokens.
    • Identificar la colección de tokens.
    • Describir el lenguaje como expresiones regulares.
    • Especificar un diagrama de transición.
    • Traducir el diagrama a una tabla de transición.
    Analizador Sintáctico.

    El analizador sintáctico o parser recibe los tokens y comprueba su ordenación correcta. Genera un árbol sintáctico.


    Tipos de Analizadores Sintácticos.


    Análisis Semántico
    • El analizador semántico comprueba que el árbol sintáctico es semánticamente válido.
    • Revisa el programa fuente para comprobar que las reglas semánticas se cumplen.
    • Genera un árbol semántico o etiquetado.

    Generación de código intermedio.
    • Después de los análisis sintácticos y semánticos, algunos compiladores generan una representación intermedia explicita del programa fuente.
    • Se puede considerar esta representación intermedia como un programa para una maquina abstracta.
    • Esta representación intermedia debe tener dos propiedades importantes, debe ser fácil de producir y fácil de traducir al programa objeto.
    Optimización de código.
    • La fase de optimización de código trata de mejorar el código intermedio, de modo que resulte un código de Maquina más rápido de ejecutar.
    • Hay mucha variación en la cantidad de optimización de código que ejecutan los distintos compiladores, una parte significativa del tiempo del compilador se ocupa en esta fase. 
    • La fase Final de un compilador es la generación de código objeto, que por lo general consiste en código máquina relocalizable código ensamblador.
    • Las posiciones de memoria se seleccionan para cada una de las variables usadas por el programa.
    • Después cada una de las instrucciones intermedias se traduce a una secuencia de instrucciones de máquina que ejecutan la misma tarea.