SlideShare una empresa de Scribd logo
Generación de código. Procesadores de
Lenguaje I

Generación de Código Intermedio
Proceso de Síntesis
Lenguaje Intermedio
Generación de Código

Ventajas del código intermedio
Facilitar la fase de optimización
Aumentar la portabilidad del compilador de una máquina a otra
Se puede utilizar el mismo analizador para diferentes generadores
Se pueden utilizar optimizadores independientes de la máquina

Facilitar la división en fases del proyecto
Fuente

Scanner

Parser

Generador
de
Código

LI

Objeto

TDS

Generación de código. Procesadores de
Lenguaje I

Generación de Código Intermedio
Aumentar la portabilidad del compilador de una máquina a otra
Se puede utilizar el mismo analizador para diferentes generadores
Se pueden utilizar optimizadores independientes de la máquina
C

back-ends

front-ends
Pascal

Ada
C++
Java

Generador
de
Código Intemedio

Optimización
independiente
de máquina

Intel X

Dec-Alpha

Motorola

N+M vs N*M

1
Generación de código. Procesadores de
Lenguaje I

Fase de Análisis
position := initial + rate * 60
lexical analyzer
id1 := id2 + id3 * 60
syntax analyzer

:=
+

id1

*

id2l

60

id3
semantic analyzer

:=
Symbol
Table

rate….

*

id2l

inttoreal

id3

position ....
initial ….

E
r
r
o
r
s

+

id1

60
intermediate code generator

Generación de código. Procesadores de
Lenguaje I

Fase de Síntesis
Symbol Table
position ....
initial ….
rate….

intermediate code generator

E
r
r
o
r
s

temp1 := inttoreal(60)
temp2 := id3 * temp1
temp3 := id2 + temp2
id1 := temp3

3 address code

code optimizer
temp1 := id3 * 60.0
id1 := id2 + temp1
final code generator
MOVF id3, R2
MULF #60.0, R2
MOVF id2, R1
ADDF R1, R2
MOVF R1, id1

2
Generación de código. Procesadores de
Lenguaje I

Tipos de representaciones
intermedias

La representación del código intermedio depende
de la máquina objeto:
0-direcciones: código para máquinas de pila (código P)
2-direcciones: códigos para máquinas con operaciones
sobre registros de memoria
3-direcciones: código para máquinas de arquitectura
RISC

En todo caso, añade un recorrido descendente
adicional para generar el código final

Generación de código. Procesadores de
Lenguaje I

Tipos de representaciones
intermedias
Propiedades:

Fácil de producir en el análisis semántico
Fácil de traducir a código máquina real
Instrucciones simples y concisas, de fácil optimización

Tipos
Árboles de Sintaxis Abstracta
Notación Polaca Inversa (RPN)
Código P
Códigos de tres direcciones
Cuartetos
Tercetos
Tercetos Indirectos

3
Generación de código. Procesadores de
Lenguaje I

Representaciones intermedias:
RPN
Notación Polaca Inversa (RPN)

Los operadores van después de los operandos
S=A+B*C

→ SABC*+=

Ventajas
Facilidad para generar código a partir de ella
Es la notación más sencilla para el lenguaje intermedio

Inconvenientes
El código es difícil de entender
Poca flexibilidad
No es útil para optimización de código

Generación de código. Procesadores de
Lenguaje I

Representaciones intermedias: P
Código P
Extensión RPN para máquina completa (etiquetas, saltos)
Razones históricas (intérpretes Pascal)
Primer caso de máquina virtual
Todas las operaciones toman como argumentos la pila
Cargar/almacenar: lod, lda, ldc, sto
Aritmética: adi, sbi, mpi
Saltos: ujp, fjp, lab

Similares ventajas e inconvenientes (es un CI muy
próximo a un lenguaje ensamblador)

4
Generación de código. Procesadores de
Lenguaje I

Representaciones intermedias: P
Ejemplos Código P
Ejemplo 1:
x:=y+1

Ejemplo 2:
if cond then x=3

Codigo P
lda x // carga direccion x
lod y // carga valor y
ldc 1 // carga constante 1
adi
// suma 2 pos pila
sto
// almacena tope en inf.

Codigo P
lod cond // carga cond
fjp L1
// si falso salta a L1
lda x
// carga direccion x
ldc 3
// carga constante 3
sto
// almacena tope en inf
lab L1 // etiqueta L1

1

3

y

cond
…

&x

&x
…

…

Generación de código. Procesadores de
Lenguaje I

Árboles de Sintaxis Abstracta
Son árboles de derivación en los que no existe
información superflua
Cada nodo hoja representa un operando y cada nohoja un operador
Ejemplos
Árbol
E
E
T
F

ASA
+

+

T
F
B

A

S:=A+B*C

IF A<B THEN X:=B

:=
B

S

A[I]:=B
:=

IF
+

A

<
*

B

A

:=
B

X

[]
B

A

B
I

C

A

5
Generación de código. Procesadores de
Lenguaje I

Códigos de Tres Direcciones
Sentencias del estilo x = y op z
Cada línea de código tiene un operador y hasta
tres direcciones
Es una representación lineal del ASA
Uso generoso de variable temporales
Directamente relacionado con evaluación de
expresiones

Ejemplo: a = b*(c+d) se traduce a:
tmp1 = c+d
tmp2 = b*tmp1
a = tmp2

Generación de código. Procesadores de
Lenguaje I

Códigos de Tres Direcciones
Ejemplos (relacionar con ASA)
Ejemplo 1:
a=b*-c+4

Codigo 3 direcciones
t1=-c
t2=b*t1
t3=4
t4=t3+t2
a=t4

Ejemplo 2:
if cond then then_statements
else
else_statements;
else_statements;
end if;
if;
Codigo 3 direcciones
t1 = cond
iff t1 else_label
codigo para “then_statements”
then_statements”
goto endif_label
else_label:
codigo para “else_statements”
else_statements”

endif_label:
endif_label:

6
Generación de código. Procesadores de
Lenguaje I

Instrucciones en Código 3
direcciones

Asignaciones: x:=y op z (op aritmético o lógico)
Asignaciones 1 argumento x:= op y
Copia x:=y
Salto incondicional: goto L (L etiqueta)
Salto condicional gotoc x L frecuente.: iff x L (if false)
Salto condicional if x relop y goto L
Etiquetas: label L
Llamada a subrutina:
param x1
...
param xn
call p,n
ret

Asignaciones indexadas
x:=y[i]
x[i]=y

Asignaciones con punteros
x:=&y, x:=*y, *x:=y

Generación de código. Procesadores de
Lenguaje I

Códigos de 3 direcciones
Cada línea de código tiene un operador y hasta tres direcciones

Tipos: Cuartetos, Tercetos, Tercetos Indirectos
Cuartetos
Se representan por cuatro valores:
(<OPERADOR>,<Operando1>,<Operando2>,<Resultado>)
Ejemplos
Expresión

Cuartetos

Otra representación

S:=A+B*C

*
+
:=

B C
A T1
T2 S

IF A<B THEN X:=B

<
A
IFF
E1
:=
B
LABEL

B

T1
T2

(*, B, C, T1)
(+, A, T1, T2)
(:=,T2, , S )

E1
E2
X
E2

(<,
A, B, E1)
(IFF,
E1, , E2 )
(:=,
B, , X )
(LABEL, , , E2)

7
Generación de código. Procesadores de
Lenguaje I

Implementación de código 3
direcciones
Implementación con cuartetos

4 campos: (op,y,z,x) para x=y op z
Campos se anulan si no se necesitan, ej.: (rd,x,,)

Implementación con tercetos
El cuarto elemento siempre es un temporal
En lugar de nombrarlo, utilizar el propio índice del
terceto
Ejemplo: a = b+(c*d)
[cuartetos]
1. (mul,c,d,t1)
2. (add,b,t1,t2)
3. (:=,a,t2,_)

[tercetos]
1: (mul,c,d)
2: (add,b,(1))
3: (:=,a,(2))

Generación de código. Procesadores de
Lenguaje I

Tercetos
Los cuartetos son la herramienta más general
Inconvenientes
Ocupan demasiado espacio
Requieren muchas variables auxiliares para
almacenar los resultados intermedios

Los tercetos resuelven este problema
suprimiendo el operando del resultado, queda
implícito y asociado a dicho terceto
(<OPERADOR>, <Operando1>, <Operando2>)
Hacen referencia a otro terceto
Son equivalentes a Árboles de Sintaxis Abstracta

8
Generación de código. Procesadores de
Lenguaje I

Tercetos y Tercetos Indirectos
Ejemplos
Expresión

Tercetos

S:=A+B*C

1
2
3
1
2
3
4

IF A<B THEN X:=B

(*, B, C)
(+, A, (1))
(:=, 2, S)
(<, A, B)
(IFF,(1),(4))
(:=, B, X)
(,,)

Los Tercetos Indirectos son análogos a los anteriores
pero en lugar de ejecutarse secuencialmente se ejecutan
según un vector llamado SECUENCIA
Son más fáciles de optimizar
Ocupan menos memoria, el mismo terceto aparece una vez

Generación de código. Procesadores de
Lenguaje I

Tercetos Indirectos, Ejemplos
Expresión
S:=A+B*C
X:=A+B*C

WHILE X<B DO X:=X+1

Tercetos Ind.
1 (*, B, C)
2 (+, A, (1))
3 (:=, (2), S)
4 (:=, (2), X)
VE=(1, 2, 3, 1, 2, 4)
1 (<, X, B)
2 (gotoc, (1), (4))
3 (goto, , (7))
4 (+, X, 1)
5 (:=, (4), X)
6 (goto, , (1))
7 (, , )
VE=(1, (2, 3, 4, 5, 6)+, 7)

9
Generación de código. Procesadores de
Lenguaje I

Generación de Código Intermedio:
Declaraciones

Definición de atributos con CI (sintetizado) + acciones
semánticas
Construcción explícita de la tabla de símbolos
Se crean entradas para cada variable según su tipo
Reserva de espacio en función del tipo empleado
offset es una variable global con dirección de la tabla actual
T.tipo, T.ancho: atributos que caracterizan cada entrada en
la tabla

Simplificación: tabla de un solo procedimiento
Extensiones para declaraciones en procedimientos y
ámbitos anidados

Generación de código. Procesadores de
Lenguaje I

Declaraciones (1 procedimiento)
Producciones
P→
D
D→D; D
D→id: T
T→integer
T→real
T→array[num]
of T

T→↑T

Reglas semánticas
{offset=0}

{ponerTabla(id.lex, T.tipo, offset)
offset=offset+T.ancho}
{T.tipo=integer
T.ancho=4}
{T.tipo=real
T.ancho=8}
{T0.tipo=array(num.lex, T1.tipo)
T0.ancho=num.lex*T1.ancho}
{T0.tipo=pointer(T1.tipo)
T0.ancho=4}

10
Generación de código. Procesadores de
Lenguaje I

Tercetos para Expresiones
Se construyen nombres temporales para los nodos interiores del
árbol sintáctico
Se calcula el valor del no terminal E en el lado izquierdo de E→E+E
dentro de un nuevo temporal t: E1 a t1; E2 a t2; t= t1+t2
E.lugar, es el nombre que contendrá el valor de E (“lugar” en TS)
E.código, es la secuencia instrucciones de tres direcciones para E
La función tempnuevo() devuelve una secuencia de nombres distintos
t1, t2, , t3,... en sucesivas llamadas
Las variables tienen el nombre id.lex, y se accede a su declaración en
la tabla de símbolos como lookup(id.lex) (detectar errores)
gen(.) genera código de tres direcciones

El número de temporales podría optimizarse posteriormente

Generación de código. Procesadores de
Lenguaje I

Asignaciones y Aritmética
Producciones Regla Semántica
S→ id := E
E→ E+E

{p=lookup(id.lex);
if (p!=null) S.código := E.código || gen(p ’:=’ E.lugar)}
{E0.lugar := tempnueva();
E0.código := E1.código || E2.código ||
gen(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar)}

E→ E*E

{E0.lugar := tempnueva();
E0.código := E1.código || E2.código ||
gen(E.lugar ´:=´ E1.lugar ´*´ E2.lugar)}

E→ -E

{E0.lugar := tempnueva();
E0.código := E1.código || gen(E0.lugar´:=menosu´ E1.lugar)}

E→ (E)

{E0.lugar := E1.lugar;
E0.código := E1.código}
{p=lookup(id.lex), if (p!=null) E.lugar := p;}

E→ id

11
Generación de código. Procesadores de
Lenguaje I

Conversiones de Tipos
Producciones Regla Semántica
S→ id := E

{p=lookup(id.lex);
S.código := E.código || gen(p ’:=’ E.lugar)}
{E0.lugar := tempnuevo();
if (E1.tipo=integer and E2.tipo=integer) then
c=gen(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar)
E0.tipo=int
if (E1.tipo=real and E2.tipo=real) then
c=gen(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar)
E0.tipo=real
if (E1.tipo=integerl and E2.tipo=real) then
c=gen(E0.lugar ´:=inttoreal´ E1.lugar ´+´ E2.lugar)
E0.tipo=real
if (E1.tipo=real and E2.tipo=integer) then
c=gen(E0.lugar ´:=l´ E1.lugar ´+ inttoreal´ E2.lugar)
E0.tipo=real}
E0.código := E1.código || E2.código ||c

E→ E+E

….

t1:=multi(i,j)
t3:=inttoreal t1
t2:=addr(y, t3)

Ej.: x:=y+i*j

x:=t2

Generación de código. Procesadores de
Lenguaje I

Evaluación de Declaraciones y
Expresiones
TS

Ej.: a: int; c: real;
a=0;c=a*4.0+1;

a
entero

Ds
Ds
Ds
λ

id : T

id : T

(c) (real)

(a) (int)

104

Ss
D

D

real

100

P

c

;

S
id = E

(a)

Código
Intermedio:

Ss
S

(0)

Ss

id =E

λ

(c)

E + E

(1)

t1:=0
a:=t1
t2:=inttoreal a
t3:= t2 *4.0
t4:= t3+1
c:=t4

E * E

(a)

(4)

12
Generación de código. Procesadores de
Lenguaje I

Evaluación de Declaraciones y
Expresiones

Con atributo código: concatenar atributos sintetizados
a: int; c: real;
t1:=0
a=0;c=a*4.0+1;
a:=t1
t2:=inttoreal a

Ss

t3:= t2 *4
t4:= t3+1

S

Ss

c:=t4

t1:=0

id = E

(a)

a:=t1

S

(0)
id

(c)

Ss

=

E
+

E
E * E

(a)

(4)

t2:=inttoreal a

λ
E

(1)

t2:=inttoreal a
t3:= t2 *4
t4:= t3+1
c:=t4

t2:=inttoreal a
t3:= t2 *4
t4:= t3+1

t3:= t2 *4

Generación de código. Procesadores de
Lenguaje I

Evaluación de Declaraciones y
Expresiones
Sin atributo código: escribir código globalmente
a: int; c: real;
a=0;c=a*4.0+1;
Ss

t1:=0

S

a:=t1

Ss

t2:=inttoreal a

t1:=0

id = E

(a)

t3:= t2 *4

a:=t1

S

(0)
id

(c)

=

E
+

E

t2:=inttoreal a

E * E

(a)

Ss

c:=t4

t4:= t3+1
c:=t4

t4:= t3+1

λ

Salida global

E

(1)

t3:= t2 *4

(4)

13
Generación de código. Procesadores de
Lenguaje I

CGI sin utilizar atributo código
Producciones

Regla Semántica

S→ id := E {p=lookup(id.lex);
if (p!=null) emitir(p ’:=’ E.lugar)}

E→ E+E

{E0.lugar := tempnuevo();
emitir(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar)}

E→ E*E

{E0.lugar := tempnuevo;
emitir(E0.lugar ´:=´ E1.lugar ´*´ E2.lugar)}

E→ -E

{E0.lugar := tempnuevo();
emitir(E0.lugar´:=menosu´ E1.lugar)}

E→ (E)

{E0.lugar := E1.lugar;}

E→ id

{p=lookup(id.lex), if (p!=null) E.lugar := p;}

Generación de código. Procesadores de
Lenguaje I

Literales numéricos
Dos posibilidades:
estricta (lugar es una dirección de memoria)
lugar es un texto
Producciones Regla Semántica
a) E→ num
b) E→ num
a=3+b+7+c

{E.lugar := nuevatemp(); emitir(E.lugar ’:=’ num.lex)}
{E.lugar := num.lex)}
tmp1=3

tmp1=3+b

tmp2=tmp1+b

tmp2=tmp1+7

tmp3=7

tmp3=tmp2+c

tmp4=tmp2+tmp3

a=tmp3

tmp5=tmp4+c
a=tmp5

14
Generación de código. Procesadores de
Lenguaje I

Expresiones con Arrays (1D)
Suponiendo almacenamiento secuencial, las direcciones se calculan
desde la dirección base (dirección en memoria) con desp. lineal:
a[i+1]:: dir_base(a)+(i+1)*sizeof(a)

Ejemplo:
a[i+1]=a[j+2]+3;

E0→id [E1]

{p=lookup(id.lex)
E0.lugar=tempnuevo()
t=tempnuevo()
gen(t ’=’ E1.lugar ’*’ size(p))
gen(E0.lugar ’=p[’ t ’]’ )
}
S→id [E1]=E2 {p=lookup(id.lex)
t=tempnuevo()
gen(t ’=’ E1.lugar ’*’ size(p))
gen(’ p[’ t ’]=’ E2.lugar)
}

t1=j+2
t2=t1*size(a)
t3=a[t2];
t4=t3+3
t5=i+1
t6=t5*size(a)
a[t6]=t4

También puede hacerse con indirecciones (punteros)
a=p[i]

t1=&p;
t2=t1+i;
a=*t2

Generación de código. Procesadores de
Lenguaje I

Evaluación de Arrays (1D)
Sin atributo código: escribir código globalmente
a[i+1]=a[j+2]+3;
t5:= t1*size(a)
a[t5]:=t4

S

t3:=t2*size(a)

id

[

(a)

E
id

(i)

E
+

]
E

=

E

t1:=i+1

num

(1)

t4:=a[t3]

id

[

(a)

E
id

(j)

E
+

]
t2:=j+2

E
num

(2)

Ejemplo:
a[i+1]=a[j+2]+3;
t1:=i+1
t2:=j+2
t3:=t2*size(a)
t4:=a[t3]
t5:= t1*size(a)
a[t5]:=t4

Salida global

15
Generación de código. Procesadores de
Lenguaje I

Expresiones con registros y punteros
Registros
Los registros tienen campos con desplazamiento fijo
…

base de cplx
typedef struct cplx{
cplx.real
desplaz. campo “imag”
double real;
cplx.imag
double imag;
…
};
código 3 dir independiente: función “offset (tipo,campo)” en la TS

E→id “.” id

{

E.lugar=tempnuevo();
t1=tempnuevo();
t2=tempnuevo();
gen(t1 ’=&’ id1.lex)
gen(t2 ‘=’ t1 +offset(’ id1.lex ’ ,’id2.lex ’)’);
gen(E.lugar ’=*’ t2);

}

Punteros tienen traducción directa
i=*x;
*x=i;

Generación de código. Procesadores de
Lenguaje I

Expresiones con registros y punteros
Combinaciones de punteros y registros
…

cplx *c1, *c2;
…
c1 ->real=c2->imag;

cplx.real
cplx.imag

base de cplx
desplaz. campo “imag”

…

E→id “->” id {
E.lugar=tempnuevo();
t=tempnuevo();
gen(t ‘=’ id1 +offset(’ id1.lex ’ ,’id2.lex ’)’);
gen(E.lugar ’=*’ t);
}

16
Generación de código. Procesadores de
Lenguaje I

Expresiones con registros y punteros
Ejemplos
…

cplx *c1, *c2;
…
c1 ->real=c2->imag;

base de cplx

cplx.real

desplaz. campo “imag”

cplx.imag
…

Ejemplo:
num.real=num.imag;

Ejemplo:
c1->real= c2-> num.imag;

t2=&num
t3=t1+offset(num,imag)
t1=*t1
t4=&num
t5=t4+offset(num,real)
*t5=t1

t2=c1+offset(c1,imag)
t3=*t2
t4=c2+offset(c2,real)
*t4=t3

Generación de código. Procesadores de
Lenguaje I

Evaluación de Arrays Multidimensionales
Un array se accede como un bloque
de posiciones consecutivas. Si empieza
en 0:
w

a[i]

…

a[1]
a[0]

base
i2

posicion a[i]: base+i*w
A[0][0]

Matriz 2 dimensiones (por filas): A[i1][i2]
posicion: base+(i1*n2+i2)*w

…

A[0][i2]

…

…

…

…

…

A[i1][0]

…

A[i1][i2]

…

…

i1

…

…

…

Generalización a k dimensiones: A[i1][i2]…[ik]

n2

posicion: base+((…((i1*n2+i2)*n3+i3)…)*nk+ik )*w
Ecuación recurrente:
e1=i1
em=em-1*nm+im

17
Generación de código. Procesadores de
Lenguaje I

Evaluación de Arrays Multidimensionales

“E” representa la evaluación de una expresión, “L” el acceso a una
variable
L.offset es distinto de null si L es un acceso con desplazamiento (array
según instrucción de código intermedio)
L.lugar es la posición de comienzo

El símbolo recurrente “Lista” efectúa el cálculo de posición de los índices
con la ecuación recursiva:
Lista0::=Lista1 , E
Lista.lugar almacena el valor em
Lista.ndim es la dimensión (Lista0.ndim= Lista1.ndim+1)
Al terminar el último índice hay que multiplicar por w

El tipo array mantiene sus propiedades, en la tabla de símbolos: id.lex
tiene asociada una dirección: Lista.array
Tamaño total: ancho (Lista.array)
Límite de una dimensión: limite(Lista.array, m)

Generación de código. Procesadores de
Lenguaje I

Evaluación de Arrays Multidimensionales
Producciones
S→ L := E
E→ L
E→ num
L→ id
L→ Lista]

Lista→Lista][E

Lista→id [E

Regla Semántica
{if (L.offset == null) gen(L.lugar’=‘ E.lugar
else gen(L.lugar ‘[‘ L.offset ‘]=’E.lugar}
{if (L.offset == null) gen(E.lugar’=‘ L.lugar
else E.lugar=tempnuevo(); gen(E.lugar ‘=‘L.lugar ‘[‘ L.offset ‘]’)}
{E.lugar=tempnuevo(); gen(E.lugar ‘=‘ num.val)}
{p=lookup(id.lex), L.lugar := p, L.offset=null}
{L.lugar= tempnuevo();
L.offset= tempnuevo();
gen(L.lugar ´:=´ base(Lista.array) )
gen(L.offset ‘=‘ Lista.lugar ‘*’ ancho (Lista.array))}
{t= tempnuevo(), m=Lista1.ndim+1
gen(t ‘=‘ Lista1.lugar ‘*’ limite(Lista1.array,m))
gen(t ‘=‘ t ‘+’ E.lugar)
Lista0.array=Lista1.array
Lista0.lugar=t, Lista0.ndim=m}
{p=lookup(id.lex), Lista.array= p
Lista.lugar=E.lugar
Lista.ndim=1}

18
Generación de código. Procesadores de
Lenguaje I

Evaluación de Arrays Multidimensionales

Ej.: x:=M[3][1] (M de tipo array{[0…4]x[0…4],int})
S1
L1

• base
• limite(i)
• ancho
celda

:= E1

id

L2

(x)

Código
Intermedio:

Lista1 ]

t1:=3
t2:=1

E3

Lista2 ] [

id

(M)

[

E2

num (1)

num (3)

t3:=t1*5
t3:=t3+ t2
t4:=base(M)
t5:=t3*4
t6:=t4[t5]
x:=t6

Generación de código. Procesadores de
S1: /S1->L1=E1/
Lenguaje I
L1: L1.lugar=x /L1->id/
L1.offset=null
E1: /E1->L2/
L2: /L2->Lista1]/
Lista1: /Lista1->Lista2][E3/
Lista2: /Lista2->E2]/
E2 :
E2.lugar=t1 /E2->num/
t1=3
Lista2.lugar=t1
Lista2.ndim=1
Lista2.array=M
E3 :
E3.lugar=t2 /E3->num/
t2=1
Lista1.lugar=t3
t1:=3
m=2
t2:=1
t3= t1*5
(*lista2*limite(M,1)*)
t3:=t1*5
t3= t3+t2 (*suma indice E3*)
Lista1.array=M
t3:=t3+ t2
Lista1.lugar=t3
t4:=base(M)
Lista1.ndim=m
L2.lugar= t4
t5:=t3*4
L2.offset=t5
t6:=t4[t5]
t4=base(M)
x:=t6
t5=t3*ancho(M)
(*lista1*ancho*)
E1.lugar=t6
t6=t5[t5]
x=t6

19
Generación de código. Procesadores de
Lenguaje I

GCI para Expresiones Booleanas
Dos posibilidades:
Valores numéricos (0,1) …
Etiquetas para control de flujo
Con valores numéricos: E toma un valor aritmético,
instrucciones de salto en función del valor
if (a<b) x=1

t1=a<b
iff t1 L1
x:=1
L1 …

E, a<b, tiene un
atributo: t1

Con etiquetas: una expresión booleana tiene directamente las
etiquetas, que son posiciones destino de control de flujo:
E.true, E.false (evaluación en cortocircuito)
Son atributos heredados
if (a<b) x=1

L1
L2

if a < b goto L1
goto L2
x:=1

E, a<b, tiene tres
atributos: L1, L2, código

…

Generación de código. Procesadores de
Lenguaje I

GCI para Expresiones Booleanas
Ejemplos:
if E then S1 else S2

while (E) S

Codigo 3 direcciones
Código de evaluación de E
evaluació
(hacia qué etiqueta salto)
qué
salto)
E.true:
E.true:
Código para S1
goto ‘Seguir’
Seguir’
E.false:
E.false:
Código para S2
Seguir:
…siguientes instrucciones

Codigo 3 direcciones
Comienzo:
Comienzo:
Código de evaluación de E
evaluació
(hacia qué etiqueta salto)
qué
salto)
E.true:
E.true:
Código para S
goto ‘Comienzo’
Comienzo’
E.false:
E.false:
…siguientes instrucciones

20
Generación de código. Procesadores de
Lenguaje I

GCI- Condiciones Booleanas
Evaluación “en cortocircuito”
AND: E0 -> E1 || E2

true

E1 false

true

false
label E1.false:
true

false

E2

E0

Generación de código. Procesadores de
Lenguaje I

GCI- Condiciones Booleanas
Evaluación “en cortocircuito”
AND: E0 -> E1 && E2

true

E1 false

true

false
label E1.true:
true

E2 false

E0

21
Generación de código. Procesadores de
Lenguaje I

GCI- Condiciones Booleanas
Evaluación “en cortocircuito”
Producción
E:=‘true’
E:=‘false’
E:=id1 relop id2
E0:=E1´or´ E2

E0:=E1´and´ E2

E0:=(E1)

Regla Semántica
{E.codigo = gen (‘goto’ E.true)}
{E.codigo = gen (‘goto’ E.false)}
{E.code=gen(‘if’ id1.lugar ‘relop’ id2.lugar ’goto’ E.true)||
gen(‘goto’ E.false)}
{E1.false= newlabel()
E1.true= E0.true
E2.true= E0.true
E2.false= E0.false
E0.codigo= E1.codigo || gen(E1.false ‘:’) || E2.codigo}
{E1.true= newlabel()
E1.false= E0.false
E2.true= E0.true
E2.false= E0.false
E0.codigo= E1.codigo || gen(E1.true ‘:’) || E2.codigo}
{E1.false= E0.false
E1.true= E0.true
E1.code= E0.code}

Generación de código. Procesadores de
Lenguaje I

GCI- Condiciones Booleanas
Evaluación “en cortocircuito”. Ejemplo:
if (B) S:
codigo de B
Lt0:
código de S
Lf0:
…

Ejemplo:
if (a<(b+32) || (b>0 && a>0))
x=1
t1=b+32
if a < t1 goto Lt0
if b > 0 goto L1
goto Lf0
Label L1:
if a > 0 goto Lt0
goto Lf0
Label Lt0
x=1
Labl Lf0
…

22
Generación de código. Procesadores de
Lenguaje I

GCI- Estructuras de control
CONDICIONAL: S-> if (B) S else S

true

B false

label B.true:
S1
goto S.next:
label B.false:
S2
label S.next:

E0

Generación de código. Procesadores de
Lenguaje I

GCI- Estructuras de control
BUCLE: S-> while (B) do S

label inicio:
true

B false

label B.true:
S
goto inicio
label S.next:

E0

23
Generación de código. Procesadores de
Lenguaje I

GCI- Sentencias Condicionales
Atributo heredado S.next: instrucción continuación
Problema: etiquetas desconocidas a priori (idem)

Producción
S:=if E then S1

S0:=if E then S1 else S2

S0:= while E do S1

Regla Semántica
{E.true= newlabel()
E.false= S0.next
S1.next= S0.next
S0.codigo=E.codigo||gen(E.true ‘:’)||S1.codigo}
{E.true= newlabel()
E.false= newlabel()
S1.next= S0.next
S2.next= S0.next
S0.codigo=E.codigo||gen(E.true ‘:’)||S1.codigo||
gen(‘goto’ S0.next||gen(E.false ‘:’)||S2.codigo}
{begin = newlabel()
E.true= newlabel()
E.false= S0.next
S1.next= begin
S0.codigo=gen(begin ‘:’)||E.codigo|| gen(E.true ‘:’)||
S1.codigo||gen(‘goto’ begin)}

Generación de código. Procesadores de
Lenguaje I

GCI- Condicionales sin atrib código
Atributo heredado S.next: instrucción continuación
Producción
S0:=if
E then
S1
S0:=if
E then
S1 else
S2
S0:= while
E do
S1

Regla Semántica
{E.true= newlabel(); E.false= S0.next}
{emitir(‘label ’ E.true ‘:’); S1.next= S0.next;}
{E.true= newlabel(); E.false= newlabel()}
{emitir(‘label ’ E.true ‘:’); S1.next= S0.next}
{emitir(‘label ’ E.false ‘:’); S2.next= S0.next}
{begin = newlabel(); E.true= newlabel();
E.false= S0.next; emitir(‘label ’ begin ‘:’);}
{S1.next= begin; emitir(‘label ’ E.true ‘:’); }

24
Generación de código. Procesadores de
Lenguaje I

Ejemplo control de flujo
while s<K do
if a>b
s=s+a
else
s=s-a

S1
while E1

id

(s)

do

S2

> id if E2 S3 else S4

(K)

id

(a)

> id

(b)

Código 3
direcciones
L1: if s<K goto L2
goto L0
L2: if a>b goto L3
goto L4
L3: t1=s+a
s=t1
goto L0
L4: t2=s-a
s=t2
goto L1
L0: …

Generación de código. Procesadores de
Lenguaje I
S1.next=L0 (**)
S1: /S1->while E1 do S2/
S1.next=L0
begin=L1
E1.true=L2
E1.false=L0
E1: /E1->id op id/
E1.codigo=if s<K goto L2
goto L0
S2.next=L0
S2: /S2->if E2 then S3 else S4/
E2.true=L3
E2.false=L4
L1: if s<K goto L2
E2 :
/E2->id op id/
goto L0
E2.codigo=if a>b goto L3
L2: if a>b goto L3
goto L4
goto L4
goto L0
L3: t1=s+a
if a>b goto L3
S3.next=L1
s=t1
goto L4
S3: /S3->s=s+a/
goto L0
L3: t1=s+a
S3.codigo=t1=s+a
L4: t2=s-a
s=t1
s=t1
s=t2
goto L0
S4.next=L0
goto L1
L4: t2=s-a
S4: /S4->s=s-a/
L0: …
s=t2
S4.codigo=t2=s+a
s=t2
S2.codigo=
S1.codigo=

25
Generación de código. Procesadores de
Lenguaje I

Relleno con retroceso (back-patching)
El código intermedio para control de flujo usa saltos a etiquetas
“futuras”
No es problema en CI puesto que se tratan como nombres
En el código final hay que transformarlas en direcciones

Una solución es diferir su ajuste final a una pasada posterior
Implementación sencilla: archivo temporal

Código

target:

goto target
...
goto target
...
mov foobar,r1

Tabla

goto target
….
goto target
…
target: mov foobar, r1

target
… backpatch list
(lista enlazada)

Generación de código. Procesadores de
Lenguaje I

Traducción de llamadas a funciones
Es el aspecto más dependiente del entorno de ejecución
Difícil de generalizar a código intermedio

Dos aspectos básicos
Declaración de función/procedimiento (o definición)
Llamada de función/procedimiento

El código intermedio define el punto de entrada y el punto de
retorno de la función
Definición
Instrucción de entrada
<código del cuerpo de la función>
Instrucción de salida
Llamada
Instrucción de comienzo de cálculo de parámetros
<código del cálculo de parámetros>
Instrucción de llamada

26
Generación de código. Procesadores de
Lenguaje I

GCI para llamadas a funciones
Instrucciones 3 direcciones
param x
call f, n

entry f
return x

Código P
mst
cup

ent f
ret

Ej.:
int f(int x, int y)
{return x+y+1;}

f(2+3,4);

entry f
t1=x+y
t2=t1+1
return t2
t1=2+3
param t1
param 4
call f 2

Código 3-dir

ent
lod
lod
adi
ldc
adi
ret
mst
ldc
ldc
adi
ldc
cup

f
x
y
1

2
3
4
f

Código P

Generación de código. Procesadores de
Lenguaje I

Llamadas a funciones dentro de
expresiones
Producciones Regla Semántica
S→ id := E
E→ E+E

{p=lookup(id.lex);
if (p!=null) emitir(p ’:=’ E.lugar)}
{E0.lugar := tempnuevo();
emitir(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar)}

…
E→ id

{p=lookup(id.lex), if (p!=null) E.lugar := p;}

E → id(lista)

{para cada elemento p en lista.pila
emitir(‘param ‘ p)
emitir(‘call’ id.lugar)}

…

27
Generación de código. Procesadores de
Lenguaje I

Ejemplo con funciones y expresiones
Sin atributo código: escribir código globalmente
a=0;c=1+f(2,4*a);
S
id

(c)

c:=t4

=

E
E

+

t1:=0

t4=1+t3
param t2

a:=t1

id

(f)

t2:=4*a

t3=call f 2

(1)

param 1

E

param t2

( lista )

param 1
t2 1

E , lista

(1)

E
E

(4)

*

t3=call f 2
t2
t2:=4*a

t4:= 1+t3
c:=t4

E

(a)

28

Más contenido relacionado

PPT
Código intermedio
PPTX
Lenguaje de programacion c#
PDF
Los lenguajes aceptados para una maquina de turing
PPTX
Unidad 2 expresiones regulares
PPTX
Maquina de pila abstracta
PDF
Arboles de derivacion
DOCX
Estándares para el Modelado de Procesos de Negocios
Código intermedio
Lenguaje de programacion c#
Los lenguajes aceptados para una maquina de turing
Unidad 2 expresiones regulares
Maquina de pila abstracta
Arboles de derivacion
Estándares para el Modelado de Procesos de Negocios

La actualidad más candente (20)

PDF
Portafolio unidad 2 [Lenguajes y autómatas]- Expresiones y lenguajes regulares
PPT
Ejercicios
PPTX
Lenguaje ensamblador
PDF
Generación código intermedio 2
PPTX
Analizador Sintáctico
PPTX
Segunda forma normal
PDF
automatas finitos
PDF
PDF
Introducción a la Programación en Visual C# (C Sharp)
PPTX
Lenguajes de programacion (exposicion)
PPTX
Taller de Base de Datos - Unidad 7 Conectividad
PDF
POO Unidad 2: Programación Orientada a Objetos
PPT
Operaciones entre lenguajes
PDF
Unidad1 2 Lenguajes y automatas
PPTX
Herramientas case full informacion
DOCX
TAREAS DE LA ING. DE REQUISITOS
PPSX
Tema 1-1 datos y tipos de datos
PPT
PARADIGMA FUNCIONAL
PPTX
Paradigmas de programación
PPTX
PARADIGMA IMPERATIVO
Portafolio unidad 2 [Lenguajes y autómatas]- Expresiones y lenguajes regulares
Ejercicios
Lenguaje ensamblador
Generación código intermedio 2
Analizador Sintáctico
Segunda forma normal
automatas finitos
Introducción a la Programación en Visual C# (C Sharp)
Lenguajes de programacion (exposicion)
Taller de Base de Datos - Unidad 7 Conectividad
POO Unidad 2: Programación Orientada a Objetos
Operaciones entre lenguajes
Unidad1 2 Lenguajes y automatas
Herramientas case full informacion
TAREAS DE LA ING. DE REQUISITOS
Tema 1-1 datos y tipos de datos
PARADIGMA FUNCIONAL
Paradigmas de programación
PARADIGMA IMPERATIVO
Publicidad

Similar a Codigo intermedio (20)

PPT
Lenguajec diapositivas
PPT
Lenguajec 1
PPSX
Lenguaje c diapositivas
PPSX
Lenguajes diapositivas
PPSX
Lenguajes diapositivas
PPT
Clase 3introduccion a_lenguace_c
PPTX
Lenguaje c
PPT
Algoritmos Conceptos Basicos - www.ingfiis.tk
PPT
Curso lenguaje c_segundo_modulo_
PPTX
Presentacion_Lenguaje_C.pptx
PPT
Algoritmosconeptosbasicos 1
PPTX
Cap4
PPTX
Introducción
PPTX
Introducción
PPT
Introduccion allenguajedeprogramacion
PDF
Introduccion del Lenguaje C
PPT
Exposición
PPT
Programa c++
PDF
Semana 1 - Principios de Algoritmos.pdf
Lenguajec diapositivas
Lenguajec 1
Lenguaje c diapositivas
Lenguajes diapositivas
Lenguajes diapositivas
Clase 3introduccion a_lenguace_c
Lenguaje c
Algoritmos Conceptos Basicos - www.ingfiis.tk
Curso lenguaje c_segundo_modulo_
Presentacion_Lenguaje_C.pptx
Algoritmosconeptosbasicos 1
Cap4
Introducción
Introducción
Introduccion allenguajedeprogramacion
Introduccion del Lenguaje C
Exposición
Programa c++
Semana 1 - Principios de Algoritmos.pdf
Publicidad

Último (20)

PDF
Híper Mega Repaso Histológico Bloque 3.pdf
PDF
Lección 6 Escuela Sab. A través del mar rojo.pdf
PDF
Conecta con la Motivacion - Brian Tracy Ccesa007.pdf
PDF
Romper el Circulo de la Creatividad - Colleen Hoover Ccesa007.pdf
PDF
CONFERENCIA-Deep Research en el aula universitaria-UPeU-EduTech360.pdf
PDF
Guia de Tesis y Proyectos de Investigacion FS4 Ccesa007.pdf
PPTX
AGENTES PATÓGENOS Y LAS PRINCIPAL ENFERMEAD.pptx
PDF
Fundamentos_Educacion_a_Distancia_ABC.pdf
PDF
Metodologías Activas con herramientas IAG
PDF
Educación Artística y Desarrollo Humano - Howard Gardner Ccesa007.pdf
PDF
Habitos de Ricos - Juan Diego Gomez Ccesa007.pdf
DOCX
Tarea De El Colegio Coding For Kids 1 y 2
PDF
OK OK UNIDAD DE APRENDIZAJE 5TO Y 6TO CORRESPONDIENTE AL MES DE AGOSTO 2025.pdf
PDF
Salvese Quien Pueda - Andres Oppenheimer Ccesa007.pdf
PDF
Breve historia de los Incas -- Patricia Temoche [Temoche, Patricia] -- Breve ...
PDF
Escuelas Desarmando una mirada subjetiva a la educación
PDF
GUIA DE: CANVA + INTELIGENCIA ARTIFICIAL
PDF
Didactica de la Investigacion Educativa SUE Ccesa007.pdf
PPT
Cosacos y hombres del Este en el Heer.ppt
DOCX
III Ciclo _ Plan Anual 2025.docx PARA ESTUDIANTES DE PRIMARIA
Híper Mega Repaso Histológico Bloque 3.pdf
Lección 6 Escuela Sab. A través del mar rojo.pdf
Conecta con la Motivacion - Brian Tracy Ccesa007.pdf
Romper el Circulo de la Creatividad - Colleen Hoover Ccesa007.pdf
CONFERENCIA-Deep Research en el aula universitaria-UPeU-EduTech360.pdf
Guia de Tesis y Proyectos de Investigacion FS4 Ccesa007.pdf
AGENTES PATÓGENOS Y LAS PRINCIPAL ENFERMEAD.pptx
Fundamentos_Educacion_a_Distancia_ABC.pdf
Metodologías Activas con herramientas IAG
Educación Artística y Desarrollo Humano - Howard Gardner Ccesa007.pdf
Habitos de Ricos - Juan Diego Gomez Ccesa007.pdf
Tarea De El Colegio Coding For Kids 1 y 2
OK OK UNIDAD DE APRENDIZAJE 5TO Y 6TO CORRESPONDIENTE AL MES DE AGOSTO 2025.pdf
Salvese Quien Pueda - Andres Oppenheimer Ccesa007.pdf
Breve historia de los Incas -- Patricia Temoche [Temoche, Patricia] -- Breve ...
Escuelas Desarmando una mirada subjetiva a la educación
GUIA DE: CANVA + INTELIGENCIA ARTIFICIAL
Didactica de la Investigacion Educativa SUE Ccesa007.pdf
Cosacos y hombres del Este en el Heer.ppt
III Ciclo _ Plan Anual 2025.docx PARA ESTUDIANTES DE PRIMARIA

Codigo intermedio

  • 1. Generación de código. Procesadores de Lenguaje I Generación de Código Intermedio Proceso de Síntesis Lenguaje Intermedio Generación de Código Ventajas del código intermedio Facilitar la fase de optimización Aumentar la portabilidad del compilador de una máquina a otra Se puede utilizar el mismo analizador para diferentes generadores Se pueden utilizar optimizadores independientes de la máquina Facilitar la división en fases del proyecto Fuente Scanner Parser Generador de Código LI Objeto TDS Generación de código. Procesadores de Lenguaje I Generación de Código Intermedio Aumentar la portabilidad del compilador de una máquina a otra Se puede utilizar el mismo analizador para diferentes generadores Se pueden utilizar optimizadores independientes de la máquina C back-ends front-ends Pascal Ada C++ Java Generador de Código Intemedio Optimización independiente de máquina Intel X Dec-Alpha Motorola N+M vs N*M 1
  • 2. Generación de código. Procesadores de Lenguaje I Fase de Análisis position := initial + rate * 60 lexical analyzer id1 := id2 + id3 * 60 syntax analyzer := + id1 * id2l 60 id3 semantic analyzer := Symbol Table rate…. * id2l inttoreal id3 position .... initial …. E r r o r s + id1 60 intermediate code generator Generación de código. Procesadores de Lenguaje I Fase de Síntesis Symbol Table position .... initial …. rate…. intermediate code generator E r r o r s temp1 := inttoreal(60) temp2 := id3 * temp1 temp3 := id2 + temp2 id1 := temp3 3 address code code optimizer temp1 := id3 * 60.0 id1 := id2 + temp1 final code generator MOVF id3, R2 MULF #60.0, R2 MOVF id2, R1 ADDF R1, R2 MOVF R1, id1 2
  • 3. Generación de código. Procesadores de Lenguaje I Tipos de representaciones intermedias La representación del código intermedio depende de la máquina objeto: 0-direcciones: código para máquinas de pila (código P) 2-direcciones: códigos para máquinas con operaciones sobre registros de memoria 3-direcciones: código para máquinas de arquitectura RISC En todo caso, añade un recorrido descendente adicional para generar el código final Generación de código. Procesadores de Lenguaje I Tipos de representaciones intermedias Propiedades: Fácil de producir en el análisis semántico Fácil de traducir a código máquina real Instrucciones simples y concisas, de fácil optimización Tipos Árboles de Sintaxis Abstracta Notación Polaca Inversa (RPN) Código P Códigos de tres direcciones Cuartetos Tercetos Tercetos Indirectos 3
  • 4. Generación de código. Procesadores de Lenguaje I Representaciones intermedias: RPN Notación Polaca Inversa (RPN) Los operadores van después de los operandos S=A+B*C → SABC*+= Ventajas Facilidad para generar código a partir de ella Es la notación más sencilla para el lenguaje intermedio Inconvenientes El código es difícil de entender Poca flexibilidad No es útil para optimización de código Generación de código. Procesadores de Lenguaje I Representaciones intermedias: P Código P Extensión RPN para máquina completa (etiquetas, saltos) Razones históricas (intérpretes Pascal) Primer caso de máquina virtual Todas las operaciones toman como argumentos la pila Cargar/almacenar: lod, lda, ldc, sto Aritmética: adi, sbi, mpi Saltos: ujp, fjp, lab Similares ventajas e inconvenientes (es un CI muy próximo a un lenguaje ensamblador) 4
  • 5. Generación de código. Procesadores de Lenguaje I Representaciones intermedias: P Ejemplos Código P Ejemplo 1: x:=y+1 Ejemplo 2: if cond then x=3 Codigo P lda x // carga direccion x lod y // carga valor y ldc 1 // carga constante 1 adi // suma 2 pos pila sto // almacena tope en inf. Codigo P lod cond // carga cond fjp L1 // si falso salta a L1 lda x // carga direccion x ldc 3 // carga constante 3 sto // almacena tope en inf lab L1 // etiqueta L1 1 3 y cond … &x &x … … Generación de código. Procesadores de Lenguaje I Árboles de Sintaxis Abstracta Son árboles de derivación en los que no existe información superflua Cada nodo hoja representa un operando y cada nohoja un operador Ejemplos Árbol E E T F ASA + + T F B A S:=A+B*C IF A<B THEN X:=B := B S A[I]:=B := IF + A < * B A := B X [] B A B I C A 5
  • 6. Generación de código. Procesadores de Lenguaje I Códigos de Tres Direcciones Sentencias del estilo x = y op z Cada línea de código tiene un operador y hasta tres direcciones Es una representación lineal del ASA Uso generoso de variable temporales Directamente relacionado con evaluación de expresiones Ejemplo: a = b*(c+d) se traduce a: tmp1 = c+d tmp2 = b*tmp1 a = tmp2 Generación de código. Procesadores de Lenguaje I Códigos de Tres Direcciones Ejemplos (relacionar con ASA) Ejemplo 1: a=b*-c+4 Codigo 3 direcciones t1=-c t2=b*t1 t3=4 t4=t3+t2 a=t4 Ejemplo 2: if cond then then_statements else else_statements; else_statements; end if; if; Codigo 3 direcciones t1 = cond iff t1 else_label codigo para “then_statements” then_statements” goto endif_label else_label: codigo para “else_statements” else_statements” endif_label: endif_label: 6
  • 7. Generación de código. Procesadores de Lenguaje I Instrucciones en Código 3 direcciones Asignaciones: x:=y op z (op aritmético o lógico) Asignaciones 1 argumento x:= op y Copia x:=y Salto incondicional: goto L (L etiqueta) Salto condicional gotoc x L frecuente.: iff x L (if false) Salto condicional if x relop y goto L Etiquetas: label L Llamada a subrutina: param x1 ... param xn call p,n ret Asignaciones indexadas x:=y[i] x[i]=y Asignaciones con punteros x:=&y, x:=*y, *x:=y Generación de código. Procesadores de Lenguaje I Códigos de 3 direcciones Cada línea de código tiene un operador y hasta tres direcciones Tipos: Cuartetos, Tercetos, Tercetos Indirectos Cuartetos Se representan por cuatro valores: (<OPERADOR>,<Operando1>,<Operando2>,<Resultado>) Ejemplos Expresión Cuartetos Otra representación S:=A+B*C * + := B C A T1 T2 S IF A<B THEN X:=B < A IFF E1 := B LABEL B T1 T2 (*, B, C, T1) (+, A, T1, T2) (:=,T2, , S ) E1 E2 X E2 (<, A, B, E1) (IFF, E1, , E2 ) (:=, B, , X ) (LABEL, , , E2) 7
  • 8. Generación de código. Procesadores de Lenguaje I Implementación de código 3 direcciones Implementación con cuartetos 4 campos: (op,y,z,x) para x=y op z Campos se anulan si no se necesitan, ej.: (rd,x,,) Implementación con tercetos El cuarto elemento siempre es un temporal En lugar de nombrarlo, utilizar el propio índice del terceto Ejemplo: a = b+(c*d) [cuartetos] 1. (mul,c,d,t1) 2. (add,b,t1,t2) 3. (:=,a,t2,_) [tercetos] 1: (mul,c,d) 2: (add,b,(1)) 3: (:=,a,(2)) Generación de código. Procesadores de Lenguaje I Tercetos Los cuartetos son la herramienta más general Inconvenientes Ocupan demasiado espacio Requieren muchas variables auxiliares para almacenar los resultados intermedios Los tercetos resuelven este problema suprimiendo el operando del resultado, queda implícito y asociado a dicho terceto (<OPERADOR>, <Operando1>, <Operando2>) Hacen referencia a otro terceto Son equivalentes a Árboles de Sintaxis Abstracta 8
  • 9. Generación de código. Procesadores de Lenguaje I Tercetos y Tercetos Indirectos Ejemplos Expresión Tercetos S:=A+B*C 1 2 3 1 2 3 4 IF A<B THEN X:=B (*, B, C) (+, A, (1)) (:=, 2, S) (<, A, B) (IFF,(1),(4)) (:=, B, X) (,,) Los Tercetos Indirectos son análogos a los anteriores pero en lugar de ejecutarse secuencialmente se ejecutan según un vector llamado SECUENCIA Son más fáciles de optimizar Ocupan menos memoria, el mismo terceto aparece una vez Generación de código. Procesadores de Lenguaje I Tercetos Indirectos, Ejemplos Expresión S:=A+B*C X:=A+B*C WHILE X<B DO X:=X+1 Tercetos Ind. 1 (*, B, C) 2 (+, A, (1)) 3 (:=, (2), S) 4 (:=, (2), X) VE=(1, 2, 3, 1, 2, 4) 1 (<, X, B) 2 (gotoc, (1), (4)) 3 (goto, , (7)) 4 (+, X, 1) 5 (:=, (4), X) 6 (goto, , (1)) 7 (, , ) VE=(1, (2, 3, 4, 5, 6)+, 7) 9
  • 10. Generación de código. Procesadores de Lenguaje I Generación de Código Intermedio: Declaraciones Definición de atributos con CI (sintetizado) + acciones semánticas Construcción explícita de la tabla de símbolos Se crean entradas para cada variable según su tipo Reserva de espacio en función del tipo empleado offset es una variable global con dirección de la tabla actual T.tipo, T.ancho: atributos que caracterizan cada entrada en la tabla Simplificación: tabla de un solo procedimiento Extensiones para declaraciones en procedimientos y ámbitos anidados Generación de código. Procesadores de Lenguaje I Declaraciones (1 procedimiento) Producciones P→ D D→D; D D→id: T T→integer T→real T→array[num] of T T→↑T Reglas semánticas {offset=0} {ponerTabla(id.lex, T.tipo, offset) offset=offset+T.ancho} {T.tipo=integer T.ancho=4} {T.tipo=real T.ancho=8} {T0.tipo=array(num.lex, T1.tipo) T0.ancho=num.lex*T1.ancho} {T0.tipo=pointer(T1.tipo) T0.ancho=4} 10
  • 11. Generación de código. Procesadores de Lenguaje I Tercetos para Expresiones Se construyen nombres temporales para los nodos interiores del árbol sintáctico Se calcula el valor del no terminal E en el lado izquierdo de E→E+E dentro de un nuevo temporal t: E1 a t1; E2 a t2; t= t1+t2 E.lugar, es el nombre que contendrá el valor de E (“lugar” en TS) E.código, es la secuencia instrucciones de tres direcciones para E La función tempnuevo() devuelve una secuencia de nombres distintos t1, t2, , t3,... en sucesivas llamadas Las variables tienen el nombre id.lex, y se accede a su declaración en la tabla de símbolos como lookup(id.lex) (detectar errores) gen(.) genera código de tres direcciones El número de temporales podría optimizarse posteriormente Generación de código. Procesadores de Lenguaje I Asignaciones y Aritmética Producciones Regla Semántica S→ id := E E→ E+E {p=lookup(id.lex); if (p!=null) S.código := E.código || gen(p ’:=’ E.lugar)} {E0.lugar := tempnueva(); E0.código := E1.código || E2.código || gen(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar)} E→ E*E {E0.lugar := tempnueva(); E0.código := E1.código || E2.código || gen(E.lugar ´:=´ E1.lugar ´*´ E2.lugar)} E→ -E {E0.lugar := tempnueva(); E0.código := E1.código || gen(E0.lugar´:=menosu´ E1.lugar)} E→ (E) {E0.lugar := E1.lugar; E0.código := E1.código} {p=lookup(id.lex), if (p!=null) E.lugar := p;} E→ id 11
  • 12. Generación de código. Procesadores de Lenguaje I Conversiones de Tipos Producciones Regla Semántica S→ id := E {p=lookup(id.lex); S.código := E.código || gen(p ’:=’ E.lugar)} {E0.lugar := tempnuevo(); if (E1.tipo=integer and E2.tipo=integer) then c=gen(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar) E0.tipo=int if (E1.tipo=real and E2.tipo=real) then c=gen(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar) E0.tipo=real if (E1.tipo=integerl and E2.tipo=real) then c=gen(E0.lugar ´:=inttoreal´ E1.lugar ´+´ E2.lugar) E0.tipo=real if (E1.tipo=real and E2.tipo=integer) then c=gen(E0.lugar ´:=l´ E1.lugar ´+ inttoreal´ E2.lugar) E0.tipo=real} E0.código := E1.código || E2.código ||c E→ E+E …. t1:=multi(i,j) t3:=inttoreal t1 t2:=addr(y, t3) Ej.: x:=y+i*j x:=t2 Generación de código. Procesadores de Lenguaje I Evaluación de Declaraciones y Expresiones TS Ej.: a: int; c: real; a=0;c=a*4.0+1; a entero Ds Ds Ds λ id : T id : T (c) (real) (a) (int) 104 Ss D D real 100 P c ; S id = E (a) Código Intermedio: Ss S (0) Ss id =E λ (c) E + E (1) t1:=0 a:=t1 t2:=inttoreal a t3:= t2 *4.0 t4:= t3+1 c:=t4 E * E (a) (4) 12
  • 13. Generación de código. Procesadores de Lenguaje I Evaluación de Declaraciones y Expresiones Con atributo código: concatenar atributos sintetizados a: int; c: real; t1:=0 a=0;c=a*4.0+1; a:=t1 t2:=inttoreal a Ss t3:= t2 *4 t4:= t3+1 S Ss c:=t4 t1:=0 id = E (a) a:=t1 S (0) id (c) Ss = E + E E * E (a) (4) t2:=inttoreal a λ E (1) t2:=inttoreal a t3:= t2 *4 t4:= t3+1 c:=t4 t2:=inttoreal a t3:= t2 *4 t4:= t3+1 t3:= t2 *4 Generación de código. Procesadores de Lenguaje I Evaluación de Declaraciones y Expresiones Sin atributo código: escribir código globalmente a: int; c: real; a=0;c=a*4.0+1; Ss t1:=0 S a:=t1 Ss t2:=inttoreal a t1:=0 id = E (a) t3:= t2 *4 a:=t1 S (0) id (c) = E + E t2:=inttoreal a E * E (a) Ss c:=t4 t4:= t3+1 c:=t4 t4:= t3+1 λ Salida global E (1) t3:= t2 *4 (4) 13
  • 14. Generación de código. Procesadores de Lenguaje I CGI sin utilizar atributo código Producciones Regla Semántica S→ id := E {p=lookup(id.lex); if (p!=null) emitir(p ’:=’ E.lugar)} E→ E+E {E0.lugar := tempnuevo(); emitir(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar)} E→ E*E {E0.lugar := tempnuevo; emitir(E0.lugar ´:=´ E1.lugar ´*´ E2.lugar)} E→ -E {E0.lugar := tempnuevo(); emitir(E0.lugar´:=menosu´ E1.lugar)} E→ (E) {E0.lugar := E1.lugar;} E→ id {p=lookup(id.lex), if (p!=null) E.lugar := p;} Generación de código. Procesadores de Lenguaje I Literales numéricos Dos posibilidades: estricta (lugar es una dirección de memoria) lugar es un texto Producciones Regla Semántica a) E→ num b) E→ num a=3+b+7+c {E.lugar := nuevatemp(); emitir(E.lugar ’:=’ num.lex)} {E.lugar := num.lex)} tmp1=3 tmp1=3+b tmp2=tmp1+b tmp2=tmp1+7 tmp3=7 tmp3=tmp2+c tmp4=tmp2+tmp3 a=tmp3 tmp5=tmp4+c a=tmp5 14
  • 15. Generación de código. Procesadores de Lenguaje I Expresiones con Arrays (1D) Suponiendo almacenamiento secuencial, las direcciones se calculan desde la dirección base (dirección en memoria) con desp. lineal: a[i+1]:: dir_base(a)+(i+1)*sizeof(a) Ejemplo: a[i+1]=a[j+2]+3; E0→id [E1] {p=lookup(id.lex) E0.lugar=tempnuevo() t=tempnuevo() gen(t ’=’ E1.lugar ’*’ size(p)) gen(E0.lugar ’=p[’ t ’]’ ) } S→id [E1]=E2 {p=lookup(id.lex) t=tempnuevo() gen(t ’=’ E1.lugar ’*’ size(p)) gen(’ p[’ t ’]=’ E2.lugar) } t1=j+2 t2=t1*size(a) t3=a[t2]; t4=t3+3 t5=i+1 t6=t5*size(a) a[t6]=t4 También puede hacerse con indirecciones (punteros) a=p[i] t1=&p; t2=t1+i; a=*t2 Generación de código. Procesadores de Lenguaje I Evaluación de Arrays (1D) Sin atributo código: escribir código globalmente a[i+1]=a[j+2]+3; t5:= t1*size(a) a[t5]:=t4 S t3:=t2*size(a) id [ (a) E id (i) E + ] E = E t1:=i+1 num (1) t4:=a[t3] id [ (a) E id (j) E + ] t2:=j+2 E num (2) Ejemplo: a[i+1]=a[j+2]+3; t1:=i+1 t2:=j+2 t3:=t2*size(a) t4:=a[t3] t5:= t1*size(a) a[t5]:=t4 Salida global 15
  • 16. Generación de código. Procesadores de Lenguaje I Expresiones con registros y punteros Registros Los registros tienen campos con desplazamiento fijo … base de cplx typedef struct cplx{ cplx.real desplaz. campo “imag” double real; cplx.imag double imag; … }; código 3 dir independiente: función “offset (tipo,campo)” en la TS E→id “.” id { E.lugar=tempnuevo(); t1=tempnuevo(); t2=tempnuevo(); gen(t1 ’=&’ id1.lex) gen(t2 ‘=’ t1 +offset(’ id1.lex ’ ,’id2.lex ’)’); gen(E.lugar ’=*’ t2); } Punteros tienen traducción directa i=*x; *x=i; Generación de código. Procesadores de Lenguaje I Expresiones con registros y punteros Combinaciones de punteros y registros … cplx *c1, *c2; … c1 ->real=c2->imag; cplx.real cplx.imag base de cplx desplaz. campo “imag” … E→id “->” id { E.lugar=tempnuevo(); t=tempnuevo(); gen(t ‘=’ id1 +offset(’ id1.lex ’ ,’id2.lex ’)’); gen(E.lugar ’=*’ t); } 16
  • 17. Generación de código. Procesadores de Lenguaje I Expresiones con registros y punteros Ejemplos … cplx *c1, *c2; … c1 ->real=c2->imag; base de cplx cplx.real desplaz. campo “imag” cplx.imag … Ejemplo: num.real=num.imag; Ejemplo: c1->real= c2-> num.imag; t2=&num t3=t1+offset(num,imag) t1=*t1 t4=&num t5=t4+offset(num,real) *t5=t1 t2=c1+offset(c1,imag) t3=*t2 t4=c2+offset(c2,real) *t4=t3 Generación de código. Procesadores de Lenguaje I Evaluación de Arrays Multidimensionales Un array se accede como un bloque de posiciones consecutivas. Si empieza en 0: w a[i] … a[1] a[0] base i2 posicion a[i]: base+i*w A[0][0] Matriz 2 dimensiones (por filas): A[i1][i2] posicion: base+(i1*n2+i2)*w … A[0][i2] … … … … … A[i1][0] … A[i1][i2] … … i1 … … … Generalización a k dimensiones: A[i1][i2]…[ik] n2 posicion: base+((…((i1*n2+i2)*n3+i3)…)*nk+ik )*w Ecuación recurrente: e1=i1 em=em-1*nm+im 17
  • 18. Generación de código. Procesadores de Lenguaje I Evaluación de Arrays Multidimensionales “E” representa la evaluación de una expresión, “L” el acceso a una variable L.offset es distinto de null si L es un acceso con desplazamiento (array según instrucción de código intermedio) L.lugar es la posición de comienzo El símbolo recurrente “Lista” efectúa el cálculo de posición de los índices con la ecuación recursiva: Lista0::=Lista1 , E Lista.lugar almacena el valor em Lista.ndim es la dimensión (Lista0.ndim= Lista1.ndim+1) Al terminar el último índice hay que multiplicar por w El tipo array mantiene sus propiedades, en la tabla de símbolos: id.lex tiene asociada una dirección: Lista.array Tamaño total: ancho (Lista.array) Límite de una dimensión: limite(Lista.array, m) Generación de código. Procesadores de Lenguaje I Evaluación de Arrays Multidimensionales Producciones S→ L := E E→ L E→ num L→ id L→ Lista] Lista→Lista][E Lista→id [E Regla Semántica {if (L.offset == null) gen(L.lugar’=‘ E.lugar else gen(L.lugar ‘[‘ L.offset ‘]=’E.lugar} {if (L.offset == null) gen(E.lugar’=‘ L.lugar else E.lugar=tempnuevo(); gen(E.lugar ‘=‘L.lugar ‘[‘ L.offset ‘]’)} {E.lugar=tempnuevo(); gen(E.lugar ‘=‘ num.val)} {p=lookup(id.lex), L.lugar := p, L.offset=null} {L.lugar= tempnuevo(); L.offset= tempnuevo(); gen(L.lugar ´:=´ base(Lista.array) ) gen(L.offset ‘=‘ Lista.lugar ‘*’ ancho (Lista.array))} {t= tempnuevo(), m=Lista1.ndim+1 gen(t ‘=‘ Lista1.lugar ‘*’ limite(Lista1.array,m)) gen(t ‘=‘ t ‘+’ E.lugar) Lista0.array=Lista1.array Lista0.lugar=t, Lista0.ndim=m} {p=lookup(id.lex), Lista.array= p Lista.lugar=E.lugar Lista.ndim=1} 18
  • 19. Generación de código. Procesadores de Lenguaje I Evaluación de Arrays Multidimensionales Ej.: x:=M[3][1] (M de tipo array{[0…4]x[0…4],int}) S1 L1 • base • limite(i) • ancho celda := E1 id L2 (x) Código Intermedio: Lista1 ] t1:=3 t2:=1 E3 Lista2 ] [ id (M) [ E2 num (1) num (3) t3:=t1*5 t3:=t3+ t2 t4:=base(M) t5:=t3*4 t6:=t4[t5] x:=t6 Generación de código. Procesadores de S1: /S1->L1=E1/ Lenguaje I L1: L1.lugar=x /L1->id/ L1.offset=null E1: /E1->L2/ L2: /L2->Lista1]/ Lista1: /Lista1->Lista2][E3/ Lista2: /Lista2->E2]/ E2 : E2.lugar=t1 /E2->num/ t1=3 Lista2.lugar=t1 Lista2.ndim=1 Lista2.array=M E3 : E3.lugar=t2 /E3->num/ t2=1 Lista1.lugar=t3 t1:=3 m=2 t2:=1 t3= t1*5 (*lista2*limite(M,1)*) t3:=t1*5 t3= t3+t2 (*suma indice E3*) Lista1.array=M t3:=t3+ t2 Lista1.lugar=t3 t4:=base(M) Lista1.ndim=m L2.lugar= t4 t5:=t3*4 L2.offset=t5 t6:=t4[t5] t4=base(M) x:=t6 t5=t3*ancho(M) (*lista1*ancho*) E1.lugar=t6 t6=t5[t5] x=t6 19
  • 20. Generación de código. Procesadores de Lenguaje I GCI para Expresiones Booleanas Dos posibilidades: Valores numéricos (0,1) … Etiquetas para control de flujo Con valores numéricos: E toma un valor aritmético, instrucciones de salto en función del valor if (a<b) x=1 t1=a<b iff t1 L1 x:=1 L1 … E, a<b, tiene un atributo: t1 Con etiquetas: una expresión booleana tiene directamente las etiquetas, que son posiciones destino de control de flujo: E.true, E.false (evaluación en cortocircuito) Son atributos heredados if (a<b) x=1 L1 L2 if a < b goto L1 goto L2 x:=1 E, a<b, tiene tres atributos: L1, L2, código … Generación de código. Procesadores de Lenguaje I GCI para Expresiones Booleanas Ejemplos: if E then S1 else S2 while (E) S Codigo 3 direcciones Código de evaluación de E evaluació (hacia qué etiqueta salto) qué salto) E.true: E.true: Código para S1 goto ‘Seguir’ Seguir’ E.false: E.false: Código para S2 Seguir: …siguientes instrucciones Codigo 3 direcciones Comienzo: Comienzo: Código de evaluación de E evaluació (hacia qué etiqueta salto) qué salto) E.true: E.true: Código para S goto ‘Comienzo’ Comienzo’ E.false: E.false: …siguientes instrucciones 20
  • 21. Generación de código. Procesadores de Lenguaje I GCI- Condiciones Booleanas Evaluación “en cortocircuito” AND: E0 -> E1 || E2 true E1 false true false label E1.false: true false E2 E0 Generación de código. Procesadores de Lenguaje I GCI- Condiciones Booleanas Evaluación “en cortocircuito” AND: E0 -> E1 && E2 true E1 false true false label E1.true: true E2 false E0 21
  • 22. Generación de código. Procesadores de Lenguaje I GCI- Condiciones Booleanas Evaluación “en cortocircuito” Producción E:=‘true’ E:=‘false’ E:=id1 relop id2 E0:=E1´or´ E2 E0:=E1´and´ E2 E0:=(E1) Regla Semántica {E.codigo = gen (‘goto’ E.true)} {E.codigo = gen (‘goto’ E.false)} {E.code=gen(‘if’ id1.lugar ‘relop’ id2.lugar ’goto’ E.true)|| gen(‘goto’ E.false)} {E1.false= newlabel() E1.true= E0.true E2.true= E0.true E2.false= E0.false E0.codigo= E1.codigo || gen(E1.false ‘:’) || E2.codigo} {E1.true= newlabel() E1.false= E0.false E2.true= E0.true E2.false= E0.false E0.codigo= E1.codigo || gen(E1.true ‘:’) || E2.codigo} {E1.false= E0.false E1.true= E0.true E1.code= E0.code} Generación de código. Procesadores de Lenguaje I GCI- Condiciones Booleanas Evaluación “en cortocircuito”. Ejemplo: if (B) S: codigo de B Lt0: código de S Lf0: … Ejemplo: if (a<(b+32) || (b>0 && a>0)) x=1 t1=b+32 if a < t1 goto Lt0 if b > 0 goto L1 goto Lf0 Label L1: if a > 0 goto Lt0 goto Lf0 Label Lt0 x=1 Labl Lf0 … 22
  • 23. Generación de código. Procesadores de Lenguaje I GCI- Estructuras de control CONDICIONAL: S-> if (B) S else S true B false label B.true: S1 goto S.next: label B.false: S2 label S.next: E0 Generación de código. Procesadores de Lenguaje I GCI- Estructuras de control BUCLE: S-> while (B) do S label inicio: true B false label B.true: S goto inicio label S.next: E0 23
  • 24. Generación de código. Procesadores de Lenguaje I GCI- Sentencias Condicionales Atributo heredado S.next: instrucción continuación Problema: etiquetas desconocidas a priori (idem) Producción S:=if E then S1 S0:=if E then S1 else S2 S0:= while E do S1 Regla Semántica {E.true= newlabel() E.false= S0.next S1.next= S0.next S0.codigo=E.codigo||gen(E.true ‘:’)||S1.codigo} {E.true= newlabel() E.false= newlabel() S1.next= S0.next S2.next= S0.next S0.codigo=E.codigo||gen(E.true ‘:’)||S1.codigo|| gen(‘goto’ S0.next||gen(E.false ‘:’)||S2.codigo} {begin = newlabel() E.true= newlabel() E.false= S0.next S1.next= begin S0.codigo=gen(begin ‘:’)||E.codigo|| gen(E.true ‘:’)|| S1.codigo||gen(‘goto’ begin)} Generación de código. Procesadores de Lenguaje I GCI- Condicionales sin atrib código Atributo heredado S.next: instrucción continuación Producción S0:=if E then S1 S0:=if E then S1 else S2 S0:= while E do S1 Regla Semántica {E.true= newlabel(); E.false= S0.next} {emitir(‘label ’ E.true ‘:’); S1.next= S0.next;} {E.true= newlabel(); E.false= newlabel()} {emitir(‘label ’ E.true ‘:’); S1.next= S0.next} {emitir(‘label ’ E.false ‘:’); S2.next= S0.next} {begin = newlabel(); E.true= newlabel(); E.false= S0.next; emitir(‘label ’ begin ‘:’);} {S1.next= begin; emitir(‘label ’ E.true ‘:’); } 24
  • 25. Generación de código. Procesadores de Lenguaje I Ejemplo control de flujo while s<K do if a>b s=s+a else s=s-a S1 while E1 id (s) do S2 > id if E2 S3 else S4 (K) id (a) > id (b) Código 3 direcciones L1: if s<K goto L2 goto L0 L2: if a>b goto L3 goto L4 L3: t1=s+a s=t1 goto L0 L4: t2=s-a s=t2 goto L1 L0: … Generación de código. Procesadores de Lenguaje I S1.next=L0 (**) S1: /S1->while E1 do S2/ S1.next=L0 begin=L1 E1.true=L2 E1.false=L0 E1: /E1->id op id/ E1.codigo=if s<K goto L2 goto L0 S2.next=L0 S2: /S2->if E2 then S3 else S4/ E2.true=L3 E2.false=L4 L1: if s<K goto L2 E2 : /E2->id op id/ goto L0 E2.codigo=if a>b goto L3 L2: if a>b goto L3 goto L4 goto L4 goto L0 L3: t1=s+a if a>b goto L3 S3.next=L1 s=t1 goto L4 S3: /S3->s=s+a/ goto L0 L3: t1=s+a S3.codigo=t1=s+a L4: t2=s-a s=t1 s=t1 s=t2 goto L0 S4.next=L0 goto L1 L4: t2=s-a S4: /S4->s=s-a/ L0: … s=t2 S4.codigo=t2=s+a s=t2 S2.codigo= S1.codigo= 25
  • 26. Generación de código. Procesadores de Lenguaje I Relleno con retroceso (back-patching) El código intermedio para control de flujo usa saltos a etiquetas “futuras” No es problema en CI puesto que se tratan como nombres En el código final hay que transformarlas en direcciones Una solución es diferir su ajuste final a una pasada posterior Implementación sencilla: archivo temporal Código target: goto target ... goto target ... mov foobar,r1 Tabla goto target …. goto target … target: mov foobar, r1 target … backpatch list (lista enlazada) Generación de código. Procesadores de Lenguaje I Traducción de llamadas a funciones Es el aspecto más dependiente del entorno de ejecución Difícil de generalizar a código intermedio Dos aspectos básicos Declaración de función/procedimiento (o definición) Llamada de función/procedimiento El código intermedio define el punto de entrada y el punto de retorno de la función Definición Instrucción de entrada <código del cuerpo de la función> Instrucción de salida Llamada Instrucción de comienzo de cálculo de parámetros <código del cálculo de parámetros> Instrucción de llamada 26
  • 27. Generación de código. Procesadores de Lenguaje I GCI para llamadas a funciones Instrucciones 3 direcciones param x call f, n entry f return x Código P mst cup ent f ret Ej.: int f(int x, int y) {return x+y+1;} f(2+3,4); entry f t1=x+y t2=t1+1 return t2 t1=2+3 param t1 param 4 call f 2 Código 3-dir ent lod lod adi ldc adi ret mst ldc ldc adi ldc cup f x y 1 2 3 4 f Código P Generación de código. Procesadores de Lenguaje I Llamadas a funciones dentro de expresiones Producciones Regla Semántica S→ id := E E→ E+E {p=lookup(id.lex); if (p!=null) emitir(p ’:=’ E.lugar)} {E0.lugar := tempnuevo(); emitir(E0.lugar ´:=´ E1.lugar ´+´ E2.lugar)} … E→ id {p=lookup(id.lex), if (p!=null) E.lugar := p;} E → id(lista) {para cada elemento p en lista.pila emitir(‘param ‘ p) emitir(‘call’ id.lugar)} … 27
  • 28. Generación de código. Procesadores de Lenguaje I Ejemplo con funciones y expresiones Sin atributo código: escribir código globalmente a=0;c=1+f(2,4*a); S id (c) c:=t4 = E E + t1:=0 t4=1+t3 param t2 a:=t1 id (f) t2:=4*a t3=call f 2 (1) param 1 E param t2 ( lista ) param 1 t2 1 E , lista (1) E E (4) * t3=call f 2 t2 t2:=4*a t4:= 1+t3 c:=t4 E (a) 28