Está en la página 1de 31

Enviad sugerencias y/o errores a la direccin de correo vivancos@dsic.upv.

es
Procesadores de lenguajes





Uni dad temti ca 8:
Generaci n de cdi go i ntermedi o







V. 11.1

2
!"#$" &' ()*+'*,&)
-. /0&,1)2 ,*+'34'&,)2 ...................................................................................................... 5
"#"# $%&'( )* +*&+*(*,-./%',*( %,-*+0*)%.( ########################################################################################################### 1
!"#$%&'( *"+#,&-$ ................................................................................................................................................................ /
012"3 45 +&(#$6&+ $2+#1$%#$ ............................................................................................................................................ /
7'4&8" 45 #15+ 4&15%%&"(5+ 9%:$1#5#"+; ..................................................................................................................... <
7'4&8" 45 4"+ 4&15%%&"(5+ 9#51%5#"+; ......................................................................................................................... =
"#2# 3,(-+4//%',*( )*5 /6)%7' )* -+*( )%+*//%',*( ################################################################################################# 8
"#9# :*,*+./%6, )* /6)%7' %,-*+0*)%' 0*)%.,-* 4,. 7+.0;-%/. )* .-+%<4-'( ######################################### =
6. 7(('2) " 4,'4#3)2 &' 8*" '2+38(+83" 9 '$'4'*+)2 &' 8* "33"9 ................................... -:
2#"# >//*(' . 0%*0<+'( )* 4,. *(-+4/-4+. ########################################################################################################### "1
2#2# >//*(' . *5*0*,-'( )* 4, .++.? ####################################################################################################################### "@
>.>.?. @%%5+" $ 3"+ 535A5(#"+ 45 :( $11$B A:3#&4&A5(+&"($3 5( C$+%$3 ................................................... ?<
>.>.>. @%%5+" $ 3"+ 535A5(#"+ 45 :( $11$B A:3#&4&A5(+&"($3 5( 7 .............................................................. ?D
5. ;<=3'2,)*'2 $01,("2 ' ,*2+38((,)*'2 &' ()*+3)$ &' >$8?) ................................................ -@
9#"# A.+%.<5*( ? *B&+*(%',*( 567%/.( ######################################################################################################################## "C
9#2# D*&+*(*,-./%6, ,40E+%/. ################################################################################################################################### 2F
9#9# D*&+*(*,-./%6, &'+ /',-+'5 )* G54H' ############################################################################################################### 21
:. A'>'3'*(,"2 *) 2"+,2>'(B"2. A'$$'*) =)3 3'+3)('2) ....................................................... 6C
1#"# I5.,-*.0%*,-' )*5 &+'<5*0. ############################################################################################################################## 2@
1#2# D*55*,' &'+ +*-+'/*(' ############################################################################################################################################ 28
1#9 D*&+*(*,-./%6, ,40E+%/. )* *B&+*(%',*( 567%/.( J/', +*55*,' &'+ +*-+'/*('K ########################### 2L
1#1 D*&+*(*,-./%6, )* *B&+*(%',*( 567%/.( &'+ /',-+'5 )* G54H' J/', +*55*,' &'+ +*-+'/*('K ####### 2=
/./.?. 7'4&8" 5( %"1#"%&1%:&#" ..................................................................................................................................... EF
/./.>. G$1&$235+ 3'8&%$+ B 15*15+5(#$%&'( *"1 %"(#1"3 45 ,3:-" ...................................................................... EF
/./.E. H(+#1:%%&"(5+ 45 %"(#1"3 45 ,3:-" ................................................................................................................... E?
C. D8#=3)13"4"2 ............................................................................................................. 5:
@#"# D*7%(-+'( )* ./-%M./%6, *, I.(/.5# ################################################################################################################### 91
<.?.?. I5%3$1$%&'( ............................................................................................................................................................. E/
<.?.>. J3$A$4$ ................................................................................................................................................................... E<
@#2# N.+/'( *, O ################################################################################################################################################################ 98
<.>.?. I5%3$1$%&'( ............................................................................................................................................................. E=
<.>.>. J3$A$4$ ................................................................................................................................................................... E=
E,#$,)13">F" 3'()4'*&"&" ............................................................................................... 5G
;?'3(,(,)2 ......................................................................................................................... 5H
D)$8(,)*'2 " $)2 '?'3(,(,)2 2'$'((,)*"&)2 ......................................................................... :H


Generacin de cdigo intermedio
3
1. Cdi gos i ntermedi os
Adems de analizar el cdigo fuente (fase de anlisis) un compilador debe generar cdigo
(fase de sntesis). Esta generacin de cdigo se realiza en dos fases. Una primer fase en la que el
front-ent del compilador produce como resultado una representacin intermedia (Intermediate
Representationo IR) del programa fuente y una segunda fase en la que el back-end producir
el cdigo objeto.
La fase de sntesis puede generar directamente como salida un cdigo mquina, pero en ese
caso el compilador ser totalmente dependiente de la mquina destino. Adems, debido a la gran
disparidad entre el tipo de instrucciones que se emplean en los lenguajes de alto nivel y en los
lenguajes mquina, la construccin del generador de cdigo ser larga y el cdigo resultante
difcil de mantener. Otra alternativa consiste en que la fase de sntesis genere cdigo en otro
lenguaje de alto nivel. En este caso se requiere del empleo de otro compilador para la mquina
destino que finalmente genere el cdigo mquina. La construccin del traductor ser mucho ms
sencilla, pero a cambio el cdigo ejecutable que obtendremos consumir en general ms recursos
(tiempo y memoria).
La utilizacin de una representacin intermedia (IR) aparece como una solucin a mitad de
camino entre las dos anteriores. El proceso de generacin de cdigo queda dividido en dos etapas
de traduccin: una primera fase independiente de la mquina destino en la que se genera una
representacin intermedia, y una segunda fase en la que, a partir de la representacin intermedia,
se genera el cdigo objeto ejecutable para la mquina destino. En la primera etapa conocida
como generacin de cdigo intermedio se genera una representacin intermedia del cdigo
fuente que se va a compilar. Esta representacin intermedia, independiente de la mquina para la
que se generar cdigo y del lenguaje fuente, ser la entrada del mdulo generador de cdigo
encargado de realizar la segunda etapa de traduccin. Esta tercera opcin es la que vamos a
estudiar con ms detalle a lo largo de este captulo.
Un cdigo intermedio es una estructura de cdigo cuya complejidad est entre el cdigo
fuente en el lenguaje de alto nivel y el cdigo mquina. Este cdigo intermedio puede ser
considerado como la interfaz entre el generador de cdigo (back-end) y las fases anteriores del
compilador (front-end). Su utilizacin presenta algunas ventajas frente a la generacin directa
de un cdigo mquina:
Se facilita la reutilizacin de toda la etapa inicial del compilador (front-end) para la
construccin de compiladores de un mismo lenguaje fuente para distintas mquinas.
(Fig. 2.1), y de toda la etapa final para construccin de compiladores de otros
lenguajes fuente sobre la misma plataforma.
Se puede aplicar a la representacin intermedia un optimizador de cdigo
independiente de la mquina.
Generacin de cdigo intermedio

4
Facilita la divisin en fases del proyecto: Permite abstraerse de los detalles propios de
la mquina destino en el desarrollo de la etapa inicial del compilador y de los propios
del lenguaje fuente en el desarrollo de la etapa final.
Fortran
Pascal
C
C++
Sparc
PowerPC
x86
ARM
Fortran
Pascal
C
C++
Sparc
PowerPC
x86
ARM
Representacin
Intermedia
(a) (b)

Figura 2.1. Compiladores para 4 lenguajes y 4 mquinas sin (a) y con (b) utilizacin de un cdigo intermedio.
Una buena representacin intermedia debe cumplir las siguientes propiedades:
Debe ser sencilla de generar y manipular.
Debe ser adecuada para permitir su traduccin al cdigo mquina de todas las
mquinas-destino deseadas.
Cada construccin debe tener un significado claro y simple que facilite la
implementacin del mdulo optimizador.
El cdigo generado por un compilador de Java, conocido como bytecode, puede considerarse
como un ejemplo de cdigo intermedio con la caracterstica peculiar de que que posteriormente
es ejecutado en la mquina virtual.
1.1. Tipos de representaciones intermedias
Hay distintos tipos de representacin intermedia. En el captulo 10 de [Tremblay, 85] puede
encontrarse una explicacin ms extensa las formas de representacin intermedias que se
presentan a continuacin.
Notacin postfija
Notacin sencilla empleada en mquinas de pila donde un operador se coloca a continuacin
de sus operandos. Por ejemplo, la instruccin de asignacin x := a+b+(c*d) quedara en notacin
postfija como: x ab+cd*+ :=
Este tipo de representacin intermedia es poco adecuada para la fase de optimizacin y es
difcil de emplear para representar estructuras de control de flujo e instrucciones de seleccin.
rbol de sintaxis abstracta
Un rbol de sintaxis abstracta (Abstract Sintax Tree o AST) no es ms que un rbol en el
que un nodo interior representa un operador, y donde sus operandos sern sus descendientes
Generacin de cdigo intermedio
5
directos. En la Fig. 2.2 se puede observar como queda un rbol de sintaxis abstracta para la
asignacin x:= (a+b*c) / d.

Figura 2.2. rbol de sintaxis abstracta para la instruccin x:= (a+b*c) / d.
Una variante de los rboles de sintaxis abstracta son los grafos dirigidos acclicos (GDA). La
principal diferencia con los rboles de sintaxis abstracta es que en los primeros se permite que un
nodo tenga ms de un padre. Este tipo de representacin facilita el anlisis del cdigo y su
optimizacin, por lo que es muy empleada en compiladores optimizadores.
Cdigo de tres direcciones (cuartetos)
Representacin intermedia en la que las instrucciones constan de un operador y tres
direcciones: dos para los operandos y una tercera para el resultado. Las instrucciones tendrn la
forma genrica
<operador> <op1> <op2> <resultado>
Por ejemplo, la instruccin de asignacin x := (a+b*c)/d se podra representar mediante una
secuencia de instrucciones en un cdigo de tres direcciones como
Operador op1 op2 res
(1) MULT b c t1
(2) SUMA a t1 t2
(3) DIV t2 d t3
(4) ASIGNA t3 x

Un cdigo de tres direcciones no es ms que una representacin lineal de un rbol de sintaxis
abstracta o de un GDA en el que se ha empleado una variable temporal para representar los
valores de los nodos interiores.
:=
x /
+ d
a *
b c
Generacin de cdigo intermedio

6
Cdigo de dos direcciones (tercetos)
En un cdigo de tres direcciones se suele emplear un gran nmero de variables auxiliares
(temporales) para almacenar los resultados parciales durante la evaluacin de una expresin. Un
cdigo de dos direcciones evita este problema permitiendo que los operandos que aparecen en
una instruccin sean apuntadores a las instrucciones cuyo resultado se desea emplear.
La forma general de una instruccin de dos direcciones es
<op> <operando1> <operando2>
El mismo ejemplo de instruccin de asignacin que hemos vistos representada mediante un
cdigo de tres direcciones, x := (a+b*c)/d se podra representar mediante un cdigo de dos
direcciones como
Operador op1 op2
(1) MULT b c
(2) SUMA a (1)
(3) DIV (2) d
(4) ASIGNA (3) x
Donde (1), (2) y (3) representan punteros a las instrucciones de cdigo dos direcciones 1, 2 3
respectivamente.
La principal ventaja del cdigo de dos direcciones frente al de tres es el ahorro de variables
temporales.
1.2. Instrucciones del cdigo de tres direcciones
Para este captulo hemos escogido como representacin intermedia un cdigo de tres
direcciones. Se muestran a continuacin los tipos de instrucciones de este cdigo y la forma
general que tendrn. En la mayora de los casos, los operadores podrn ser constantes,
direcciones de memoria donde se encuentra el valor a usar, o directamente direcciones de
memoria.
Asignacin
x := y op z
Donde op es una operador aritmtico.
x := op z
Siendo op un operador unario.
x := z
Salto incondicional
Generacin de cdigo intermedio
7
goto E
Donde E es la etiqueta (representada por un nmero) de la instruccin de cdigo
intermedio a la que se saltar.
Salto condicional
if x op y goto E
Siendo op un operador lgico binario. Si se cumple la relacin se saltar a la instruccin
etiquetada E.
Pila de activacin
push x
Apila x en la pila de activacin.
pop
Devuelve el valor que se desapila.
Llamada y retorno de subprograma
call E
Salta a la instruccin etiquetada E.
ret
Finaliza el subprograma y salta a la direccin que se encuentra en la cima de la pila de
activacin.
Asignaciones relativas
a [i] := x
x quedar almacenada i posiciones ms all de la direccin base a.
x := a[i]
Asigna a x el valor de la posicin que se encuentra i unidades ms all de la posicin base
a.
Acceso a la pila de activacin
Acceso en las instrucciones de asignacin al frame pointer (FP) y al tope de la pila (TOP).
Generacin de cdigo intermedio

8
Generacin de etiquetas
Los destinos de los saltos se indican mediante etiquetas. Al definir el cdigo intermedio
podemos elegir entre dos formas de generar estas etiquetas:
Generacin explcita de etiquetas: Cada vez que se desee poner una etiqueta a una
instruccin de cdigo intermedio se debe crear y emitir una etiqueta que tendr la forma:
<nombre_etiqueta> :
Esta forma es la usada habitualmente por los lenguajes ensambladores. En el ejercicio
8.20 se puede ver un ejemplo de utilizacin de este tipo de etiquetas.
Generacin implcita de etiquetas: Podemos suponer que cada instruccin de cdigo
intermedio generada tendr implcitamente una etiqueta que se corresponder con un
nmero entero. Este nmero se corresponde con el nmero de orden de la instruccin
dentro de programa. Esta forma es empleada en algunos lenguajes de alto nivel como
Basic, que comienza cada lnea con un nmero que representa la etiqueta de la
instruccin.
El cdigo intermedio que se emplea en este captulo utiliza etiquetas implcitas.
1.3. Generacin de cdigo intermedio mediante una gramtica de atributos
En temas anteriores se ha mostrado la utilizacin de las gramticas atribuidas como
formalismo para la especificacin semntica. En este tema se seguirn empleando las gramticas
atribuidas, pero sus acciones generan cdigo intermedio de tres direcciones. Para ello vamos a
emplear un procedimiento llamado emite que recibir como parmetros una instruccin de
cdigo intermedio y sus argumentos. Este procedimiento se encargar de almacenar
secuencialmente las instrucciones en una estructura intermedia (que podra ser un fichero o un
vector de instrucciones de cdigo intermedio). De esta forma, como resultado colateral de la
evaluacin de la gramtica, en la estructura intermedia empleada por emite, tendremos toda la
secuencia de instrucciones de cdigo intermedio generadas, las cuales forman el programa en
cdigo intermedio equivalente al programa fuente. Este programa en cdigo intermedio tendr
todas sus instrucciones etiquetadas con un nmero entero: el nmero de instruccin que ser
generado automticamente por el procedimiento emite.
Las expresiones que aparezcan entrecomilladas en la llamada al procedimiento emite, se
tomarn literalmente, mientras que el resto de expresiones se evaluarn antes de generar la
instruccin de cdigo intermedio.
Generacin de cdigo intermedio
9
Ejemplo 2.1.-
emite (x := 5 + 9)
emite (x := 5 + 9)
La primera llamada al procedimiento emite generar la instruccin de cdigo tres direcciones
correspondiente a la asignacin en la posicin x del resultado de sumar las constantes 5 y 9 (se
emite una instruccin de suma, es decir, la suma se realizar en tiempo de ejecucin). En cambio
la segunda llamada al procedimiento emite generar una instruccin que almacenar en la
posicin x el valor 14 (se emite una instruccin de asignacin, la suma se ha realizado en tiempo
de compilacin).
En las gramticas atribuidas que construyamos para generar cdigo intermedio utilizaremos
la siguiente notacin:
id.nom: Atributo asociado el smbolo lxico identificador que representa su lexema (nombre).
Su valor es devuelto por el analizador lxico. Este nombre nos permitir buscar la posicin en la
tabla de smbolos (TDS) donde se encuentra la informacin del identificador.
id.pos: Atributo del smbolo lxico que representa la posicin de memoria que contendr
durante la ejecucin el valor de la variable representada por el identificador. Se le asigna a la
variable cuando se declara, se almacena en la TDS y puede ser consultado mediante la funcin
BuscaPos(...). En un lenguaje con estructura de bloques esta posicin suele estar representada
por el par (nivel, desplazamiento). Cuando otros smbolos de la gramtica tengan un atributo con
el mismo (.pos) nombre tendrn el mismo significado.
id.tipo: Atributo que representar la expresin de tipo asignada al identificador. Est
almacenado en la TDS y se puede consultar mediante la funcin BuscaTipo(...). Cuando otros
smbolos de la gramtica tengan un atributo con el mismo nombre tendrn el mismo significado.
num.val: Atributo asociado al smbolo lxico constante numrica (num) que representa su
valor. Es devuelto por el analizador lxico. Cuando otros smbolos de la gramtica tengan un
atributo con el mismo nombre tendrn el mismo significado.
Para simplificar los esquemas de traduccin dirigidos por la sintaxis, nos vamos a permitir
emplear en las acciones semnticas variables globales. Estas variables globales podrn ser
accedidas desde cualquier accin semntica, es decir, se correspondern con variables globales
del cdigo fuente del compilador desarrollado. Para distinguirlas, aparecern siempre en
maysculas. Si en alguna accin semntica aparece una variable en minsculas se tratar de una
variable local asociada al smbolo no-terminal del lado izquierdo de la produccin en la que
aparece.
Generacin de cdigo intermedio

10
SIGINST: Variable global del compilador que estamos construyendo que representa el
nmero de la SIGuiente INSTruccin que se va a generar. Esta variable es inicializada a 0 y el
procedimiento emite se encarga de incrementarla automticamente cada vez que se emite una
instruccin.
Dada la siguiente gramtica que representa una instruccin de asignacin de un lenguaje de
alto nivel similar a C
Asig ! id = E
E ! E + E
E ! id
podemos construir un esquema de traduccin dirigido por la sintaxis (ETDS) que genere
cdigo de tres direcciones para instrucciones de asignacin usando el procedimiento emite:

Asig ! id = E { Asig.pos := BuscaPos ( id.nom ) ;
emite ( Asig.pos := E.pos ); }
E ! E1 + E2 { E.pos := CrearVarTemp() ;
emite ( E.pos := E1.pos + E2.pos ) }
E ! id { E.pos := BuscaPos (id.nom ) }
Veamos cada una de las acciones semnticas asociadas a estas producciones.

Asig ! id = E { Asig.pos := BuscaPos ( id.nom )
;
emite ( Asig.pos := E.pos ) }
En el ETDS (esquema de traduccin dirigido por la sintaxis) anterior se puede observar que
no aparecen acciones semnticas necesarias para realizar las comprobaciones semnticas. Esto es
debido a que este captulo se centra nicamente en la generacin de cdigo intermedio.
Se puede observar como en la primera accin semntica se realiza una llamada a la funcin
BuscaPos. La funcin BuscaPos recibe como argumento el lexema (nombre) del identificador,
busca la entrada del identificador en la TDS y devuelve la posicin de memoria que se ha
asignado a dicho identificador. Esta posicin de memoria en un lenguaje con estructura de
bloques ser habitualmente el nivel de anidamiento (o contexto) del identificador y su
desplazamiento relativo.
La siguiente accin semntica es una llamada al procedimiento emite. ste emitir una
instruccin en cdigo de tres direcciones que asignar en la posicin del identificador id el
contenido de la posicin de memoria representada por E.pos. Tambin se puede observar que la
accin semntica devuelve en el atributo sintetizado Asig.pos la posicin de memoria donde
Generacin de cdigo intermedio
11
estar en tiempo de ejecucin el valor de la variable id.nom. Esto se hace porque en C una
instruccin de asignacin debe devolver el valor asignado a la variable del lado izquierdo de la
asignacin. La utilidad de este atributo sintetizado se puede observar si aadimos a la gramtica
anterior la produccin
E ! Asig { E.pos :=Asig.pos }
donde se puede observar que una expresin puede ser una asignacin.
La siguiente produccin del ETDS es:

E ! E1 + E2 { E.pos := CrearVarTemp() ;
emite ( E.pos := E1.pos + E2.pos ) }
La primera accin de esta produccin realiza una llamada a la funcin CrearVarTemp(). Est
funcin devolver la direccin de la primera posicin de memoria libre (no asignada) dentro del
rea de datos del bloque que se est compilando. En esa posicin de memoria se almacenar el
valor de una variable temporal (de ah el nombre de la funcin).
La segunda accin emite una instruccin de cdigo de tres direcciones. Esta instruccin se
almacenar en la estructura intermedia empleada por emite para guardar el cdigo intermedio.
Cuando en tiempo de ejecucin se ejecute la instruccin, se asignar a la posicin de memoria
representada por E.pos (la posicin que devolvi CrearVarTemp) el resultado de sumar el
contenido de las posiciones de memoria representadas por E1.pos y E2.pos. Podemos observar
que E.pos es un atributo sintetizado que toma valor en esta produccin mientras que E1.pos y
E2.pos son dos atributos sintetizados cuyo valor se usa en esta produccin.

E ! id { E.pos := BuscaPos (id.nom ) }
La nica accin semntica asociada a esta produccin se encarga de dar al atributo E.pos la
posicin de memoria asignada al identificador id. Para ello se realiza un llamada a la funcin
BuscaPos que recibe como argumento el lexema del identificador (id.nom), lo busca en la tabla
de smbolos y devuelve la posicin de memoria que se le adjudic en la fase de asignacin de
memoria.
Ejemplo:
Veamos el comportamiento de este ETDS mediante la construccin del rbol anotado
correspondiente a la cadena a = b + c (Fig. 2.3). Suponemos que en la TDS tenemos la
informacin asociada a cada identificador que aparece en la Fig. 2.3.

Generacin de cdigo intermedio

12
TDS
Nom tipo posicin [nivel, desp]
a tentero [0,24]
b tentero [0,26]
c tentero [0,28]





Figura 2.3. rbol anotado y cdigo
intermedio generado para la cadena
a=b+c.
Para que resulte ms cmodo de leer el cdigo intermedio, en lugar de poner las posiciones
de memoria, en el resto de este captulo se utilizar el nombre de la variable a la que
corresponde. En el caso de las variables temporales, su nombre comenzar por la letra minscula
t seguida de un nmero entero que indicar el orden en el que ha sido generada: t1, t2, En la
Fig. 2.3 se puede observar como al llamar a la funcin CrearVarTemp(), sta ha devuelto como
posicin de memoria la primera posicin libre dentro del rea de datos del bloque para el que se
estaba generando cdigo (nivel 0, desplazamiento 30). Como sta es la primera variable temporal
que se crea se le ha dado el nombre t1. De esta forma el cdigo generado anteriormente puede
representarse para mayor claridad como:

(1) t1 := b + c
(2) a := t1
Veamos a continuacin como se puede extender el ETDS anterior para generar cdigo
tambin para otras expresiones aritmticas sencillas.

Instruc
id.pos=[0,24] = E.pos = [0,30]
+ E.pos = [0,28] E.pos = [0,26]
id.pos=[0,26] id.pos=[0,28]

Cdigo tres direcciones generado
(1) [0,30] := [0,26] + [0,28]
(2) [0,24] := [0,30]

Generacin de cdigo intermedio
13

E ! E1 * E2 { E.pos := CrearVarTemp() ;
emite ( E.pos := E1.pos * E2.pos ) }
E ! num { E.pos := CrearVarTemp() ;
emite ( E.pos := num.val ) }
E ! ( E1 ) { E.pos := E1.pos }
E ! - E1 { E.pos := CrearVarTemp() ;
emite ( E.pos := - E1.pos) }
Las acciones semnticas de la primera produccin son semejantes a las que aparecan en la
produccin que representaba la suma de expresiones, pero en este caso se genera una instruccin
de cdigo intermedio de multiplicacin. En la segunda produccin podemos observar que cuando
la expresin es una constante numrica se ha decidido crear una variable temporal y generar una
instruccin de cdigo intermedio que asigne en la posicin de la variable temporal el valor de la
constante numrica (num.val) que proporciona el analizador lxico. Una opcin ms adecuada
habra sido que el no-terminal E devolviese el valor de la constante numrica, lo que habra
evitado la creacin de una variable temporal. Sin embargo, esta segunda opcin habra obligado
a que el no-terminal E, adems del atributo .pos tuviese al menos otro atributo para devolver
valores constantes, lo que obligara a aadir ms acciones semnticas a todas las producciones
del no-terminal E. Para simplificar los esquemas de traduccin hemos elegido la primera opcin.
Hay que tener en cuenta que esta eleccin no afectar a la calidad del cdigo finalmente
generado porque este tipo de variables temporales son fcilmente eliminadas durante la fase de
optimizacin de cdigo intermedio.
En la tercera produccin, una expresin (E) se reescribe como una expresin entre parntesis
(E1). Puesto que el valor de una expresin entre parntesis es el mismo de la expresin sin
parntesis, basta con hacer que el atributo E.pos tome el mismo valor del atributo E1.pos. De esta
manera los dos atributos representan la misma posicin de memoria (y por lo tanto el mismo
valor de la expresin).
Finalmente, en la ltima expresin observamos que E se reescribe como una expresin
cambiada de signo. Este caso es diferente del anterior, puesto que la expresin representada por
E no tomar el mismo valor que E1, por lo tanto es necesario utilizar una nueva posicin de
memoria para almacenar el nuevo valor.
Ejercicio
Construye una gramtica no-ambigua equivalente a la anterior. A continuacin asocia a
cada produccin las acciones semnticas necesarias para generar el cdigo intermedio
correspondiente.
Generacin de cdigo intermedio

14
2. Acceso a mi embros de una estructura y el ementos de un
array
2.1. Acceso a miembros de una estructura
El acceso a los miembros de un estructura en C depende de la informacin que se almacene
en la TDS sobre la posicin de los miembros. La forma habitual consiste en almacenar, junto a
cada miembro, su desplazamiento con respecto al comienzo del rea de memoria asignada a esa
estructura (Fig. 2.4).
Ejemplo 2.2.- Dada la definicin de las variables a y b de tipo estructura en el lenguaje C

struct ej {
int c1 ;
float c2 ;
}a, b;
La TDS quedara:
TDS
nom tipo posicin ref
a testructura 0 , 124
b testructura 0 , 130
Figura 2.4. Asignacin de memoria en la TDS para los miembros de una estructura.
De esta forma, en la entrada en la TDS de cada miembro de un tipo de estructura concreta se
almacenar el mismo desplazamiento independientemente de que hayan declaradas ms de una
variable de ese tipo. Lo nico que cambiar ser la direccin base de cada variable de ese tipo de
estructura. Evidentemente antes de generar cdigo intermedio para acceder a un miembro de una
estructura ser necesario sumar a la direccin base de la variable estructura, el desplazamiento
asignado al miembro. En la Fig. 2.5 se muestra como quedara un ETDS para acceder a los
miembros de una estructura de esta manera.
Se ha usado la funcin EsMiembro(id1.nom, id2.nom) que devolver el valor TRUE si el
nombre id2.nom es un miembro de la estructura de nombre id1.nom. La funcin
BuscaPos(id1.nom) devuelve la posicin de memoria base a partir de la cual se encontrarn en
tiempo de ejecucin los miembros de la estructura id1.nom. La llamada a
BuscaPosMiembro(id1.nom, id2.nom) devolver el desplazamiento relativo del miembro a partir
de la posicin de memoria base de la estructura.

TALLA_REAL = 4
TALLA_ENTERO = 2

Tabla de miembros
nom tipo posicin
c1 tinteger 0
c2 treal 2

Generacin de cdigo intermedio
15
Inst_simple ! id1 . id2 = E

{ si BuscaTipo (id1.nom) <> testructura ent MemError();
sino base := BuscaPos (id1.nom) ;
si no EsMiembro (id1.nom, id2.nom) ent MemError()
sino desp_miembro:=BuscaPosMiembro(id1.nom, id2.nom);
pos := base + desp_miembro ;
emite ( pos := E.pos ) }
Figura 2.5. ETDS Para el acceso a los miembros de una estructura.
2.2. Acceso a elementos de un array
En los lenguajes de alto nivel podemos ver que frecuentemente se permite definir arrays de
varias dimensiones (como en Pascal o C), con un lmite inferior (Pascal) y superior (Pascal y C)
definido para cada una de las dimensiones. En cambio, en el cdigo intermedio definido solo
disponemos de instrucciones de asignacin con un modo de direccionamiento relativo: de
z:=a[x] (en la posicin z se almacena el valor de la posicin resultante de sumar a la
direccin base a el contenido de la posicin x) y a[x]:=z. Esto obliga a realizar proceso de
traduccin que requiere el clculo de la posicin de memoria que ocupar en tiempo de ejecucin
cada elemento del array definido en el programa fuente.
2.2.1. Acceso a los elementos de un array multidimensional en Pascal
Una forma bastante frecuente y cmoda de almacenar las matrices consiste en almacenar
todos sus elementos en posiciones consecutivas de memoria. Con esta representacin, cada vez
que nos encontremos en el lenguaje de alto nivel con una expresin donde aparezca un elemento
de una matriz, ser necesario calcular el desplazamiento que hay que sumar a la direccin base
de la matriz para acceder al elemento indicado. Veamos como se realiza este clculo en el caso
en el que se pueden definir lmites inferiores y superiores (Pascal).
Si suponemos la declaracin de una variable A de tipo vector (matriz de una dimensin) en
Pascal:
A: array [inf..sup] of integer ;
y se desea acceder al elemento A[i], ste se encontrar en la posicin
base +(i - inf) * Talla
donde
base es la direccin base donde se encuentra el primer elemento del vector,
inf es el lmite inferior de vector, y
Generacin de cdigo intermedio

16
Talla es el nmero deposiciones de memoria que ocupa cada elemento del vector
(dependiente del tipo de elementos que contiene el vector).
De igual forma, si se define una matriz de dos dimensiones:
A: array [inf1..sup1, inf2..sup2] of integer ;
la frmula para acceder a un elemento A[i1,i2] sera:
base +((i1 inf1) * n2 +(i2-inf2) ) *Talla
donde n2 es el nmero de elementos de la segunda dimensin de la matriz (n2 = sup2
inf2+1)
que puede quedar como:
base +( (i1*n2 +i2) (inf1*n2 + inf2) )*Talla
(inf1* n2+inf2) puede ser calculado en tiempo de compilacin, y recibe el nombre de
desplazamiento inicial de la matriz. Este valor, puesto que no depende del elemento de la matriz
al que se quiera acceder, puede ser almacenado en la TDS. En cambio, (i1*n2+i2) tendr que ser
calculado en tiempo de ejecucin y por lo tanto habr que generar cdigo para realizar este
clculo.
En general, dada la declaracin de una matriz n-dimensional:
A: array [inf1..sup1, inf2..sup2, ... infn..supn] of integer ;
la frmula para acceder a un elemento A[i1,i2,...in ] quedar como:
base +( (((i1*n2+i2)*n3+i3 )*nn+in) (((inf1*n2+inf2)*n3+inf3)*nn+infn) ) * Talla
donde (((inf1*n2+inf2)*n3+inf3)*nn+infn) es el desplazamiento inicial de la matriz.
Puesto que el acceso a un elemento de una matriz puede aparecer en el lado derecho o
izquierdo de una asignacin, las producciones que definen la sintaxis de este acceso aparecern
en dos lugares distintos de la gramtica. Como el cdigo generado para los dos casos es
prcticamente el mismo, se muestra nicamente uno de los casos (cuando el acceso al elemento
de la matriz aparece en el lado izquierdo de la asignacin):
Inst_simple ! id [ Lista_indices ] := E
Lista_indices ! E Resto_LI
Resto_LI ! , E Resto_LI
| "
Generacin de cdigo intermedio
17
En la Fig. 2.6 se muestra un ETDS que genera cdigo intermedio para el acceso a los
elementos de una matriz n-dimensional en Pascal.

Inst_simple -> id { Lista_indices.nom := id.nom }
[ Lista_indices ] := { temp := Lista_indices.pos ;
emite (temp := temp Desp_inicial(id.nom)) ;
emite (temp := temp * Talla (id.nom)) }
E { pos := BuscaPos (id.nom) ;
emite ( pos [ temp ] := E.pos }
Lista_indices ! E { temp := CrearVarTemp()
emite (temp := E.pos); Resto_LI.ndim := 1;
Resto_LI.temp := temp ; Resto_LI.nom := Lista_indices.nom }
Resto_LI { Lista_indices.pos := Resto_LI.pos }
Resto_LI ! , E { Resto_LI.ndim := Resto_LI.ndim + 1;
emite (Resto_LI.temp :=
Resto_LI.temp*Num_elementos(Resto_LI.nom, Resto_LI.ndim));
emite (Resto_LI.temp := Resto_LI.temp + E.pos)
Resto_LI1.ndim := Resto_LI.ndim ;
Resto_LI1.temp := Resto_LI.temp ;
Resto_LI1.nom := Resto_LI.nom ; }
Resto_LI1 Resto_LI1 { Resto_LI.pos:= Resto_LI1 pos }
Resto_LI ! " { Resto_LI.pos:= Resto_LI.temp }
Figura 2.6. ETDS para el acceso a los elementos de un array en Pascal.
La funcin Desp_inicial(R_Inst_simple.nom) devuelve el desplazamiento inicial de la matriz
de nombre R_Inst_simple.nom que se guard en la TDS cuando se declar la matriz. De igual
forma, la funcin Talla(R_Inst_simple.nom), devuelve el tamao de cada elemento de la matriz,
y Num_elemen(Lista_indices.nom,n_dim) devuelve el nmero de elementos de la dimensin
n_dim de la matriz Lista_indices.nom.
Ejemplo 2.3.- Veamos qu cdigo generar este ETDS para el acceso a un elemento de una
matriz bidimensional que se define en el siguiente trozo de cdigo fuente en Pascal:

var
...
A: array [2..11,1..20] of real ;
x,y: integer ; z: real;
begin
...
A[x,y] := z
...

Generacin de cdigo intermedio

18
TDS
nom tipo posicin tipo_elem desp_ini ref
A tarray 0, 140 treal 41
x tentero 0, 940 -
y tentero 0, 942 -
z treal 0, 944 -


Figura 2.7. Contenido de la TDS para el Ejemplo 2.3.
Suponiendo que el contenido en la TDS es el de la Fig. 2.7 se generar el siguiente cdigo
intermedio:

(100) t1 := x
(101) t1 := t1 * 20
(102) t1 := t1 + y
(103) t1 := t1 41
(104) t1 := t1 * 4
(105) A [t1] := z
2.2.2. Acceso a los elementos de un array multidimensional en C
La generacin de cdigo intermedio para acceder a arrays multidimensionales en C es ms
sencilla que la del caso de Pascal, ya que en C todos los arrays comienzan en la posicin 0. Se
trata por lo tanto de un caso particular del visto para Pascal.
En general, dada la declaracin de un array n-dimensional en C
int A[n1][n2]... [nn];
la frmula para acceder al elemento A[i1][i2]...[in] quedara como:
base +(((i1*n2+i2)*n3+i3 )*nn+in) * Talla
donde ni es el nmero de elementos de la i-sima dimensin.
Se puede construir un ETDS que genere cdigo para el acceso a los elementos de una matriz
n-dimensional en Pascal tal y como aparece en la Fig. 2.8.

Tabla de arrays
n_dim lim_inf lim-sup
1 2 11
2 1 20

TALLA_REAL = 4
TALLA_ENTERO = 2 desp_ini = (inf1 * n2 + inf2) = 2*20+1 =
41
Generacin de cdigo intermedio
19
Inst_simple -> id { LI.nom := id.nom }
LI = E { emite (LI.pos := LI.pos * Talla (id.nom)) ;
pos := BuscaPos (id.nom) ;
emite ( pos [ LI.pos ] := E.pos ; }
LI ! [ E ] { LI.pos := CrearVarTemp() ;
emite (LI.pos := E.pos); LI.ndim := 1; }
LI ! { LI1.nom := LI.nom ; }
LI1 [ E ] Resto_LI1 { LI.ndim := LI1.ndim + 1; LI.pos := LI1.pos ;
emite (LI.pos := LI.pos * Num_elementos(LI.nom, LI.ndim)) ;
emite (LI.pos := LI.pos + E.pos) ; }
Figura 2.6. ETDS para el acceso a los elementos de un array en C.
3. Expresi ones l gi cas e i nstrucci ones de control de fl ujo
En un lenguaje de alto nivel las expresiones de tipo lgico se emplean principalmente como
expresiones condicionales en instrucciones de control de flujo. Debido a esto hay una
dependencia elevada entre la forma de representar los valores de las expresiones lgicas y el
cdigo que se debe generar para traducir las instrucciones de control de flujo. Por esta razn
vamos a ver en la misma seccin la representacin de los valores lgicos y la traduccin de
instrucciones de control de flujo.
3.1. Variables y expresiones lgicas
Cualquier variable necesita una posicin de memoria en la que, durante la ejecucin del
cdigo generado, se almacene su valor. Cuando se trata de una variable de tipo lgico o boolena,
para representar su valor tambin se necesita una posicin de memoria (bastara un bit!) para
almacenar su valor. Como el cdigo intermedio definido en este captulo no dispone del tipo
lgico ni el tipo bit, en la posicin de memoria de una variable lgica se almacenar un entero
que representar su valor. Para esta representacin numrica se emplear el mismo criterio
seguido en el lenguaje C
1
de que un cero representa el valor de verdad falso, mientras que
cualquier valor distinto de cero representa el valor de verdad cierto.
Pero adems de variables lgicas, en los lenguajes de alto nivel aparecen otro tipo de
expresiones lgicas, conteniendo comparaciones y/o conectivas lgicas. Para representar el valor
de una expresin lgica se pueden emplear dos mtodos: la representacin numrica y la
representacin por control de flujo.

1
El tipo bool (lgico) no aparece en el lenguaje C hasta el estndar C99 (a travs de <stdbool.h>) y no todos los
compiladores lo soportan. Por esta razn, las instrucciones de control de flujo en C utilizan expresiones enteras (0 es
falso y distinto de cero es cierto) para decidir el flujo.
Generacin de cdigo intermedio

20
En la representacin numrica de una expresin lgica toda expresin lgica tendr asignada
una posicin de memoria donde se almacenar su valor de verdad: un entero igual a 0 para
falso o distinto de cero para cierto. Por el contrario, en la representacin por control de flujo
no se emplea una posicin de memoria para representar el valor de verdad de la expresin. Su
valor vendr determinado implcitamente por la instruccin de cdigo intermedio que se ejecute.
Tal y como se afirma en [AHOA90], ninguno de los dos mtodos es siempre mejor que el otro.
En este apartado se muestran las dos formas de representacin.
3.2. Representacin numrica
En la representacin numrica a cada expresin lgica se le asigna una posicin de memoria
donde se almacena un valor numrico que indica el valor de verdad de la expresin. Si el cdigo
intermedio permite emplear valores y operadores binarios bastara con usar un 0 para representar
el valor falso y un 1 para el valor cierto. Si, como es nuestro caso, el cdigo intermedio no
permite el empleo de valores binarios, se puede usar un nmero entero con un valor de cero para
representar el valor falso y un nmero distinto de cero para representar el valor cierto. Con esta
forma de representacin, la evaluacin de una expresin lgica se convierte en la evaluacin de
una expresin aritmtica.
En los siguientes ETDS se va a presentar una generacin de cdigo intermedio para el caso
en el que el lenguaje fuente permite la utilizacin de expresiones booleanas (como en Pascal) en
lugar de utilizar valores enteros (como en C). Como se ha comentado anteriormente, esto
obligar a realizar una traduccin entre la representacin del lenguaje fuente (booleanos) y la del
lenguaje intermedio (enteros).
Podemos escribir un ETDS para una sencilla gramtica que genere expresiones lgicas
similares a las de Pascal tal y como aparece en el Fig. 2.8.

E ! true { E.pos:= CrearVarTemp() ;
emite( E.pos := 1 ) }
E ! false { E.pos:= CrearVarTemp() ;
emite( E.pos := 0 ) }
E ! ( E1 ) { E.pos := E1.pos }
E ! id { E.pos := BuscaPos(id.nom) }
Figura 2.8. ETDS representacin numrica de expresiones lgicas.
Tal y como se puede apreciar en el ETDS anterior, cuando una expresin lgica sea la
constante TRUE o FALSE, basta con crear una nueva variable temporal y asignar en la posicin
de memoria correspondiente un 1 o un 0 respectivamente. En el caso de que la expresin lgica
sea una variable (id), al igual que ocurra en el caso de las expresiones aritmticas, basta con que
el atributo E.pos tome el valor de la posicin de memoria donde se almacena el valor de verdad
del identificador (devuelto por la funcin BuscaPos).
Generacin de cdigo intermedio
21
Para evaluar una expresin relacional, como a<5 hay que tener en cuenta que su valor de
verdad, en general, no se puede conocer en tiempo de compilacin. Por esta razn es necesario
generar cdigo de tres direcciones cuya ejecucin produzca como resultado la evaluacin de la
expresin relacional, asignando en la posicin de memoria reservada para la expresin un valor 0
o distinto de cero segn sea falsa o cierta la expresin, respectivamente.
Ejemplo
Para evaluar la expresin a<5, se puede generar la siguiente secuencia de cdigo de tres
direcciones:
(1) t1 := 1
(2) if a < 5 goto 4
(3) t1 := 0
(4) ...
Tal y como fcilmente se puede comprobar, la ejecucin del fragmento anterior de cdigo de
tres direcciones produce como resultado que si a < 5 se almacenar un 1 en la posicin de
memoria reservada para almacenar el valor de verdad de la expresin (en el ejemplo t1). En caso
contrario se almacenar un 0. El ETDS para generar la secuencia de cdigo intermedio anterior
es

E ! E
1
oprel E
2
{ E.pos := CrearVarTemp() ;
emite( E.pos := 1 ) ;
emite( if E
1
.pos oprel.op E
2
.pos goto SIGINST+ 2 ) ;
emite( E.pos := 0 ) }
En este ETDS puede verse la utilizacin del atributo oprel.op. Este atributo represente al
valor del operador relacional que aparece en el cdigo fuente que se est compilando: =, >,
>=, <, Tambin se puede observar la aparicin de una nueva variable global: SIGINST.
En el cdigo intermedio de este tipo de expresiones se debe generar una instruccin de salto
condicional que se salte la instruccin que le sigue. Para generar esta instruccin se debe conocer
cul es el nmero de la instruccin que se est generando. Con este fin, en el ETDS (y por lo
tanto en el cdigo fuente del compilador desarrollado) existe un contador del nmero de
instrucciones de cdigo intermedio generadas: SIGINST. Esta variable global del compilador es
actualizada de forma automtica por el procedimiento emite cada vez que se genera una
instruccin. De esta forma, si en el momento de llamar al procedimiento emite para generar la
instruccin de salto condicional if E
1
.pos oprel.op E
2
.pos goto SIGINST+ 2, la variable
SIGINST vale 15, se generar la instruccin (15) if pos
1
oprel pos
2
goto 17.
Cuando la expresin lgica incluye operadores lgicos and y or, si el cdigo intermedio
no dispone de estos operadores, como es nuestro caso, ser necesario buscar una equivalencia
con los operadores disponibles en el cdigo intermedio. En nuestro caso, podemos observar que
el operador lgico and puede implementarse como una operacin de multiplicacin entre
Generacin de cdigo intermedio

22
valores de verdad, y el operador or como una suma. De esta manera, podemos obtener el
ETDS:

E ! E
1
or E
2
{ E.pos:= CrearVarTemp() ;
emite( E.pos := E
1
.pos + E
2
.pos ) }
! E
1
and E
2
{ E.pos:= CrearVarTemp() ;
emite( E.pos := E
1
.pos * E
2
.pos ) }
Al generar cdigo intermedio de esta manera hay que tener en cuenta que, cuando se realice
una operacin or entre dos expresiones con el valor de verdad cierto, el resultado ser otra
expresin con el valor cierto pero representado con un valor entero distinto de 1. Esto
introduce un nuevo problema: En algn momento podra darse el caso de que el valor entero
sobrepase el rango vlido de los enteros, apareciendo enteros negativos. Esto a su vez puede
provocar que una operacin or entre dos expresiones ciertas representadas por valores enteros
iguales pero con signos distintos den como resultado el valor falso. As por ejemplo, si
consideramos dos expresiones booleanas con el valor cierto pero representadas
respectivamente por los valores enteros -5 y 5, la operacin or entre ellas (su suma) dar
como resultado 0 (valor falso). Esto es un error provocado por la forma en la que generamos
el cdigo y por lo tanto debe corregirse. Una posible forma de corregir este problema consiste en
asegurarse de que un valor cierto siempre se representa por el entero 1. Para ello
generaremos una instruccin que compruebe el valor entero despus de la operacin or. De
esta manera, el ETDS anterior quedara:
E ! E
1
or E
2
{ E.pos:= CrearVarTemp() ;
emite( E.pos := E
1
.pos + E
2
.pos )
emite( if E.pos <= 1 goto SIGINST+2 ) ;
emite( E.pos := 1)}
Para generar el cdigo correspondiente al operador lgico not, si no est disponible en el
cdigo intermedio, tal y como es nuestro caso, ser necesario generar una secuencia de
instrucciones cuya ejecucin produzcan el resultado equivalente. As por ejemplo, para obtener
en la posicin de memoria t1 el valor numrico de verdad de la expresin not a se puede
generar la secuencia de instrucciones de cdigo intermedio:
Generacin de cdigo intermedio
23
(1) t1 := 0
(2) if a <> 0 goto 4
(3) t1 := 1
(4) ...

El ETDS correspondiente quedar como aparece en la Fig. 2.9.

E ! E
1
or E
2
{ E.pos:= CrearVarTemp() ;
emite( E.pos := E
1
.pos + E
2
.pos )
emite( if E.pos <= 1 goto SIGINST+2 ) ;
emite( E.pos := 1)}
! E
1
and E
2
{ E.pos:= CrearVarTemp() ;
emite( E.pos := E
1
.pos * E
2
.pos ) }
! not E
1
{ E.pos:= CrearVarTemp() ;
emite( E.pos := 0 ) ;
emite( if E
1
.pos <> 0 goto SIGINST+2 ) ;
emite( E.pos := 1) }
Figura 2.9. ETDS operadores lgicos con representacin numrica.
Para ver un ejemplo de la utilizacin de las expresiones lgicas en las instrucciones de
control de flujo, se va a construir un ETDS que genere cdigo de tres direcciones para la
instruccin de do-while de C. Su sintaxis es
I ! do I1 while ( E )
El esquema del cdigo a generar se puede representar tal y como aparece en la Fig. 2.10. El
bloque I1 representa todas las instrucciones que se han generado en las producciones del no-
terminal I para el cuerpo del bucle. De igual forma, el bloque E representa todo el cdigo
intermedio emitido para la evaluacin de la expresin E.
I
1
E
if E.pos = 0 goto

Figura 2.10: Esquema de cdigo para un do-while con representacin numrica.
La ejecucin del cdigo intermedio generado para la evaluacin de la expresin lgica dejar,
tal y como se ha visto, en una posicin de memoria (E.pos) un valor 0 o distinto de 0 (1) segn
sea falsa o cierta la expresin. El cdigo que se genera para la instruccin do-while, saltar al
inicio del bucle si en esa posicin hay un nmero igual a 0. El ETDS quedar por lo tanto
Generacin de cdigo intermedio

24

I ! do
I1
while ( E )
{ I.inicio := SIGINST }

{ emite( if E.pos <> 0 goto I.inicio) }
Se puede observar que se ha utilizado el atributo I.inicio para guardar el valor de la variable
global SIGINST justo antes de I1. Este atributo almacenar el nmero de la primera instruccin
de cdigo intermedio generada en I1. Esta instruccin ser el destino del salto condicional
generado para ejecutar una nueva iteracin del bucle. Este ETDS emite nicamente una
instruccin, el salto que aparece al final del bucle, ya que las instrucciones del cuerpo del bucle
sern emitidas por las acciones semnticas de las producciones I y las correspondientes a la
evaluacin de la expresin lgica por las del no-terminal E.
De forma semejante se puede intentar construir una gramtica atribuida que genere cdigo de
tres direcciones para una instruccin while de C:

I! while
( E )
I1
{ I.inicio:= SIGINST }
{ emite( if E.pos =0 goto I.fin ) }
{ emite( goto I.inicio ) ;
I.fin := SIGINST }
Sin embargo, se puede observar que esta gramtica no es L-atribuida. Esto es debido a que en
la accin semntica de generacin de la instruccin de salto condicional { emite( if E.pos=0
goto I.fin ) } aparece el atributo I.fin que toma su valor en una accin que aparece a la derecha
de la accin semntica del emite. Esto significa que si se realiza una traduccin dirigida por la
sintaxis, en el momento en que se realiza la llamada a emite para generar la instruccin de salto
condicional, no se conoce todava el valor del atributo I.fin que debera contener el nmero de la
primera instruccin de cdigo intermedio generada despus del bucle (se trata de un argumento
de la llamada a emite cuyo valor no se conoce). Este problema de tener que generar una
instruccin antes de conocer todos sus argumentos se resolver en la seccin dedicada a las
referencias no satisfechas.
3.3. Representacin por control de flujo
En la representacin por control de flujo se considera la representacin de expresiones
lgicas dentro del contexto en el que ms frecuentemente aparecen: las instrucciones de control
del flujo. En una instruccin de control de flujo el valor de la expresin lgica se utiliza para
decidir a qu bloque de cdigo se debe saltar. El cdigo generado para una expresin lgica
consistir en la generacin de una instruccin de salto para el caso en el que la expresin sea
cierta y otra para el caso en el que la instruccin sea falsa. Veamos un ejemplo de utilizacin de
esta representacin en el contexto de un lenguaje de programacin de alto nivel similar a Pascal.
El cdigo generado para las constantes lgicas TRUE y FALSE quedara:

Generacin de cdigo intermedio
25
E ! true { emite( goto E.verdadero) }
E ! false { emite( goto E.falso) }
donde E.verdadero y E.falso son etiquetas que representan el nmero de la instruccin a la
que hay que saltar cuando la expresin es cierta o falsa respectivamente.
Considerando una representacin de los valores lgicos por control de flujo, un ETDS para la
instruccin repeat-until de Pascal podra ser:

I ! repeat
I1
until E
{ E.falso:= SIGINST }

{ E.verdadero := SIGINST) }
Se puede observar que en este ETDS no se ha generado ninguna instruccin. nicamente ha
sido necesario dar un valor a los atributos E.falso y E.verdadero. L instruccin de salto que
provocar que se vuelva al principio del bucle si la expresin E se avala a falso se ha generado
en las producciones para el no-terminal E.
Desgraciadamente en el momento de generar el cdigo para la expresin lgica no siempre se
conoce el valor de estas etiquetas. Este problema de tener que generar una instruccin antes de
conocer todos sus argumentos apareci tambin en la representacin numrica y se resolver en
la seccin dedicada a las referencias no satisfechas.
4. Referenci as no sati sfechas. Rel l eno por retroceso
4.1. Planteamiento del problema
En la seccin anterior se ha visto que frecuentemente se debe generar una instruccin de
cdigo de la que no se conoce el valor de todos sus argumentos. Una primera aproximacin para
solucionar este problema es realizar dos pasadas: En una primera pasada se generan las
instrucciones aunque algunas de ellas contengan referencias cuyo valor no se conoce todava.
Tras esta pasada, en la que se han generado todas las instrucciones, se realiza una segunda
pasada en la que se van sustituyendo las referencias por sus valores.
Una alternativa que permite solucionar el problema de las referencias no-satisfechas sin tener
que realizar una segunda pasada es la conocida como relleno por retroceso. Bsicamente esta
tcnica consiste en la generacin de cada instruccin aunque alguno de sus argumentos quede
incompleto. Cada vez que se genera una instruccin incompleta se guarda el nmero de la
instruccin incompleta en un atributo relacionado con al argumento cuyo valor no se conoce.
Cuando posteriormente, al seguir generando el resto de las instrucciones, se conozca el valor se
incorpora directamente a la instruccin que qued incompleta, quedando de esta manera
completada.
Generacin de cdigo intermedio

26
4.2. Relleno por retroceso
Para realizar la implementacin de esta tcnica se pueden definir tres funciones con el
siguiente perfil:
ptro CreaLans(E): Crea una lista que solo contiene un nmero de instruccin E a rellenar
posteriormente. Devuelve un puntero a dicha lista.
ptro CompletaLans( ptro, E ): Rellena todas las instrucciones incompletas, cuyo nmero est
contenido en la lista apuntada por ptro, con el valor de argumento E.
ptro FusionaLans (ptro, ptro): Concatena las listas apuntadas por sus dos argumentos y
devuelve un puntero a la nueva lista.
Veamos mediante un ejemplo cmo pueden utilizarse estas funciones para implementar la
tcnica de relleno por retroceso. Supongamos que en el momento de generar la instruccin de
salto incondicional de la lnea 100 no se conoce cul ser el nmero de la instruccin destino de
este salto.
100 goto
Se puede anotar en una lista, relacionada con el destino del salto, el nmero de la instruccin
generada que contiene este argumento no-satisfecho. Esto se hace mediante una llamada a la
funcin CreaLans(100). La lista ahora contendr el nmero de la instruccin 100: lista={100}

Se contina generando cdigo y, si se genera otra instruccin de salto incompleta (por
ejemplo la nmero 103) cuyo destino sea el mismo, se aade a la lista asociada a ese destino el
nmero de la nueva instruccin incompleta: lista={100, 103}.

101 ...
102 ...
103 if a>0 goto ---
Contina la generacin de cdigo intermedio y, en el momento en el que se conozca el valor
del argumento (por ejemplo el destino de los dos saltos podra ser la instruccin nmero 105), se
llama a la funcin CompletaLans(lista ,105) que se encargar de completar las instrucciones
100 y 103 con el valor 105. El cdigo del ejemplo quedar por tanto:
100 goto 105
101 ...
102 ...
103 if a>0 goto 105
104 ...
105 ...
En la seccin 3.1 se construy un ETDS para la instruccin while de C suponiendo que se
utilizaba una representacin numrica para las expresiones lgicas:

Generacin de cdigo intermedio
27
I! while
( E )
I1
{ I.inicio:= SIGINST }
{ emite( if E.pos =0 goto I.fin )
}
{ emite( goto I.inicio ) ;
I.fin := SIGINST }

En este ETDS ya aparece el problema de tener que generar una instruccin de salto
condicional en la que no se conoce el nmero de la instruccin destino. Ahora se puede resolver
este problema usando relleno por retroceso. Justo antes de generar la instruccin de salto se crea
una lista en la que se guarda el nmero de la instruccin que contiene la referencia no-satisfecha:
CreaLans(SIGINST). Cuando finalmente se conozca el destino del salto (la instruccin que se
genere justo despus de la ltima instruccin del bucle), se llamar a la funcin
CompletaLans(final, SIGINST) para completar la instruccin de salto condicional. El ETDS
quedar por tanto como aparece en la Fig. 2.11.

I! while
( E )

I1
{ Iinicio:= SIGINST }
{ I.final:= CreaLans(SIGINST) ;
emite( if E.pos =0 goto --- ) }
{ emite( goto I.inicio ) ;
CompletaLans(I.final, SIGINST) }
Figura 2.11. ETDS while con relleno por retroceso (representacin numrica de expresiones lgicas).
4.3 Representacin numrica de expresiones lgicas (con relleno por retroceso)
Usando relleno por retroceso se puede resolver tambin el problema de argumentos no
satisfechos que aparece al intentar generar cdigo para otras instrucciones de control de flujo en
C. Suponiendo que se emplea una representacin numrica de las expresiones lgicas, se puede
generar cdigo intermedio para una instruccin if-else de C mediante el siguiente ETDS:

I ! if E

I
1
else


I
2

{ I.falso:= CreaLans(SIGINST);
emite( if E.pos =0 goto --- ); }
{ I.fin := CreaLans( SIGINST) ;
emite( goto --- ) ;
CompletaLans(I.falso, SIGINST) }
{ CompletaLans (I.fin, SIGINST) }

En este ETDS, adems del salto al cdigo del else para el caso en que la expresin sea falsa,
se emite un salto emite( goto --- ) que garantiza que, tras la ejecucin del cdigo de I1 no se
Generacin de cdigo intermedio

28
ejecuta siempre el del I2. Las dos instrucciones de salto se generan de forma incompleta (falta el
destino de los saltos) y se completan posteriormente con las llamadas a CompletaLans(I.falso,
SIGINST) para aadir el destino del salto a I2 y con CompletaLans (I.fin, SIGINST) para
completar el salto emitido despus del cdigo de I1.
De forma similar, podemos construir un ETDS que genere cdigo intermedio para un bucle
for parecido al del lenguaje C:
I ! for ( I1 ;
E ;




I2 )

I
{ I.cond := SIGINST; }
{ I.fin := CreaLans (SIGINST);
emite( if E.pos =0 goto --- );
I.cuerpo := CreaLans (SIGINST);
emite( goto --- ) ;
I. incr := SIGINST ; }
{ emite(goto I.cond);
CompletaLans(I.cuerpo, SIGINST) ; }
{ emite(goto I.incr);
CompletaLans(I.fin, SIGINST) ;
}

4.4 Representacin de expresiones lgicas por control de flujo (con relleno por retroceso)
Usando relleno por retroceso podemos resolver el problema que apareci en el ejemplo de la
representacin de expresiones lgicas por control de flujo en Pascal. El ETDS para la evaluacin
de la expresin lgica (solo para el caso de las constantes TRUE y FALSE) quedara:

E ! True { E.listaverdad := CreaLans( SIGINST) ;
E.listafalso := nil }
emite( goto --- ) }
E ! False { E.listafalso := CreaLans( SIGINST) ;
E.listaverdad := nil ;
emite( goto --- ) }
Como se puede apreciar, en cada produccin se emite una instruccin de salto que queda
incompleta, pero se guarda una referencia a la instruccin en la lista E.listaverdad (para TRUE) o
E.listafalso (para FALSE). Estas instrucciones de salto incompletas se completarn cuando se
conozca el destino del salto. Por ejemplo, el ETDS para un repeat-until de Pascal quedara tal y
como aparece en la Fig. 2.12.

Generacin de cdigo intermedio
29
I! repeat
I1
until E
{ I.inicio:= SIGINST }

{ CompletaLans(E.listafalso, I.inicio);
CompletaLans(E.listaverdad, SIGINST) }
Figura 2.12. ETDS repeat-until con relleno por retroceso (representacin expresiones lgicas por control de flujo).
El ETDS para un do-while de C sera muy parecido, ya que bastara con intercambiar los
valores con los que se completan las listas de referencias no satisfechas .listaverdad y .listafalso:

I! do
I1
while (E)
{ inicio:= SIGINST }

{ CompletaLans(E.listaverdad, inicio);
CompletaLans(E.listafalso, SIGINST) }
Figura 2.13. ETDS do-while con relleno por retroceso (representacin expresiones lgicas por control de flujo).
Siguiendo esta tcnica se puede construir un ETDS que genere cdigo intermedio para la
evaluacin de expresiones lgicas e instrucciones de control de flujo empleando una
representacin de los valores lgicos mediante control de flujo, solucionando el problema de las
referencias no-satisfechas mediante relleno por retroceso.
Hemos visto que en la representacin de los valores lgicos mediante control de flujo se
generan instrucciones de salto de las que no se conoce a donde se debe saltar. Para solucionar
este problema, se genera la instruccin de salto sin especificar la direccin destino. Se anota el
nmero de la instruccin incompleta en una lista que se corresponde con el valor de verdad de la
expresin: E.lv para el valor verdadero y E.lf para el valor falso. De esta forma, E.lv (E.lf) ser
una lista que contendr los nmeros de las instrucciones de cdigo intermedio donde se ha
generado un salto a la direccin destino para el caso de que la expresin sea cierta (falsa).
Cuando se conozca la direccin destino correspondiente, se completarn las instrucciones
incompletas con el valor de la direccin. El ETDS para las expresiones lgicas empleando esta
tcnica quedar tal y como se muestra en la Fig. 2.14.
E ! E
1
or
E
2

{ CompletaLans( E
1
.lf,SIGINST) ;
E.lv := FusionaLans( E
1
.lv, E
2
.lv ) ;
E.lf := E
2
.lf }
E ! E
1
and
E
2

{ CompletaLans( E
1
.lv, SIGINST) ;
E.lv := E
2
.lv ;
E.lf := FusionaLans( E
1
.lf,E
2
.lf ) }
E ! not E
1
{ E.lv := E
1
.lf ;
E.lf := E
1
.lv }
E ! ( E
1
) { E.lv := E
1
.lv ;
Generacin de cdigo intermedio

30
E.lf := E
1
.lf }
E ! E
1
oprel E
2
{ E.lv := CreaLans( SIGINST) ;
emite( if E
1
.pos oprel.op E
2
.pos goto --- ) ;
E.lf := CreaLans( SIGINST ) ;
emite( goto --- ) }
E ! True { E.lf := nil ;
E.lv := CreaLans( SIGINST) ;
emite( goto --- ) }
E ! False { E.lv := nil ;
E.lf := CreaLans( SIGINST) ;
emite( goto --- ) }
E ! id { si BuscaTipo( id.nom ) = tlgico
ent E.lf := CreaLans( SIGINST)
emite( if id.pos = 0 goto --- ) ;
E.lv := CreaLans( SIGINST) ;
emite( goto --- ) }
Figura 2.14. ETDS expresiones lgicas con representacin por control de flujo y relleno por retroceso.
4.4.1. Cdigo en cortocircuito
Del ETDS de la Fig. 2.14 se puede destacar el tratamiento que han recibido los operadores
lgicos and y or. Para estos dos operadores se ha decidido generar cdigo en la forma
conocida como cortocircuito. Esto supone que no siempre se avaluarn todos los componentes
de la expresin lgica: se finalizar la evaluacin de la expresin tan pronto como se conozca su
valor de verdad. As por ejemplo la evaluacin de la expresin lgica
TRUE or (a<b) or (a=5)
no llegar hasta las dos ltimas subexpresiones, puesto que al evaluar la primera
subexpresin (la constante TRUE) ya se conoce el valor lgico de toda la expresin.
El cdigo intermedio que se genera realiza esta evaluacin en cortocircuito porque las acciones
semnticas de la produccin E ! E
1
or E
2
fusionan las listas de los atributos E
1
.lv y E
2
.lv. Lo
mismo se puede decir del operador and, solo que en este caso la evaluacin de la expresin
lgica se interrumpir en cuanto se evale una subexpresin cuyo valor sea FALSE.
4.4.2. Variables lgicas y representacin por control de flujo
Teniendo en cuenta que una variable siempre debe tener almacenado su valor en una posicin
de memoria, parece evidente que esto ser tambin cierto para las variables lgicas. Por esta
razn es necesario utilizar una representacin numrica para almacenar el valor de una variable
lgica. Si para representar los valores de expresiones lgicas tambin se utiliza una
representacin numrica no habr ningn problema, ya que en ambos casos se utiliza el mismo
tipo de representacin. En cambio, si se desea realizar una asignacin de una expresin lgica
Generacin de cdigo intermedio
31
cuya representacin es por control de flujo a una variable lgica (cuya representacin es
numrica), ser necesario realizar una conversin. Para realizar esta conversin es necesario
generar cdigo intermedio tal y como se muestra en el ETDS de la Fig. 2.15.

I ! id := E { id.pos := BuscaPos(id.nom) ;
si BuscaTipo( id.nom ) = tlgico
ent
CompletaLans( E.lf , SIGINST) ;
emite( id.pos := 0 ) ;
emite( goto SIGINST+ 2 ) ;
CompletaLans( E.lv, SIGINST) ;
emite ( id.pos := 1 ) ;
sino
emite ( id.pos := E.pos ) }
Figura 2.15. ETDS asignacin de valor a variable lgica.
4.4.3. Instrucciones de control de flujo
En el ETDS de la Fig. 2.15 puede apreciarse que el cdigo emitido para evaluar las
expresiones lgicas contiene instrucciones de salto cuyo destino no se conoce en el momento de
emitirla (referencias no satisfechas). Por lo tanto, en las instrucciones de control de flujo ser
necesario realizar el relleno de los argumentos no satisfechos. En el ETDS de la Fig. 2.16 se
emite cdigo intermedio para tres instrucciones tpicas de los lenguajes de programacin de alto
nivel (en este caso Pascal) suponiendo que las expresiones lgicas se representan mediante
control de flujo. Obsrvese que en el ETDS se asume que el cdigo intermedio generado para
evaluar las expresiones lgicas realiza la evaluacin de stas mediante cortocircuito.

I ! if E then
I
1
else


I
2

{ CompletaLans( E.lv, SIGINST) }
{ I. listaSig := CreaLans( SIGINST) ;
emite( goto --- ) ;
CompletaLans( E.lf, SIGINST) }
{ CompletaLans (I. listaSig, SIGINST) }
I ! while
E
do I
1

{ I. inicio := SIGINST }
{ CompletaLans( E.lv, SIGINST) }
{ emite( goto I.inicio ) ;
CompletaLans( E.lf, SIGINST) }
Generacin de cdigo intermedio

32
I ! for id := E1

to E2


do I1
{ id.pos := BuscaPos (id.nom) ;
emite( id.pos := E1.pos ) }
{ I. inicio := SIGINST ;
condic := CreaLans( SIGINST) ;
emite( if id.pos > E2.pos goto -- ) }
{ emite( id.pos := id.pos + 1 ) ;
emite( goto I. inicio ) ;
CompletaLans (condic, SIGINST) }
Figura 2.16a. ETDS instrucciones de control de flujo del lenguaje Pascal con relleno por retroceso (expresiones
lgicas con representacin por control de flujo).
Ejemplo 2.4.- Para entender un poco mejor como funciona el ETDS anterior, se puede
comparar el cdigo que se generara para la asignacin x:= a<b or (c<d and e<f)
suponiendo que se utilice una representacin por control de flujo o numrica para las expresiones
lgicas. En la Fig. 2.17. se muestra el rbol anotado para la instruccin cuando se emplea una
representacin por control de flujo.

Instruc
id.
pos
=X := E
or
E
oprel.
op
=<
(
E
id.
pos
=a
id.
pos
=b E
)
E E
and
oprel.
op
=< id.
pos
=c
id.
pos
=d
oprel.
op
=< id.
pos
=e
id.
pos
=f
.
lv
= {100,104}
.
lf
= {103,105}
.
lv
= {100}
.
lf
= {101}
.
lv
= {104}
.
lf
=
{103,105}
.
lv
= {102}
.
lf
= {103}
.
lv
= {104}
.
lf
= {105}
.
lv
= {104}
.
lf
= {103,105}

Figura 2.17: rbol anotado para la cadena x:=a<b or (c<d and e<f).
Generacin de cdigo intermedio
33
Repr. Numrica Repr. por control de flujo
100 t1 := 1 100 if a<b goto 108
101 if a<b goto 103 101 goto 102
102 t1 := 0 102 if c<d goto 104
103 t2 := 1 103 goto 106
104 if c<d goto 106 104 if e<f goto 108
105 t2 := 0 105 goto 106
106 t3 := 1 106 x := 0
107 if e<f goto 109 107 goto 109
108 t3 := 0 108 x := 1
109 t4 := t2 * t3 109
110 t5 := t1 + t4
111 x := t5

Ejemplo 2.5.- Veamos cul sera el cdigo intermedio generado para un bucle while-do de
Pascal, utilizando una representacin por control de flujo para las expresiones lgicas

while a<b or (c<d and e<f) do a:=a+1

100 if a<b goto 106

101 goto 102

102 if c<d goto 104
E w
103 goto 110
h
104 if e<f goto 106
i
105 goto 110
l


106 t1 := 1
e
107 t2 := a + t1
I
108 a := t2



109 goto 100

110


El siguiente ETDS genera cdigo para varias instrucciones de control del flujo en C
suponiendo una representacin del valor de las expresiones lgicas por control de flujo y usando
relleno por retroceso para resolver el problema de los argumentos no satisfechos:

Generacin de cdigo intermedio

34
I ! if E
I
1
else


I
2

{ CompletaLans( E.lv, SIGINST) }
{ I. listaSig := CreaLans( SIGINST) ;
emite( goto --- ) ;
CompletaLans( E.lf, SIGINST) }
{ CompletaLans (I.listaSig, SIGINST) }
I ! while
( E )
I
1

{ I.inicio := SIGINST }
{ CompletaLans( E.lv, SIGINST) }
{ emite( goto I.inicio ) ;
CompletaLans( E.lf, SIGINST) }
I ! do
I1
while ( E )
{ I.inicio:= SIGINST }

{ CompletaLans(E.listaverdad, I.inicio);
CompletaLans(E.listafalso, SIGINST) }
Figura 2.16b. ETDS instrucciones de control de flujo del lenguaje C con relleno por retroceso (expresiones lgicas
con representacin por control de flujo).

En [Aho 90] pueden encontrarse ETDS similares a los presentados en esta seccin, en los que
se utiliza un atributo .siguiente asociado a un auxiliar S, para representar el nmero (o etiqueta)
de la instruccin siguiente a las generadas por el auxiliar S. Adems, puede encontrarse en ese
tema cmo se genera cdigo cuando el cdigo intermedio permite la utilizacin de etiquetas
explcitas (similar a uno de los ejercicios que aparecen al final de este tema).
5. Subprogramas
En el captulo anterior ya se vio con bastante detalle cul sera la secuencia de carga y
descarga de un registro de activacin para la llamada y finalizacin de un subprograma. En esta
seccin se presentan los ETDS que especifican la generacin del cdigo intermedio que se
encarga de realizar la carga y descarga de un registro de activacin (Pascal) y marco (C).
5.1. Registros de activacin en Pascal.
5.1.1. Declaracin
Cuando se genera cdigo para la declaracin de un subprograma es necesario generar el
cdigo que realiza la parte de la secuencia del carga y descarga del registro de activacin que
lleva a cabo el subprograma llamado. Se muestra a continuacin como quedara esta parte del
ETDS correspondiente a la declaracin a una funcin en Pascal. Obsrvese como es necesario
utilizar relleno por retroceso para completar la instruccin de salto incondicional encargada de
saltar el posible cdigo de subprogramas locales al subprograma que se est compilando.
Generacin de cdigo intermedio
35
La instruccin PUSH permite apilar el valor del display del nivel de anidamiento
correspondiente al subprograma que estamos compilando (PUSH Display[NIVEL]). As mismo,
suponemos que el tope de la pila se encuentra almacenado en la posicin (o registro) TOP.

Decl_Subprg ! function id (Param_Form):
Tipo;



Bloque ;



Decl_Subprg

{emite(push Display[NIVEL]);
emite(display[NIVEL] := top);
area_datos := CreaLans(SIGINST);
emite(incTop ---) ; }
{ CompletaLans (area_datos, DESP)
emite(top := Display[NIVEL]);
emite(pop Display[NIVEL]);
emite(ret) }
Bloque ! Decl_Var

Decl_Subprg begin
Instrucciones end
{ inst := CreaLans(SIGINST);
emite(goto ----); }
{ CompletaLans(inst,SIGINST); }

Figura 2.18. ETDS carga/descarga de un registro de activacin por el procedimiento llamado.
5.1.2. Llamada
Cuando se genera cdigo para la llamada a un subprograma es necesario generar el cdigo
que realiza la parte de la secuencia de carga y descarga de un registro de activacin que lleva a
cabo el subprograma llamador. Se muestra a continuacin como quedara el ETDS
correspondiente al lenguaje Pascal. Obsrvese como se utiliza la instruccin INCTOP para
reservar espacio para el valor devuelto por la funcin, y la instruccin PUSH para apilar los
parmetros actuales. Posteriormente, durante la secuencia de descarga del registro de activacin,
se utiliza una instruccin DECTOP para decrementar el valor del tope de la pila y de esta forma
desapilar los parmetros que se cargaron al realizar la llamada.

E ! id

( Param_Act )
{ E.pos := CreaVarTemp();
emite(incTop Talla_Tipo(id.nom)) }
{ emite(push <estado mquina>);
emite(call BuscaPos(id.nom)) ;
emite(pop <estado mquina>);
emite(decTop TallaParam(id.nom)) ;
emite(pop E.pos) }
Param_Act ! E { emite(push E.pos) }
Param_Act ! Param_Act , E { emite(push E.pos) }
Figura 2.19. ETDS carga/descarga de un registro de activacin por el procedimiento llamador.
Generacin de cdigo intermedio

36
5.2. Marcos en C
5.2.1. Declaracin
Se muestra a continuacin como quedara un ETDS correspondiente a la declaracin a una
funcin en C. La instruccin push FP que se emite, permitir en tiempo de ejecucin apilar el
valor del frame pointer correspondiente al subprograma que se estar cargando.

Decl_Subprg ! Tipo id ( Param_Form )



Bloque ;



{ emite(push FP);
emite(FP := TOP);
area_datos := CreaLans(SIGINST);
emite(TOP := TOP + ---) ; }
{ CompletaLans (area_datos, DESP)
emite(TOP := FP);
emite(FP := pop);
emite(ret) }
Figura 2.18. ETDS carga/descarga de un frame en C realizado por la funcin llamada.
5.2.2. Llamada
Al igual que en Pascal, en C cuando se genera cdigo para la llamada a una funcin es
necesario generar el cdigo que realiza la parte de la secuencia de carga y descarga del frame de
la funcin llamada. La instruccin top := top + Talla_Tipo(id.nom) se emite para que al
ejecutarse reserve espacio para el valor devuelto por la funcin. De igual forma, la instruccin
push se emite para que en tiempo de ejecucin apile los parmetros actuales. Durante la
secuencia de descarga del frame se utiliza decrementa el valor del tope de la pila para, de esta
forma, desapilar los parmetros que se cargaron al realizar la llamada.


E ! id

( Param_Act )
{ E.pos := CreaVarTemp();
emite(TOP := TOP + Talla_Tipo(id.nom)) }
{ emite(push <estado mquina>);
emite(call BuscaPos(id.nom)) ;
emite(pop <estado mquina>);
emite(TOP := TOP - TallaParam(id.nom)) ;
emite(pop E.pos) }
Param_Act ! E { emite(push E.pos) }
Param_Act ! Param_Act , E { emite(push E.pos) }
Figura 2.19. ETDS carga/descarga de un frame realizado por la funcin llamadora.
Generacin de cdigo intermedio
37
Bi bl i ograf a recomendada
En [Tremblay 85] se puede encontrar un tema dedicado a formas de representacin de cdigo
intermedio. El tema de generacin de cdigo intermedio que ms coincide con el contenido de
este tema es el que aparece en [Aho 90].

[Aho 08] Aho, Alfred V.; Lam, Monica S.; Sethi, Ravi; Ullman, Jeffrey D. Compiladores:
Principios, tcnicas y herramientas. Segunda edicin Pearson/Addison-Wesley
Iberoamericana, 2008
[Tremblay 85] Tremblay, Jean-Paul; Sorenson, Paul G. The Theory and Practice of
Compiler Writing. McGraw-Hill, 1985

Generacin de cdigo intermedio
38
Ejerci ci os
*8.1.- La siguiente gramtica genera bucles for muy parecidos a los de Pascal estndar pero
con algunos matices:
I ! for id := E to E S do I
| begin LI end
S ! step E
| "
LI ! I ; LI
| I
...
donde E es una expresin de tipo entero.
La opcin step E que puede aparecer en la cabecera del bucle indica que la variable
contador (id) en vez de incrementarse en una unidad (como ocurre cuando no aparece la opcin
(step), se incrementar en E unidades al final de cada iteracin.
Construir un ETDS que incluya las acciones semnticas necesarias para la comprobacin de
tipos y la generacin de cdigo intermedio. Deben emplearse listas de referencias no satisfechas
(relleno por retroceso) para el control de los saltos.
*8.2.- Dado el siguiente fragmento de una gramtica que genera instrucciones de asignacin con
sumas y multiplicaciones, donde las llaves { } representan la clausura reflexivo-transitiva
(0 o ms ocurrencias):
IS ! id := E
E ! T { + T }
T ! F { * F }
F ! num
| id
| ( E )
...
a) Construir un ETDS para la generacin de cdigo intermedio.
b) Partiendo del ETDS anterior, incluir en el analizador descendente recursivo asociado a la
gramtica, las acciones necesarias para la generacin de cdigo intermedio.
NOTAS:
No incluir comprobaciones de tipo.
Generacin de cdigo intermedio
39
Emplear el juego de instrucciones de tres direcciones. (Ejemplo: id.pos:=id.pos*5)
El analizador lxico devuelve para cada identificador su entrada en la TDS en la variable
ind, y para una constante numrica su valor en la variable global num.
Se suponen definidas las siguientes funciones:
CrearVarTemp(): Crea una variable temporal y devuelve su posicin.
BuscaPos(id.nom): Devuelve la posicin de memoria asignada al identificador cuya
entrada en la TDS es id.nom.
En la declaracin de cada parmetro formal, deber indicarse si el uso es por valor o
referencia.
*8.3.- Dada la siguiente gramtica (inspirada en la proposicin switch del C):
I ! switch ( E ) { L }
L ! case num : P ; L
L ! default : P ;
L ! "
...
P ! P ; P
P ! break
P ! I
P ! "
...
Donde:
a) Tanto E como la constante num deben ser enteras.
b) Si la constante de un case coincide con el valor de la expresin E, se deber
comenzar a ejecutar todas las instrucciones asociadas a ese case y a los que le siguen.
La proposicin break provoca una salida inmediata del switch. Las instrucciones
asociadas al default se ejecutarn siempre (excepto si se encontr antes una
instruccin break).
Construir un ETDS que realice las acciones semnticas necesarias para la generacin de
cdigo intermedio de tres direcciones.
*8.4.- Construir un Esquema de Traduccin Dirigido por la Sintaxis que realice las
comprobaciones semnticas y genere cdigo de tres direcciones para una gramtica con las
siguientes reglas de produccin.
Generacin de cdigo intermedio

40
S ! case E of L end
L ! num : S ; L
L ! "
...
Tanto las constantes de seleccin, como la expresin, deben ser de tipo entero.
*8.5.- Dada la siguiente gramtica:
P ! D ; I .
D ! id : T # D ; D # "
T ! pila ( num ) de TS # TS
TS ! entero # real
I ! apilar ( id , E ) # id := E # I ; I # "
E ! desapilar ( id ) # cima ( id ) # id
Donde:
pila (num) de TS, representa la definicin del tipo pila, con un mximo de num
elementos de tipo entero o real.
apilar (id, E), indica que se apila el valor de E en la pila id
desapilar (id), devuelve el elemento que desapila de la pila id
cima (id) devuelve el elemento que hay en la cima de la pila id (no lo desapila).
Construir un ETDS que realice las acciones semnticas necesarias para la comprobacin de
tipos, la asignacin de memoria y la generacin de cdigo tres direcciones teniendo en cuenta
que:
a) La talla de los enteros y reales es 1.
b) No se debe permitir la asignacin de pilas.
c) No hay coercin de entero a real.
Se deben realizar las comprobaciones dinmicas para los controles de desborde de pila y pila
vaca.

Generacin de cdigo intermedio
41
*8.6.- Dada la siguiente gramtica:
P ! D ; I .
D ! id : T | D ; D | "
T ! cadena ( num ) | TS
TS ! entero | real | caracter
...
I ! concatena ( id , id ) | id := E | I ; I | "
E ! longitud ( id ) | id
Donde:
cadena(num) representa la definicin de un objeto de tipo cadena de caracteres
cuyo tamao mximo viene dado por num.
concatena(id1, id2) concatena al final de la cadena id1 la cadena id2.
longitud(id) devuelve el tamao de la cadena id.
Construir un ETDS que realice las acciones semnticas necesarias para la comprobacin de
tipos, la asignacin de memoria y la generacin de cdigo de tres direcciones teniendo en cuenta
que:
a) La talla de los enteros, reales y caracteres es 1, y no hay coercin entre tipos.
b) Se deben realizar las comprobaciones dinmicas para controlar que no se sobrepasa el
tamao mximo permitido de una cadena.
c) No se deben permitir las asignaciones entre cadenas.
NOTA: Se recomienda implementar una cadena declarada de tamao mximo num, como un
vector de num+1 elementos, donde el elemento 0 se puede usar para almacenar la longitud actual
de la cadena.
*8.7.- Incorporar a la gramtica siguiente, las acciones semnticas necesarias para la
comprobacin de tipos, la asignacin de memoria y la generacin de cdigo intermedio (tres
direcciones):
S ! D S
D ! D ; D | id : T
T ! char | integer | string(num)
S ! S ; S | id := E
E ! F + F | id (num : num)
F ! id | /id/
NOTAS:
Generacin de cdigo intermedio

42
1) string(num) representa una cadena de caracteres de talla mxima num.
2) id(a:b) representa la subcadena de id comprendida entre a y b.
3) /id/ es la longitud de la cadena id.
4) Ser necesario considerar explcitamente la talla actual de las cadenas.
*8.8.- Dado el siguiente fragmento de gramtica.
I ! while E do I Rw
Rw ! except E do I
Construye un ETDS para la comprobacin de tipos y emisin de cdigo intermedio. La
sentencia while-do tiene el comportamiento estndar de Pascal, pero con un pequeo matiz:
La parte except permite indicar una instruccin alternativa a ejecutar en las iteraciones en
las que se cumple la condicin booleana introducida por la palabra except. La expresin del
except se evala antes de entrar en el cuerpo del bucle.
Ejemplo:
a := 9 ;
while a < 15 do
begin a:= a +1; write(a) end => 10 11 12 13 15
except a=13 do a:= a+1;
*
8.9.- Escribe un ETDS que genere cdigo intermedio para el siguiente fragmento de una
gramtica independiente del contexto, correspondiente a un lenguaje de programacin. La
semntica de la instruccin loop es la siguiente: Si la expresin E que sigue a loop es cierta
se ejecutan las instrucciones que siguen al then y preceden a exitloop, y la instruccin loop
finaliza, en caso contrario, se irn evaluando sucesivamente las expresiones que siguen al
elseif hasta que una sea cierta, en cuyo caso, se ejecutan las instrucciones que siguen a ese
then y el flujo del programa vuelve al principio de la instruccin loop. Si ninguna expresin
es cierta se ejecutan las instrucciones que siguen al else y se vuelve al principio de la
instruccin loop.
I ! loop E then I exitloop O
O ! elseif E then I O
O ! else I endloop
I ! I ; I
E ! E oprel E

El diagrama de flujo de la instruccin sera el de la figura.


Generacin de cdigo intermedio
43











*8.10.- Definir un ETDS que
realice la generacin de cdigo intermedio para la instruccin WHILE-DO, en la que se
permita la posibilidad de una instruccin EXITLOOP. La instruccin Exitloop supone la
salida inmediata del bucle. Para ello utilizar la sintaxis propia de Pascal.
*8.11.- Dada la siguiente gramtica (inspirada en la proposicin for del C), construir un ETDS
que realice las acciones semnticas necesarias para la comprobacin de tipos y la generacin
de cdigo intermedio de tres direcciones usando una representacin por control de flujo de
las expresiones boolenas.
I ! for ( I
1
; E ; I
2
) { P }
...
P ! I ; P
P ! I
...
Donde:
a) Tanto I1 como I2 son instrucciones, tpicamente de asignacin o llamadas a funcin. I1 se
ejecutar antes del bucle e I2 dentro del bucle despus de las instrucciones asociadas a la
proposicin P.
b) E debe ser una expresin booleana que determine la condicin de finalizacin del bucle.
*8.12.- Construir un ETDS que realice la declaracin, la comprobacin esttica de tipos y la
generacin de cdigo intermedio para la siguiente gramtica:
E
E
E
E
I
I
I
I
True
False
False
False
False
True
True
True
I
...
salida
Generacin de cdigo intermedio

44
P ! D ; I .
D ! id : T | D ; D | !
T ! integer | set of [ num ]
E ! member ( E , id ) | num | id
...
I ! for-each id in id do I
Siendo:
set of [ num ] un tipo de datos que representa un conjunto cuyos elementos pueden ser {0, 1,
2, 3, . . . num}. Por ejemplo: a: set of [5] declara la variable a cuyo valor puede ser cualquier
subconjunto de {0, 1, 2, 3, 4, 5}.
member(E, id) una funcin que devuelve TRUE ( 1) si el elemento E est en el conjunto id
(FALSE 0, en caso contrario).
for-each id1 in id2 do I una instruccin donde la variable entera id1 toma todos los valores
que corresponden a la variable conjunto id2 . Adems, la instruccin I se ejecutar para cada uno
de los valores de id1 cuando este valor pertenezca al conjunto id2. Por ejemplo:
a: set of [5];
.....
a := {1, 3, 5}
for-each n in a do print (n);
producir como resultado: 1, 3, 5.
Nota.- Se recomienda representar las variables de tipo conjunto set of [num] como un
num + 1 posiciones consecutivas de memoria. Donde cada posicin de memoria representar
la pertenencia (1 0) de un elemento al conjunto. Por ejemplo, la variable a, de"nida
anteriormente, se representara por 6 posiciones de consecutivas memoria, que si contuviesen los
valores (1, 0, 1, 0, 0, 1) indicaran que el conjunto a contiene los elementos {0, 2, 5}.
8.13.- Dada la siguiente gramtica, construir un ETDS que realice: las comprobaciones
semnticas y de tipo usuales en la instruccin FOR y la generacin de cdigo intermedio.
Utilizar listas de referencias no satisfechas para la gestin de las expresiones booleanas.
S ! for id := E R E do S
R ! to | downto
8.14.- Construir un ETDS que genere cdigo intermedio para comprobar en tiempo de ejecucin
que los ndices de una matriz estn dentro de los lmites definidos en su declaracin. Para la
generacin de este cdigo, se puede suponer la existencia de otros atributos necesarios, cuya
evaluacin se realiza en otras producciones, siempre que se indique su carcter sintetizado o
heredado.
Generacin de cdigo intermedio
45
8.15.- Considrese la siguiente instruccin cuya semntica viene dada por el diagrama de flujo
que se adjunta. Disear el ETDS para la generacin de cdigo tres direcciones. Utilizar listas
de referencias no satisfechas (relleno con retroceso) para el control de los saltos.
S ! pseudowhile id , E until E do S then S

8.16.- Dada la siguiente gramtica que representa registros en Pascal, construir un ETDS que
realice:
P ! D ; I
D ! D ; D | id : T
T ! integer | real | record LC end
LC ! id : T RLC
RLC ! ; LC | "
I ! L := E
L ! L . id | id
E ! E + E | L
a) Las comprobaciones semnticas de: Compatibilidad de tipos, los tipos de los campos de
un RECORD solo pueden ser de tipo simple y no se permite la asignacin de registros.
b) El clculo de las posiciones relativas de los objetos en memoria.
c) La generacin de cdigo intermedio para las expresiones e instrucciones.
d) Extender el ETDS para generar cdigo intermedio para la asignacin de registros.
e) Extender el ETDS para permitir registros con parte variante.
8.17.- La siguiente gramtica representa expresiones en las que un operador (suma o producto)
acta sobre una lista de operandos que se encuentran entre parntesis junto al operador.
Adems, alguno de estos operandos puede ser a su vez toda una expresin entre parntesis.
S ! ( + P L ) | ( * P L )
P ! id | S
L ! P L | "
a) Escribir en PASCAL las rutinas del Anlisis Sintctico por Descenso Recursivo LL(1)
para esta gramtica.
b) Introducir en el esquema anterior las acciones semnticas necesarias para la generacin
de cdigo tres direcciones.
id > E'
id > E''
S' S''
No
No
Si
Si
Generacin de cdigo intermedio

46
8.18.- Suponiendo que una matriz A[a1..b1,a2..b2,...an..bn] se representa en memoria por el
mtodo de divisin en subtablas (tal y como se ilustra en la figura). En las subtablas de los
niveles 1..n-1 nicamente aparecen referencias (de talla 1) a los orgenes de las subtablas de
los niveles inmediatamente siguientes. Solo en las subtablas de nivel n se almacenarn los
elementos de la matriz.

a) Determinar la funcin de acceso para el elemento genrico A[i1,i2,...in].
b) Disear el ETDS para la generacin del cdigo intermedio correspondiente, para la
siguiente gramtica.
S ! L := E
E ! L
L ! id
L ! I ]
I ! I , E
I ! id [ E
8.19.- Dada la siguiente gramtica:
P! var D_V I
D_V ! D_V D_V | Lista_id : T ;
Lista_id ! Lista_id , id | id
T ! record ListaCampos Cvar end | T_simple
T_simple ! T_disc | integer | real
ListaCampos ! ListaCampos ; ListaCampos | id : T_simple
T_disc ! num..num | boolean
Cvar ! case id : T_disc of LCV | "
LCV ! LCV ; LCV | Val_sel : ( ListaCampos )
Val_sel ! num | id
I ! id := E | id . id := E | if E then I else I
E ! E oprel E | id . id | id
a) Dar un ETDS que realice el clculo de las posiciones relativas de las variables en
memoria para esta gramtica.
a1
b1
i1 i2
a2
b2
.
.
2
.
.
in-1
in
.
.
.
.
n-1
.
.
n
.
.
an
bn
A[i1,i2,..in]
1
Generacin de cdigo intermedio
47
b) Ampliar el anterior ETDS para que realice la comprobacin de tipos y genere el cdigo
intermedio necesario para evaluar las expresiones y realizar las asignaciones adecuadas en
dicha gramtica.
NOTA: Disear la estructura de la tabla de smbolos que permita la realizacin de los
apartados anteriores. Igualmente, describir brevemente los atributos, as como los perfiles y
acciones realizadas por las funciones y/o procedimientos que utilicis.
*8.20.- El cdigo intermedio definido en este captulo se modifica para permitir generar etiquetas
y utilizarlas como destino de los saltos (similares a las utilizadas en los lenguajes
ensambladores). Por ejemplo, podramos generar secuencias de cdigo intermedio similares a:

if e<f goto L1
goto L2
L2: a:= a-1
L1: a := a + 1
a) Construye un ETDS que genere este cdigo intermedio para la evaluacin de expresiones
lgicas (mediante representacin por control de flujo) para la siguiente gramtica:
E ! E or E | E and E | not E

| ( E

) | E oprel E
| true | false | id
b) Construye otro ETDS que genere cdigo intermedio para las instrucciones representadas
por la siguiente gramtica, que sea coherente con el ETDS del apartado anterior.
Instruc ! if E then Instruc

else Instruc
| while E do Instruc
| for id := E to E do Instruc
| id := E /* de tipo lgico */

c) Qu cdigo generar tu ETDS para las siguientes cadenas?
x := a<b or (c<d and e<f)
while a<b or (c<d and e<f) do a:=a+1
while (not a) or (x < b and true) do x := x + 1
Generacin de cdigo intermedio

48
Sol uci ones a l os ejerci ci os sel ecci onados
8.1.-
E1
id.pos := E1.pos
E2
if id > E2 goto
goto
(step) E
goto
I
goto
id := id +E


I ! for id := E1


to E2




S
do I

{ si E1.tipo <> tentero ent MemError()
id.pos:=BuscaPos(id.nom);
emite(id.pos := E1.pos) }
{ si E2.tipo <> tentero ent MemError()
fin:=CreaLans(SIGINST); comi:=SIGINST;
emite(if id.pos > E2.pos goto ---)
cont:=CreaLans(SIGINST);
emite(goto -- ); inc:=SIGINST; S.pos:=id.pos; }
{ emite(goto comi); CompletaLans(cont, SIGINST) }
{ emite(goto inc);
CompletaLans(fin, SIGINST) }
S ! step E { si E.tipo <> tentero ent MemError()
emite(S.pos := S.pos + E.pos) }
S ! " { emite(S.pos := S.pos + 1) }

8.2.-
a)
E ! T1
{ +
T2
}
{ E.pos:=CreaVarTemp(); emite (E.pos := T1.pos) }

{ emite(E.pos := E.pos + T2.pos ) }
T ! F1
{ *
F2
{ T.pos:=CreaVarTemp(); emite (T.pos := F1.pos) }

{ emite(T.pos := T.pos * F2.pos ) }
Generacin de cdigo intermedio
49
}
F ! num { F.pos:=CrearVarTemp();
emite(F.pos := num.val) }
F ! id { F.pos:=BuscaPos(id.nom) }
F ! ( E ) { F.pos:=E.pos }
IS ! id := E { id.pos:=BuscaPos(id.nom);
emite(id.pos := E.pos) }

b)
Procedure E ( var E.pos );
var
T1.pos, T2.pos
begin
T(T1.pos); E.pos:=CrearVarTemp(); emite (E.pos`:=T1.pos);
while sim=mas do
begin
obtsym;
T(T2.pos); emite(E.pos := E.pos + T2pos);
end;
end; { procedure E }
Procedure T ( var T.pos );
var
F1.pos, F2.pos
begin
F(F1.pos); T.pos:=CrearVarTemp(); emite(T.pos `:=F1.pos);
while sim=multi do
begin
obtsym;
F(F2.pos); emite(T.pos := T.pos * F2.pos);
end;
end; { procedure T }

Procedure F ( var F.pos );
var
E.pos
begin
case sim of
num:
F.pos:=CrearVarTemp(); emite(F.pos:=num.val);
obtsym;
identificador:
F.pos:=BuscaPos(id.nom);
obtsym;
abrepar:
Generacin de cdigo intermedio

50
obtsym;
E(E.pos); F.pos:=E.pos;
empareja(cierrapar);
end; { case }
end; { prcedure F }

Procedure IS;
var
E.pos, id.pos
begin
id.pos:=BuscaPos(id.nom);
empareja(identificador);
empareja(asignacin);
E(E.pos); emite(id.pos:=E.pos);
end; { procedure IS }
8.3.-
E
if E<>cte
1
goto
P
1
goto
P
2
goto (break)
if E<>cte
2
goto
goto
P (default)
...


En la solucin propuesta se puede observar que se genera una instruccin goto
inmediatamente a continuacin del cuerpo de un case cuya finalidad es saltar al cuerpo del
siguiente case. Con esto se consigue que si se cumple la igualdad de la constante de un
case, tras ejecutarse su cuerpo se ejecuten las instrucciones del cuerpo de todos los case
que le siguen (hasta que se encuentre un salto generado para un break).

I ! switch ( E )
{ L }
{ L.pos:=E.pos; L.anterior := nil; L.fin:=nil}
L ! case num :


P ;
{ sigcond:=CreaLans(SIGINST) ;
emite(if num.val <> L.pos goto --);
CompletaLans(L.anterior, SIGINST) }
{ L1.anterior:=CreaLans(SIGINST) ; emite (goto --);
Generacin de cdigo intermedio
51


L1
L1.pos:=L.pos; CompletaLans(sigcond, SIGINST);
L1.fin:=FusionaLans(P.fin, L.fin) }

L ! default :
P ;
{ CompletaLans(L.anterior, SIGINST) }
{ CompletaLans(L.fin, SIGINST);
CompletaLans(P.fin, SIGINST) }
L ! " { CompletaLans(L.anterior, SIGINST)
CompletaLans(L.fin, SIGINST);}
P ! P1 ; P2 { P.fin:=FusionaLans(P1.fin,P2.fin) }
P ! break { P.fin:=CreaLans(SIGINST); emite(goto --) }
P ! I { P.fin:=I.fin }
P ! " { P.fin:=nil }

8.4.-
E
if E.pos<>cte.val goto
S
goto
S
if E.pos<>... goto
goto
.
.
.


L ! num :


S ;



L1
{ si num.tipo $ tentero ent MemError() ;
sig:=CreaLans(SIGINST);
emite(if num.val <> L.pos goto --) }
{ falsa:=CreaLans(SIGINST);
emite(goto --);
CompletaLans(sig, SIGINST);
L1.pos:=L.pos }
{ L.fin:=FusionaLans(falsa, L1.fin) }
L ! " { L.fin:=nil }
S ! case E

of L
{ si E.tipo $ tentero ent MemError();
L.pos:=E.pos }
{ CompletaLans(L.fin, SIGINST) }
8.5.-
Generacin de cdigo intermedio

52
Es importante observar que en tiempo de compilacin no conocemos el tamao de la pila,
solo conocemos el tamao mximo de la pila. Por lo tanto, ser necesario reservar una
posicin de memoria para que en tiempo de ejecucin se almacene all el tope de la pila.
Podemos implementar la pila de num elementos como un vector (array) de num+1
elementos, donde el elemento 0 se puede usar para almacenar el tamao actual (tope) de la
pila. Cada vez que apilemos un nuevo elemento, lo haremos sobre la posicin indicada en
pila[0] (direccin base del vector). A continuacin incrementaremos el valor de pila[0]. De
esta forma, las acciones semnticas para generar cdigo para apilar, desapilar, y obtener la
cima podran ser:

I ! apilar ( id ,



E )
{ pos := BuscaPos (id.nom) ;
emite ( pos := pos + 1 );
emite (if pos <= limite goto SIGINST +2 )
emite (fin) }
{ emite ( pos [ pos ] := E.pos) }
E ! desapilar (id) { pos := BuscaPos (id.nom) ;
emite (if pos > 0 goto SIGINST + 2 ) ;
emite (fin) ;
E.pos := CrearVarTemp() ;
emite ( E.pos := pos [ pos ] );
emite (pos:= pos - 1) }
E ! cima (id) { pos := BuscaPos (id.nom) ;
emite (if pos > 0 goto SIGINST +2 );
emite (fin)
E.pos := CrearVarTemp();
emite (E.pos := pos [ pos ] ) }

En el ETDS anterior hemos se puede ver que pos[0] y pos hacen referencia al mismo
valor, ya que es lo mismo tomar el contenido de la direccin base del vector (pos) o el
contenido de la direccin resultante de sumar a la base del vector un desplazamiento cero
(pos[0]) .

El ETDS, incluyendo algunas comprobaciones de tipo quedar finalmente:

P !
D ; I .
{ DESP:=0 }
D ! id : T { InsertarTDS (id.nom, T.tipo, DESP);
DESP := DESP + T.talla ;
si T.tipo = Tpila(limite,tipo) ent emite (DESP := 0) }
D ! D ; D
D ! "
T ! pila ( num ) de { si num.val <=0 ent T.tipo := terror
Generacin de cdigo intermedio
53
TS sino T.tipo:= tpila (num.val, TS.tipo) ;
T.talla := TS.Talla * (num.val +1) }
T ! TS { T.talla := TS.talla ; T.tipo := TS.tipo }
TS ! entero { T.talla := 1 ; T.tipo := tentero }
TS ! real { T.talla := 1 ; T.tipo := treal }
I ! apilar ( id , E )







{ si BuscaTipo (id.nom) <> tpila (limite,tipo) ent I.tipo := terror
sino pos := BuscaPos (id.nom) ;
emite ( pos := pos + 1 );
emite (if pos <= limite goto SIGINST + 2 )
emite (fin)
si E.tipo <> tipo ent I.tipo := terror
sino emite ( pos[ pos ] := E.pos)
I.tipo := tvaco }
I ! id := E { id.tipo := BuscaTipo (id.nom) ;
si id.tipo = tpila (limite, tipo) ent I.tipo := terror
sino id.pos = BuscaPos (id.nom) ;
si id.tipo <> E.tipo ent I.tipo := terror
sino emite (id.pos := E.pos) ;
I.tipo := tvacio }
I ! I ; I
I ! "
E ! desapilar ( id ) { si BuscaTipo (id.nom) <> tpila (limite, tipo ) ent E.tipo := terror
sino pos := BuscaPos (id.nom) ;
emite (if pos > 0 goto SIGINST + 2 ) ;
emite (fin) ;
E.pos := CrearVarTemp() ;
emite ( E.pos := pos [ pos ] );
emite ( pos := pos - 1 ) ;
E.tipo := tipo }
E ! cima ( id ) { si BuscaTipo (id.nom) <> tpila (limite, tipo) ent E.tipo := terror
sino pos := BuscaPos (id.nom) ;
E.pos := CrearVarTemp();
emite (E.pos := pos [ pos ] );
E.tipo := tipo }
E ! id { E.tipo := BuscaTipo (id.nom) ; E.pos := BuscaPos (id.nom) }

Generacin de cdigo intermedio

54
8.6.-

P ! { DESP:=0 } D ; I .
D ! id : T
| D ; D
| "
{ InsertaTDS(id.nom, T.tipo, DESP) ; DESP:=DESP+T.talla }
T ! cadena ( num )
| TS
{ T.tipo:=tcadena(num.val) ; T.talla:=num.val }
{ T.tipo:=TS.tipo ; T.talla:=TS.talla }
TS ! entero
| real
| caracter
{ TS.tipo:=tentero ; TS.talla:=1 }
{ TS.tipo:=treal ; TS.talla:=1 }
{ TS.tipo:=char ; TS.talla:=1 }
I ! concatena ( id1 , id2)
















| id := E



| I ; I
| "
{ id1.pos:=BuscaPos(id1.nom); id2.pos:=BuscaPos(id2.nom);
si BuscaTipo(id1.nom)=BuscaTipo(id2.nom)=tcadena
ent
I.tipo:=tvaco;
t1:=CrearVarTemp();
emite ( t1 := 1);
inicio:=SIGINST;
listaFin:=CreaLans(SIGINST);
emite ( if t1 > id2.pos goto -- );
emite ( id1.pos := id1.pos + 1 );
emite (if id1.pos<=Talla(id1.nom) goto SIGINST+2 );
emite ( fin );
emite ( id1.pos [ id1.pos ]:= id2.pos [ t1 ] );
emite ( t1 := t1 + 1 );
emite ( goto inicio );
CompletaLans ( listaFin, SIGINST );
sino I.tipo:=terror; }
{ si (BuscaTipo(id.nom):=E.tipo) $ tcadena $terror
ent emite( BuscaPos(id.nom) := E.pos );
I.tipo:=tvaco;
sino I.tipo:=terror; }

E ! longitud ( id )


| id
{ si BuscaTipo(id.nom) $ tcadena ent E.tipo:=terror;
sino E.tipo:=tentero;
E.pos:=BuscaPos(id.nom); }
{ E.tipo:=BuscaTipo(id.nom); E.pos:=BuscaPos(id.nom); }

Se puede observar que en lugar de usar la tcnica de relleno por retroceso con:
listaFin:=CreaLans(SIGINST);
Generacin de cdigo intermedio
55
emite ( if t1 > id2.pos goto -- );
en este caso podamos haber contado las instrucciones que separaban la instruccin de salto y su
destino, y haber emitido directamente la instruccin
emite ( if t1 > id2.pos goto SIGINST +7 ) */

8.7.-
Las comprobaciones de tipo sern las tpicas del bloque de declaraciones. Para asignar
memoria basta con emplear una variable global que se incremente (segn la talla del elemento
definido) cada vez que se declare una variable. En el caso de una cadena de caracteres
(tcadena), la talla nos viene determinada por el valor de la constante num (ms uno por la
razn que se explica ms adelante).
Respecto a la generacin de cdigo intermedio, se trata de un ejercicio muy parecido a los
dos anteriores. De forma parecida a como ocurra en ellos, en tiempo de compilacin solo
conocemos el tamao mximo de la cadena, pero no su tamao real en un instante dado de la
ejecucin. Una solucin consistira en reservar la primera posicin de la cadena para que en
tiempo de ejecucin se almacene su tamao. En este caso, cada vez que realicemos una
asignacin de cadenas, ser necesario calcular el tamao de la cadena resultado. Con este fin,
se puede observar que la instruccin para obtener una subcadena: id(num1:num2) nos
devuelve una cadena de tamao num2 .val - num1.val +1.
8.8.-
El esquema del cdigo que queremos generar ser:

E
I
1
goto
goto
.v
.f
E (RW)
.v
.f
I (RW)

El ETDS pedido quedara:

I ! while
E do

I1

RW
{ RW.inicio := SIGINST }
{ si E.tipo <> tlgico ent MemError() ;
RW.cuerpo := SIGINST }
{ emite (goto RW.inicio) ;
CompletaLans (E.lv , SIGINST) }
{ CompletaLans (E.lf, SIGINST) }
Generacin de cdigo intermedio

56
RW ! except E


do I
{ si E.tipo <> tlgico ent MemError() ;
CompletaLans (E.lv, SIGINST) ;
CompletaLans (E.lf, RW.cuerpo) }
{ emite (goto RW.inicio) }

8.9.-
Solucin usando representacin por control de flujo para las expresiones lgicas.
I ! loop
E then
I exitloop
O
{ O.inicio := SI; }
{ CompletaLans(E.lv, SI); }
{ fin:= CreaLans(SI); emite (goto -); CompletaLans(E.lf, SI);}
{ CompletaLans(fin, SI); }
O ! elseif E
then I

O1
{ CompletaLans(E.lv, SI); }
{ emite(goto O.inicio) ; CompletaLans(E.lf, SI);
O1. inicio := O.inicio ;}
O ! else I endloop { emite(goto O.inicio) ;}
I ! I ; I
E ! E oprel E { E.lv := CreaLans( SI) ;
emite( if E
1
.pos oprel.op E
2
.pos goto --- ) ;
E.lf := CreaLans( SI ) ;
emite( goto --- ) }

8.10.-
Vamos a usar la gramtica que se muestra a continuacin, donde I representa una instruccin,
y E una expresin. El no-terminal I tendr ms producciones, pero las que nos interesan son
las relacionadas directamente con la generacin de cdigo intermedio para las instrucciones
while-do y Exitloop.
I ! while E do I
I ! Exitloop
I ! I ; I
I !
Usaremos listas de referencias no satisfechas (relleno por retroceso) para el control de los
saltos. El no-terminal E, que representa la expresin lgica, tendr asociados dos atributos:
E.lv y E.lf que representan respectivamente las listas de referencias no satisfechas de saltos
para cuando la expresin es cierta (E.lv) y para cuando es falsa (E.lf).
Generacin de cdigo intermedio
57
SIGINST, es una variable global que contiene la etiqueta de la siguiente instruccin de
cdigo intermedio que se va a generar.

I ! while
E
do I1
{ inicio := SIGINST }
{ CompletaLans (E.lv, SIGINST) }
{ emite (goto inicio)
CompletaLans (I1.salida, SIGINST) ;
CompletaLans (E.lf, SIGINST) ;
I.salida := nil }
I ! Exitloop { I.salida := CreaLans (SIGINST) ;
emite (goto ---) }
I ! I1 ; I2 { I.salida:= FusionaLans (I1.salida, I2.salida) ; }
8.11.-
El esquema del cdigo intermedio que queremos generar es el siguiente:

I
1
E
I
2
goto
P
goto
.v
.f

El ETDS por tanto quedara:

I ! for ( I1 ;
E ;

I2 )

{ P }
{ inicio:=SIGINST; }
{ si E.t $ tlgico ent MenError()
sino incr:=SIGINST; }
{ emite(goto inicio);
CompletaLans(E.lv, SIGINST) }
{ emite(goto incr);
CompletaLans(E.lf, SIGINST) }

Generacin de cdigo intermedio

58
8.12.-

P ! D ; I .
D ! id : T { insertaTDS( id.nom, T.tipo) }
| D ; D
| "
T ! set of [ num ] { T.tipo := conjunto(num.val) }
| integer { T.tipo := entero }
E ! member ( E1 , id ) { si (E1.tipo <> entero) or (BuscaTipo(id.nom) <> conjunto(n))
ent error;
E.tipo := lgico;
E.pos := CreaVarTemp;
emite( E.pos := id.pos[E1.pos]) }
| num { E.tipo := entero;
E.pos:= CreaVarTemp;
emite(E.pos:= num.val) }
| id { E.tipo := BuscaTipo(id.nom)
E.pos := BuscaPos(id.nom) }
I! for_each id1 in id2










do I
for_each id1 in id2
{ si (BuscaTipo(id1.nom)<> entero)
or (BuscaTipo(id2.nom) <> conjunto(n))
ent error;
t1 := CreaVarTemp;
emite (id1.pos := 0);
fin := Crealans(si);
inicio := si;
emite( if id1.pos > buscalimite(id2.nom) goto __);
emite (t1 := id2.pos[id1.pos]);
salta := Crealans(si);
emite( if t1 = 0 goto __); }

{ completalans(salta, si);
emite( id1.pos := id1.pos + 1);
emite( goto (inicio));
completalans(fin, si); }

Generacin de cdigo intermedio
59
8.20.-
a) Usaremos la funcin CreaEtiqueta par crear una etiqueta. Para generar mediante el
procedimiento emite una etiqueta bastar con realizar una llamada del tipo:
emite (<NombreEtiqueta> :)
Se puede observar la similitud de este ETDS con el construido usando relleno por retroceso
para la misma gramtica:

- Las instrucciones generadas, excepto los destinos de los saltos que en este ETDS son
etiquetas, son las mismas.

- Donde se emite una etiqueta que anteriormente se us como destino de un salto, en el
ETDS mediante relleno por retroceso apareca un completaLans.

El ETDS para las expresiones lgicas quedara:


E !
E
1
or
E
2

{ E
1
.f := CreaEtiqueta(); E
1
.v := E.v }
{ emite( E
1
.f :);
E
2
.v := E.v; E
2
.f := E.f }
|
E
1
and
E
2

{ E
1
.v := CreaEtiqueta(); E
1
.f := E.f }
{ emite( E
1
.v :);
E
2
.v := E.v; E
2
.f := E.f }
| not E
1
{ E
1
.v := E.f ;
E
1
.f := E.v }
| ( E
1
) { E
1
.v := E.v ;
E
1
.f := E.f }
| E
1
oprel E
2
{ emite( if E
1
.pos oprel.op E
2
.pos goto E.v );
emite( goto E.f ) }
| True { emite( goto E.v ) }
| False { emite( goto E.f ) }
| id { emite( if id.pos = 0 goto E.f ) ;
emite( goto E.v ) }



Instruc ! id :=

E
{ E.v := CreaEtiqueta(); E.f := CreaEtiqueta()
fin := CreaEtiqueta() }
{ emite( E.f :) ;
emite( id.pos := 0 ) ,
emite( goto SIGINST + 2 ) ,
emite( E.v :);
emite ( id.pos := 1 ) ; emite( fin : ) }

Generacin de cdigo intermedio

60
b)
Instruc !
if E then
Instruc
1
else
Instruc
2

{ E.v:= CreaEtiqueta(); E.f:= CreaEtiqueta(); fin:= CreaEtiqueta() }
{ emite( E.v : ) }
{ emite( goto fin ) ; emite( E.f :) }
{ emite( fin :) }
| while

E
do Instruc
1

{ Inicio := CreaEtiqueta() ; E.t := CreaEtiqueta() ;
E.f := CreaEtiqueta() ; emite(inicio :) : }
{ emite( E.v :) }
{ emite( goto inicio ) ;
emite( E.f :) }
| for id := E1
to E2
do Instruc1
{ id.pos := BuscaPos (id.pos) ;
emite( id.pos := E1.pos ) }
{ inicio := CreaEtiqueta() ;
fin := CreaEtiqueta() ;
emite( inicio :) ;
emite( if id.pos > E2.pos goto fin ) }
{ emite( id.pos := id.pos + 1 ) ;
emite( goto inicio ) ;
emite( fin :) }

c) x := a<b or (c<d and e<f)

if a<b goto L1
goto L3
L3: if c<d goto L4
goto L2
L4: if e<f goto L1
goto L2
L2: x := 0
goto L5
L1: x := 1
L5:

while a<b or (c<d and e<f) do a:=a+1

L0:

if a<b goto L1

goto L3
L3: if c<d goto L4 E w
goto L2 h
L4: if e<f goto L1 i
goto L2 l

L1: t1 := 1 I e
t2 := a + t1
a := t3
goto L0
L2:
Generacin de cdigo intermedio
61
while (not a) or (x < b and true) do x := x + 1

L0:

if a = 0 goto L1

goto L3
L3: if c<d goto L4 E w
goto L2 h
L4: goto L1 i

L1: t1 := 1 I l
t2 := a + t1 e
a := t3
goto L0
L2:

También podría gustarte