2017 09 13 analise semantica ast escopo

Page 1

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→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


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.