1
Geração de Código Intermediário
Prof. Alexandre Monteiro
Baseado em material cedido pelo Prof. Euclides Arcoverde
Recife
Contatos
Prof. Guilherme Alexandre Monteiro Reinaldo
Apelido: Alexandre Cordel
E-mail/gtalk: [email protected]
Site: http://www.alexandrecordel.com.br/fbv
Celular: (81) 9801-1878
3
Etapas da Compilação
Análise Léxica
Análise Sintática
Analise Semântica
Geração de CódigoIntermediário
Geração de CódigoFinal
4
Sumário da Aula
Introdução
Código de Três Endereços
Traduzindo Expressões
Traduzindo Comandos
Introdução
6
Geração de Código Intermediário
O objetivo dessa etapa é gerar um código intermediário equivalente ao código fonte dado como entrada para o compilador
Entrada: árvore sintática anotada
Saída: código intermediário
7
Código Intermediário
O nome “intermediário” indica que ele não é mais tão abstrato quanto o código fonte, nem é também o código final (específico de máquina)
Idealmente, um código intermediário deve ser simples e independente de máquina
8
Objetivo
É simples para:• Ser fácil de traduzir para código de máquina
É independente de máquina para:• Deixar apenas o back-end dependente de máquina
• Permitir gerar código para várias máquinas diferentes (a partir de uma mesma linguagem fonte)
9
Código Intermediário
Existem vários tipos de código intermediário
A escolha depende da linguagem fonte e, até mesmo, da(s) linguagem(ns) alvo
Um desenvolvedor pode criar novos tipos de código intermediário, conforme a necessidade
10
Código Intermediário
O livro considera a árvore sintática (já vista) como um tipo de código intermediário
• Mas não é tão simples... :)
Veremos aqui um tipo mais interessante de código intermediário – o código de três endereços
• Mais fácil de traduzir para códigos assembly (x86 ou MIPS, por exemplo)
Código de Três Endereços
12
Código de Três Endereços
É uma linguagem de baixo nível (simples), porém independente de máquina
Programas representados como uma simples lista de instruções
As instruções usam, no máximo, três operandos (endereços)
13
Tipos de Endereços
Um endereço pode ser:
• Um nome – representando uma variável, função, etc.
• Uma constante – valor literal de um número, uma string, um caractere, etc.
• Um temporário – variável auxiliar criada pelo compilador (t1, t2, etc.)
• Um rótulo – localização de uma instrução
14
Tipos de Instruções
Instruções de atribuição da forma
Onde op é um operador binário aritmético, binário ou lógico• Exemplo:
x = y op z
aux = t1 + temp
15
Tipos de Instruções
Instruções de atribuição da forma
Onde op é um operador unário, como: negação lógica, menos, conversão de tipo• Exemplos:
x = op y
t1 = (int) temp; t1 = - temp;
16
Tipos de Instruções
Instruções de cópia
Usadas, em alguns casos, para facilitar a geração do código intermediário
Numa fase posterior, de otimização, essa instrução pode ser removida
x = y
17
Tipos de Instruções
Desvio incondicional
Desvia para o rótulo L : faz com que a próxima instrução a ser executada seja a que tem o rótulo L• Exemplo:
goto L
label2: aux = t + 1; ... goto label2
18
Tipos de Instruções
Desvios condicionais
Desviam para o rótulo L dependendo do valor booleano de x
if x goto L
ifFalse x goto L
19
Tipos de Instruções
Desvios condicionais com operadores relacionais (<, >, ==, !=, ...)
Desvia para L se o resultado da operação relacional for verdadeiro• Exemplo:
if x op_cond y goto L
label2: aux = t + 1; if aux < temp goto label2
20
Tipos de Instruções
Chamada de procedimento
Chama o procedimento Proc
call Proc
21
Tipos de Instruções
Preparação de parâmetros
Definem os valores que serão passados em uma chamada de procedimento• O exemplo dado representa: Proc(x1, x2, ...)
param x1 param x2 ... call Proc
22
Tipos de Instruções
Retorno de valor
Usada dentro de um procedimento para retornar o valor y
return y
23
Tipos de Instruções
Atribuições de endereços e ponteiros
Acessam, respectivamente:
• O endereço de memória da variável y• O valor que está no endereço que y guarda
• O valor que está no endereço que x guarda
x = &yx = *y*x = y
Traduzindo Expressões
25
Traduzindo Expressões
Uma expressão com várias operações...
...é decomposta em expressões menores, com uma operação cada
myVar = aux + temp * 3
t1 = 3 t2 = temp * t1 t3 = aux + t2 myVar = t3
26
Traduzindo Expressões
A árvore sintática, na verdade, já guarda as expressões decompostas da forma desejada
Cada sub-expressão terá o seu valor guardado por alguma variável
• Pode ser necessário criar uma variável temporária
• Criar atributo em cada nó da árvore
27
Traduzindo Expressões
A regra geral para traduzir um nó (que realiza uma só operação) é:
• Gerar o código das sub-expressões
• Receber os nomes das variáveis usadas para guardar o valor de cada uma delas
• Criar uma instrução para executar a operação sobre essas variáveis
28
Exemplo
Figura 6.20 do livro (página 243)
Traduzindo Comandos
30
Traduzindo Instruções
Veremos como fazer a tradução de alguns comandos mais representativos
• Atribuição• If-Else• While
Referências• Figuras 6.20 (pag. 243) e 6.36 (pág. 257) do
livro
31
Atribuição
Primeiro, deve-se gerar código para a expressão do lado direito
• Retorna o nome da variável que terá o valor da expressão
Por fim, basta fazer uma instrução de cópia entre a variável retornada e a variável do lado esquerdo da atribuição
32
Atribuição
Exemplo:
Código de três endereços:
myVar = aux + temp * 3
t1 = 3 t2 = temp * t1 t3 = aux + t2 myVar = t3
33
If-Else
Criar dois labels (rótulos) únicos
• Fx: para o caso falso
• Rx: para a próxima instrução, após o if-else
34
If-Else
A primeira coisa a fazer é gerar o código da expressão de teste
• Retorna o nome de uma variável
Depois, deve-se gerar um comando de desvio condicional ifFalse-goto aplicado à variável e ao label Fx
• Só vai desviar quando for falso
35
If-Else
Depois, deve-se gerar o código do comando dentro do if
• Só vai ser atingido quando a expressão for verdadeira
E então, gerar um desvio incondicional goto para o label Rx
• Impede que seja executado o comando do else
36
If-Else
A seguir, deve-se gerar o label Fx
• Marca o início do código do else
Gerar o código do comando dentro do else
E, por fim, gerar o label Rx
• Marca o início do comando seguinte
37
If-Else
Exemplo:
int x = 0; if (x < 10) { x = 20; } else { x = 10; } int y = x;
x = 0 t1 = x < 10 ifFalse t1 goto F1 x = 20 goto R1 F1: x = 10 R1: y = x
38
While
Criar dois labels únicos
• Ix: para o início do while
• Rx: para o próximo comando, após o while
Naturalmente, deve-se começar gerando o label Ix na saída
39
While
Depois, gerar primeiro o código da expressão
• Receber o nome da variável
Depois, gerar um desvio condicional ifFalse-goto aplicado à variável e ao label Rx
• Quando a expressão não for verdade, passa para o comando após o while
40
While
Em seguida, deve-se gerar o código do comando interno do while
Depois, gerar uma instrução de desvio incondicional goto para o label Ix
• Para avaliar a expressão novamente
Por fim, gerar o label Rx
41
While
Exemplo:
x = 0; while (x < 10) { x = x + 1; } y = x;
x = 0 I1: t1 = x < 10 ifFalse t1 goto R1 t2 = x + 1 x = t2 goto I1 R1: y = x
42
Traduzindo Instruções
Essa é UMA possível maneira de gerar código para esses comandos
É uma maneira mais direta e mais fácil de implementar, mas gera código ineficiente
• A fase de otimização, poderia melhorá-lo
Usem como base para os demais comandos
43
Bibliografia
AHO, A., LAM, M. S., SETHI, R., ULLMAN, J. D., Compiladores: princípios, técnicas e ferramentas. Ed. Addison Wesley. 2a Edição, 2008 (Capítulo 4)