Compiladores 
 (IF688) Leopoldo Teixeira lmt@cin.ufpe.br | @leopoldomt
Situação atual •
•
Programas bem-formados lexicamente •
identificadores tem nomes válidos
•
strings são delimitadas apropriadamente
•
nenhum caractere inesperado
Programas bem-formados sintaticamente •
declarações de classes e métodos com estrutura
•
expressões sintaticamente válidas
Isto significa que o programa ĂŠ vĂĄlido?
Considere x… antes de gerar código…
Perguntas a serem respondidas • Que tipo de valor é armazenado em x? • Qual o tamanho de x? • Se x é uma função, que argumentos recebe? Qual o tipo de valor retornado, se aplicável? • Por quanto tempo o valor de x deve ser preservado? • Quem é responsável por alocar espaço para x? (e inicializá-lo?)
Considere o programa a seguir‌
class Factorial { public static void main(String[] a){ System.out.println(new Fac().calcula(true)); } } class Fac extends A { public int ComputeFac(int num){ if (num < 1) num_aux = 1 ; else num_aux = num * (this.ComputeFac(num-1)) ; return num_aux ; } }
class Factorial { public static void main(String[] a){ System.out.println(new Fac().calcula(true)); } } class Fac extends A { public int ComputeFac(int num){ if (num < 1) num_aux = 1 ; else num_aux = num * (this.ComputeFac(num-1)) ; return num_aux ; } }
Análise Semântica • Garantir que o programa de um significado bem definido • Verificar propriedades que não são capturadas nas fases anteriores • Uma vez encerrada a análise semântica, consideramos o programa de entrada válido
Propriedades • Variáveis usadas sem terem sido declaradas • definição sem uso (warning) • Expressões tem o tipo correto • Indexação em variável que não é array • Tipos incompatíveis • Classes herdando de classes inexistentes • …
Organização do Compilador AST tokens
parser
analisador semântico
tabela de símbolos
AST
gerador de IR
representação intermediária
Desafios • Rejeitar o maior número de programas incorretos • Aceitar o maior número de programas corretos
Desafios • Rejeitar o maior número de programas incorretos • Aceitar o maior número de programas corretos • Fazer isto rapidamente
https://xkcd.com/303/
Outros objetivos • Coletar informação útil sobre o programa para fases subsequentes • Determinar quais variáveis são associadas com cada identificador • Construir representação interna da hierarquia de herança • Contar quantas variáveis estão no escopo em um dado ponto do programa
Então… não era melhor já fazer isto durante a fase de parsing?
Limitações de GLC • Como você previne definições de classes duplicadas? • Como você diferencia variáveis de um tipo de variáveis de outro tipo? • Como você garantiria que uma dada classe implementa todos os métodos de uma interface?
Limitações de GLC • Para a maioria das linguagens de programação, estas limitações podem ser provadas • lema do bombeamento para linguagens livres de contexto
Implementando • Gramáticas de Atributos • fazer algumas checagens durante parsing • tem suas limitações • Travessia na AST • construir a AST e usar funções virtuais e recursão para explorar a árvore • padrão de projeto visitor
Exemplo de Gramática de Atributos Produção
D→TL T → int T → real L → L1, id L → id
Regra Semântica
Exemplo de Gramática de Atributos Produção
Regra Semântica
D→TL
L.in = T.type
T → int
T.type = integer
T → real
T.type = real
L → L1, id
L1.in = L.in
L → id
addtype(id.entry, L.in)
Atributo type é sintetizado e atributo in é herdado
Como fica a รกrvore de real id1, id2, id3$?
real id1, id2, id3$ Direção da avaliação do atributo in
Direção da avaliação do atributo type
Construção de ASTs
Árvores Sintáticas Abstratas •
A parse tree normalmente tem muita informação redundante e desnecessária •
separadores, não-terminais auxiliares, etc…
•
AST foca nas informações importantes, classificando nós de acordo com seu papel na estrutura da linguagem
•
Representação compacta da estrutura do programa, facilita o trabalho do compilador
Exemplo •
Seja a gramática •
E→n|(E)|E+E
•
E a entrada 42 + (57+22)
•
Após a fase de análise léxica, temos os tokens n(42) “+” “(“ n(57) “+” n(22) “)”
Árvore Sintática 42 + (57 + 22) E
E
+
E
n(42)
(
E
)
E
+
E
n(57)
n(22)
E→n|(E)|E+E
AST 25 + (57 + 22)
+
25
+
57
22
Eâ&#x2020;&#x2019;n|(E)|E+E
Representando ASTs •
Cada estrutura sintática representativa da linguagem (geralmente associada com produções da gramática) é um nó da AST
•
Em termos de Java e OO, criamos uma classe para cada tipo de nó
•
Não-terminais com várias produções ganham interface ou classe abstrata, e cada produção implementa ou estende a interface/classe pai
Exemplo Eclipse
ASTs e OO •
No código visto, cada classe da AST tem um construtor e um método eval(), para retornar o valor da expressão representada
•
Um estilo orientado a objetos de programar
•
Considere a alternativa…
Como poderíamos escrever o código para avaliação de expressões separado do código de representação (AST) das expressões?
Separando sintaxe de interpretação.
Tipos e Interpretações •
A escolha de um estilo pode afetar a modularidade do compilador
•
Em geral, temos vários tipos (kinds) de objetos: statements de assignment, print, compostos, etc.
•
Também podemos ter diferentes interpretações de cada um destes objetos: checar tipos, traduzir para código Pentium, traduzir para código Sparc, otimizar, interpretar, etc…
Tipos e Interpretações •
Cada interpretação é aplicada a um tipo
•
Se adicionarmos um novo tipo, devemos implementar cada interpretação para este tipo
•
Se adicionarmos uma interpretação, temos que implementá-la para cada um dos tipos
Direções de Modularidade
Adaptado de Andrew Appel Modern Compiler Implementation in Java
Modularidade •
No estilo de sintaxe separada da interpretação, adicionar uma nova interpretação é fácil e modular. •
Uma nova função é escrita, com cláusulas para todos os diferentes tipos
•
Adicionar novo tipo afeta a implementação de todas as funções de interpretação
Modularidade •
No estilo orientado a objetos, cada interpretação é um método em cada uma das classes. É fácil e modular adicionar um novo tipo. •
Todas as interpretações deste tipo são agrupadas como métodos da nova classe
•
Adicionar uma interpretação significa adicionar um método a todas as classes existentes
GUIs vs. Compiladores qual estilo ĂŠ mais adequado?
GUIs vs. Compiladores •
Em interfaces gráficas, cada aplicação terá seu conjunto de widgets •
•
Embora não seja possível predeterminar os widgets que serão usados, as operações (interpretações) são comuns a todos
Em compiladores, podemos querer adicionar interpretações, como otimizações, traduzir para código-alvo de uma nova máquina, etc.
PadrĂŁo de Projeto Visitor
Visitor •
Um visitor implementa uma interpretação
•
É um objeto que contem um método visit para cada classe da AST
•
Cada classe da AST deve conter (pelo menos) um método accept •
este método serve como gancho para todas as interpretações
•
é chamado pelo visitor e tem apenas uma tarefa, passa o controle de volta ao método apropriado do visitor
Desacoplando estrutura de dados do algoritmo que opera na estrutura
Exemplo cรณdigo
Checando Escopo
Um nome pode ter diferentes significados em um mesmo programa
Código Java válido public class Name { int Name; Name Name(Name Name) { Name.Name = 137; return Name((Name) Name); } } Adaptado de Keith Schwartz
Código Java válido public class Name { int Name; Name Name(Name Name) { Name.Name = 137; return Name((Name) Name); } } Adaptado de Keith Schwartz
Código C++ válido int Awful() { int x = 137; { string x = “Scope!"; if (float x = 0) double x = x; } if (x == 137) cout << "Y"; }
Adaptado de Keith Schwartz
Código C++ válido int Awful() { int x = 137; { string x = “Scope!"; if (float x = 0) double x = x; } if (x == 137) cout << "Y"; }
Adaptado de Keith Schwartz
Escopo •
O escopo de uma entidade é o conjunto de pontos em um programa onde o nome da entidade se refere a si mesma
•
A introdução de novas variáveis pode “esconder” variáveis existentes
•
Como manter o registro do que é visível?
Tabelas de Símbolos •
Mapeamento de nomes para a entidade a que o nome se refere
•
Na medida que rodamos análise semântica, continuamente atualizamos a tabela com informações sobre o escopo
•
O que utilizar na prática para implementar?
•
Que operações precisam ser definidas?
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x, y, z); 4: { 5: int x, z; 6: z = y; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x, y, z); 4: { 5: int x, z; 6: z = y; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x, y, z); 4: { 5: int x, z; 6: z = y; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x, y, z); 4: { 5: int x, z; 6: z = y; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x, y, z); 4: { 5: int x, z; 6: z = y; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x, y, z); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x@5, y@9, z@5); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x@5, y@9, z@5); 12: } 13: printf("%d,%d,%d\n", x, y, z); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x@5, y@9, z@5); 12: } 13: printf("%d,%d,%d\n", x@5, y@9, z@5); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x@5, y@9, z@5); 12: } 13: printf("%d,%d,%d\n", x@5, y@9, z@5); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x@5, y@9, z@5); 12: } 13: printf("%d,%d,%d\n", x@5, y@9, z@5); 14: } 15: printf("%d,%d,%d\n", x, y, z); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x@5, y@9, z@5); 12: } 13: printf("%d,%d,%d\n", x@5, y@9, z@5); 14: } 15: printf("%d,%d,%d\n", x@5, y@2, z@5); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x@5, y@9, z@5); 12: } 13: printf("%d,%d,%d\n", x@5, y@9, z@5); 14: } 15: printf("%d,%d,%d\n", x@5, y@2, z@5); 16: } 17:} Adaptado de Keith Schwartz
0: int x = 137; 1: int z = 42; 2: int MyFunction(int x, int y) { 3: printf("%d,%d,%d\n", x@2, y@2, z@1); 4: { 5: int x, z; 6: z = y@2; 7: x = z@5; 8: { 9: int y = x@5; 10: { 11: printf("%d,%d,%d\n", x@5, y@9, z@5); 12: } 13: printf("%d,%d,%d\n", x@5, y@9, z@5); 14: } 15: printf("%d,%d,%d\n", x@5, y@2, z@5); 16: } 17:} Adaptado de Keith Schwartz
Operações •
Tipicamente implementadas como pilha de tabelas
•
Cada tabela corresponde a um escopo em particular
•
Pilha facilita operações de ‘entrada’ e ‘saída’ de escopo •
push/pop scope
•
insert/lookup symbol
Usando Tabela de Símbolos •
•
Para processar uma porção do programa que delimita novo escopo •
‘Entre’ em um novo escopo
•
Adicione todas as declarações de variáveis à tabela de símbolos
•
Processe o corpo do bloco/função/classe
•
‘Saia’ do escopo
Muitas das análises semânticas são definidas em termos de travessias recursivas como a descrita acima
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
int x; int y; int MyFunction(int x, int y) { int w, z; { int y; } { int w; } }
Adaptado de Keith Schwartz
Spaghetti Stacks •
Trata a tabela de símbolos como uma lista encadeada de escopos
•
Cada escopo armazena um ponteiro para o seu pai mas a recíproca não é verdadeira
•
Em qualquer ponto do programa a tabela pode ser vista como uma pilha
Duas visões •
A estrutura de escopo é melhor representada pela spaghetti stack
•
Spaghetti - Estrutura estática
•
Pilha explícita - Estrutura dinâmica
•
A pilha explícita pode ser vista como uma otimização da spaghetti
Escopo em OO •
Herança - o escopo da classe filha tem ponteiro para o escopo da classe pai
•
Acessar um atributo significa subir na cadeia de escopos até encontrar o atributo ou erro
•
Podemos desambiguar o escopo explicitamente
public class Base { public int value = 1; } public class Derived extends Base { public int value = 2; public void doSomething() { int value = 3; System.out.println(value); System.out.println(this.value); System.out.println(super.value); } }
Adaptado de Keith Schwartz
Escopo na prรกtica public class A { private B myB; }
Adaptado de Keith Schwartz
Escopo na prรกtica public class A { private B myB; } class B { private A myA; }
Adaptado de Keith Schwartz
Passadas •
Conseguimos resolver análise léxica e sintática com uma única passada sobre a entrada
•
Alguns compiladores também combinam análise semântica e geração de código •
•
chamados de single-pass compilers
Outros passam novamente pela entrada •
chamados de multi-pass compilers
Escopo em multi-pass •
Ler a entrada e construir a AST (primeira passada)
•
Caminhar pela AST coletando informações sobre as classes (segunda passada)
•
Caminhar pela AST checando outras propriedades (terceira passada)
•
…
•
Pode combinar algumas destas passadas, embora sejam logicamente distintas