Compiladores. Guía 8 1
Tema: Análisis de código intermedio
En esta guía se abordarán los conceptos pertenecientes al componente de análisis de código intermedio, se analizaran los bloques de básicos de código a partir de un código en cualquier lenguaje previamente indicado.
Además se analizara el uso de la notación polaca inversa y el uso de direcciones en ellas.
Conocer las características y principal función de un bloque básico de código.
Analizar e interpretar como un compilador ordena los bloques de código para posterior ejecución.
Aprender a usar la notación polaca inversa para aplicar su uso en la asignación de memoria para variables.
Guía de Laboratorio Nº 8.
Computadora con programa “Dev C++”.
Generación de código intermedio Representación de bloques básicos
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
Introducción Teórica Guía 3
Guía 4
fía
Facultad: Ingeniería Escuela: Computación Asignatura: Compiladores
Contenido
Objetivos Específicos
Material y Equipo
2
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:
1. La primera instrucción de código máquina.
2. Cualquier instrucción situada en la dirección a la que se refiere una instrucción de salto condicional o incondicional.
3. 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:
1. Si el bloque básico termina en un salto incondicional, entonces incluir un arco hasta la dirección señalada
2. 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.
Una instrucción de tres direcciones del tipo x:= y + z, se dice que define a x y que hace referencia a y (y también a z).
Una variable se dice que está activa en un determinado punto de la secuencia de instrucciones de tres direcciones si después de haber sido definida se hace referencia a ella en cualquier otro punto del programa que se ejecute posteriormente, (en el mismo bloque básico o en cualquier otro). Es decir, una variable está activa desde que nace con una definición, hasta que muere con el último uso que de ella hace cualquier instrucción del programa. Por el contrario,
Compiladores. Guía 8 3 una variable esta inactiva, desde la última vez que se usa hasta que se define nuevamente.
El concepto de actividad e inactividad de las variables tiene importancia para la asignación de registros que se efectúa durante la generación de código máquina.
Ejemplo: Considere el siguiente fragmento de código en lenguaje C
while (j < n) {
k = k + j * 2;
m = j * 2;
j++;
}
Este ciclo se traduce en la representación en proposiciones de tres direcciones que se muestra a continuación:
(101) t1 := j (102) t2 := n
(103) t3 := t1 < t2 (104) if(t3) goto (105) (105) t4 := k
(106) t5 := j
(107) t6 := t5 * 2 (108) t7 := t4 + t6 (109) k := t7
(110) t8 := j
(111) t9 := t8 * 2 (112) m := t9
(113) t10 := j
(114) t11 := t10 + 1 (115) j := t11
(116) goto (101)
En la figura 1, podremos observar el diagrama de bloques básicos correspondiente a este programa.
NOTACIÓN POLACA / NOTACIÓN POLACA INVERSA
Notación prefija (polaca): Se escribe primero el nombre de la función seguida de los operando de izquierda a derecha. Si un operando es a su vez operación con operando, se aplican las mismas reglas. Por ejemplo:
( a + b ) * ( c – a ) == + a b – c a
No hay ambigüedad alguna ni se necesitan paréntesis para saber cómo evaluar la expresión. Debido a que el matemático
4
polaco Lucasiewicz inventó la notación libre de paréntesis, se ha aplicado el término de polaca a esta notación y sus derivados.
Figura 1: Diagrama de bloques básicos
Notación postfija (o polaca inversa): Es similar a la notación postfija, excepto que el símbolo de operación sigue a la lista de operando. Por ejemplo:
a b + c a - *
Notación infija: Es la más adecuada para operaciones binarias. El operador se escribe entre los operando. Por su uso natural, ha sido adoptada por muchos lenguajes para operaciones aritméticas y lógicas. Cuando la operación no es binaria, se usa de manera algo torpe empleando varios delimitadores; por ejemplo el comando condicional en C:
(?S1:S2) Tripletes
No se pone el resultado, se sustituye por referencias a tripletes. Por ejemplo: la expresión a * b + c * d equivale a:
Compiladores. Guía 8 5 (1) (*,a,b)
(2) (*,c,d) (3) (+,(1),(2))
Mientras que a * b + 1 equivale a:
(1) (*,a,b) (2) (*,(1),1)
Tripletes indirectos: se numeran arbitrariamente los tripletes y se da el orden de ejecución. Solucionan el problema de la reordenación mediante indirecciones. Ejemplo, sean las instrucciones:
a = b * c b = b * c
Equivalen a los tripletes (1) (*,b,c)
(2) (=,(1),a) (3) (=,(1),b)
Y el orden de ejecución es (1), (2), (1), (3). Esta forma es útil para preparar la optimización de código. Si hay que alterar el orden de las operaciones o eliminar alguna, es más fácil hacerlo ahí.
Considérese el fragmento de código fuente que se muestra a continuación, el cual calcula el producto punto de dos vectores a y b de longitud 20.
begin
prod := 0;
i := 1;
do begin
prod := prod + a[i] * b[i];
i := i + 1;
end
while i <= 20 end
El código de tres direcciones para este algoritmo es:
(1) prod := 0 (2) i := 1 (3) t1 := 4 * i
(4) t2 := a [ t1 ] //calcula a[i]
Procedimiento Guía 3
Guía 4
fía
6
(5) t3 := 4 * i
(6) t4 := b [ t3 ] //calcula b[i]
(7) t5 := t2 * t4
(8) t6 := prod + t5 (9) prod := t6
(10) t7 := i + 1 (11) i := t7
(12) if i <= 20 goto (3)
Dibuje el diagrama de bloques básicos para las proposiciones de tres direcciones según las reglas indicadas en la introducción teórica de esta guía.
Ahora escriba las proposiciones de tres direcciones y dibuje el diagrama de bloques básicos para la generación de código intermedio para las siguientes instrucciones:
int i=0;
int a[10];
while(i<=10) a[i]=0;
Usando los conceptos de notación polaca y tripletas, re- escriba las instrucciones en forma de tripletas.
Fuente:
w*x+(y+z) Operaciones:
1. ___________________________________________________
2. ___________________________________________________
3. ___________________________________________________
Usando los conceptos de notación polaca y tripletas, re- escriba las instrucciones en forma de tripletas indirectas.
Fuente:
A = B + C * D / E F = C * D
Operaciones:
1. ___________________________________________________
2. ___________________________________________________
3. ___________________________________________________
4. ___________________________________________________
5. ___________________________________________________
Compiladores. Guía 8 7
Análisis de resultados
Escriba las proposiciones de tres direcciones y dibuje el diagrama de bloques básicos para la generación de código intermedio para el siguiente pseudocódigo del algoritmo de burbuja:
for (i=1; i<TAM; i++)
for j=0 ; j<TAM - 1; j++) if (lista[j] > lista[j+1]) temp = lista[j]
lista[j] = lista[j+1];
lista[j+1] = temp;
Traduzca las siguientes expresiones aritméticas a notación polaca y re-escriba las expresiones en forma de tripletas.
X = (A * B) + (C – (D + E)) X = A/ (B + C) – D*(E + F)
X = A + (B + (C/D) * E) / (F * G – H * I)
Investigación complementaria
Investigue:
Que es un árbol en CoSeL y para qué sirve.
Que es, a partir de que se realiza y cual es el resultado que se obtiene de la etapa de “Generación de código” de un compilador.
Como se realiza la generación de código utilizando las bibliotecas desarrolladas con lenguajes de alto nivel.
Bibliografía
Ejemplo de bloques básicos de código intermedio:
http://cnx.org/content/m38394/latest/?collection=col1 1356/latest
Estructura de datos, Luís Joyanes Aguilar, McGrawhill
Compiladores- principios, técnicas y herramientas. Aho - Lam – Sethi – Ullman. Editorial Pearson – Addison Wesley Segunda edición
Construcción de compiladores. Kenneth C. Louden.
Editorial Thomson
8
EVALUACION
% 1-4 5-7 8-10 Nota
CONOCIMIENTO Del 20 al 30%
Conocimie nto deficient e de los fundament os
teóricos
Conocimiento y explicación incompleta de los
fundamentos teóricos
Conocimiento completo y explicación clara de los fundamentos teóricos
APLICACIÓN DEL
CONOCIMIENTO
Del 40%
al 60%
ACTITUD
Del 15%
al 30%
No tiene actitud proactiva .
Actitud
propositiva y con
propuestas no aplicables al contenido de la guía.
Tiene actitud proactiva y sus propuestas son concretas.
TOTAL 100%
Máquina No:
Máquina No:
Alumno:
Alumno:
Docente:
Docente:
GL:
GL:
Fecha:
Guía 8: Análisis de código intermedio
Tema: Presentación del programa
Hoja de cotejo:
Docente:
Máquina No:
GL:
a