Você está na página 1de 4

Universidade Estadual do Centro-Oeste – UNICENTRO

Curso de Ciência da Computação


Professora Sandra Mara Guse Scós Venske

Aula 25 – Geração de Código Intermediário

"The Java bytecode is the intermediate representation of your program


that contains instructions the Java Virtual Machine will execute.
Thus, the output of javac is not code that can be directly executed.”
Herbert Schildt (Java: The Complete Reference, Seventh Edition)
INTRODUÇÃO
Alguns compiladores, após as Análises Sintática e Semântica, geram uma representação intermediária
explícita do programa-fonte. Essa representação deve ser fácil de produzir e fácil de traduzir no
programa-alvo.
Existem várias formas de representação intermediária. As árvores sintáticas, a notação pós-fixa
e código de três endereços são alguns tipos de representações deste tipo. As representações
intermediárias precisam tratar do cômputo de expressões, das construções de fluxo e das chamadas de
procedimentos.

GERAÇÃO DE CÓDIGO INTERMEDIÁRIO - CÓDIGO DE TRÊS ENDEREÇOS


A forma intermediária Código de Três Endereços é como uma linguagem de montagem para uma
máquina, na qual cada localização de memória pode atuar como um registrador. O motivo para o
termo “código de três endereços” está em que cada comando contém, normalmente, três endereços,
sendo dois para os operandos e um para o resultado.
Resumidamente, o código de três endereços consiste em uma seqüência de instruções, sendo
que cada uma possui no máximo três operandos. O seguinte trecho de programa

Montante := DepósitoInicial + TaxaDeJuros * 60

poderia ser expresso no código de três endereços como

temp1 := IntToReal (60)


temp2 := id3 * temp1
temp3 := id2 + temp2
id1 := temp3

sendo
id1 --> Montante
id2 --> DepósitoInicial

1
Universidade Estadual do Centro-Oeste – UNICENTRO
Curso de Ciência da Computação
Professora Sandra Mara Guse Scós Venske

id3 --> TaxaDeJuros


Observando as propriedades desta forma intermediária:
 Cada instrução de três endereços possui, no máximo, um operador (além do operador de
atribuição). Assim, ao gerar as instruções, o compilador deve decidir sobre a ordem em que as
mesmas devem ser realizadas. No exemplo, primeiro a multiplicação, depois a soma.
 O compilador deve gerar um nome temporário para receber o valor computado em cada
instrução.
 As instruções podem possuir menos do que três operandos, como nas primeira e última
instruções do exemplo.
A fase de Otimização de Código tenta melhorar o Código Intermediário para que em tempo de
execução o código de máquina resultante seja mais rápido.
No exemplo acima, o código intermediário apresentado seria gerado por um algoritmo natural
após as análise sintática e semântica, baseando-se na representação em árvore do programa (gerando
uma instrução para cada operador). Nota-se que existem maneiras mais adequadas para que a mesma
computação seja realizada, como por exemplo
temp1:= id3 * 60.0
id1 := id2 + temp1

não há nenhum problema em gerar o código com o algoritmo simples, já que a melhoria feita acima
pode ser feita durante a fase de otimização de código. Assim sendo, o compilador pode deduzir que a
conversão de 60 (de inteiro para real) pode ser realizada uma vez em tempo de compilação, podendo
ser eliminada a operação IntToReal. Da mesma forma, temp3 transmite seu valor a id1 uma única
vez, então pode-se substituir temp3 por id1, eliminando o último enunciado.
A representação intermediária é utilizada pelos módulos de retaguarda de um compilador para
geração do código-alvo.
O código de três endereços é uma seqüência de enunciados da forma geral

x := y op z

sendo
x, y, e z são nomes, constantes ou objetos de dados temporários criados pelo compilador;
op é qualquer operador (aritmético de ponto fixo ou flutuante, lógico).

Salienta-se que só é permitido um operador no lado direito de um enunciado. Por exemplo,


uma expressão de linguagem-fonte como

x + y * z
poderia ser traduzida na seqüência

t1 := y * z
t2 := x + t1
sendo t1 e t2 nomes temporários
gerados pelo compilador.
O código de três endereços é uma representação linearizada de uma árvore sintática, no qual os
nomes explícitos correspondem aos nós interiores do grafo.
A representação de árvore sintática para a := b * -c + b * - c aparece na Figura 1.

2
Universidade Estadual do Centro-Oeste – UNICENTRO
Curso de Ciência da Computação
Professora Sandra Mara Guse Scós Venske

Figura 1: Árvore sintática.

A representação das sequências de código de três endereços para o mesmo exemplo é

t1 := -c
t2 := b * t1
t3 := -c
t4 := b * t3
t5 := t2 + t4
a := t5
Nota-se que os nomes das variáveis aparecem diretamente nos comandos de três endereços.

Exemplo 1: x = x + 3 + 4
Código de Três endereços:
T1 = X + 3
X = T1
T2 = T1 + 4

Exemplo 2: Geração de código para uma função de Fatorial em código de três endereços pode ser
vista na Figura 4.

Figura 2 - Exemplo de Código de Três Endereços para Fatorial.

3
Universidade Estadual do Centro-Oeste – UNICENTRO
Curso de Ciência da Computação
Professora Sandra Mara Guse Scós Venske

Exemplo 3:
while (i < 10*j)
{
a[i] = i + 2*j;
++i;
}
Código de três endereços:
L1: t1 := 10 * j
if i >= _t1 goto L2
t2 := 2 * j
a[i] := i + t2
i := i + 1
goto L1
L2: ...

Fonte:
AHO, Alfred V.; SETHI, Ravi; ULLMAN, Jeffrey D. Compiladores: Princípios, Técnicas e
Ferramentas. São Paulo: Guanabara Koogan, 1995.
JOSÉ, João Neto. Introdução à Compilação. Rio de Janeiro: LTC, 1987.

Você também pode gostar