Departamento de Estatística e Informática
Universidade Federal de Sergipe
Compiladores
Tradução para Código Intermediário
Giovanny Lucero
[email protected]
1
CI: Portabilidade e Modularidade
Linguagem
Arquitetura Alvo
Java
Sparc
MIPS
4 diferentes
compiladores
completos
Pentium
Alpha
Compilação
2
CI: Portabilidade e Modularidade
Linguagem
Arquitetura Alvo
Java
Sparc
ML
MIPS
Pascal
Pentium
20 diferentes
compiladores
completos
C
Alpha
C++
Compilação
3
Problema
• A cada nova arquitetura, n novos
compiladores (um para cada linguagem).
• O projeto dos n novos compiladores não faz
reuso
do
que
foi
desenvolvido
anteriormente.
• Solução:
– Geração de Código Intermediário
4
CI: Portabilidade e Modularidade
Java
ML
Sparc
MIPS
Pascal
Pentium
C
C++
Alpha
5
CI: Portabilidade e Modularidade
Java
ML
Sparc
vanguardas
Java
MIPS
ML
Pascal
Pascal
Pentium
C
C++
retaguardas
Sparc
MIPS
Código
Intermediário
Pentium
C
Alpha
C++
Representação
abstrata do código
de máquina
Alpha
6
Código Intermediário
• Independente da máquina
• Independente da linguagem fonte
• Conveniente para que a análise semântica o
produza
• Conveniente para traduzir para código de
máquina
• Semântica clara e simples de c/construtor
7
Código Intermediário
• Exemplos:
– TREE (Appel & Palsberg)
– Código de 3 endereços (Aho et al)
– E muitos outros...
8
A linguagem intermediária Tree
abstract class Exp
CONST(int value)
NAME(Label label)
TEMP(Temp temp)
BINOP(int binop,
Exp left,
Exp right)
MEM(Exp exp)
CALL(Exp func,
ExpList args)
ESEQ(Stm stm,
Exp exp)
abstract class Stm
MOVE(Exp dst, Exp src)
EXP(Exp exp)
JUMP(Exp exp,
LabelList targets)
CJUMP(int relop,
Exp left,
Exp right,
Label iftrue,
Label iffalse)
SEQ(Stm left, Stm right)
LABEL(Label label)
constantes em CJUMP
BINOP
PLUS,
EQ,
NE,MINUS,
LT, GT,MUL,
LE, GE,
DIV,ULT, ULE, UGT, UGE
AND, OR, LSHIFT, RSHIFT, ARSHIFT, XOR
4
Tradução
• Pode ser feita depois ou em paralelo com a checagem de
tipos.
public class ExpTranslator extends ExpVisitorR {
...
public ExpTy translate(Expression e) {
return (StmTy) e.accept(this);
}
protected Object visitAndExpR(AndExp e) {
// código para checagem e tradução
class StmTy }
... stm;
public Tree.Stm
}
public lps.semantica.vinculaveis.Type
ty;
}
10
Tradução de variáveis simples
MEM
Ou então:
BINOP
TEMP t
PLUS
TEMP fp CONST k
MEM(BINOP(PLUS, TEMP fp, CONST k))
• k é o offset da variável dentro do frame
• Calculado na tradução da declaração da variável
11
• Simplificaremos as árvores, assim:
MEM
+
CONST k
TEMP fp
MEM(+( TEMP fp, CONST k))
12
Variáveis não locais
• Quando x é declarada num escopo externo, vínculos
estáticos devem ser usados
MEM(+(CONS Kn, MEM(+(CONS Kn-1, ...
MEM(+(CONS K1, TEMP fp))...)
Onde K1,...,Kn-1 são os offsets do vínculo estático nas
funções aninhadas e Kn é o offset de x no seu frame
• As informações de aninhamento deverão estar registradas
no ambiente (tabela de símbolos)
13
Valores estruturados
• Valores não atômicos (não escalares)
• Tratamento depende da linguagem. Por exemplo:
– Pascal
• Variável estruturada armazena um valor estruturado
• Variáveis estruturadas são criadas na Pilha
• Atribuição e comparação por cópia
– Java
• Não há variáveis estruturadas, só valores
estruturados.
• Variáveis de tipo estruturado armazenam, na pilha,
uma referência a um valor estruturado
• Valores estruturados são criados no heap
• Atribuição e comparação por referência
14
Variáveis array
• Pascal
– Criação na pilha
– Limites fazem parte da variável (para checagem
dinâmica)
• O gerenciamento de heap é abstraído por uma biblioteca de
procedimentos externos
15
Seleção de componentes
• Array em Pascal: a[i]
(i-lb)*s+a, onde a é o endereço base, s é o tamanho
de cada elemento, lb é o limite inferior dos índices de a
– Se a for global a-s*lb pode ser calculado na
compilação
– Adicionalmente checagem de limites deve ser feita
MEM
+
*
MEM
e
MEM(+(MEM(e), *(i, CONST(W)))
i
CONST
w
16
Seleção de componentes
• Seleção de campo: a.f
a + offset de f em a
– A informação do offset deve estar no ambiente
– A árvore para a.f é:
MEM (+(TEMP fp, +(CONST ka, CONST ka.f)))
17
Criação de registros e arrays
• Em geral:
– Campos inicializados com null ou 0
• Obs. Outra linguagem pode requerer a criação
recursiva dos componentes
– Criação no heap
• Chamando uma função do runtime system (função
externa)
• Esta função retorna um ponteiro para área onde o
registro/array é criado.
CALL(NAME(malloc), EXPLIST(A1,...(new EXPLIST(AN,NULL)))
18
Criação de registros e arrays
19
Aritmética
• Em geral, um operador aritmético binário da
sintaxe abstrata tem um correspondente em
Tree.
• Tree não tem operadores unários.
– Negação unária de inteiros implementada como
subtração de zero.
– Etc.
20
Condicionais
• Expressões booleanas são representadas usando CJUMP
– Combinar com if_then_else, while ...
– Combinar em expressões com operadores lógicos de
circuito curto
• 5 < x é traduzido para
CJUMP(LT, CONST(5), x, t, f )
• 5 < x && x < 10
SEQ ( CJUMP(LT, CONST(5), x, c, f ),
SEQ ( LABEL c,
CJUMP(LT, x, CONST(10), t, f ) ) )
21
If then else
• Considere:
– s1(t, f) = CJUMP(BINOP, left, right, t, f)
• If e1 then e2 else e3.
–e1 é sempre uma expressão booleana
–No entanto e2 e e3 podem ser:
• Um statement que não retorna valor algum
• Uma expressão booleana
• Uma expressão numérica
–É preciso analisar cada um dos casos.
22
If then else
• Caso e2 e e3 statements:
–SEQ ( S1(t, f ),
SEQ ( LABEL t,
SEQ(e2, SEQ(LABEL f, e3))))
• Caso e2 e e3 expressões booleanas:
SEQ(s1(z,f), SEQ(LABEL z,
SEQ(s2(t,f), SEQ(LABEL f, s3(r,f)))
23
If then else
• Caso e2 e e3 expressões:
ESEQ(s1(t,f), SEQ(LABEL t, SEQ(
MOVE(TEMP r, e2), SEQ(LABEL F,
MOVE(TEMP r, e3)))), Temp r)
• Observação:
–e2 e e3 podem ser diferentes. Neste casos
emprega-se
as
abordagens
apresentadas
anteriormente de forma híbrida.
24
While
• Layout:
While (cond) {
body
}
25
While
• Layout:
While (cond) {
body
}
test:
if not (condition) goto done
body
goto test
done:
26
While
• Layout:
test:
if not (condition) goto done
body
goto test
done:
LABEL(test);
CJUMP(BINOP, e1,
e2, done, body)
LABEL(body);
Loop body statements
JUMP (NAME test)
LABEL(done);
• Se um break é encontrado no interior do laço, a
tradução é simplesmente um jump(done).
27
FOR
• O for pode ser expresso usando o que foi
definido pelo while:
For (i = lo; i <= hi; i++;){
//body
}
i = lo;
Limit = hi;
While (i <=
limit){
//body
i++
}
28
FOR
• Problema
– E se limit igual ao maior inteiro positivo
possível?
i = lo;
limit = hi;
While (i <= limit){
//body
i++
}
29
FOR
• Solução
– Colocar um teste adicional no fim do looping,
antes do incremento.
i = lo;
limit = hi;
While (i <= limit){
//body
if (i == maxInt)
break;
i++
}
30
Chamada a subrotina
• f(a1,a2,...,an)
call(NAME(lf),[e1,...,en])
– Onde lf é o label para a função f.
– [e1,...,en] representa um Explist.
31
Chamada a subrotina
• Para linguagens que suportam funções
aninhadas, temos:
• f(a1,a2,...,an)
call(NAME(lf),[sL,e1,...,en])
– Onde SL é o vínculo estático.
32
Declarações
• Declaração de tipos
– Em geral, não geram código
• Declaração de variáveis
– Define o local de memória
• Definição de função
– Prólogo
– Corpo
– Epílogo
33
Definição de função
• Uma função é traduzida para um segmento de linguagem
assembly com um prólogo, corpo e epilogo.
• O prologo contém:
–
–
–
–
Pseudo-instruções
O label relativo ao nome da função
Uma função para ajustar o stack pointer (alocar um novo frame)
Instruções para salvar argumentos escapados para o frame e mover
argumentos não escapados para os registradores.
– Armazenar instruções para salvar qualquer callee save registers,
incluindo o registro que armazena o endereço de retorno.
34
Definição de função
• Em seguida vem o corpo.
• Depois do corpo vem o epilogo, que contém:
– Uma instrução para mover o valor de retorno para o
registro reservado para esta proposta.
– Instruções de carregamento para restaurar os callee save
registers.
– Uma instrução para reiniciar o stack pointer (desalocar
frames).
– Uma instrução de retorno (jump to return address).
– Pseudo instruções para anunciar o fim de uma função.
35
Strings
• Um literal String é implementado como um
endereço constante de um segmento de memória
inicializado para os próprios caracteres.
– NAME(lab)
• Toda string é colocada em uma lista global (lista
de fragmentos).
• Todas operações com string são executadas por
funções providas pelo próprio sistema.
36
Classes e Objetos
• Criação de objetos similar a criação de variáveis
registro.
• Chamada a métodos similar a chamadas de
funções.
– Primeiro deve determinar qual classe declara o método.
– This pointer é passado como argumento do método.
• Acesso a variáveis
– Similar ao acesso a campo de registro.
37
Download

Um compilador simples