Compiladores
Cristiano Biancardi 2
Geração de Código Intermediário
Transformação da árvore de derivação em um
segmento de código.
Vantagens:
Possibilita a otimização do código intermediário para prover um código otimizado mais eficiente;
Simplifica a implementação do compilador, resolvendo gradativamente as dificuldades de passagem de código fonte para código intermediário;
Possibilita a tradução de código intermediário para diversas máquinas.
Diferença entre o código intermediário e o
código objeto final
Código intermediário não especifica detalhes
da máquina alvo:
quais registradores serão usados
quais endereços de memória serão referenciados
Cristiano Biancardi 4
Linguagens Intermediárias
Categorias:
Representações gráficas: árvore e grafo de sintaxe.
Notação pós-fixada e pré-fixada.
Árvore de sintaxe
Forma condensada da árvore de derivação.
As cadeia de produções simples (
A → B, B → C)
não aparecem.
Somente os operadores (nós internos) e os operandos (nós folhas).
Grafo de sintaxe
Inclui simplificações da árvore de sintaxe.
Funcionamento:
Antes de construir um novo nó com rótulo op e ponteiros ptr1 e ptr2 para sub-árvores que
representam sub-expressões, a função geranodo verifica se já existe algum nó com rótulo op e
ponteiros que apontem para árvores idênticas às apontadas por ptr1 e ptr2.
Caso positivo, a função apenas retoma um ponteiro para o nó previamente construído.
Cristiano Biancardi 8
Código de três endereços (TAC)
Cada instrução referencia, no máximo, três
variáveis (endereços de memória).
Necessita variáveis temporárias!
As instruções possíveis são as seguintes:
A := B op C
A := op B
A := B
goto L
Cristiano Biancardi 10
Representação de TAC para A := X + Y * Z
T1 := Y * Z
T2 := X + T1
A := T2
Um TAC pode ser representado através de
Quádruplas:
• Constituída de quatro campos:
Um operador, dois operandos e o resultado.
Triplas:
• Formadas por:
Um operador e dois operandos.
Utiliza ponteiros para a própria estrutura, evitando a nomeação explícita de temporários.
Exemplo:
Com TAC é possível gerar de código de três
endereços para:
– Expressões
– Declarações (escopo simples)
– Declarações (escopos aninhados)
– Comandos de atribuição
– Arrays e Registros
– Expressões booleanas
– Comandos de decisão
Cristiano Biancardi 14
Esquema de tradução de código de 3-endereços
• geratemp: gera o nome de uma variável temporária
• nome: nome associado ao símbolo
• geradcod: gera uma String com o código
• cod: contém o código final gerado pelo comando
S → id :=E {S.cod = E.cod
geracod(id.nome”:=“ E.nome)}
E → E1 + E2 {E.nome = geratemp; E.cod = E1.cod + E2.cod geracod (E.nome “:=“ E1.nome “+” E2.nome} E → E1 * E2 {E.nome = geratemp; E.cod = E1.cod * E2.cod
geracod (E.nome “:=“ E1.nome “*” E2.nome} E → (E1) {E.nome = E1.nome; E.cod = E1.cod }
Reaproveitamento de temporários
Deve-se poupar os temporários
Exemplo: X := A*B + C*D – E*F • Necessita apenas 2 temporários. • T1 := A * B • T2 := C * D • T1 := T1 + T2 • T2 := E * F • T1 := T1 – T2 • X := T1
Cristiano Biancardi 16
Declarações
Esquema de tradução que reconhece declaração de variáveis. Associar posições de memória para nomes locais de
procedimentos
Na área de dados do procedimeto.
Atualizar na tabela de símbolos:
– endereço de memória relativo.
Geração de endereços pode ter máquina alvo em mente:
Em linguagens como C, Pascal e Fortran,
variáveis de um mesmo procedimento
pertencem a um mesmo grupo:
Indexação base + deslocamento
Antes da primeira declaração zera o deslocamento
Para cada declaração processada:
• – criar entrada na tabela de símbolos com deslocamento igual ao deslocamento atual
• – incrementar o valor do deslocamento proporcional ao tamanho do objeto definido na declaração.
Cristiano Biancardi 18
Usar tradução dirigida pela sintaxe:
Atributos: • tipo
• tamanho: tamanho em bytes para os diferentes tipos • deslocamento: não é atributo de símbolo da gramática
variável desloc: contém o próximo endereço disponível na área de dados do procedimento.
Rotina Suporte:
• adSimb(nome, tipo, deslocamento):
cria uma nova entrada na tabela de símbolos para nome, com seu tipo e o endereço
• array(num, tipo) • ponteiro(tipo)
Cálculo de tamanhos:
– inteiro: 4 bytes
– real: 8 bytes
– array: número de elementos x tamanho do tipo
Cristiano Biancardi 20
Esquema de tradução: tabela de símbolos de
bloco unitário
Cristiano Biancardi 22
Controlando Escopo
Como estender para múltiplos escopos ?
Cada procedimento possui um escopo onde endereços relativos devem ser criados.
Deve-se usar uma tabela de símbolos para cada escopo.
Ações semânticas geraTab(ptr):
• – cria uma tabela de símbolos (filha da tabela apontada por ptr) retornando um apontador para a mesma.
adSimb(ptr, nome, tipo, deslocamento)
• – cria uma nova entrada para nome na tabela de símbolos apontada por ptr.
defTam(ptr, tam)
• – registra na tabela de símbolos apontada por ptr o tamanho da área de dados local do procedimento correspondente
adProc(ptr, nome, pt)
• – insere na tabela de símbolos apontada por ptr o nome do procedimento e o ponteiro para a tabela de símbolos desse procedimento.
Cristiano Biancardi 24
Estruturas auxiliares
Pilhas de tabela de símbolos (tabPtr)
• Contém um ponteiro para a tabela de símbolos de cada procedimento
• Durante a compilação, o ponteiro no topo da pilha aponta para a tabela de símbolos do procedimento em análise.
• Cada tabela tem um ponteiro para a tabela de símbolos envolvente.
Tabela “filha” tem um ponteiro para a tabela “pai”.
Pilha de deslocamentos (desloc)
• Contém o próximo endereço (de memória local) disponível na área de dados do procedimento.
Exemplo: esquema de tradução para gerar uma
árvore de tabelas de símbolos
Cristiano Biancardi 30
20
Esquema de tradução para comandos de
atribuição
Cristiano Biancardi 32
Lookup: procura o identificador armazenado id.nome na tabela de símbolos:
• Deve primeiro verificar se o identificador está na tabela de símbolos corrente, apontada por top(tabptr). Caso negativo, lookup usa o ponteiro dessa tabela para encontrar a tabela de símbolos do procedimento envolvente.
• Se não é encontrado em nenhum dos escopos envolventes, lookup retorna NULL.
Conversão de tipos em Expressões
Aritméticas
Tipo dos operandos determina a natureza da
operação que deve ser efetuada.
Ações semânticas , associada à operação de
soma, fazem a verificação do tipo dos
operandos para determinar o tipo de operação
a ser aplicada.
Ações semânticas análogas à anterior podem
ser anexadas às produções que reconhecem
as operações aritméticas de subtração,
multiplicação, etc.
Para o comando X : = Y + I * J
X e Y do tipo real I e J do tipo inteiro seriam geradas: • T1 := I *int J • T3 := convreal T1 • T2 := Y +real T3Cristiano Biancardi 36
Expressões Lógicas e Comandos de
Controle
Expressões Iógicas são usadas como expressões
condicionais em comandos de controle (if, while.
etc) e em comandos de atribuição lógica.
Existem dois métodos de tradução para expressões lógicas:
Representação numérica
Representação numérica:
este método codifica numericamente as constantes true e false (true=1 e faIse=0)
avalia as expressões Iógicas de forma numérica, ficando o resultado da avaliação numa variável temporária.
operações Iógicas and, or e not:
• são avaliadas numericamente para 1 quando resultarem em true, e para 0, quando resultarem em false.
Cristiano Biancardi 38
EXEMPLO: Código para avaliar expressões lógicas
de forma numérica.
• Supondo que o código gerado seja armazenado a partir do rótulo 100, o comando de atribuição "X := A or B and not C” (onde A, B e C são variáveis Iógicas) seria
traduzido para:
100: T1 := not C 101: T2:= B and T1 102: T3 := A or T2 103: X :=T3
A expressão relacional A < B (onde A e B são variáveis numéricas) seria traduzida para:
• 100: if A < B goto 103 • 101: T1 :=0
• 102: goto 104 • 103: T1 := 1 • 104:
OBS: o valor da expressão fica no último temporário gerado.
Cristiano Biancardi 40
EXEMPLO: Esquema de tradução para avaliação
numérica de expressões lógicas.
• gera código para expressões lógicas.
• função geracod utiliza a variável proxq para indicar o índice do próximo rótulo disponível.
• após gerar um código, a função geracod incrementa
Cristiano Biancardi 42
EXEMPLO: Código gerado para a expressão A < B
or C < D and E < F.
• 0 esquema anterior gera a seguinte sequência de rótulos para a expressão acima:
100. if A < B goto 103 101: T1 := 0 102: goto 104 103: T1 := 1 104: if C < D goto 107 105: T2 := 0 106: goto 108 107: T2 : = 1 108: if E < F goto 111 109: T3 := 0 110: goto 112 111: T3 := 1 112: T4 := T2 and T3 113: T5 :=T1 or T4