Etapa 5: Semântica - Escopo e Visibilidade
Objetivos
- Implementar as regras de visibilidade de identificadores.
- Evoluir a Tabela de Símbolos para suportar escopos aninhados.
- Realizar o “Passe de Declaração” na AST.
Fundamentação Teórica
A Análise Semântica garante que o programa faça sentido. A primeira parte disso é o Escopo. Em Pascal (e na maioria das linguagens), variáveis declaradas dentro de um procedimento só existem lá dentro (escopo local), enquanto outras podem ser globais. Além disso, você não pode usar uma variável x se ela não foi declarada antes.
Atividades Práticas
1. Evoluindo a Tabela de Símbolos
Sua SymbolTable da Etapa 1 precisa mudar. Agora ela deve funcionar como uma pilha de escopos ou uma árvore. Uma abordagem comum (Pilha): - enterScope(): Empilha um novo Map vazio. - exitScope(): Desempilha o Map do topo. - add(name, symbol): Adiciona no Map do topo (escopo atual). - lookup(name): Procura no Map do topo. Se não achar, desce para o anterior, até chegar no global. Retorna null se não encontrar em nenhum.
2. O Semantic Visitor
Crie uma nova classe SemanticAnalyzer que percorre a AST (pode usar o padrão Visitor novamente, mas agora sem retornar AST, só validando).
Lógica do Visitor: - Ao visitar Program: Chama enterScope(), visita os filhos, chama exitScope() no final. - Ao visitar VarDecl: Para cada variável declarada, verifica se já existe no escopo atual. - Se sim: Erro “Variável já declarada”. - Se não: table.add(name, symbol). - Ao visitar Identifier (em expressões/comandos): - Chama table.lookup(name). - Se retornar null: Erro “Variável não declarada:” + name. - Se encontrar: Pode associar o Símbolo encontrado ao nó da AST para uso posterior (decorar a AST).
3. Preenchendo os Tipos
Na declaração var x: integer;, o Símbolo criado para x deve ter o campo Type preenchido com Type.INTEGER. Isso será crucial para a próxima etapa.
O que entregar
- Código da
SymbolTableaprimorada. - Código do
SemanticAnalyzer. - Casos de teste
.pas:- Uso de variável não declarada (deve falhar).
- Dupla declaração no mesmo escopo (deve falhar).
- Declaração em escopo local sombreando global (opcional, se implementar funções).
- Código correto (deve passar sem erros).