Compiladores - Universidade dos Açores

Propaganda
Compiladores
Ciência e Tecnologia da Computaç
Computação
Engenharia Informá
Informática e de Computadores
Tabela de Símbolos
Universidade dos Açores
Departamento de Matemática
www.uac.pt/~hguerra
Programa fonte
(cadeia de caracteres)
Tabela de símbolos
Analisador léxico
y
Conceito chave na compilação.
Cadeia de tokens
y
y
Armazenam os nomes das
variáveis, dos tipos, das classes
e outras estruturas de
programação….
Geralmente, todas as fases da
compilação necessitam da
tabela de símbolos para criar
novas entradas, adicionar
informação às entradas
existentes e consultar
informação.
2008/09
Compiladores
Analisador sintáctico
Tabela de
símbolos
Árvore sintáctica
Analisador semântico
Representação
intermédia
Gerador de código
Programa alvo
(código assembly)
Exemplo
1.
class C{
2.
inta,intb,intc;
3.
public void m(){
4.
System.out.println(a+c);
5.
intj=a+b;
6.
String a=“Hello”;
7.
System.out.println(a);
8.
System.out.println(j);
9.
System.out.println(a)
}
10.
11.
}
2008/09
Compiladores
2008/09
Compiladores
Exemplo
1.
package M{
2.
class E{
staticinta=5;
3.
4.
}
5.
class N{
staticintb=10;
6.
staticinta=E.a+b;
7.
8.
}
9.
class D{
staticintd=E.a+N.a;
10.
}
11.
12.
}
Tabela de símbolos
y
A tabela de símbolos é uma estrutura de dados que armazena para
cada identificador todos os elementos informativos (atributos):
◦ Nome (geralmente é a chave)
◦ Tipo
◦ Alcance
◦ Local, global, modificável
◦ Endereço de memória onde se situa a entidade representada
pelo identificador (variável, procedimento, função, etc.)
2008/09
Compiladores
Tabela de símbolos
y
Contém um registo para cada identificador com os campos
contendo os respectivos atributos.
y
Deve ser uma estrutura que permita armazenamento/alteração dos
dados e pesquisa eficiente.
2008/09
Compiladores
Tabela de símbolos
y
Tabela de símbolos com um nível
◦ têm apenas um único nível de acesso para as variáveis.
◦ usadas em linguagens que têm apenas variáveis globais.
y
Tabela de símbolos multinível
◦ usadas em linguagens com estruturas de bloco, para guardar a
informação do alcance dos nomes.
2008/09
Compiladores
Tabela de símbolos com um nível
y
O analisador léxico pode criar as entradas na tabela.
y
Suporta as seguintes operações:
◦ add(x) – criar nova entrada com nome x
◦ lookup(x) – retorna a posição na tabela contendo o nome x, ou
a indicação de que não existe.
◦ delete(x) – retira nome x da tabela.
2008/09
Compiladores
Tabela de símbolos multinível
y
A estrutura da tabela reflecte o aninhamento dos blocos.
y
O mesmo identificador para uma variável pode ter significados
diferentes em locais diferentes.
y
Pode ser criada uma tabela (individual) de símbolos para cada
alcance ou uma tabela (global) de símbolos com indicação do
alcance de cada símbolo.
y
A hieraquia de níveis deriva do encandeamento de alcances.
2008/09
Compiladores
Tabela de símbolos multinível
y
Deverá suportar as seguintes operações:
◦ create_scope(parent_scope) – cria novo nível embutido no nível
“parent_scope”, retornando a respectiva referência.
◦ insert(scope,x) – coloca nome x no nível “scope”
◦ lookup(x) – procura nome x, começando no alcance mais
próximo. Retorna a posição na tabela contendo o nome x, ou a
indicação de que não existe.
◦ Lookup_last(x) – procura nome x no alcance mais próximo.
◦ delete_scope(scope) – retira nível correspondente ao alcance
“scope”.
2008/09
Compiladores
Tabela de símbolos multinível
y
Pode ser implementada através de tabelas de símbolos
individuais para cada alcance.
y
A pesquisa é feita mediante o uso de uma pilha de tabelas de
identificadores.
◦ Sempre que se inicia um novo bloco, o endereço da nova tabela
de identificadores é inserido no topo da pilha de tabelas.
◦ Acesso é feito começando pelo topo da pilha.
◦ Quando a análise de um bloco termina, o respectivo endereço
para a tabela de símbolos é retirado da pilha
◦ Muitas vezes, os compiladores limitam o aninhamento de blocos
a uma dezena.
2008/09
Compiladores
Tabela de símbolos multinível
y
Pode ser implementada através de uma única tabela de
símbolos.
y
Para diferenciar o uso do mesmo identificador para variáveis
diferentes, é associado a cada identificador o número de
alcance.
y
Os números de alcance possuem o formato xx.yy, onde .
representa um subbloco.
y
A pesquisa é feita simultaneamente pelo identificador e alcance.
2008/09
Compiladores
Implementação da Tabela de símbolos
y
Pode ser implementada recorrendo a:
◦ Tabelas de dispersão
◦ Árvores binárias (de pesquisa)
◦ Listas ligadas (ordenadas, não ordenadas)
◦ …
2008/09
Compiladores
2008/09
Compiladores
Listas ligadas
Àrvores binárias de pesquisa
2008/09
Compiladores
Tabelas ou dicionários
y
Estrutura de dados que armazena um conjunto finito de registos
y
Cada registo é um par de valores:
◦ Chave – identifica
univocamente o elemento
em relação aos restantes
◦ Valor do elemento–
informação que se
pretende armazenar.
2008/09
Compiladores
Tabelas ou dicionários
2008/09
Compiladores
Tabelas de dispersão
y
Uma tabela de dispersão é uma implementação do TDA tabela que
usa a chave para calcular a posição onde o elemento deve ser
inserido.
y
Recorre a uma função (de dispersão) que relaciona o domínio
do tipo da chave e o contradomínio definido pelo conjunto de
endereços da estrutura de dados.
y
Uma função de dispersão perfeita associa a cada chave uma posição
diferente para inserir o elemento.
2008/09
Compiladores
Tabela de dispersão
y
Método de dispersão por divisão
◦ h(k) = ord(k) mod N, onde N é a dimensão do vector
y
Muitas vezes, a função de dispersão não é injectiva: retorna o
mesmo endereço para identificadores distintos. Diz-se que ocorreu
uma Colisão.
y
É necessário:
◦ Escolher uma função de dispersão que seja fácil de calcular e
que proceda a uma dispersão o mais uniforme possível
◦ Resolver as potenciais colisões
2008/09
Compiladores
Resolução de colisões
y
y
Endereçamento fechado
◦ elementos cuja chave devolve o mesmo valor de dispersão são
armazenados numa lista.
Endereçamento aberto
◦ as chaves que são enviadas para o mesmo endereço são
reenviadas para uma posição livre (aberta)
◦ Precisa de outra função que permita encontrar posições
alternativas – função de pesquisa.
2008/09
Compiladores
Principais técnicas de reendereçamento
y
Método de pesquisa linear (linear probing)
hi(k,i)=(h(k)+i) mod N
y
Método de pesquisa quadrática
hi(k,i)=(h(k)+i2) mod N
y
Método de pesquisa com dispersão dupla
hi(k,i)=(h(k)+i.h1(k)) mod N, onde h1 é a segunda função de
dispersão.
2008/09
Compiladores
y
Compiladores de linguagens de programação imperativas recorrem
às tabelas de dispersão
y
Compiladores de linguagens de programação funcionais recorrem
às árvores binárias de pesquisa
2008/09
Compiladores
Compiladores
Ciência e Tecnologia da Computaç
Computação
Engenharia Informá
Informática e de Computadores
Código Intermédio
Universidade dos Açores
Departamento de Matemática
www.uac.pt/~hguerra
Código intermédio
y
y
y
y
1ª etapa da fase de síntese (backend).
Representação abstracta do código
final.
Facilita o transporte de
compiladores de determinada
linguagem de programação para
máquinas distintas.
A escolha de uma linguagem de
representação intermédia para
linguagens de paradigmas distintos
não é trivial.
2008/09
Compiladores
Analisador sem‰ntico
Representa¨ ‹ o
intermˇ dia
Gerador de c—digo
Programa alvo
(c—digo assembly)
Código intermédio
y
Diferentes esquemas de representação.
y
Esquemas mais usados nos compiladores:
◦ Notação em árvore
◦ Notação sufixa
◦ Código de triplo endereço
2008/09
Compiladores
Notação em árvore
y
Representação gráfica do programa fonte.
y
Permite separar os aspectos sintácticos dos semânticos –
modularidade.
y
Transmite a estrutura sintáctica do programa fonte já com os
problemas da análise sintáctica resolvidos (e.g., recursividade à
esquerda, ambiguidade).
y
Sem interpretação semântica.
2008/09
Compiladores
Árvore sintáctica abstracta
y
abstract syntatic tree – AST
y
Versão simplificada da árvore sintáctica concreta
y
Nós com variáveis são eliminados
y
Reflecte dependência estrutural entre os terminais
y
Nós internos são “operadores”
y
Folhas são “operandos” ou informação
2008/09
Compiladores
AST - Árvores binárias de expressões
2008/09
Compiladores
AST - Árvores binárias de expressões
2008/09
Compiladores
Árvores Sintácticas Abstractas
a*3/(b-4)
E → E+T | E – T | T
T → T*F | T / F | F
F → id | num | (E)
‰ Podem ser construídas
recorrendo a gramáticas de
atributos sintetizados
2008/09
Compiladores
Árvores Sintácticas Abstractas
E → E+E | E – E | T | E*E | E / E | id | num | (E)
// uma classe abstracta para cada variável
public abstract class E {
//uma classe derivada para cada produção
public class PlusExp extends E{
private e1, e2;
public PlusExp( E e1, E e2) {e1=a1; e2=a2;}
}
public class MinusExp extends E{
…
}
public class TimesExp extends E{
…
}
2008/09
Compiladores
Árvores Sintácticas Abstractas
public
…
}
public
…
}
public
…
}
public
…
}
class DivExp extends E{
class Identifier extends E{
class IntegerLiteral extends E{
class ParenExp extends E{
2008/09
Compiladores
Notação sufixa
y
Notação infixa
◦ Operadores binários aparecem entre os operandos
◦ a + b
y
Notação prefixa
◦ Operadores binários aparecem antes dos operandos
◦ + a b
y
Notação sufixa
◦ Operadores binários aparecem após os operandos
◦ a b +
2008/09
Compiladores
Notação sufixa
y
As expressões sufixas definem-se indutivamente do seguinte modo:
◦ literais são expressões na notação sufixa.
◦ se op é um operador de aridade k (>0) e e1, e2, …, ek são
expressões na notação sufixa, então a e1e2…ekop é uma
expressão na notação sufixa.
y
Exemplo: a expressão x+1 na notação infixa é x1+ na
notação sufixa.
y
As expressões não necessitam de parentesis para
definirem a prioridade das operações.
2008/09
Compiladores
Conversão da expressão na notação infixa
a + b * c para a notação sufixa
2008/09
Compiladores
Conversão da expressão na notação infixa
a – b + c para a notação sufixa
2008/09
Compiladores
Conversão da expressão na notação infixa
a^b^c para a notação sufixa
2008/09
Compiladores
Conversão da notação infixa para a notação sufixa
a/b*(c+(d–e))
2008/09
Compiladores
Avaliação de expressões na notação sufixa
Expression sufixa a b /, onde a é 2 e b é 4
2008/09
Compiladores
Avaliação de expressões na notação
sufixa
Expression sufixa a b + c /
onde a é 2, b é 4 e c é 3
2008/09
Compiladores
Algoritmo de avaliação de expressão sufixa
Algorithm evaluatePostfix(postfix) // Evaluates a postfix
expression.
valueStack = a new empty stack
while (postfix has characters left to parse)
{
nextCharacter = next nonblank character of postfix
switch (nextCharacter)
{
case variable:
valueStack.push(value of the variable nextCharacter)
break
case '+': case '-': case '*': case '/': case '^':
operandTwo = valueStack.top(), valueStack.pop()
operandOne = valueStack.top(), valueStack.top()
result = the result of the operation in nextCharacter
and
its operands operandOne and operandTwo
valueStack.push(result)
break
default: break
}
}
return valueStack.top()
2008/09
Compiladores
Código de triplo endereço C3E
y
A forma de representação é imagem do processador onde o programa irá
ser executado, excluindo detalhes como a gestão dos registos.
y
É fácil de transcrever para assembly.
y
Instruções são da forma
NNN oper (arg1, arg2, res)
◦ res=arg1 oper arg2
◦ NNN é o endereço abstracto de memória
y
Recorre a variáveis temporárias para guardar valores intermédios.
2008/09
Compiladores
Tipos de instruções C3E
y
Instruções de operadores binários e unários
◦ +, -, x, /, not, =
y
Instruções de cópia de literal ou variável
◦ cpy(y, _, z)
y
z=y
Instruções de acesso a elementos de um vector
◦ idxr(x,i,z)
z=x[i]
◦ idxl(x,i,z)
x[i]=z
2008/09
Compiladores
Tipos de instruções C3E
y
Instruções de salto
◦ Condicional
x if oper (x,y,m)
se (x oper y) execução salta para endereço m, senão
executa instrução seguinte.
◦ Incondicional
x jmp(_,_,m)
2008/09
Compiladores
Tipos de instruções C3E
y
Instruções de chamada e retorno de rotinas
P(A1,…,An)
◦ Param(A1,_,_)
◦ …
◦ Param(An,_,_)
◦ Call(P,_,z)
z=P(A1,…,An)
2008/09
Compiladores
Implementação de Instruções C3E
y
Existem duas estratégias de representação das instruções:
◦ Quádruplos – representação explicita das variáveis temporárias
◦ Triplos – sem representação explicita das variáveis temporárias
2008/09
Compiladores
Quádruplos
y
O operador, os dois operandos e o resultado são campos de
registos de C3E.
y
Maior facilidade na implementação do código e na optimização.
2008/09
Compiladores
Triplos
y
O operador e os dois operandos são os campos de registos de
C3E.
y
Sempre que uma instrução tiver um operando com referencia a
uma variável temporária, é indicado no seu lugar o endereço
abstracto da instrução onde o valor foi calculado.
y
Maior poupança de memória.
2008/09
Compiladores
Download