Carregar apresentação
A apresentação está carregando. Por favor, espere
1
Giovanny Lucero giovanny@ufs.br
Departamento de Estatística e Informática Universidade Federal de Sergipe Compiladores Ambientes Giovanny Lucero
2
Ambientes Também conhecidos como tabela de símbolos
Mapeamento de Símbolos a atributos (tipicamente tipos e endereço de memória) Não confundir símbolos com tokens Implementam os bindings (amarrações / vínculos) Dois tipos de ocorrência dos identificadores definição (declaração) – inserção na tabela Uso -- lookup Escopo de um identificador
3
Ambientes Suponha ambiente inicial 0 Linha 2:
1 = 0 + {aint, bint, cint} Linha 4: 2 = 1 + {jint} Linha 5: 3 = 2 + {aString} sobrepondo o binding dado para a anteriormente (em 1) Linha 8: Descartamos 3 e voltamos para 1 Linha 10: Voltamos para 0 function f(a: int, b:int , c:int) = ( print_int(a+c); let var j:= a+b; var a:= “hello”; in print(a); print_int(j); end; print_int(b); ) Exemplo na linguagem Tiger + não é comutativo
4
Como implementar “descartar-voltar”
Estilo imperativo Modificamos 1 até virar 2 Problema: destruímos 1, como “volto”? Solução: pilha de ambientes Estilo funcional Implementamos a função + Não há problema um ambiente novo não é construído “destrutivamente” a partir de um anterior Implementações eficientes para ambos estilos Crítico: um programa pode ter milhares de símbolos
5
Vários ambientes ativos ao mesmo tempo
Ambientes múltiplos structure M = struct structure E = struct val a = 5 end structrure N = struct val b = 10; val a = E.a + b structure D = struct val d = E.a + N.a package M; class E { static int a = 5; } class N { static int b = 10; static int a = E.a + b; class D { static int d = E.a + N.a Vários ambientes ativos ao mesmo tempo
6
Implementação imperativa eficiente
Tabela de Hash com external chaining inserimos novos bindings no começo das listas, implementação eficiente de “deleção” a int y real a int y real b int b int b real Adicionamos o binding {breal}
7
Tabela de Hash com external chaining
class Bucket {String key; Object binding; Bucket next; Bucket(String k, Object b, Bucket n) { key = k; binding = b; next = n; } } class HashT { final int SIZE = 256; Bucket table = new Bucket[SIZE] int hash(String s) { int h=0; for (int i = 0; i < s.length(), i++) h= h* s.charAt(i); return h }
8
void insert(String s, Bind b) { int index = hash(s) % SIZE;
table[index] = new Bucket(s,b,table[index]); } void lookup(String s) { for (Binding b = table[index]; b!null; b = b.next) if (s.equals(b.key)) return b.binding; return null; void pop(String s) { table[index]=table[index].next; É uma espécie de superconjunto (com key repetidos). Pop, tira o último que foi inserido
9
Implementação funcional eficiente
Tabela de Hash não serve (trabalha destrutivamente) Árvores balanceadas Inserção “cria” uma árvore nova Não há o problema descartar-voltar data Tree a = ConsT (String,a) Tree Tree | EmptyTree insert :: Tree a (String,a) Tree a insert EmptyTree (s,v) = ConsT (s,v) EmptyTree EmptyTree insert (ConsT (s,v) left right) (s1,v1) | s1 < s = ConsT (s,v) (insert s1 left) right | s1 > s = ConsT (s,v) left (insert s1 right) | s1 = s = ConsT (s,v1) left right Complexidade: O(log2 n), supondo a árvore balanceada Qual é a complexidade de insert? insert “cria uma nova árvore”, no entanto: Quantos novos nós são criados realmente?
10
A interface de uma tabela imperativa
package lps.simbolo; public class Symbol { public String toString(); public static Symbol symbol(String s); } public class Table { public Table(); public void put(Symbol key, Object value) throws AlreadyBound; public Object get(Symbol key); public void beginScope(); public void endScope(); public java.util.Enumeration keys(); } beginScope e endScope precisam de uma pilha Ver exercício 5.1 para melhorar a implementação
11
Interface para tabela funcional
public class Table { public Table(); public Table put(Symbol key, Object value); public Object get(Symbol key); public java.util.Enumeration keys(); } Ver exercício 1.1 para fazer uma implementação eficiente
12
Exercício (para o projeto)
Implementar eficientemente a tabela de símbolos Escolher um estilo
13
Implementação eficiente de Symbol
Implementação de tabela de símbolos é crítica Operações eficientes necessárias Comparar dois símbolos por igualdade Extrair o código de hash (quando se usa hash) Comparar por “<=” (quando se usam árvores) Numa implementação ingênua, cada caractere de um string é analisado a cada Operação hash Cada comparação com outro string (put e get) Como evitar comparações caractere por caractere? Que padrão uso?
14
Padrão Flyweight Por uniformidade, podemos querer tratar valores “leves” como objetos. Exemplo Os caracteres de um texo (num editor) Implementação ingênua traz problemas de espaço Solução: criamos um pool de objetos leves No nosso caso podemos tratar símbolos como objetos leves, assim teremos igualdade por referência Poderia ter uma outra classe para criar instâncias de Symbol: FactorySymbol Para uma implementação funcional da tabela de símbolos. Devo definir eficientemente “<=“. Sugestão: usar o hashcode( ) de objeto (devolve a referência em int)
15
Symbol: Padrão Flyweight
package lps.simbolo; public class Symbol { private String name; private Symbol (String n) {name=n;} private static java.util.Map dict = new java.util.Hashtable(); public String toString() {return n; } public static Symbol symbol(String n) { String u = n.intern(); // Um string único – precisa? Symbol s = (Symbol) dict.get(u); if (s==null) { s = new Symbol(u); dict.put(u,s); } return s; } } Poderia ter uma outra classe para criar instâncias de Symbol: FactorySymbol Para uma implementação funcional da tabela de símbolos. Devo definir eficientemente “<=“. Sugestão: usar o hashcode( ) de objeto (devolve a referência em int) Agora só é preciso comparar referências
Apresentações semelhantes
© 2024 SlidePlayer.com.br Inc.
All rights reserved.