Aula 16: Verificação de Tipos e Escopo
Objetivos
- Implementar o Type Checker.
- Entender sistemas de tipos estáticos vs dinâmicos.
Motivação
Sistemas de tipos são uma das ferramentas mais poderosas para garantir correção e segurança em programas de Engenharia de Computação:
- Previnem acessos inválidos à memória.
- Garantem que operações numéricas, lógicas e de ponteiros sejam usadas de forma consistente.
- Permitem otimizações agressivas pelo compilador (sabendo que certos erros não podem acontecer em tempo de execução).
Conteúdo
A verificação de tipos é a principal tarefa da análise semântica: garantir que cada operação (atribuição, soma, chamada de função, etc.) respeita as regras de tipos da linguagem.
flowchart LR
AST[AST] --> Visitor[Visitor pós-ordem]
Visitor --> Tab[Tabela de símbolos]
Visitor --> Tipos[Tipos nos nós]
Tab --> Tipos
Tipos --> Erro[Erros de tipo]
Sistemas de Tipos
- Estático (Compile-time): Java, C++, Rust. Tipos verificados antes da execução. Garante ausência de certos erros, melhora performance.
- Dinâmico (Run-time): Python, JS. Tipos verificados durante a execução. Mais flexível, mas pode falhar na mão do usuário.
- Forte vs Fraco: C é estático mas fraco (permite somar char com int implicitamente, ponteiros void). Haskell é estático e forte.
Implementando Type Checking
Geralmente feito com um Visitor pós-ordem (Bottom-Up): 1. Visita as folhas, determinando seus tipos (literais ou lookup na tabela de símbolos). 2. Sobe para os pais: - Nó Soma: Verifica se Esq.tipo == Int e Dir.tipo == Int. Se sim, Soma.tipo = Int. Se não, Erro. - Nó Atribuição (x = E): Verifica se x.tipo é compatível com E.tipo (considerando coerções/promções, se houver).
Polimorfismo e Inferência
Linguagens modernas incluem genéricos (List<T>) e inferência de tipos (var x = 10). Isso exige algoritmos de unificação (ex.: Hindley-Milner) e tratamento de restrições de tipo. Em Mini-Pascal, o foco é tipos simples (integer, real, boolean) e compatibilidade em atribuições e expressões.
Resumo
- Type checking percorre a AST (geralmente em pós-ordem), atribui tipos aos nós e verifica compatibilidade. A tabela de símbolos fornece os tipos das variáveis e funções.
- Tipagem estática vs dinâmica; forte vs fraca. A implementação do type checker reflete as regras da linguagem.
Referências
- Aho et al. (2006). Compilers: Principles, Techniques, and Tools. Cap. 6.
- Cooper & Torczon (2011). Engineering a Compiler.
Materiais da aula
Última atualização: 08/03/2026