Sie sind auf Seite 1von 46

TEMA 7

GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

Bibliografa:

Aho, A.V., Sethi, R., Ullman, J.D. (1990), Compiladores: principios, t cnicas y herramientas, Tema 8, 9, 10 (pag. 478-666). e Louden, K.C. (1997), Compiler Construction: Principles and Practice, Tema 8, p ginas: 398-481. a

1 Introducci n. o 2 Tipos de representaciones intermedias: C digo de 3-direcciones. o 3 C digo intermedio como un atributo sintetizado. o 4 Generaci n de c digo para expresiones y sentencias de control: o o 4.1 Proposiciones de asignaci n. o 4.2 Expresiones aritm ticas. e 4.3 Expresiones booleanas. 4.4 Sentencias de control. 5 Optimizaci n de c digo: o o 5.1 Bloques b sicos y optimizaci n local. a o 5.2 Eliminaci n de subexpresiones comunes. o 5.3 Eliminaci n de c digo muerto. o o

206

7.1. INTRODUCCION

5.4 Transformaciones aritm ticas. e 5.5 Empaquetamiento de variables temporales. 5.6 Mejoras en lazos.

7.1

INTRODUCCION

Como se coment en el primer captulo el proceso de la compilaci n se o o desglosa en dos partes: la parte que depende s lo del lenguaje fuente (etapa o inicial o front-end ) y la parte que depende s lo del lenguaje objeto (etapa o nal o back-end).

Etapa inicial: corresponde con la parte de an lisis (l xico, sint ctico a e a y sem ntico). a Etapa nal: corresponde con la parte de sntesis (generaci n de c digo). o o

La etapa inicial traduce un programa fuente a una representaci n intermeo dia a partir de la cual la etapa nal genera el c digo objeto. o De esta forma, los detalles que tienen que ver con las caractersticas del lenguaje objeto (c digo ensamblador, c digo m quina absoluto o relocalo o a izable, . . . ), la arquitectura de la m quina (n mero de registros, modos de a u direccionamiento, tama o de los tipos de datos, memoria cache, ...), el enn torno de ejecuci n (estructura de registros y memoria de la m quina donde o a se va a ejecutar el programa . . . ) y el sistema operativo se engloban en la etapa nal y se aislan del resto. La generaci n de c digo es la tarea m s complicada de un compilador. o o a Las ventajas de utilizar esta representaci n intermedia, independiente de o la m quina en la que se va a ejecutar el programa, son: a Se puede crear un compilador para una nueva m quina distinta uniena do la etapa nal de la nueva m quina a una etapa inicial ya existente. a Se facilita la redestinaci n. o

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

207

La gura 7.1 muestra las dos etapas y como se relacionan entre s a trav s e de la representaci n intermedia. o
Programa fuente ETAPA INICIAL ETAPA FINAL Analizador Lxico Componentes lxicos Analizador Sintctico Arbol Sintctico Analizador Semntico Cdigo Intermedio Optimizador de Cdigo mquina Generador de cdigo mquina

En este captulo veremos c mo traducir las construcciones de los lenguajes o de programaci n como: las declaraciones, asignaciones y proposiciones o de ujo de control a una representaci n intermedia. La mayor parte de las o traducciones de estas proposiciones se pueden implantar durante el an lisis a sint ctico utilizando las t cnicas de traducci n vistas en en el dise o de a e o n esquemas de traducci n dirigidos por la sintaxis (ETDS). o

Se puede aplicar, a la representaci n intermedia, un optimador de o c digo independiente de la m quina. o a

Cdigo mquina

Optimizador de cdigo intermedio

Figura 7.1: Etapa inicial y nal de un compilador

208

7.2. TIPOS DE REPRESENTACIONES INTERMEDIAS: EL CODIGO DE 3-DIRECCIONES

7.2

TIPOS DE REPRESENTACIONES INTERMEDIAS: EL CODIGO DE 3-DIRECCIONES

Una representaci n intermedia es una estructura de datos que representa al o programa fuente durante el proceso de la traducci n a c digo objeto. Haso o ta ahora hemos usado el arbol de an lisis sint ctico como representaci n a a o intermedia, junto con la tabla de smbolos que contena informaci n sobre o los nombres (variables, constantes, tipos y funciones) que aparecan en el programa fuente. Aunque el arbol de an lisis sint ctico es una representaci n v lida, no se a a o a parece ni remotamente al c digo objeto, en el que s lo se emplean saltos o o a direcciones en memoria en vez de construcciones de alto nivel, como sentencias if-then-else. Es necesario generar una nueva forma de representaci n intermedia. A esta representaci n intermedia, que se parece o o al c digo objeto pero que sigue siendo independiente de la m quina, se le o a llama c digo intermedio. o El c digo intermedio puede tomar muchas formas. Todas ellas se consido a eran como una forma de linearizaci n del arbol sint ctico, es decir, una o representaci n del arbol sint ctico de forma secuencial. El c digo intero a o medio m s habitual es el c digo de 3-direcciones. a o El c digo de tres direcciones es una secuencia de proposiciones de la o forma general x = y op z donde op representa cualquier operador; x,y,z representan variables denidas por el programador o variables temporales generadas por el compilador. y,z tambi n pueden representar constantes o literales. op repree senta cualquier operador: un operador aritm tico de punto jo o otante, o e un operador l gico sobre datos booleanos. o

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

209

No se permite ninguna expresi n aritm tica compuesta, pues s lo hay un o e o operador en el lado derecho. Por ejemplo, x+y*z se debe traducir a una secuencia, donde son variables temporales generadas por el compilador.
   

Las expresiones compuestas y las proposiciones de ujo de control se han de descomponer en proposiciones de este tipo, deniendo un conjunto sucientemente amplio de operadores. Se le llama c digo de 3-direcciones o porque cada proposici n contiene, en el caso general, tres direcciones, dos o para los operandos y una para el resultado. (Aunque aparece el nombre de la variable, realmente corresponde al puntero a la entrada de la tabla de smbolos de dicho nombre). El c digo de tres direcciones es una representaci n linealizada (de izquiero o da a derecha) del arbol sint ctico en la que los nombres temporales correa sponden a los nodos internos. Como estos nombres temporales se representan en la memoria no se especica m s informaci n sobre ellos en este a o tipo de c digo. Normalmente se asignar n directamente a registros o se o a almacenar n en la tabla de smbolos. a 2*a+b-3

Cdigo de 3-direcciones: o

= 2 * a = b - 3 = +

% &"

!   #" # $" % &" ' &"

+
t1

t3

* 2 a b

t2

210

7.2. TIPOS DE REPRESENTACIONES INTERMEDIAS: EL CODIGO DE 3-DIRECCIONES

7.2.1

Tipos de proposiciones de 3-direcciones

La forma de c digo de 3-direcciones que hemos visto hasta ahora es insuo ciente para representar todas las construcciones de un lenguaje de programaci n (saltos condicionales, saltos incondicionales, llamadas a funciones, o bucles, etc), por tanto es necesario introducir nuevos operadores. El conjunto de proposiciones (operadores) debe ser lo sucientemente rico como para poder implantar las operaciones del lenguaje fuente. Las proposiciones de 3-direcciones van a ser en cierta manera an logas al a c digo ensamblador. Las proposiciones pueden tener etiquetas simb licas o o y existen instrucciones para el ujo de control (goto). Una etiqueta simb lica o representa el ndice de una proposici n de 3-direcciones en la lista de in o strucciones. Las proposiciones de 3-direcciones m s comunes que utilizaremos: a 1 Proposiciones de la forma x = y op z donde op es un operador binario aritm tico, l gico o relacional. e o 2 Instrucciones de la forma x = op y, donde op es un operador unario (operador negaci n l gico, menos unario, operadores de desplazao o miento o conversi n de tipos). o 3 Proposiciones de copia de la forma x = y, donde el valor de y se asigna a x. 4 Salto incondicional goto etiq. La instrucci n con etiqueta etiq o es la siguiente que se ejecutar . a 5 Saltos condicionales como if false x goto etiq. 6 param x y call f para apilar los par metros y llamadas a funa ciones (los procedimientos se consideran funciones que no devuelven valores). Tambi n return y, que es opcional, para devolver vale ores. C digo generado como parte de una llamada al procedimiento o p(x 1,x 2,...,x n).

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

211

param param ... param call p,n 7 Asignaciones con ndices de la forma x = y[i], donde se asigna a x el valor de la posici n en i unidades de memoria m s all de la o a a posici n y. O tambi n x[i] = y . o e 8 Asignaciones de direcciones a punteros de la forma x = &y (el valor de es la direcci n de ), x = *y (el valor de se iguala al cono tenido de la direcci n indicada por el puntero ) o *x = y (el objeto o apuntado por se iguala al valor de ). Ejemplo. Consideremos el c digo que calcula el factorial de un n mero. o u La tabla 7.1 muestra el c digo fuente y el c digo de 3-direcciones. Existe o o un salto condicional if false que se usa para traducir las sentencias de control if-then, repeat-until que contiene dos direcciones: el valor condicional de la expresi n y la direcci n de salto. La proposici n o o o label s lo tiene una direcci n. Las operaciones de lectura y escrituo o ra, read, write, con una sola direcci n. Y una instrucci n de parada o o halt que no tiene direcciones.
       ) 0

(

212

7.2. TIPOS DE REPRESENTACIONES INTERMEDIAS: EL CODIGO DE 3-DIRECCIONES

Tabla 7.1: C digo fuente y c digo de 3-direcciones para el c lculo del factorial o o a

7.2.2

Implementaci n de c digo de tres direcciones o o

Una proposici n de c digo de 3-direcciones se puede implantar como una o o estructura tipo registro con campos para el operador, los operandos y el resultado. La representaci n nal ser entonces una lista enlazada o un o a vector de proposiciones. Implementaci n mediante cu druplos o a

Un cu druplo es una estructura tipo registro con cuatro campos que se llaa man (op, result, arg1, arg2). El campo op contiene un c digo o interno para el operador. Por ejemplo, la proposici n de tres direcciones x = y + z se representa o mediante el cu druplo (ADD, x,y, z). Las proposiciones con operadores a . Los campos que no se usan se dejan vacos o un unarios no usan el valor NULL. Como se necesitan cuatro campos se le llama representaci n o mediante cu druplos. a
7 5 3 8642

read x; if 0 x then fact:=1; repeat fact:=fact*x; x:=x-1; until x=0; write fact; end;
1

read x t1 = 0 x if false t1 goto L1 fact=1 label L2 t2=fact * x fact=t2 t3=x-1 x=t3 t4=x==0 if false t4 goto L2 write fact label L1 halt

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

213

Una posible implantaci n del programa que calcula el factorial mediante o cu druplos se muestra ahora en la parte izquierda de la tabla 7.2. a
(a) Cu druplos a (read,x,,) (isbigger,t1,x,0) (if false,t1,L1,) (assign,fact,1,) (label,L2,,) (mult,t2,fact,x) (assign,fact,t2,) (sub,t3,x,1) (assign,x,t3,) (isequal,t4,x,0) (if false,t4,L2,) (write,fact,,) (label,L1,,) (halt,,,) (b) Tripletes (0) (read,x,) (1) (isbigger,x,0) (2) (if false, (1), (11)) (3) (assign, fact,1) (4) (mult, fact,x) (5) (assign, (4), fact) (6) (sub, x,1) (7) (assign, (6), x) (8) (isequal, x, 0) (9) (if false, (8),(4)) (10) (write,fact,) (11) (halt,,)

Tabla 7.2: C digo de 3-direcciones mediante: (a) cu druplos y (b) tripletes o a

214

7.2. TIPOS DE REPRESENTACIONES INTERMEDIAS: EL CODIGO DE 3-DIRECCIONES

Implementaci n mediante tripletes o Para evitar tener que introducir nombres temporales en la tabla de smbolos, se hace referencia a un valor temporal seg n la posici n de la proposici n u o o que lo calcula. Las propias instrucciones representan el valor del nombre temporal. La implantaci n se hace mediante registros de s lo tres campos o o (op, arg1, arg2). La parte derecha de la tabla 7.2 muestra la implantaci n mediante tripletes o del c lculo del factorial. Los n meros entre par ntesis representan puna u e teros dentro de la lista de tripletes, en tanto que los punteros a la tabla de smbolos se representan mediante los nombres mismos. En la notaci n de tripletes se necesita menor espacio y el compilador no o necesita generar los nombre temporales. Sin embargo, en esta notaci n, o trasladar una proposici n que dena un valor temporal exige que se modo iquen todas las referencias a esa proposici n. Lo cual supone un incono veniente a la hora de optimizar el c digo, pues a menudo es necesario o cambiar proposiciones de lugar. A partir de ahora nos vamos a centrar en la notaci n de cu druplos, que es o a la que se implantar en la pr ctica 3. La gura 7.2 a continuaci n muesa a o tra en c digo C como se podra implantar la estructura de datos para los o cu druplos: a
typedef enum assign, add, mult,if false, goto, label, read, write, isequal, . . . OpKind; typedef struct int val;// para valores char *name;// para identicadores de variables Address; typedef struct OpKind op; Address result, arg1, arg2; Quad;
@ 9 9 9 @ @

Figura 7.2: Posible implantaci n en C de la estructura cu druplo o a

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

215

Por simplicidad se podrian considerar los campos result, arg1, arg2 como punteros a caracter. En esta implantaci n s lo se permite que un aro o gumento represente una constante entera o una cadena ( la cadena representa el nombre de un temporal o una variable de la tabla de smbolos). Una alternativa a almacenar nombres en el cu druplo es almacenar punteros a a la tabla de smbolos, con lo que se evita tener que hacer operaciones de b squeda en un procesado posterior. u

7.3

CODIGO INTERMEDIO COMO UN ATRIBUTO SINTETIZADO

El c digo intermedio puede ser considerado como un atributo sintetizao do. El c digo intermedio es visto como una cadena de caracteres y se o puede dise ar un esquema de traducci n dirigido por la sintaxis (ETDS) n o que genere dicho c digo al recorrer el arbol de an lisis sint ctico en orden o a a postjo. Consideremos como ejemplo la siguiente gram tica simplicada que gena se calcula el era expresiones aritm ticas. Dada la expresi n e o valor del no-terminal en un nombre temporal . Por el momento, se crea un nuevo nombre cada vez que se necesita. M s tarde veremos un sencillo a m todo para reutilizar los nombres temporales. e Cada no-terminal tiene dos atributos:
A A C A B A A

E.lugar, nombre temporal que contendr el valor de a

,(

E.cod, serie de todas las proposiciones de c digo de 3-direcciones o que calculan .


A

Ambos atributos son sintetizados. La funci n nuevotemp() genera nomo bres distintos , , ... cada vez que es llamada. Las llaves indican


E E E GGFD

).

216

7.3. CODIGO INTERMEDIO COMO UN ATRIBUTO SINTETIZADO

una instrucci n de c digo de 3-direcciones. El smbolo // representa la o o concatenaci n de los trozos de c digo. o o
Producci n o
V V
+ 4

Regla Sem ntica a


@ w DG6q X V T Q iRP hpidcaipigaghegaV h Q b `X V h h Q b `X V T Q b `X y e v fr u r w G6q g g db T X V y w v r t rq uxusd9 h h Q b `X V T Q b `X pigUfWedcaYH
cod=t1=x+3 t2=t1+4 x=t2

Tabla 7.3: ETDS para expresiones aritm ticas e

Veamos el ejemplo x=x+3+4. La gura 7.3 muestra el arbol sint ctico. a El c digo de 3-direcciones correspondiente es: o
#"
= x + 3 =

x =

S
cod=t1=x+3 E lugar=t2 t2=t1+4

id (x)

cod=t1=x+3 E lugar=t1

cod= E lugar=4

cod=

E lugar=x + id (x)

cod= E lugar=3 num

(4) num (3)

Figura 7.3: Arbol sint ctico para el ejemplo x=x+3+4 a

@ w DFkq

X V ij

w F6q

X V gWT

w DF6q

X fV 9

g g

v k uxusq y w v r t r

Q iRP

w G6q

y w v r t r uxusq

QbgaXghVegaV ` T Q b `X w G6q X V

X V mhT

oopegaV T Q b `X w G6q X V

oopegaV T Q b `X w G6q X V

V TS Q WURP lhV v u Q nP y

I V I V I V I V #" % &" % &"

I H

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

217

Reutilizaci n de los nombres temporales o Hasta ahora se ha supuesto que la funci n nuevotemp() genera un nomo bre temporal cada vez que se necesita un temporal . Sin embargo, los nombres temporales utilizados para guardar valores intermedios de los c lculos a de expresiones tienen que ser introducidos en la tabla de smbolos para guardar sus valores con el consiguiente aumento de espacio. Los nombres temporales se pueden reutilizar mediante un sencillo m todo e que consiste en llevar una cuenta , iniciada a cero, de variables temporales. Cuando se utilice un nombre temporal como operando hay que decrementar el valor de en . Siempre que se genere un nuevo nombre temporal se usa el valor del contador (sprintf(simbolo,t%d,c)) y se incrementa el valor de en . Consideremos el ejemplo:
Proposici n o t0 = a * b t1 = c * d t0 = t0 + t1 t1 = e * f t0 = t0 - t1 x = t0
= id (x) * a b c + * d e * f

Valor de c 0 1 2 1 2 1 0

Figura 7.4: Arbol sint ctico para el ejemplo x=a*b+c*d-e*f a

z  x w u y(v

t4 s

218

7.4. TRADUCCION DE PROPOSICIONES DE ASIGNACION Y EXPRESIONES ARITMETICAS

7.4

TRADUCCION DE PROPOSICIONES DE ASIGNACION Y EX PRESIONES ARITMETICAS

La tabla 7.4 a continuaci n muestra como se puede realizar la traducci n o o de expresiones aritm ticas m s complejas. La funci n e a o gen cuad(op, result, arg1, arg2) genera el correspondiente c digo de 3-direcciones en notaci n de cu druplos. o o a Cada vez que es llamada genera una lista de c digo con s lo un cu druplo. o o a
Producci n o
V V V V V h V y V TS Q U|nP I V I V I V I V I {H

Reglas Sem nticas a


w F6&q w DF6q X V i X V  w G6q w F6&q w G6q X V  w Fkq X V  X QP  H 6Ri8H Q Q w u w u i ` ` ~ sy r F r F hphidcaipidcamWdcaV Q b `X V h h Q b `X V T Q b `X y e v fr u r w F6&q b T X V w u r F ` h h Q b `X V T Q b `X pigaW}gUYH hphiQdcaipidcamWdcaV b `X V h h Q b `X V T Q b `X y e v fr u r w F6&q b T X V Q inP y w v r t r uxu&q oodcaV T Q b `X w F6&q X V T Q

Tabla 7.4: ETDS para expresiones aritm ticas e

En la pr ctica las proposiciones de 3-direcciones se pueden escribir de a forma consecutiva a un archivo de salida en lugar de construir la lista de proposiciones en el atributo cod, lo que facilita la implementaci n. o Veamos ahora como se puede implantar una funci n recursiva que genera o el c digo de 3-direcciones, que llamaremos genera cdigo(). Al n o o y al cabo se trata de un atributo sintetizado y podemos recorrer el arbol en modo postjo. Supongamos que la funci n devuelve un registro llamado o TAC (Three-Address-Code), que contiene dos campos: lugar (nombre temporal donde se almacena el valor de una expre-

X V gh

w DF6q

X V h

w F6&q X V c

w F6&q

X V 

w G6q

0$y X V YH

~ &y

Q b `X V T Q b `X dcamWdcaV w F6&q w F6&q X V gWT X V Ry u w r F Q ` h h Q b `X V T Q b `X pidcamWdcaV y e v fr u r w F6&q b T X V

QP I RV

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

219

si n) o

cod (puntero a la lista de cu druplos que almacena el c digo). a o

Se utiliza el lexema, pero sera en realidad un puntero a la tabla de smbolos.

220

7.4. TRADUCCION DE PROPOSICIONES DE ASIGNACION Y EXPRESIONES ARITMETICAS

NodeKind kind; int nchilds; // nmero de hijos u struct streenode childs[MAXNUMCHILDS]; // se puede usar una lista con primer hijo que apunta a hermanos int val; // para constantes numricas e char *strval; // para identificadores, deberia ser puntero a la TS STreeNode;

typedef STreeNode * SyntaxTreeRoot;

char lugar[10]; lista codigo *cod; //puntero a lista de cudruplos a TAC;

= E

id

n_id

TAC datos; TAC aux1, aux2; lista codigo *cod=NULL; datos.cod=NULL;

case n assign:

aux1=genera codigo(childs[1]); cod=gen cuad(assign, lexema(id), aux1.lugar,--); datos.cod=concatena codigo(aux1.cod,cod); break;

switch (node- kind)

// childs[0]=id, childs[1]=E

o TAC genera cdigo (STreeNode *nodo)

typedef struct

n_mas

E 1

n_num

Figura 7.5: Tipos de nodo

n_menos n_mult n_uminus E2 E 1 E2 E 1 E2 E

typedef struct streenode

typedef enum

n assign, n mult, n add, n id, ...

NodeKind;

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

221

aux1=genera codigo(childs[0]); aux2=genera codigo(childs[1]); datos.lugar=nuevotemp(); cod=gen cuad(add, datos.lugar,aux1.lugar,aux2.lugar); datos.cod=concatena codigo(aux1.cod,aux2.cod,cod); break;

aux1=genera codigo(childs[0]); aux2=genera codigo(childs[1]); datos.lugar=nuevotemp(); cod=gen cuad(mult, datos.lugar,aux1.lugar,aux2.lugar); datos.cod=concatena codigo(aux1.cod,aux2.cod,cod); break;

// no haria falta crear este tipo de nodo datos=genera codigo(childs[1]); break; case n id: datos.lugar=lexema(id); datos.cod=NULL;

case n num: datos.lugar=lexema(num); datos.cod=NULL;

return(datos);

break;

break;

case n parentesis:

// childs[1]=

case n mult:

// childs[0]=

, childs[1]=

case n add:

// childs[0]=

, childs[1]=

222

7.5. TRADUCCION DE EXPRESIONES BOOLEANAS

7.5

TRADUCCION DE EXPRESIONES BOOLEANAS

Las expresiones booleanas se utilizan principalmente como parte de las proposiciones condicionales que alteran el ujo de control del programa, if-then, if-then-else, while-do. Las expresiones booleanas se componen de los operadores booleanos and,or,not aplicados a variables booleanas o expresiones relacionales. A su vez, las expresiones relacionales son de la forma oprel , donde y son expresiones aritm ticas y oprel es cualquier operador e relacional <, >, <=, >=,.... Consideremos expresiones booleanas generadas por la gram tica: a

E E or E | E and E | not E | ( E ) | id oprel id | true | false | id

Uno de los m todos para traducir expresiones booleanas a c digo de 3e o direcciones consiste en codicar num ricamente los valores true y false e y evaluar una expresi n booleana como una expresi n aritm tica, siguieno o e do unas prioridades. A menudo se utiliza para indicar true y 0 para indicar false. Las expresiones booleanas se eval an de manera similar a una expresi n u o aritm tica de izquierda a derecha. Supongamos el ejemplo: a or b and e not c. La secuencia de c digo de 3-direcciones correspondiente es: o
r

= a or b

w F6q

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

= not c = and

Producci n o

La funci n para generar c digo se podra ampliar a adiendo nuevos casos o o n a la sentencia switch correspondientes a los tipos de nodos asociados a los operadores l gicos. Por ejemplo, para el nodo correspondiente al o operador l gico and, nodo tipo n and, se insertara el siguiente trozo de o c digo: o
w Fkq

La siguiente gram tica en la tabla 7.5 muestra el ETDS para producir a c digo de 3-direcciones para las expresiones booleanas. o

Tabla 7.5: ETDS para expresiones booleanas utilizando una representaci n num rica o e

case n and: // childs[0]= , childs[1]= aux1=genera codigo(childs[0]); aux2=genera codigo(childs[1]); datos.lugar=nuevotemp(); cod=gen cuad(and, datos.lugar,aux1.lugar,aux2.lugar
A A Q RP r q $Dw r u q r 6e I V I V I V I V y I V I V I V I V o o T Q b `X ppegaV y w v r t r xu&q w G6q Q iRP T X V w F6q di$y u w w r F G X V fY P Q ` T Q b `X egaV y e v r u r w G6q g g db T X V wF6q di$y u w w r F p XfY P V Q ` T Q b `X egaV y e v r u r w G6q gg db T X V ywxvrut&q r y w r t xvur&q wF6&q q6e y u r w r F cRP Q mlGRP Q XV b Q ` T Q b `X egaV y e v r u r w G6q db T X V g g Q b `X V T Q b `X gaghegaV w G6q w G6q X V ghT X V wG6q DwF6q y u w r F X V XfVm Q b ` h h Q b `X V T Q b `X pigaghegaV y e v r u r w G6q db T X V X V m w DF6q X V Q f6 w $y Q w u ` r F hphiQdcaipigaghegaV b `X V h h Q b `X V T Q b `X y e v r u r w G6q db T X V hphiQdcaipigaghegaV b `X V h h Q b `X V T Q b `X y e v r u r w G6q db T X V Q tnP b Q fGRP lV V b hf V Q iv V w hV b fhV X V i w Fkq X V i w DF6q X V h w F6&q y u w r F X V  b Q `

Reglas Sem nticas a


223

224

7.5. TRADUCCION DE EXPRESIONES BOOLEANAS

datos.cod=concatena codigo(aux1.cod,aux2.cod,cod); break;

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

225

7.6

TRADUCCION DE PROPOSICIONES DE CONTROL

Pasemos a considerar ahora la traducci n de proposiciones de control ifo then, if-then-else, while-do generadas por la siguiente gram tica: a

S if E then

7.6.1

Proposici n if-then o
A B

Supongamos una sentencia if-then de la forma if then , ver diagrama de ujo en gura 7.6. Para generar el c digo correspondio ente a esta proposici n habra que a adir a la funci n genera cdigo() o n o o un nuevo caso para la sentencia switch que contemple este tipo de nodo en el arbol sint ctico, nodo n ifthen. a

CODIGO CALCULO E

SALTO CONDICIONAL V CODIGO S Etiqueta 1

(a)

Figura 7.6: (a) Diagrama de ujo para la proposici n if-then y (b) tipo de nodo o
TAC datos; TAC aux1, aux2; lista codigo *cod; datos.cod=NULL; direcciones dir; //usamos direccin al salto, en vez de etiquetas o

aux1=genera codigo(childs[0]); cod=gen cuad(if false,--, aux1.lugar, dir?);

case n ifthen:

// childs[0]=E, childs[1]=

| while E do

| if E then

else

%
n_ifthen E S

(b)

226

7.6. TRADUCCION DE PROPOSICIONES DE CONTROL

// an no se sabe la direc. u

de salto

aux2=genera codigo(childs[1]); dir=sgtedirlibre(); //relleno de retroceso rellena(cod,arg3,dir) datos.cod=concatena codigo(aux1.cod,cod,aux2.cod); break;

Supondremos que tenemos una funci n, sigtedirlibre(), que guaro da el ndice de la siguiente instrucci n libre (la funci n gen cuad() in o o crementa ese contador). En la implantaci n se ha optado por utilizar direco ciones directamente a las instrucciones en vez de usar etiquetas.

7.6.2

Proposici n if-then-else o
A B p

Supongamos una sentencia if-then-else de la forma if then else , cuyo diagrama de ujo tiene la forma representada en la gura 7.7. Para generar el c digo correspondiente a esta proposici n o o o habra que a adir a la funci n genera cdigo() un nuevo caso para la n o sentencia switch que contemple este tipo de nodo en el arbol sint ctico, a nodo n ifthenelse. Este fragmento de c digo se podra implantar de o forma similar a como hemos hecho en la secci n anterior. Ver ejercicios. o

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

227

CODIGO CALCULO E

SALTO CONDICIONAL V CODIGO S1

SALTO INCONDICIONAL Etiqueta 2 CODIGO S2 Etiqueta 1

n_ifthen_else

S1

S2

(a=

(b)

Figura 7.7: (a)Diagrama de ujo para la proposici n if-then-else y (b) tipo de nodo o

7.6.3

Proposici n while-do o

while do , cuyo Una sentencia while -do tiene la forma diagrama de ujo viene representado en la gura 7.8. Para generar el c digo correspondiente a esta proposici n habra que a adir a la funci n o o n o genera cdigo() un nuevo caso para la sentencia switch que contemo ple este tipo de nodo en el arbol sint ctico. a
Etiqueta 1 CODIGO CALCULO E

SALTO CONDICIONAL V CODIGO S

n_while
SALTO INCONDICIONAL Etiqueta 2

(a=

(b)

Figura 7.8: (a)Diagrama de ujo para la proposici n while do y (b) tipo de nodo o

Supondremos que tenemos una funci n, sigtedirlibre(), que guarda el o ndice de la siguiente instrucci n libre (se asume que la funci n gen cuad() o o

228

7.7. OPTIMIZACION DE CODIGO INTERMEDIO

incrementa ese contador).


TAC datos; datos.cod=NULL; TAC aux1, aux2; lista codigo *cod1=NULL, *cod2=NULL; direcciones dir1,dir2;

dir1=sgtedirlibre(); aux1=genera codigo(childs[0]); cod1=gen cuad(if false,--, aux1.lugar, dir?); aux2=genera codigo(childs[1]); cod2=gen cuad(goto,--, dir1,--);// salto incondicional a dir1 dir2=sigtedirlibre(); // rellena argumento de cod1, direccion salto condicional rellena(cod1,arg3,dir2) datos.cod=concatena codigo(aux1.cod,cod1,aux2.cod,cod2); break;

Se ha optado por utilizar direcciones directamente a las instrucciones en vez de etiquetas.

7.7

OPTIMIZACION DE CODIGO INTERMEDIO

La optimizaci n de c digo intermedio se puede realizar: o o

a nivel local: s lo utilizan la informaci n de un bloque b sico para o o a realizar la optimizaci n. o

a nivel global: que usan informaci n de varios bloques b sicos. o a

El t rmino optimizaci n de c digo es inadecuado ya que no se garantiza e o o el obtener, en el sentido matem tico, el mejor c digo posible atendiendo a o a maximizar o minimizar una funci n objetivo (tiempo de ejecuci n y eso o

case n while:

// childs[0]=E, childs[1]=

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

229

pacio). El t rmino de mejora de c digo sera m s apropiado que el de e o a optimizaci n. o Nos concentraremos b sicamente en la optimizaci n de c digo de tresa o o direcciones, puesto que son siempre transportables a cualquier etapa nal, a son optimizaciones independientes de la m quina. Las optimizaciones a nivel de la m quina, como la asignaci n de registros y la utilizaci n de a o o instrucciones especcas de la m quina, se salen del contexto de esta asig a natura. La mayora de los programas emplean el del tiempo de ejecuci n en el o de su c digo. Lo m s adecuado es identicar las partes del programa o a que se ejecutan m s frecuentemente y tratar de que se ejecuten lo m s a a ecientemente posible. En la pr ctica, son los lazos internos los mejores a candidatos para realizar las transformaciones. Adem s de la optimizaci n a nivel de c digo intermedio, se puede reducir a o o el tiempo de ejecuci n de un programa actuando a otros niveles: a nivel de o c digo fuente y a nivel de c digo objeto. o o
Codigo fuente Etapa Inicial Codigo Intermedio Codigo Objeto
el compilador puede usar registros seleccionar instrucciones

el programador puede modificar algoritmos transformar lazos

el compilador puede mejorar los lazos

Figura 7.9: Niveles en los que el programador y el compilador pueden mejorar el c digo o

Generador de Codigo

230

7.7. OPTIMIZACION DE CODIGO INTERMEDIO

Un bloque b sico es una unidad fundamental de c digo. Es una secuencia a o de proposiciones donde el ujo de control entra en el principio del bloque y sale al nal del bloque. Los bloques b sicos pueden recibir el control desde a m s de un punto en el programa (se puede llegar desde varios sitios a una a etiqueta) y el control puede salir desde m s de una proposici n (se podra a o ir a una etiqueta o seguir con la siguiente instrucci n). Cuando aplicamos o optimizaci n dentro de un bloque b sico s lo nos tenemos que preocupar o a o sobre los efectos de la optimizaci n en los valores de las variables a la o entrada del bloque y los valores que tienen a la salida del bloque, que han de ser los mismos que en el c digo original sin transformar. o El algoritmo para particionar un programa en bloques se describe a continuaci n: o
1 Encontrar todas las proposiciones que comienzan el principio de un bloque bsico: a

2 Para cualquier proposicin que comienza un bloque bsico, el bloque o a consiste de esa proposicin y de todas las siguientes hasta el prino cipio del siguiente bloque o el final del programa.

El ujo de control de un programa puede visualizarse como un grafo dirigido de bloques b sicos. A este grafo se le llama grafo de ujo. Como a ejemplo consideremos este trozo de c digo escrito en pseudoC que suma o los diez primeros n meros que se muestra en la tabla 7.6 (a): u

La primera sentencia del programa. Cualquier proposicin del programa que es el objetivo de un salto. o Cualquier proposicin que sigue a una bifurcacin. o o

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

231

void main() int i,s; i=10; s=0;


i = 10 s=0 label l1 iffalse t0 goto l2

t0 = i 0 do

while i

s=s+i i=i-1 goto l1 label l2 ... (b)

s=s+i; i=i-1;

(a)

Tabla 7.6: Ejemplo (a) c digo fuente, (b) c digo de 3-direcciones o o

La gura 7.10 muestra el diagrama de ujo para el ejemplo anterior. Aparecen 4 bloques b sicos. a
i = 10 s=0

label l1 t0 = i > 0 iffalse t0 goto l2 s= s+i i=i-1 goto l1

label l2 ...

Figura 7.10: Diagrama de ujo

232

7.7. OPTIMIZACION DE CODIGO INTERMEDIO

Algunas deniciones previas:

Dada una proposici n de 3-direcciones de la forma a = b op c decimos o que la proposici n referencia b y c y que dene a. o

Se dice que un nombre en un bloque b sico vive al nal del bloque si a su valor es referenciado en otro bloque b sico en el programa. a

Se dice que un nombre est muerto si no es referenciado en el resto a del programa.

Se presentan algunas de las transformaciones m s utiles para mejorar el a c digo. Son transformaciones locales, se pueden realizar observando s lo o o las proposiciones de un bloque b sico. a

7.7.1

Eliminaci n de subexpresiones comunes o

Si una expresi n se calcula m s de una vez, se puede remplazar el c lculo o a a de la segunda por el valor de la primera expresi n. Consideremos el siguo iente ejemplo del c digo 7.7 (a). Vemos que la expresi n o o se calcula dos veces, por tanto podemos escribir el c digo de la gura 7.7 (b): o
t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t3 * t1 t7 = t6 + b c = t5 * t7 (a) t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t4 t7 = t6 + b c = t5 * t5 (b)
|

Tabla 7.7: Eliminaci n de subexpresiones comunes o

Esto s lo es posible si los operandos que est n implicados en el c lculo de o a a la expresi n no han modicado su valor en las proposiciones intermedias. o

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

233

7.7.2

Propagaci n de copias o

. La propagaci n de copias considera las proposiciones de la forma o Despu s de esta sentencia sabemos que y tienen el mismo valor, por e tanto, podemos remplazar cada vez que aparezca por , con la esperanza de que podamos remplazar todas las ocurrencias de hasta que se convierta en un nombre muerto y se pueda entonces eliminar la proposici n de copia. o A partir del c digo anterior podemos eliminar la proposici n de copia o o . Sustituimos por . Vease gura 7.8 (a). Ahora se puede ver que hay de nuevo una subexpresi n com n que puede ser eliminada, obteniendo o u el c digo que se muestra en 7.8 (b). Y nalmente realizando otra vez o propagaci n de copias, obtenemos 7.8 (c): o
t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t4 t7 = t4 + b c = t5 * t7 (a) t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t4 t7 = t5 c = t5 * t7 (b) t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t4 t7 = t5 c = t5 * t5 (c)
{ c c

Tabla 7.8: Propagaci n de copias y eliminaci n de subexpresiones comunes o o

Vemos que el haber hecho una optimizaci n puede dar lugar a que sea o posible aplicar nuevas optimizaciones.

234

7.7. OPTIMIZACION DE CODIGO INTERMEDIO

7.7.3

Eliminaci n de c digo muerto o o

Podemos tener proposiciones que denen un nombre que nunca m s es a referenciado, est muerto. Estas proposiciones pueden entonces ser elima inadas. Dada la proposici n a= b op c, se dice que es c digo muerto o o o o inactivo si no es referenciada. En general, el c digo muerto aparece como consecuencia de la propagaci n de copias y es esto lo que hace que la o t cnica de propagaci n de copias sea tan util. Veamos como aplicar esta e o t cnica al ejemplo anterior en la gura 7.8 (c). e Vemos que y no tienen ninguna referencia a partir de su denici n, o por tanto pueden ser eliminadas. Obtenemos el c digo que aparece en o la gura 7.9. Se ha supuesto que todas las variables no-temporales est n a vivas, se hace referencia a ellas en el resto del programa.
d

t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b c = t5 * t5 Tabla 7.9: Eliminaci n de c digo muerto o o

Aunque es poco probable que el programador introduzca c digo muerto o o inactivo, este puede aparecer como resultado de transformaciones anteriores.

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

235

7.7.4

Transformaciones aritm ticas e

Se pueden hacer uso de transformaciones algebraicas simples para reducir la cantidad de computaci n transformando operaciones m s costosas o a por otras menos costosas. Existen tres tipos de transformaciones algebraicas b sicas. a C lculo previo de constantes a Se trata de calcular a nivel de compilaci n el valor previo de constantes o en vez de hacerlo en tiempo de ejecuci n que retardara la ejecuci n de un o o programa. A esta optimizaci n se le llama c lculo previo de constantes o a (en ingl s constant folding). El c digo de la gura 7.9 puede ser mejorado e o dando lugar al c digo de la gura 7.10 (a). Haciendo una propagaci n de o o copias y eliminaci n de c digo muerto tenemos el c digo de la gura 7.10 o o o (b). Realizando de nuevo un c lculo previo de constantes obtenemos 7.10 a (c). Y nalmente podemos hacer de nuevo la propagaci n de copias y la o eliminaci n de c digo muerto, obteniendo el c digo de la gura 7.10 (d). o o o
t1 =2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b c = t5 * t5 (a) (b) (c) (d) t2 = 2 / 2 t3 = a * t2 t4 = t3 * 2 t5 = t4 + b c = t5 * t5 t2 = 1 t3 = a * t2 t4 = t3 * 2 t5 = t4 + b c = t5 * t5 t3 = a * 1 t4 = t3 * 2 t5 = t4 + b c = t5 * t5

Tabla 7.10: C lculo previo de constantes a

Hemos pasado de seis proposiciones a tener cuatro, eliminado una substracci n y una divisi n en el proceso. o o

236

7.7. OPTIMIZACION DE CODIGO INTERMEDIO

Transformaciones algebraicas Podemos hacer uso de identidades algebraicas para simplicar el c digo. o Las principales identidades son:
 

Partiendo de la gura 7.10 (d) podemos obtener el c digo de la gura 7.11 o (a). De nuevo si usamos propagaci n de copias y eliminaci n de c digo o o o muerto obtenemos el c digo de la gura 7.11 (b) : o
t3 = a t4 = t3 * 2 t5 = t4 + b c = t5 * t5 (a) (b) t4 = a * 2 t5 = t4 + b c = t5 * t5

Tabla 7.11: Identidades algebraicas

Reducci n de intensidad o En la mayora de las m quinas las operaciones de multiplicaci n y divisi n a o o son substancialmente m s costosas que las operaciones de suma y resta. Y a a su vez, las potencias son m s costosas que las multiplicaciones y dia visiones. Por tanto, siempre que sea posible es conveniente sustituir un operador m s costoso por otro menos costoso. A esto se le conoce como a reducci n de la intensidad. Las identidades m s comunes son: o a
!

En nuestro ejemplo de la gura 7.11 (b) podemos obtener el c digo 7.12 o

Otra transformaci n tpica es usar desplazamientos de bits cuando se divio da o se multiplique por potencias de dos.

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

237

t4 = a + a t5 = t4 + b c = t5 * t5 Tabla 7.12: Reducci n de intensidad o

7.7.5

Empaquetamiento de temporales

Se trata de reusar los temporales con el n de ahorrar espacio. Despu s e de haber optimizado el c digo es normal pensar que se puedan usar menos o temporales y sera conveniente entonces renombrar estos temporales. Supongamos que tenemos una tabla de temporales disponibles (por ejemplo de a ), de manera que marcamos si un temporal est vivo en un a cierto punto del bloque b sico. En general, es posible remplazar dos tema porales por uno unico si no existe ning n punto donde los dos temporales u est n vivos a la vez. Para cada temporal lo remplazamos por el primer tema poral en la tabla que est muerto en todos los lugares en el que el temporal a bajo consideraci n est vivo. o a Veamos nuestro ejemplo de la gura 7.12. se dene en la primera proposici n y est vivo en la segunda, entonces lo remplazamos por el o a o primer terminal muerto de la tabla, , obteniendo el c digo de la gura 7.13 (a). Por otro lado, es denido en la segunda proposici n y vivo en o la proposici n 3. Esto no interacciona con el temporal , que esta vivo o s lo en la segunda proposici n, por tanto o o puede ser sustituido por . Obteniendo el c digo de la gura 7.13 (b). o
t1 = a + a t5 = t1 + b c = t5 * t5 (a) t1 = a + a t1 = t1 + b c = t1 * t1 (b)
c d d

Tabla 7.13: Empaquetamiento de temporales

Comparando este c digo con el original que tena ocho proposiciones, o siete temporales, dos adiciones, una substracci n, cuatro multiplicaciones o

238

7.7. OPTIMIZACION DE CODIGO INTERMEDIO

y una divisi n, lo hemos reducido a tres proposiciones que implican dos o adiciones y una multiplicaci n. o

7.7.6

Mejora de los lazos

Traslado de c digo o Una modicaci n importante que disminuye la cantidad de c digo en o o un lazo es el traslado de c digo. Esta transformaci n toma una expresi n o o o que produce el mismo resultado independientemente del n mero de veces u que se ejecute un lazo y la coloca antes del lazo. Por ejemplo:
while (i<=limite-2) ...

Se puede transformar en:


t=limite -2; while (i<=t) ...

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

239

Variables de inducci n o Se trata de identicar las variables que permanecen ligadas entre s en la ejecuci n, est n relacionadas entre s de forma que conocido el valor de o a una se puede obtener el de la otra. Supongamos el siguiente fragmento de c digo donde se ha supuesto que los elementos de la matriz ocupan 4 bytes o y ya se ha realizado cierta optimaci n. o
suma=0; j=0; while j 10 suma = suma + a[j]; j=j+1; ...

suma=0; j=0; label l1 t1= j 10 iffalse t1 goto l2 t2=4*j t3=a[t2] suma=suma+t3 j=j+1 goto l1 label l2 ...

Tabla 7.14: (a) c digo fuente y (b) c digo de 3-direcciones o o

en la tabla 7.14 (b) signica la direcci n de m s un deo a donde splazamiento . Sabemos que no cambia en ning n momento salvo en u , por tanto justo despu s de la proposici n e o se cumple que , y se puede sustituir la asignaci n o por , debiendo inicializar el valor de . Siempre que haya variables de inducci n se pueden hacer sustituciones de o este tipo y eliminar todas menos una.
  y U

240

7.8. EJERCICIOS

7.8

EJERCICIOS

1 (0.25 ptos) Escribe el pseudoc digo correspondiente, usando la noo taci n que hemos visto a lo largo del captulo, para la implementaci n o o de la generaci n de c digo de tres direcciones medinate cuadr plos o o u para la construccion if-then-else. 2 (0.25 ptos) Escribe el pseudoc digo correspondiente, usando la noo taci n que hemos visto a lo largo del captulo, para la implementaci n o o de la generaci n de c digo de tres direcciones medinate cuadr plos o o u para la construcci n repeat until. o 3 (0.25 ptos) Escribe el pseudoc digo correspondiente, usando la noo taci n que hemos visto a lo largo del captulo, para la implementaci n o o de la generaci n de c digo de tres direcciones medinate cuadr plos o o u para la construcci n switch. o 4 (0.3 ptos) Supongamos una nueva construcci n de los lenguajes de o programaci n que llamaremos do-while-do (hacer-mientras-hacer). o Esta construcci n nace de forma natural, como las construcciones o while-do, do-while que ya conoc is. Esta construcci n surge para e o implementar la idea en que hay casos en los que no se desea salir de la iteraci n al principio, ni al nal de la iteraci n, sino a la mitad, o o despu s de que se ha hecho cierto procesamiento. e Por ejemplo para implementar el c digo: o
dowhiledo read(X); while (no final fichero) process(X); end dowhiledo

La sintaxis de esta construcci n es: o

hhhf

hlhh

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

241

donde se ha usado el operador * para indicar cero o m s repeticiones. a Se pide:


Dibujar el diagrama de ujo de esta construcci n. o Dibujar la forma del arbol abstracto de an lisis sint ctico que a a usaras para su traducci n a c digo de 3-direcciones. o o Escribir el pseudoc digo de la funci n generar cdigo para trao o o ducir este tipo de sentencias a una lista de cu druplos. a Desafortunadamente ning n lenguaje com n de programaci n u u o implementa esta construcci n. A qu crees que se debe esto?. o e Qu construcci n(es) usa el lenguaje C para implementar esta e o idea?

242

7.9. EJEMPLO DE GENERACION DE CODIGO PARA UNA CALCULADORA USANDO PCCTS

7.9

EJEMPLO DE GENERACION DE CODIGO PARA UNA CALCULADORA USANDO PCCTS

Supongamos una peque a calculadora que realizar operaciones aritm ticas n e sencillas seg n la gram tica: u a

Se pide implementar un traductor que traduzca las expresiones aritm ticas e a c digo de 3-direcciones, implementado mediante cu duplos de la foro a ma (operador, resultado, arg1, arg2). Los tipos de operadores son:
(ASSIGN, result, arg1,NULL) (ADD, result, arg1,arg2) (SUB, result, arg1,arg2) (MULT, result, arg1,arg2) (DIV, result, arg1,arg2) (NEG, result, arg1,NULL) (HALT,NULL, NULL, NULL) asigna arg1 a result suma arg1, arg2 y lo alamacena en result resta arg1, arg2 y lo alamacena en result multiplica arg1, arg2 y lo alamacena en result divide arg1, argg2 y lo alamacena en result mult. por (-1) arg1, y lo alamacena en result nal de programa

entrada ecuacion expresion termino factor dato

(ecuacion)+ id = expresion ; termino ( + termino - termino )* factor ( * factor / factor)* ( expresion ) dato num id - num - id

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

243

Se ha implementado la clase cuadruplo (Cuad.h). Se ha implementado la clase TAC (Three-Address-Code), a partir de una lista de cuaduplos y se ha introducido el lugar como un dato protegido adicional. Se ha implementado el m todo generar c digo en la clase AST. Fichero con la especie o cacion de la gram tica p3.g. a Para la entrada: a=3+2; b=a*2; c=a+b+2*6; d=-1+a;

Obtenemos la salida: ( ENTRADA ( = a ( + 3 2 ) ) ( = b ( * a 2 ) ) ( = c ( + ( + a b ) ( * 2 6 ) ) ) ( = d ( + ( UMINUS 1 ) a ) ) ) Numero de lineas analizadas 6 (ADD,t0,3,2) (ASSIGN,a,t0,NULL) (MULT,t1,a,2) (ASSIGN,b,t1,NULL) (ADD,t2,a,b) (MULT,t3,2,6) (ADD,t4,t2,t3) (ASSIGN,c,t4,NULL) (NEG,t5,1,NULL) (ADD,t6,t5,a) (ASSIGN,d,t6,NULL) (HALT,NULL,NULL,NULL)

Numero de cuadruplos 12

244

Impreso por Elena Daz Fernndez Pgina 1/1

06 may 03 18:43

Cuad.h

#ifndef Cuad_h #define Cuad_h

#include <iostream.h> #include <fstream.h> #include <string.h>

typedef enum{EMPTY,ASSIGN, NEG, ADD, SUB,MULT, DIV, HALT} OpKind;

class Cuad { protected: OpKind op; char *opname; char *res; char *arg1; char *arg2;

public: Cuad(); Cuad( Cuad &); Cuad(OpKind, const char *, const char*, const char *, const char *); ~Cuad();

OpKind GetOp(); void PutOp(OpKind);

char * GetOpName(); void PutOpName(char *);

char * GetRes(); void PutRes(char *);

char * GetArg1(); void PutArg1(char *);

char * GetArg2(); void PutArg2(char *);

friend ostream &operator << (ostream &f, const Cuad & c); Cuad & operator = (const Cuad &); bool operator== (const Cuad &) const;

};

7.9. EJEMPLO DE GENERACION DE CODIGO PARA UNA CALCULADORA USANDO PCCTS

#endif

martes 06 mayo 2003

Cuad.h

1/1

Impreso por Elena Daz Fernndez Pgina 1/4


void Cuad::PutOp(OpKind t) { op=t; } char * Cuad::GetOpName(){ cout << "Esto es dentro " << opname ; return (opname); } void Cuad::PutOpName(char *s){ delete(opname); opname = new char [strlen(s)+1]; if (opname==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(opname,s); } char * Cuad::GetRes() { return res; }

06 may 03 19:03

Cuad.cpp
06 may 03 19:03

Cuad.cpp

Pgina 2/4

#include "Cuad.h"

Cuad::Cuad(){ op=EMPTY;

opname = new char [strlen("NULL")+1]; if (opname==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(opname, "NULL");

res=new char [strlen("NULL")+1]; if (res==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(res,"NULL");

arg1=new char [strlen("NULL")+1]; if (arg1==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(arg1,"NULL");

arg2=new char [strlen("NULL")+1]; if (arg2==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(arg2,"NULL"); }

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

Cuad::Cuad(OpKind ope, const char *name, const char *r, const char *a1, const char *a2){ op=ope; char * Cuad::GetArg1() { return arg1; }

void Cuad::PutRes(char *s) { delete(res); res = new char [strlen(s)+1]; if (res==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(res,s); }

opname=new char [strlen(name)+1]; if (opname==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(opname, name);

res=new char [strlen(r)+1]; if (res==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(res,r);

arg1=new char [strlen(a1)+1]; if (arg1==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(arg1,a1);

void Cuad::PutArg1(char *s) { delete arg1 ; arg1 = new char [strlen(s)+1]; if (arg1==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(arg1,s); } char * Cuad::GetArg2() { return arg2; }

arg2=new char[strlen(a2)+1]; if (arg2==NULL) cerr << "ERROR reservando memoria" << endl; strcpy(arg2,a2);

Cuad::~Cuad(){ delete [] opname; delete [] res; delete [] arg1; delete [] arg2; }

void Cuad::PutArg2(char *s) { delete arg2; arg2 = new char [strlen(s)+1]; if (arg2==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(arg2,s); } ostream & operator << (ostream &f, const Cuad & c) { f<< "(" << c.opname << "," << c.res << "," << c.arg1 << "," << c.arg2 << ")" << endl; return f; }

245

OpKind Cuad::GetOp() { return op; }

martes 06 mayo 2003

Cuad.cpp

1/1

246

Impreso por Elena Daz Fernndez Pgina 3/4


bool Cuad::operator== (const Cuad & x) const { if (op!=x.op) return (false); if (strcmp(opname,x.opname)!=0) return (false); if (strcmp(res,x.res)!=0) return (false); if (strcmp(arg1,x.arg1)!=0) return (false); if (strcmp(arg2,x.arg2)!=0) return (false); return (true); }

06 may 03 19:03

Cuad.cpp
06 may 03 19:03 Pgina 4/4

Cuad.cpp

Cuad & Cuad::operator = (const Cuad &c){

if (this!=&c){ char *auxopname; auxopname = new char [strlen(c.opname)+1]; if (auxopname==NULL) cerr << "ERROR reservando memoria" << endl; else strcpy(auxopname,c.opname); delete [] opname; opname=auxopname;

char *auxres; auxres = new char [strlen(c.res)+1]; if (auxres==NULL) cerr << "ERROR reservando memoria" << endl; else strcpy(auxres,c.res); delete [] res; res=auxres;

char *auxarg1; auxarg1 = new char [strlen(c.arg1)+1]; if (auxarg1==NULL) cerr << "ERROR reservando memoria" << endl; else strcpy(auxarg1,c.arg1); delete [] arg1; arg1=auxarg1;

char *auxarg2; auxarg2 = new char [strlen(c.arg2)+1]; if (auxarg2==NULL) cerr << "ERROR reservando memoria" << endl; else strcpy(auxarg2,c.arg2); delete [] arg2; arg2=auxarg2;

op=c.op; } return(*this);

Cuad::Cuad(Cuad & c) { op=EMPTY;

opname = new char [strlen("NULL")+1]; if (opname==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(opname, "NULL");

res=new char [strlen("NULL")+1]; if (res==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(res,"NULL");

arg1=new char [strlen("NULL")+1]; if (arg1==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(arg1,"NULL");

7.9. EJEMPLO DE GENERACION DE CODIGO PARA UNA CALCULADORA USANDO PCCTS

arg2=new char [strlen("NULL")+1]; if (arg2==NULL) cerr << "ERROR reservando memoria"<< endl; strcpy(arg2,"NULL");

(*this)=c;

martes 06 mayo 2003

Cuad.cpp

1/1

Impreso por Elena Daz Fernndez Pgina 1/1

05 may 03 18:08

TAC.h

#ifndef TAC_h #define TAC_h

#include "Cuad.h" #include "Ldligada.h"

class TAC: public dllista<Cuad> { //OJO mas que derivar sera una lista de cuadruplos

protected: char *lugar;

public:

TAC(); ~TAC(); void PutLugar(char *); char * GetLugar(void);

};

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

#endif

247

martes 06 mayo 2003

TAC.h

1/1

248

Impreso por Elena Daz Fernndez

07 may 03 13:01
tree = (AST *) tree>right(); } } void genera_codigo(TAC & tac); };

AST.h
Pgina 1/4 07 may 03 13:01 Pgina 2/4

AST.h

#ifndef AST_h #define AST_h

#include #include #include #include #include void AST:: genera_codigo(TAC & tac) { AST *down,*right; AST *tree=this;

"ASTBase.h" "AToken.h" "ATokPtr.h" "Cuad.h" "TAC.h"

extern char * newtemp();

class AST : public ASTBase { protected: ANTLRTokenPtr token; public: AST(ANTLRTokenType tok, char *s) { token = new ANTLRToken(tok, s); } AST(ANTLRTokenPtr t) { token = t; } void preorder_action() { cout << token>getText() << " " ; } void postorder_action() { cout << token>getText() << " "; } virtual void preorder_before_action() { cout << " (" ; } virtual void preorder_after_action() { cout << " )" ; } virtual void postorder_before_action() { cout << " ("; } virtual void postorder_after_action() { cout << " )"; }

virtual int type() { return token>getType(); } char *getText() { return token>getText(); }

void postorder() { AST *tree = this; AST *down,*right;

while ( tree!= NULL ) { down=(AST *)tree>down(); right=(AST *)tree>right(); if ( down != NULL ) tree>postorder_before_action(); if ( down!=NULL ) down>postorder(); tree>postorder_action(); if ( down!=NULL ) tree>postorder_after_action(); tree = (AST *)right; }

void preorder( ){ AST *tree = this; while ( tree!= NULL ) { if ( tree>down() != NULL ) { tree>preorder_before_action(); }; tree>preorder_action(); if ( tree>down()!=NULL ) { AST *d; d= (AST *) tree>down(); d>preorder(); tree>preorder_after_action(); }

down=(AST *)tree>down(); right=(AST *)tree>right(); switch (tree>type()) { case TKN_ENTRADA: { TAC aux1; down>genera_codigo(aux1); tac.concatenar(aux1); right=(AST *) down>right(); while (right!=NULL) { TAC aux; right>genera_codigo(aux); tac.concatenar(aux); right=(AST *)right>right(); } Cuad c(HALT,"HALT","NULL", "NULL", "NULL"); TAC cuad; if (cuad.Insertar(c)==false) cerr << "Error al insertar" << endl; tac.concatenar(cuad); break; } case TKN_ASIGN:{ TAC aux1, aux2; down>genera_codigo(aux1); ((AST *) down>right())>genera_codigo(aux2); Cuad c(ASSIGN,"ASSIGN",aux1.GetLugar(),aux2.GetLugar(),"NULL"); TAC cuad; if (cuad.Insertar(c)==false) cerr << "Error al insertar" << endl; aux1.concatenar(aux2); aux1.concatenar(cuad); tac.concatenar(aux1); break; } case TKN_MAS: { TAC aux1, aux2; char *temp; down>genera_codigo(aux1); ((AST *)down>right())>genera_codigo(aux2); temp = newtemp(); tac.PutLugar(temp); free(temp); Cuad c(ADD,"ADD",tac.GetLugar(),aux1.GetLugar(),aux2.GetLugar()); TAC cuad; if (cuad.Insertar(c)==false) cerr << "Error al insertar" << endl; aux1.concatenar(aux2); aux1.concatenar(cuad); tac.concatenar(aux1); break; }

7.9. EJEMPLO DE GENERACION DE CODIGO PARA UNA CALCULADORA USANDO PCCTS

mircoles 07 mayo 2003

AST.h

1/1

Impreso por Elena Daz Fernndez Pgina 3/4


break;} default: { cout << "Error" << endl;} } } #endif

TEMA 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

07 may 03 13:01

AST.h
07 may 03 13:01

AST.h

Pgina 4/4

249

case TKN_MULT: { TAC aux1, aux2; char *temp; down>genera_codigo(aux1); ((AST *)down>right())>genera_codigo(aux2); temp = newtemp(); tac.PutLugar(temp); free(temp); Cuad c(MULT,"MULT",tac.GetLugar(),aux1.GetLugar(),aux2.GetLugar()); TAC cuad; if (cuad.Insertar(c)==false) cerr << "Error al insertar" << endl; aux1.concatenar(aux2); aux1.concatenar(cuad); tac.concatenar(aux1); break; } case TKN_MENOS: { TAC aux1, aux2; char *temp; down>genera_codigo(aux1); ((AST *)down>right())>genera_codigo(aux2); temp = newtemp(); tac.PutLugar(temp); free(temp); Cuad c(SUB,"SUB",tac.GetLugar(),aux1.GetLugar(),aux2.GetLugar()); TAC cuad; if (cuad.Insertar(c)==false) cerr << "Error al insertar" << endl; aux1.concatenar(aux2); aux1.concatenar(cuad); tac.concatenar(aux1); break; } case TKN_DIV: { TAC aux1, aux2; char *temp; down>genera_codigo(aux1); ((AST *)down>right())>genera_codigo(aux2); temp = newtemp(); tac.PutLugar(temp); free(temp); Cuad c(DIV,"DIV",tac.GetLugar(),aux1.GetLugar(),aux2.GetLugar()); TAC cuad; if (cuad.Insertar(c)==false) cerr << "Error al insertar" << endl; aux1.concatenar(aux2); aux1.concatenar(cuad); tac.concatenar(aux1); break; } case TKN_UMINUS: { TAC aux1; char *temp; down>genera_codigo(aux1); temp = newtemp(); tac.PutLugar(temp); free(temp); Cuad c(NEG,"NEG",tac.GetLugar(),aux1.GetLugar(),"NULL"); TAC cuad; if (cuad.Insertar(c)==false) cerr << "Error al insertar" << endl; aux1.concatenar(cuad); tac.concatenar(aux1); break; } case TKN_NUM:{ tac.PutLugar(tree>getText()); break; } case TKN_ID: { tac.PutLugar(tree>getText());

mircoles 07 mayo 2003

AST.h

1/1

250

Impreso por Elena Daz Fernndez Pgina 1/2


#token #token #token #token #token #token #token #token TKN_NUM "[09]+" TKN_ID "[azAZ][azAZ09]*" "\n" <<skip(); nlineas++;>> "[\ \t]" <<skip();>> TKN_ASIGN "=" TKN_PTOCOMA ";" TKN_UMINUS TKN_ENTRADA

07 may 03 12:59

p3.g
07 may 03 12:59 Pgina 2/2

p3.g

#header<< #include <iostream.h> #include <math.h> #include "AToken.h" typedef ANTLRCommonToken ANTLRToken; #include "MiParser.h" #include "Cuad.h" #include "TAC.h" extern int nlineas;

>>

<< #include #include #include template template

"DLGLexer.h" "PBlackBox.h" "AST.h" class dllista<Cuad>; class Iter_dllista<Cuad>;

int nlineas=0; int ntemp=0; TAC lista_cod;

#token BEGIN_COMMENT "/\*" << for (; ;){ advance(); while ((ch!=*) && (ch!=EOF)) advance(); if (ch==*) { advance(); while (ch==*) advance(); if (ch==/) break; } if (ch==EOF){ errstd( "Found EOF inside a comment" ); break; } } advance(); skip(); >> class MiParser { entrada : << #0=#(#[TKN_ENTRADA,"ENTRADA"], NULL); >> (c:ecuacion )+ << AST *raiz; raiz= (AST *)#0; raiz>preorder(); raiz>genera_codigo(lista_cod);>>; ecuacion : TKN_ID TKN_ASIGN^ exp TKN_PTOCOMA!; exp : term ( TKN_MAS^ term | TKN_MENOS^ term)* ; factor)* ; dato ;

char * newtemp() { char *res=NULL; res=new char [20]; sprintf(res,"t%d",ntemp); ntemp++; return(res); }

void ascendente(TAC & l) { Iter_dllista<Cuad> j; int cont =0; for (j=l.Inicio(); j.Valido(); j++) {cout << j.Dato(); cont++;} cout << "Numero de cuadruplos " << cont; }

term : factor ( TKN_MULT^ factor | TKN_DIV^ factor : TKN_PA! exp TKN_PC! |

int main() { ASTBase *root=NULL; ParserBlackBox<DLGLexer, MiParser, ANTLRToken> p(stdin);

p.parser()>entrada(&root); cout << endl << "Numero de lineas analizadas " << nlineas << endl; ascendente(lista_cod);

dato : TKN_ID^ | TKN_NUM^ | TKN_MENOS^ (c:TKN_ID <<#0=#(#[TKN_UMINUS,"UMINUS"],#c);>> | d:TKN_NUM <<#0=#(#[TKN_UMINUS,"UMINUS"],#d);>>) ; }

} >>

7.9. EJEMPLO DE GENERACION DE CODIGO PARA UNA CALCULADORA USANDO PCCTS

// Operadores especiales

#token #token #token #token #token #token

TKN_PA "\(" TKN_PC "\)" TKN_MAS "\+" TKN_MENOS "\" TKN_MULT "\*" TKN_DIV "/"

mircoles 07 mayo 2003

p3.g

1/1

Das könnte Ihnen auch gefallen