miércoles, 13 de mayo de 2009

GENERACION DE CODIGO INTERMEDIO

El generador de código toma como entrada una representación intermedia del programa fuente y produce como salida un programa objeto equivalente; Es posible producir o no una fase de optimización antes de la generación de código. Dicha fase intente transformar el código intermedio en una forma de la que se pueda producir código objeto más eficiente.
El código intermedio es un código abstracto independiente de la máquina para la que se generará el código objeto. El código intermedio ha de cumplir dos requisitos importantes: ser fácil de producir a partir del análisis sintáctico, y ser fácil de traducir al lenguaje objeto. Esta fase puede no existir si se genera directamente código máquina, pero suele ser conveniente emplearla.

Ejemplo:

Consideremos, por ejemplo, un código intermedio de tercetos, llamado así porque en cada una de sus instrucciones aparecen como máximo tres operandos. La sentencia traducida a este código intermedio quedaría2:
temp1 := inttoreal (2)temp2 := id3 * temp1temp3 := id2 + temp2id1 := temp3


El analizador sintáctico va generando acciones que valida el analizador semántico y que se convierten en tercetos. Esta conversión en tercetos constituye el generador de código intermedio.
Dado que el lenguaje puede presentar distintas funciones anidadas, los tercetos los generamos por orden del parser y son almacenados en un sitio u otro dependiendo del contexto en que nos encontremos. Es decir, se almacenan en una lista de tercetos dependiente de la Tabla de Símbolos. Hay tantas listas de tercetos como funciones haya en el código fuente más una lista de tercetos asociada a la Tabla de Símbolos Global
No obstante una vez finalizado el análisis, todos estos tercetos repartidos en distintas listas se vuelcan a una sola lista de tercetos global. Esta será la que finalmente se optimice y a partir de la que se generará el programa en ensamblador.
El problema de tener que manejar tercetos indirectos fue resuelto modificando el método de inserción sobre la lista de tercetos utilizada en cada momento, de manera que se realiza previamente una búsqueda de algún terceto que sea exactamente igual al que estamos insertando. En caso afirmativo, insertamos en la lista no un terceto nuevo, sino un puntero al ya existente, y marcamos dicho terceto como terceto indirecto. Son tercetos indirectos aquellos marcados con un asterisco después del índice en los volcados de la lista de tercetos.

Ventajas:

• Permite abstraer la máquina, separar operaciones de alto nivel de su implementación a bajo nivel.
• Permite la reutilización de los front-ends y back-ends.
• Permite optimizaciones generales
• El código objeto es abstraído para una maquina virtual. esta abstracción ayuda a separar operaciones de alto nivel y realizar dependientes de la maquina.
• La generación de código y el asignamiento de registros temporales son separados de las rutinas semánticas, los cuales solo trabajan con la abstracción presentada por la representación intermedia. las dependencias del código objeto son aisladas de las rutinas de generación de código.
• La abstracción puede ser hecha en el nivel de representación intermedia. esta organización ayuda a hacer una optimización completamente independiente del código objeto, con lo que hace que las rutinas de optimización complejas sean más transportables. debido a que las representaciones intermedias son por diseño mas abstracta y uniforme, las rutinas de optimización puede ser más simples.

Desventajas:

• Implica una pasada más para el compilador (no se puede utilizar el modelo de una pasada, conceptualmente simple).
• Dificulta llevar a cabo optimizaciones específicas de la arquitectura destino.
• Suele ser ortogonal a la máquina destino, la traducción a una arquitectura específica será más larga e ineficiente


Formas de Representación Intermedia

En la historia de los compiladores han sido utilizadas una amplia variedad de representaciones intermedias sin embargo la forma más simple es la notación posfija, la cual también es conocida en matemáticas como notación libre de paréntesis para expresiones aritméticas que han sido utilizadas mucho tiempo antes que los compiladores. Como su nombre lo implica la notación posfija es una representación en la cual los operadores aparecen después que los operandos para los cuales se aplican.
Una de las atracciones principales de la notación posfija es la simplicidad en la traducción de los procesos, y la consistencia de la representación. Estos factores hacen de esta notación la más usual como una representación intermedia para el manejo de intérpretes. de hecho la notación posfija no es muy efectiva como entrada para un optimizador a un generador de código, a menos que el código objeto a generar tenga una arquitectura en forma de pila.

La siguiente clase de representación de código intermedio se refiere a un árbol de 3 direcciones, 2 para los operandos y una para la ubicación del resultado. Esta clase incluye un amplio número de representaciones diferentes entre las cuales encontramos cuádruplos y triples. la principal diferencia entre estas notaciones y la notación posfija es que ellos incluyen referencias explicitas para los resultados de los cálculos intermedios. Mientras que la notación posfija los resultados son implícitos al representarlos en una pila.
La diferencia entre triples y cuádruplos es que con los triples es referenciado el valor intermedio hacia el número del triple que lo creo, pero en los cuádruplos requiere que ellos tengan nombre implícitos.
Los triples tienen una ventaja obvia de ser más consistente, pero ellos dependen de su posición, y hacen que la optimización presente cambios de código mucho más compleja.

Aspectos de Diseño de un Generador de Código

Entrada al generador de código

La entrada para la generación de código consta de una representación intermedia del programa fuente, junto con la información de la tabla de símbolos que se utiliza para determinar las direcciones durante la ejecución de los datos denotados por los nombres de la representación intermedia. El código se puede generar desde el punto de vista del código de 3 direcciones, notación posfija, cuádruplos, triples, etc.
Se asume que antes de la generación de código la etapa inicial a hecho los análisis léxico, semántico, sintáctico y se ha traducido el programa fuente a una representación intermedia razonablemente detallada, así que los valores de los nombres que aparecen en el lenguaje intermedio pueden ser representados por cantidades que la maquina objeto puede manipular directamente. Por lo tanto, la fase de generación de código puede proseguir con la hipótesis de que su entrada no contiene errores.
Programas objeto: La salida del generador de código es el programa objeto. Al igual que el código intermedio esta salida puede adoptar una variedad de formas: Lenguajes de maquina absoluto, lenguaje de maquina relocalizable o lenguaje ensamblador

Lenguaje Máquina Absoluto


Para producir como salida un programa en lenguaje absoluto tiene la ventaja de que se puede colocar en una posición fija de memoria y ejecutarse inmediatamente. Un programa pequeño se puede compilar y ejecuta.

Lenguaje Máquina Relocalizable


Producir como salida un lenguaje maquina relocalizable (modulo objeto) permiten que los programas se compilen por separado .Un conjunto de módulos objeto relocalizables se pueden enlazar. Aunque se tenga que pagar costo de enlazar y cargar si se producen módulos objetos relocalizables, se gana mucha flexibilidad al poder compilar subrutinas por separado y llamar desde el modulo objeto a otros programas previamente compilados.

Lenguaje Ensamblador


Producir Como la salida un programa en lenguaje ensamblador facilita la generación de código. Se pueden generar instrucciones simbólicas y utilizar las macros del ensamblador para ayudar a generar el código, el precio que se paga es el paso de ensamble después de la generación de código.
Como producir código ensamblador no duplica la tarea completa del compilador esta elección es otra alternativa razonable, especialmente para una maquina con memoria pequeña, donde un compilador debe utilizar varias pasadas.

No hay comentarios:

Publicar un comentario