Análise Semântica Eduardo Ferreira dos Santos Ciência da Computação Centro Universitário de Brasília UniCEUB Outubro, 2016 1 / 40
Sumário 1 Conceitos 2 A linguagem Cool 3 Análise semântica Símbolos Tipos 2 / 40
Conceitos 1 Conceitos 2 A linguagem Cool 3 Análise semântica Símbolos Tipos 3 / 40
Conceitos Fases Figura 1.1: Fases do compilador [Aho et al., 2007] 4 / 40
Conceitos Árvore de sintaxe Figura 1.2: Modelo de tradução e atribuição [Aho et al., 2007] 5 / 40
Conceitos Introdução O papel da análise semântica é produzir uma lista de tarefas; Para produzir a lista de tarefas o compilador vai precisar da lista de símbolos; Nesse momento também se faz a vericação de tipos; Objetivo: facilitar a tradução da lista de tarefas em linguagem de máquina. 6 / 40
Conceitos Etapas da compilação Análise léxica Detecta entradas com caracteres inválidos; Análise sintática Produz a árvore de parsing e verica erros de formação da árvore; Análise semântica Última fase do front end, detecta os erros que ainda podem existir. 7 / 40
Conceitos Justicativa Alguns erros não são detectados pelo parsing; A análise semântica pode realizar várias vericações [Schwarz et al., 2016]: 1 Todos os identicadores estão declarados; 2 Os tipos são consistentes; 3 Relações de herança; 4 As classes são unicamente identicadas; 5 Os métodos em uma classe são denidos apenas uma vez; 6 As palavras reservadas não estão sendo utilizadas de maneira equivocada; 7... Os requisitos semânticos dependem da linguagem. 8 / 40
A linguagem Cool 1 Conceitos 2 A linguagem Cool 3 Análise semântica Símbolos Tipos 9 / 40
A linguagem Cool Visão geral de Cool Para estudar os próximos exemplos, vamos introduzir uma linguagem chamada Cool: Classroom Object Oriented Language [Schwarz et al., 2016]; Princípios de design: Implementação rápida; Utilização de: Abstração; Tipagem estática; Reuso (herança); Gerência de memória;... Pela simplicidade, alguns outros conceitos são deixados de fora. 10 / 40
A linguagem Cool Exemplo simples Os programas em Cool são simples denições de classe; Uma classe especial chamada Main com um método especial chamado main; Nenhum conceito de subrotina; classe = coleção de atributos e métodos; As instâncias de uma classe são objetos. c l a s s P o i n t { x : I n t < 0 ; y : I n t < 0 ; } ; Listing 1: Exemplo de atribuição simples em Cool 11 / 40
A linguagem Cool Objetos em Cool A expressão new Point cria um novo objeto da classe Point; Um objeto pode ser visto como um registro com um slot para cada atributo. Listing 2: Objetos em Cool [Schwarz et al., 2016] c l a s s P o i n t { x : I n t < 0 ; y : I n t ; ( u s e d e f a u l t v a l u e ) } ; 12 / 40
A linguagem Cool Métodos A classe pode denir métodos para manipular os atributos; Os métodos se referem ao objeto atual utilizando a chamada self. Listing 3: Métodos em Cool [Schwarz et al., 2016] c l a s s P o i n t { x : I n t < 0 ; y : I n t < 0 ; movepoint ( newx : I n t, newy : I n t ) : P o i n t { { x < newx ; y < newy ; s e l f ; } c l o s e b l o c k e x p r e s s i o n } ; c l o s e method } ; c l o s e c l a s s 13 / 40
A linguagem Cool Herança Extensão de Point para ColorPoint utilizando herança. Listing 4: Herança em Cool [Schwarz et al., 2016] c l a s s C o l o r P o i n t i n h e r i t s P o i n t { c o l o r : I n t < 0 ; movepoint ( newx : I n t, newy : I n t ) : P o i n t { { c o l o r < 0 ; x < newx ; y < newy ; s e l f ; } } ; } ; 14 / 40
1 Conceitos 2 A linguagem Cool 3 Análise semântica Símbolos Tipos 15 / 40
Escopo Denição: verica a compatibilidade entre a declaração e a utilização dos identicadores; Importante etapa de análise estática na maior parte das linguagens; O escopo do identicador é a parte do programa onde o identicador está acessível; O mesmo identicador pode mudar de signicado a depender da parte do programa; O identicador pode ter escopo restrito. 16 / 40
Estático versus dinâmico A maior parte das linguagens possui escopo estático: O escopo depende apenas do texto do programa e não da execução; C, C++ e Javascript possuem escopo estático; Outras linguagens possuem escopo dinâmico [Schwarz et al., 2016]: Lisp, SNOBOL; Lisp agora possui escopo dinâmico; O escopo depende da execução do programa. 17 / 40
Escopo estático Listing 5: O valor de x se refere à denição mais próxima [Schwarz et al., 2016] l e t x : I n t < 0 i n { x ; l e t x : I n t < 1 i n x ; x ; } 18 / 40
Escopo dinâmico Uma variável de escopo dinâmico tem seu valor calculado no momento da execução. Listing 6: O valor de a se refere ao valor no momento da execução #d e f i n e a ( x+1) i n t x = 2 ; void b ( ) { i n t x = 1 ; p r i n t f ( "%d\n", a ) ; } void c ( ) { p r i n t f ( "%d\n", a ) ; } void main ( ) { b ( ) ; c ( ) ; } 19 / 40
Exemplo comparativo Figura 3.1: Exemplo de escopo estático versus dinâmico 1 1 Fonte: https://msujaws.wordpress.com/2011/05/03/static-vs-dynamic-scoping/ 20 / 40
Escopo em Cool Os identicadores em Cool são introduzidos por: Declarações de classe (introduz o nome da classe); Denições de método (introduz o nome do método); Parâmetros formais (introduz o id do objeto); Denições de atributo (introduz o id do objeto); Outros. 21 / 40
Exceções ao escopo em Cool Nem todas as denições em Cool seguem a regra da denição mais próxima; Denições de classe: Não podem ser aninhadas; São visíveis no escopo global do programa. É possível utilizar o nome da classe antes de deni-la. 22 / 40
Exemplo de uso Listing 7: Exemplo de uso antes de denir a classe [Schwarz et al., 2016] C l a s s Foo {... l e t y : Bar i n... } ; C l a s s Bar {... } ; 23 / 40
Mais escopo Os atributos da classe são globais dentro dela mesma. Listing 8: Exemplo de utilização de atributo de classe global [Schwarz et al., 2016] C l a s s Foo { f ( ) : I n t { a } ; a : I n t < 0 ; } 24 / 40
Símbolos 1 Conceitos 2 A linguagem Cool 3 Análise semântica Símbolos Tipos 25 / 40
Símbolos Tabela de símbolos Considere a seguinte expressão em Cool: let x: Ideia [Schwarz et al., 2016]: Int <- 0 in e Antes de processar e adicione a denição de x ao conjunto de denições atual, sobrescrevendo qualquer atribuição anterior de x; Navegue na árvore de parsing recursivamente; Depois de processar e, remova a denição de x e restaure o valor anterior. A tabela de símbolos é uma estrutura de dados que armazena as atribuições de valor mais atuais para os identicadores. 26 / 40
Símbolos Implementação simples Estrutura de dados utilizada: pilha; Operações: add_symbol(x) Executa uma operação de push na pilha para x, com todas as informações associadas; nd_symbol(x) Busca na pilha, de cima para baixo, o valor de x. Retorna NULL se não for encontrado; remove_symbol() Executa uma operação de pop na pilha. 27 / 40
Símbolos Limitações A tabela de símbolos funciona bem para o operador let: Os símbolos são adicionados individualmente de maneira sequencial; As declarações estão perfeitamente aninhadas. E se a ordem das atribuições for diferente? 28 / 40
Símbolos Tabela de símbolos mais completa enter_scope() Inicia um novo escopo aninhado; nd_symbol(x) Encontra o valor atual de x (ou NULL); add_symbol(x) Adiciona o símbolo x na tabela; check_scope(x) Verdadeira se x estiver denido no escopo atual; exit_scope() Executa uma operação de pop na pilha. 29 / 40
Símbolos Denições de classe Os nomes de classe podem ser utilizados antes de ser denidos; Não é possível vericar os nomes das classes: Solução: Utilizando uma tabela de símbolos; Em uma única passagem pela árvore. Passo 1 Reúna todos os nomes de classe; Passo 2 Faça a checagem. A análise semântica requer múltiplas passagens pela árvore. 30 / 40
Tipos 1 Conceitos 2 A linguagem Cool 3 Análise semântica Símbolos Tipos 31 / 40
Tipos Tipos O que é um tipo? A noção varia de acordo com a linguagem; Consenso: Um conjunto de valores; Um conjunto de operações com esses valores. As classes são uma instância da denição moderna de tipo [Schwarz et al., 2016]. 32 / 40
Tipos Por que tipos? Listing 9: Quais os tipos de dado para $r1 $r2 e $r3? [Schwarz et al., 2016] add $r1, $r2, $ r 3 33 / 40
Tipos Tipos e operações Cada tipo de dado possui um conjunto válido de operações; Não faz sentido executar uma operação de adição entre um ponteiro e um inteiro na linguagem C; Faz sentido a adição de dois inteiros; Contudo, ambos executam a mesma operação em assembly. O sistema de tipos da linguagem especica os tipos e suas operações permitidas; O objetivo da vericação de tipos é garantir que as operações sejam realizadas com os tipos de dado corretos. É a única etapa que realiza interpretação de valores.; Para o computador, tudo se resume a 0 e 1. 34 / 40
Tipos Vericação de tipos Existem três tipos de linguagens: Statically typed Vericação estática de tipos. Quase toda a validação de tipos é feita no momento da compilação (C, Java, Cobol); Dynamically typed Vericação dinâmica de tipos. Quase toda a validação de tipos é feita no momento da execução do programa (Scheme, Python); Untyped Não faz vericação de tipos (código de máquina). 35 / 40
Tipos Necessidade de vericação Existem visões concorrentes em relação às vericações estática e dinâmica; Os defensores da vericação estática dizem: A vericação estática encontra muitos problemas no momento da compilação; Evita o overhead da vericação de tipo em tempo de execução. Os defensores da vericação dinâmica dizem: Os sistemas de vericação estática são muito restritivos; Não é possível realizar a prototipagem rápida em sistemas de vericação estática. 36 / 40
Tipos Conclusões sobre tipos Na prática, a maior parte do código é escrita em linguagens com vericação estática de tipo com algum tipo de mecanismo de escape; Ex.: Unsafe casts in C, Java É discutível saber se essa decisão representa o melhor dos dois mundos. 37 / 40
Tipos Vericação e inferência A vericação de tipos é o processo de vericar programas onde a tipagem é forte; A inferência de tipos é o processo de descobrir a informação de tipo que está faltando; Os processos são diferentes mas os termos são intercambiáveis. Utilização de regras de inferência. 38 / 40
Tipos OBRIGADO!!! PERGUNTAS??? 39 / 40
Tipos Aho, A., Lam, M., Sethi, R., and Ullman, J. (2007). CompiladoresPrincpios Técnicas e Ferramentas. Pearson, 2a. edition. Schwarz, K., Papadakis, H., and Mittal, R. (2016). Compilers. Disponível em http://web.stanford.edu/class/cs143/ Acessado em 30/09/2016. 40 / 40