Etapa 6: Semântica - Tipos e Verificações
Objetivos
- Implementar o sistema de tipos da linguagem.
- Verificar consistência em operações (ex: não somar booleano com inteiro).
- Validar expressões lógicas em estruturas de controle.
Fundamentação Teórica
Após garantir que as variáveis existem (Etapa 5), precisamos saber se estão sendo usadas corretamente. Se x é integer, x := "ola" deve ser um erro. A verificação de tipos geralmente ocorre Bottom-Up (das folhas para a raiz): 1. Descobre-se o tipo das folhas (literais e variáveis). 2. Propaga-se o tipo para os nós pais (uma soma de dois inteiros resulta num inteiro). 3. Verifica-se as regras nos nós de comando.
Atividades Práticas
1. Inferência de Tipos na AST
Crie um pacote br.com.comcet.tp6. Adicione um campo Type type na classe abstrata Expression. No seu SemanticAnalyzer (ou num novo passe TypeChecker), implemente a lógica ao visitar os nós:
- Literal:
10->Type.INTEGER"ola"->Type.STRINGtrue->Type.BOOLEAN
- Identifier:
- Consulta a Tabela de Símbolos. Se a variável
xfoi declarada comointeger, o nóxtem tipoType.INTEGER.
- Consulta a Tabela de Símbolos. Se a variável
- BinaryExpression:
- Se operador é
+,-,*,/: Verifica se Esq e Dir sãoINTEGER. Se sim, tipo do nó éINTEGER. Senão, Erro. - Se operador é
>,<,=: Verifica se Esq e Dir são compatíveis. Tipo do nó éBOOLEAN.
- Se operador é
2. Verificação de Comandos
- Atribuição (
var := expr):- Verifica se
tipo(var) == tipo(expr).
- Verifica se
- If / While (
cond):- Verifica se
tipo(cond) == BOOLEAN.
- Verifica se
3. Reportando Erros
Acumule os erros encontrados em uma lista. Não pare no primeiro erro, tente encontrar o máximo possível. Exemplos de mensagens: - “Erro Semântico na linha 10: Operação ‘+’ não suportada para tipos INTEGER e STRING.” - “Erro Semântico na linha 15: Condição do ‘if’ deve ser booleana.”
4. Testes Automatizados (JUnit) — públicos
Crie ao menos um teste JUnit público para validar a checagem de tipos. A recomendação é testar casos pequenos e bem definidos.
Crie, por exemplo, src/test/java/br/com/comcet/tp6/TypeCheckerTest.java:
package br.com.comcet.tp6;
import br.com.comcet.tp1.ast.AstNode;
import br.com.comcet.tp4.MyVisitor;
import br.com.comcet.tp4.parser.MiniPascalLexer;
import br.com.comcet.tp4.parser.MiniPascalParser;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class TypeCheckerTest {
private AstNode parse(String codigo) {
CharStream input = CharStreams.fromString(codigo);
MiniPascalLexer lexer = new MiniPascalLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
MiniPascalParser parser = new MiniPascalParser(tokens);
ParseTree tree = parser.program();
return new MyVisitor().visit(tree);
}
@Test
void falhaAoSomarIntComBoolean() {
String codigo =
"program p; var x: integer; begin x := 10 + true; end.";
AstNode ast = parse(codigo);
TypeChecker tc = new TypeChecker(); // ou SemanticAnalyzer da etapa 6
tc.check(ast); // adapte para o nome do seu método
assertTrue(tc.hasErrors());
assertTrue(tc.getErrors().stream().anyMatch(e -> e.contains("Operação '+'")));
}
}Observação: como na Etapa 5, o teste acima assume que você já consegue construir AST via ANTLR+Visitor (Etapa 4). Se preferir, você pode montar uma AST manualmente e testar apenas o
TypeChecker.
O que entregar
- Código de verificação de tipos.
- Casos de teste
.pas:- Atribuição inválida (
int := string). - Operação aritmética com booleanos (
10 + true). - Condição de if numérica (
if 10 then ...). - Programa complexo válido (fatorial, fibonacci) passando sem erros.
- Atribuição inválida (
- Pelo menos um teste JUnit público cobrindo erros de tipos (como acima).