Etapa 6: Semântica - Tipos e Verificações

Published

25/03/2026

Modified

17/03/2026

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.STRING
    • true -> Type.BOOLEAN
  • Identifier:
    • Consulta a Tabela de Símbolos. Se a variável x foi declarada como integer, o nó x tem tipo Type.INTEGER.
  • BinaryExpression:
    • Se operador é +, -, *, /: Verifica se Esq e Dir são INTEGER. Se sim, tipo do nó é INTEGER. Senão, Erro.
    • Se operador é >, <, =: Verifica se Esq e Dir são compatíveis. Tipo do nó é BOOLEAN.

2. Verificação de Comandos

  • Atribuição (var := expr):
    • Verifica se tipo(var) == tipo(expr).
  • If / While (cond):
    • Verifica se tipo(cond) == BOOLEAN.

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:
    1. Atribuição inválida (int := string).
    2. Operação aritmética com booleanos (10 + true).
    3. Condição de if numérica (if 10 then ...).
    4. Programa complexo válido (fatorial, fibonacci) passando sem erros.
  • Pelo menos um teste JUnit público cobrindo erros de tipos (como acima).
Back to top