Вы находитесь на странице: 1из 5

GENERACIÓN DE CÓDIGO INTERMEDIO

1.-INTRODUCCION

Esta fase del compilador no es en realidad una parte separada del compilador, la mayoría
de los compiladores generan código como parte del proceso de análisis sintáctico, esto es
debido a que requieren del árbol de sintaxis y si este no va a ser construido físicamente,
entonces deberá acompañar al analizador sintáctico al barrer el árbol implícito.
En lugar de generar código ensamblador directamente, los compiladores generan un código
intermedio que es más parecido al código ensamblador.

Los compiladores generan un código intermedio que es más parecido al código


ensamblador, las operaciones por ejemplo nunca se hacen con más de dos operandos.
Al no generarse código ensamblador el cual es dependiente de la computadora
específica, sino código intermedio, se puede reutilizar la parte del compilador que genera
código intermedio en otro compilador para una computadora con diferente procesador
cambiando solamente el generador de código ensamblador al cual llamamos back-end, la
desventaja obviamente es la lentitud que esto
conlleva.
La tarea de síntesis suele comenzar generando un código intermedio.
El código intermedio no es el lenguaje de programación de ninguna máquina real, sino que
corresponde a una máquina abstracta, que se debe de definir lo más general posible, de
forma que sea posible traducir este código intermedio a cualquier máquina real.

2.-OBJETIVOS

El objetivo del código intermedio es reducir el número de programas necesarios para


construir traductores, y permitir más fácilmente la transportabilidad de unas
máquinas a otras.
Los árboles sintácticos y la notación postfija son dos clases de representaciones
intermedias.
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.
Entonces:

 Los lenguajes intermedios nos sirven para representar la producción final de


nuestro
lenguaje fuente.
 Existen muchos lenguajes intermedios, la mayoría de ellos son una representación
más simplificada del código original para facilitar la traducción hacia el código
final.
 Otros lenguajes intermedios sirven de base o como representación parcial de otros
procesos.

3.- Tipos de presentación de códigos intermedios


Existen muchas formas de código intermedio, de hecho, el diseñador del compilador puede
definir la máquina abstracta que considere más adecuada al lenguaje fuente o a la clase de
máquinas a las que va destinado. Las representaciones que más se emplean son:
 Árboles semánticos y grafos acíclicos dirigidos: Una forma de representar el código
generado por un compilador es mediante una estructura de tipos arborescente, a la
que se denomina árbol semántico a fin de diferenciarlo del árbol sintáctico o árbol
del análisis sintáctico que representa la estructura gramatical.

Así, por ejemplo, para la representación de la sentencia: a:=b*-c+b*-c, se tiene:


En el árbol semántico los nodos son ocupados por operadores y sus operandos se obtienen
evaluando las operaciones de sus nodos descendientes.

Pueden usarse grafos acíclicos dirigidos (DAG) para obtener una representación
condensada de los árboles semánticos. Cuando se encuentran subestructuras idénticas
dentro de un mismo árbol basta usar múltiples referencias a la misma subestructura, sin
necesidad de duplicar la subestructura repetida. Esta representación consigue por sí misma
una mejora considerable en el tamaño y la eficiencia del código generado.

 Códigos de tres direcciones: La representación mediante código de tres direcciones


se basa en un conjunto de instrucciones capaces de manejar un máximo de tres
direcciones de memoria. En general dos de estas direcciones corresponden a los
argumentos y la tercera al resultado. Una instrucción de tres direcciones por
ejemplo puede consistir en sumar el contenido de dos direcciones y situar el
resultado en una tercera dirección, o saltar a una determinada dirección si el valor
contenido en una dirección es mayor que el contenido en otra, etc.

El código de tres direcciones se basa en 2 conceptos principalmente en 2


conceptos: direcciones e instrucciones.

 Tripletas: Para evitar tener que introducir nombres temporales en la tabla de


símbolos, se hace referencia a un valor temporal según la posición de la proposición
que lo calcula. Las propias instrucciones representan el valor del nombre temporal.
La implementación se hace mediante registros de solo tres campos (op, arg1, arg2).
En la notación de tripletes se necesita menor espacio y el compilador no necesita
generar los nombres temporales. Sin embargo, en esta notación, trasladar una
proposición que defina un valor temporal exige que se modifiquen todas las
referencias a esa proposición. Lo cual supone un inconveniente a la hora de
optimizar el código, pues a menudo es necesario cambiar proposiciones de lugar.
Una forma de solucionar esto, consiste en listar las posiciones a las tripletas en lugar
de listar las tripletas mismas. De esta manera, un optimizador podría mover una
instrucción reordenando la lista, sin tener que mover las tripletas en sí.
 Cuádruplas: Una cuádrupla es una estructura tipo registro con cuatro campos que se llaman
(op, result, arg1, arg2). El campo op contiene un código interno para el operador.
Por ejemplo, la proposición de tres direcciones x = y + z se podría representar mediante la
cuádrupla (ADD, x,y, z). Las proposiciones con operadores unarios no usan el arg2. Los
campos que no se usan se dejan vacíos o un valor NULL. Como se necesitan cuatro campos
se le llama representación mediante cuádruplas.

4. BLOQUES BÁSICOS Y DIAGRAMAS DE FLUJO

Los bloques básicos son trozos de código intermedio en los que el flujo de control es lineal, es
decir, trozos de código cuyas instrucciones se ejecutan una detrás de otra sin saltos intermedios.
Los bloques básicos tienen por tanto una única instrucción de comienzo de bloque y una única
instrucción de salida del bloque. Por ejemplo, la siguiente secuencia de instrucciones de tres
direcciones forma un bloque básico.

(100) t1:=-c

(101) t2:=b*t1

(102) t3:=-c

(103) t4:=b*t3

(104) t5:=t2*t4

(105) a:=t5

(106) if (a>0) goto (712)

Para identificar los bloques básicos que componen una secuencia de instrucciones en código
máquina puede seguirse el siguiente algoritmo:
1. Buscar los puntos de entrada, que corresponden a:

 La primera instrucción de código máquina.


 Cualquier instrucción situada en la dirección a la que se refiere una instrucción de salto
condicional o incondicional.
 Cualquier instrucción consecutiva a una instrucción de salto condicional o incondicional.

2. Para cada punto de entrada construir un bloque básico que vaya desde el punto de entrada
hasta el siguiente punto de entrada.
3. Los arcos del diagrama de flujo se obtienen mediante las reglas:
 Si el bloque básico termina en un salto incondicional, entonces incluir un arco hasta la
dirección señalada.
 Si el bloque básico termina en un salto condicional, entonces incluir un arco hasta la
dirección señalada y otro al siguiente bloque básico.

Вам также может понравиться