Código de tres direcciones - Página personal de César Ignacio

Transcripción

Código de tres direcciones - Página personal de César Ignacio
Introducción
• En el modelo de análisis y síntesis de un compilador, la etapa inicial traduce
un programa fuente a una representación intermedia a partir de la cual la
etapa final genera el código objeto. Los detalles del lenguaje objeto se
confinan en la etapa final, si esto es posible.
• Al generar el código intermedio facilito la independencia de la máquina,
además es más fácil la optimización del código intermedio.
a la entrada para b
id
1
• Los códigos intermedios pueden ser:
a la entrada para c
id
2
asigna
– Árbol sintáctico
– Notación postfija
– Código de 3 direcciones
a
+
Ejemplo: a:=b*-c+b*-c
*
asigna
b
a
3
4
5
6
7
8
menosu
+
*
b
Código
para el
árbol
César Ignacio García Osorio. Universidad de Burgos.
t1:=-c
t2:=b*t1
t5:=t2+t2
a:=t5
a la entrada para a
a la entrada
para a
+
*
c
id
a la entrada
para b
a la entrada
para c
PL. Generación de código
Código de tres direcciones
• Es una especie de código máquina de la forma general:
x:=y op z
donde x, y y z son nombres, constantes o variables temporales
generadas por el compilador, op representan cualquier operador.
• No se permite ninguna expresión aritmética compuesta, pues sólo
hay un operador en el lado derecho de una proposición.
• El uso de nombres para los valores intermedios calculados por un
programa permite que el código de tres direcciones se reorganice
fácilmente – a diferencia de la notación postfija –.
• Es una representación linealizada de un árbol sintáctico o un GDA
en la que los nombres explícitos corresponden a los nodos
interiores del grafo.
t1:=-c
t2:=b*c
t3:=-c
t4:=b*t3
t5:=t2+t4
a:=t5
5
id
menosu
César Ignacio García Osorio. Universidad de Burgos.
Ejemplos
6
menosu
a b c menosu * b c menosu * + asigna
(1)
3
4
id
*
menosu b
1
1
4
asigna
c
c
Código de tres direcciones
-
*
+
id
:=
2
(2)
• Tipos de proposiciones de tres direcciones
1. Asignación de operadores binarios:
• x:=y op z
2. Asignación de operadores unarios:
• x:=op y
3. Proposiciones de copia:
• x:=y
4. Salto incondicional:
• goto E
5. Saltos condicionales:
• if x oprel y goto E
Código
para el
GDA
6. Llamadas a procedimientos:
• param x
• call p, n
• return y
PL. Generación de código
3
César Ignacio García Osorio. Universidad de Burgos.
PL. Generación de código
4
Código de tres direcciones
(3)
Código de tres direcciones
• D.D.S. para producir código de tres direcciones
7. Asignaciones con índices:
• x:=y[i]
• x[i]:=y
PRODUCCIÓN
S → id := E
E → E1 + E2
8. Asignaciones de direcciones y apuntadores:
• x:=&y
• x:=*y
• *x:=y
E → E1 * E2
E → - E1
E → ( E1 )
E → id
• El conjunto de operadores debe ser lo bastante rico como para
implantar las operaciones del lenguaje fuente.
PL. Generación de código
Código de tres direcciones
5
(5)
• Esquema de traducción para producir código de tres direcciones
id:= E {emite(id.lugar ':=' E.lugar) }
E1+E2 {E.lugar:= tempnuevo; emite(E.lugar ':=' E1.lugar '+' E2.lugar) }
E1*E2 {E.lugar:= tempnuevo; emite(E.lugar ':=' E1.lugar '*' E2.lugar) }
-E1
{E.lugar:=tempnuevo; emite(E.lugar ':=' 'menosu' E1.lugar) }
{E.lugar:=E1.lugar }
(E1)
{E.lugar:=id.lugar }
id
while {S.comienzo:=etiqnueva; S.después:=etiqnueva; emite(S.comienzo ':') }
E do {emite('if' E.lugar '=' '0' 'goto' S.despues)}
{emite('goto' S.comienzo); emite(S.despues ':') }
S1
{I.falso:=etiqnueva;}
S→ if
E then {emite('if' E.lugar '=' '0' 'goto' I.falso); }
S1 I
I→ endif {emite(I.falso ':') }
{I.después:=etiqnueva; emite('goto' I.después); emite(I.falso ':') }
I→ else
S endif {emite(I.después ':') }
PL. Generación de código
E.lugar:= E1.lugar;
E.lugar:= id.lugar;
E.código:= E1.código
E.código:= ' '
César Ignacio García Osorio. Universidad de Burgos.
PL. Generación de código
Código de tres direcciones
S→
E→
E→
E→
E→
E→
S→
César Ignacio García Osorio. Universidad de Burgos.
REGLAS SEMÁNTICAS
S.código:= E.código || gen(id.lugar ':=' E.lugar)
E.lugar:= tempnuevo;
E.código:= E1.código||E2.código||gen(E.lugar ':=' E1.lugar '+' E2.lugar)
/* similar al operador de suma de la regla anterior */
E.lugar:= tempnuevo;
E.código:= E1.código || gen(E.lugar ':=' 'menosu' E1.lugar)
S → while E do S1 S.comienzo:= etiqnueva;
S.después:= etiqnueva;
S.código:= gen(S.comienzo ':') || E.código ||
gen('if' E.lugar '=' '0' 'goto' S.despues) ||
S1.código || gen('goto' S.comienzo) ||
gen(S.despues ':')
– Aunque un conjunto de operadores pequeño es más fácil de implantar,
un conjunto de instrucciones limitado puede obligar a la etapa inicial a
generar largas secuencias de proposiciones para algunas operaciones del
lenguaje fuente lo que obliga a trabajar más al optimizador y al
generador de código para producir buen código.
César Ignacio García Osorio. Universidad de Burgos.
(4)
7
6
(5)
• Implantación de proposiciones de tres direcciones
– Cuádruplos: Es una estructura tipo registro con cuatro campos, que se
llamarán op, arg1, arg2 y resultado. El campo op contiene un código
interno para el operador. La proposición de tres direcciones x:=y op z
se representan poniendo y en arg1, z en arg2 y x en resultado.
– Los contenidos de los campos arg1, arg2 y resultado son generalmente
apuntadores a las entradas de la tabla de símbolos.
Ejemplo
op
arg1 arg2 resultado
a:=b*-c+b*-c
(0) menosu
c
(1)
b
*
t1
t1
t2
(2) menosu
c
(3)
*
b
t3
t4
(4)
+
t2
t4
t5
(5)
:=
t5
César Ignacio García Osorio. Universidad de Burgos.
t3
a
PL. Generación de código
8
Código de tres direcciones
(6)
Código de tres direcciones
– Triples: Estructura tipo registro con sólo tres campos: op, arg1 y arg2.
– Para evitar introducir nombres temporales en la TS, se hace referencia a
un valor temporal según la posición de la proposición que lo calcula.
– Los campos arg1 y arg2 son apuntadores a la tabla de símbolos o
apuntadores dentro de la estructura de triple.
Ejemplos
op
a:=b*-c+b*-c
arg1
(0) menosu
c
(1)
b
*
arg2
(0)
(2) menosu
c
(3)
*
b
(2)
(4)
+
(1)
(3)
a
(4)
(5) asigna
César Ignacio García Osorio. Universidad de Burgos.
(0)
arg1
arg2
[]=
x
i
(0)
(14)
(14) menosu
c
(0)
y
(1)
(15)
(15)
b
(2)
(16)
(16) menosu
c
x[i]:=y
arg2
(3)
(17)
(17)
*
b
(16)
=[]
y
i
(4)
(18)
(18)
+
(1)
(17)
x
(0)
(5)
(19)
(19)
:=
a
(18)
(1) asigna
x:=y[i]
PL. Generación de código
9
(1)
César Ignacio García Osorio. Universidad de Burgos.
10
(2)
• Proceso de declaraciones en procedimientos anidados
{ desplazamiento:=0 }
{ introduce(id.nombre, T.tipo, desplazamiento);
desplazamiento := desplazamiento + T.ancho }
{ T.tipo:=integer; T.ancho:=4 }
{ T.tipo:=real; T.ancho:=8 }
{ T.tipo:=array(núm.val, T1.tipo);T.ancho:= núm.val×T1.ancho }
{ T.tipo:=pointer(T1.tipo); T.ancho:= 4}
• introduce(nombre, tipo, desplazamiento) crea una entrada en la TS para nombre, le
da el tipo tipo y la dirección relativa desplazamiento en su área de datos.
• El atributo tipo representa una expresión de tipos construida a partir de los tipos
básicos integer y real aplicando los constructores de tipos pointer y array. Si las
expresiones de tipos se representan por medio de grafos, entonces el atributo tipo
puede ser un apuntador al nodo que representa una expresión de tipo.
PL. Generación de código
PL. Generación de código
Declaraciones
P→MD
César Ignacio García Osorio. Universidad de Burgos.
(14)
arg1
• Cálculo de los tipos y direcciones relativas de nombres declarados
T → integer
T → real
T → array [ núm ] of T1
T → ^T1
*
op
Declaraciones
P→MD
M→ ε
D → D1 ; D2
D → id : T
– Triples indirectos: Se utiliza una lista de los apuntadores a triples, en
lugar de hacer una lista de los triples mismos.
– Esta implantación tiene la ventaja de que en un compilador optimizador
no sería necesario cambiar los triples (y por tanto el índice mediante el
que son referenciados) sino únicamente el índice en la matriz
proposición.
Ejemplo
op
arg1 arg2
proposición
op
(1) asigna
(0)
(7)
11
{ añadeancho(tope(tblpn), tope(desplazamiento));
saca(tblapn); saca(desplazamiento) }
{ t:=creatabla(nil); mete(t, tblapn); mete(0, desplazamiento) }
M→ ε
D → D1 ; D2
D → proc id ; N D1 ; S { t:=tope(tblapn);
añadeancho(t, tope(desplazamiento));
saca(tblapn); saca(desplazamiento);
introduceproc(tope(tblapn), id.nombre, t); }
{ introduce(tope(tblapn), id.nombre, T.tipo, tope(desplazamiento));
D → id : T
tope(desplazamiento):= tope(desplazamiento) + T.ancho }
{ t:=creatabla(tope(tblapn));
N→ ε
mete(t, tblapn); mete(0, desplazamiento) }
{ T.tipo:=record(tope(tblapn)); T.ancho:=tope(desplazamiento));
T → record L D end
saca(tblapn); saca(desplazamiento) }
{ t:=creatabla(tope(tblapn));
L→ ε
mete(t, tblapn); mete(0, desplazamiento) }
César Ignacio García Osorio. Universidad de Burgos.
PL. Generación de código
12
Proposiciones de asignación
(1)
Almacenamiento en memoria de
una matriz A de dimensiones
(n1=2)×(n2=3)×(n3=4)
if p≠nil then
emite(p ':=' E.lugar)
E → E1 * E2
E → - E1
E → ( E1 )
E → id
base
else error }
{ E.lugar:=tempnuevo;
emite(E.lugar ':=' E1.lugar '+' E2.lugar) }
{ E.lugar:=tempnuevo;
emite(E.lugar ':=' E1.lugar '*' E2.lugar) }
{ E.lugar:=tempnuevo;
emite(E.lugar ':=' 'menosu' E1.lugar) }
A[inf1, inf2, inf3+3]
E→(E1)
E→L
A[inf1+1,*,*]
PL. Generación de código
13
(3)
base+(i3−inf3+n3·(i2−inf2+n2·(i1−inf1)))·a
{ E.lugar:= E1.lugar }
{ if L.desplazamiento=null then E.lugar:=L.lugar
else begin E.lugar:=tempnuevo;
emite(E.lugar ':=' L.lugar '[ ' L.desplazamiento ']');
end}
{ L.lugar:=tempnuevo;
L.desplazamiento:=tempnuevo;
emite(L.lugar ':=' c(listaE.matriz));
emite(L.desplazamiento ':=' listaE.lugar '*' ancho(listaE.matriz)); }
{ L.lugar:=id.lugar; L.desplazamiento:=null }
L→id
listaE→listaE1,E { t:=tempnuevo;
m:= listaE1.ndim+1 ;
emite(t ':=' límite(listaE1.matriz,m) '*' listaE1.lugar);
emite(t ':=' E.lugar '+' t);
listaE.matriz:=listaE1.matriz; listaE.lugar:=t; listaE.ndim:=m }
{ listaE.matriz:=id.lugar; listaE.lugar:=E.lugar; listaE.ndim:=1 }
listaE→ id[E
L→listaE]
PL. Generación de código
[base−(inf3+n3·(inf2+n2·inf1)))·a]+(i3+n3·(i2+n2·i1)))·a
Esta fórmula se puede generalizar a una matriz de k
dimensiones n1×n2×... ×nk con nm=supm−infm+1 para
la que los elementos que dependen de los índices se
pueden calcular utilizando la recurrencia:
César Ignacio García Osorio. Universidad de Burgos.
e1=i1
em=im+nm·em-1
PL. Generación de código
Proposiciones de asignación
14
(4)
• Conversión de tipo dentro de asignaciones
• En la práctica, hay muchos tipos diferentes de variables y constantes, así que el
compilador debe rechazar algunas operaciones de tipos mixtos o bien generar las
instrucciones de coerción (conversión de tipos) apropiadas.
• Por ejemplo, para la producción E→E1+E2 se podría tener la siguiente acción semántica.
E.lugar:=tempnuevo
if E1.tipo=integer and E1.tipo=integer then begin
emite(E.lugar ':=' E1.lugar '+ent' E2.lugar);
E.tipo=integer
end else if E1.tipo=real and E2.tipo=real then begin
emite(E.lugar ':=' E1.lugar '+real' E2.lugar);
E.tipo=real
end else if E1.tipo=integer and E2.tipo=real then begin
u:=tempnuevo;
emite(u ':=' 'entareal' E1.lugar);
E.tipo=real
emite(E.lugar ':=' u '+real' E2.lugar);
end else if E1.tipo=real and E2.tipo=integer then begin
u:=tempnuevo;
emite(u ':=' 'entareal' E2.lugar);
E.tipo=real
emite(E.lugar ':=' E1.lugar '+real' u);
end else E.tipo=error_tipo;
{ if L.desplazamiento=null then emite(L.lugar ':=' E.lugar);
else emite(L.lugar '[ ' L.desplazamiento ']' ':=' E.lugar); }
{ E.lugar:=tempnuevo; emite(E.lugar ':=' E1.lugar '+' E2.lugar) }
César Ignacio García Osorio. Universidad de Burgos.
base+ n3·a
base+n3·n2·a
• Esquema de traducción para acceder a elementos de matrices
E→E1+E2
base+(n3·n2·(i1−inf1)+n3·(i2−inf2) +(i3−inf3))·a
Factorizando queda:
A[inf1, inf2+2, *]
Proposiciones de asignación
S→L:=E
La posición del elemento A[i1,i2,i3] en esta matriz
viene dada por la fórmula:
Separando los elementos que dependen
exclusivamente de la estructura de la matriz:
{ E.lugar:= E1.lugar }
{ p:=busca(id.nombre);
if p≠nil then
E.lugar:= p
else error }
César Ignacio García Osorio. Universidad de Burgos.
(2)
• Acceso a elementos de matrices
• Esquema de traducción para producir cód. de 3 direcciones para las asignaciones
{ p:=busca(id.nombre);
S → id := E
E → E1 + E2
Proposiciones de asignación
15
César Ignacio García Osorio. Universidad de Burgos.
PL. Generación de código
16
Expresiones booleanas
• Esq. traduc. utilizando una representación numérica para los valores booleanos
E → E1 or E2
{ E.lugar:=tempnuevo;
emite(E.lugar ':=' E1.lugar 'or' E2.lugar) }
E → E1 and E2
{ E.lugar:=tempnuevo;
emite(E.lugar ':=' E1.lugar 'and' E2.lugar) }
E → not E1
{ E.lugar:=tempnuevo;
emite(E.lugar ':=' 'not' E1.lugar) }
E → ( E1 )
E → id1 oprel id2
{ E.lugar:= E1.lugar }
{ E.lugar:=tempnuevo;
después:=etiqnueva;
cierto:=etiqnueva;
emite('if' id1.lugar oprel.op id2.lugar 'goto' cierto);
emite(E.lugar ':=' '0'); emite('goto' después);
emite(cierto ':');
emite(E.lugar ':=' '1');
emite(después ':');
E → true
E → false
}
{ E.lugar:=tempnuevo;
{ E.lugar:=tempnuevo;
César Ignacio García Osorio. Universidad de Burgos.
emite(E.lugar ':=' '1');
emite(E.lugar ':=' '0');
}
}
PL. Generación de código
17

Documentos relacionados