O que você vai aprender
Calcular FIRST e FOLLOW de uma gramática.
Explicar o que a tabela LL(1) garante ao compilador que a descida da aula 6, sozinha, não garante.
Montar e usar a tabela preditiva LL(1).
Diagnosticar conflitos e por que uma gramática não é LL(1).
Consolidar os conceitos para a Avaliação 1.
Como o parser decide sem errar?
No parser descendente, ao expandir um não-terminal com várias produções, qual escolher? Olhar o próximo token e adivinhar dá errado se a escolha for ruim. Precisamos de um critério seguro.
Os conjuntos FIRST e FOLLOW dão exatamente isso: ao ver o próximo token, o parser sabe qual produção aplicar — sem retroceder. É a base do parsing preditivo LL(1).
O que a aula 6 deixou em aberto
A aula 6 terminou com um parser que funciona: uma função por não-terminal, a gramática sem recursão à esquerda e fatorada. Mas deixou uma pergunta sem resposta: como saber que a escolha com um token está sempre certa? A descida escolhe “a primeira alternativa cujo FIRST contém o token” — e, quando nenhuma contém, segue pela ε, sem olhar o que vem depois. Isso funciona na gramática da aula. Em outras, falha em silêncio. E, antes da aula 6, só com a gramática da aula 5, a única saída seria tentar: derivar, conferir os terminais com a entrada e voltar atrás a cada engano.
| Aula 5: só a gramática (tentativa e erro) | Aula 6: a primeira que casa | Aula 7: a tabela LL(1) | |
|---|---|---|---|
| Como escolhe | tenta a 1ª alternativa, confere os terminais e volta atrás se não batem | a primeira alternativa cujo FIRST contém o token; senão, ε | a célula M[A, token], montada com FIRST e FOLLOW |
| Custo | pode explodir (exponencial) | linear | linear |
| Resposta certa? | sim | garantida só se a gramática for LL(1) — e nada avisa quando não é | sim, e a garantia vem antes: sem conflito na tabela, vale para toda entrada |
| Erro de sintaxe | descoberto depois de esgotar as tentativas | às vezes só no fim, como “sobrou token” | na célula vazia, no não-terminal onde ele está, com a lista do que cabia ali |
É essa a vantagem para o compilador: a aula 6 dá um parser rápido; a aula 7 dá a certeza de que ele está certo — ou aponta a célula exata onde não está, antes de o primeiro programa ser compilado. A bancada abaixo põe as três aulas lado a lado: a mesma gramática, o mesmo programa e a mesma unidade de trabalho. Siga as três fases — antes do primeiro programa, este programa, todos os programas curtos — e repare em quando cada uma descobre o defeito: na gramática ③, o checklist da aula 6 aprova tudo e a descida recusa um programa válido; a tabela recusa a gramática antes de rodar e aponta a célula.
O que veremos nesta aula
- O conjunto FIRST e como calculá-lo.
- O conjunto FOLLOW e seu papel com ε.
- A construção da tabela preditiva e o que é uma gramática LL(1).
- Consolidação das aulas 1 a 6.
FIRST e FOLLOW
FOLLOW(A). Conjunto de terminais que podem aparecer imediatamente após o não-terminal A em alguma derivação.
Calculando FIRST
Regras para FIRST(X):
- Se X é terminal, FIRST(X) = { X }.
- Se X → ε é produção, adicione ε a FIRST(X).
- Se X → Y1 Y2 ... Yk, adicione FIRST(Y1) (sem ε). Se Y1 pode derivar ε, inclua também FIRST(Y2), e assim por diante.
FIRST e FOLLOW da gramática de expressões
Para E → T E', E' → + T E' | ε, T → F T', T' → * F T' | ε, F → ( E ) | id:
| Não-terminal | FIRST | FOLLOW |
|---|---|---|
| E | ( id | ) $ |
| E' | + ε | ) $ |
| T | ( id | + ) $ |
| T' | * ε | + ) $ |
| F | ( id | + * ) $ |
O símbolo $ marca o fim da entrada.
Esse quadro não sai de uma vez: sai de repetir as regras, produção por produção, até uma rodada inteira não acrescentar nada — o ponto fixo. Na bancada abaixo o cálculo roda exatamente assim, na ordem em que você faria no papel: dá para ver E esperando T, que espera F, e clicar em qualquer símbolo para saber quem o colocou ali.
Passo a passo: FOLLOW(T)
Gramática LL(1)
Montando a tabela preditiva
Para cada produção A → α, preenche-se a tabela (linha A, coluna terminal):
- Coloque A → α em cada coluna t de FIRST(α).
- Se ε ∈ FIRST(α), coloque A → α também em cada coluna t de FOLLOW(A).
O mapa de decisões
FIRST × FOLLOW
| FIRST(α) | FOLLOW(A) | |
|---|---|---|
| O que descreve | O que pode começar α | O que pode vir depois de A |
| Aplica-se a | Qualquer cadeia α | Não-terminais A |
| Pode conter ε? | Sim | Não (mas contém $) |
| Uso na tabela | Colunas onde a produção entra | Colunas extras quando α deriva ε |
Hora de montar a tabela com as suas mãos. Na bancada abaixo, uma produção por vez: marque as colunas em que ela entra e confira — a correção diz, coluna a coluna, se ela entrou pelo FIRST, pelo FOLLOW, ou por que não entra. Repare em E' → ε: é a produção que só entra pelo FOLLOW.
Do cálculo à decisão
A construção do parser preditivo segue uma cadeia bem definida:
O último elo é a decisão. Na bancada abaixo, o analisador preditivo usa a tabela: com um não-terminal no topo da pilha, ele consulta uma célula — M[topo, token] — e ela acende na tabela. Com um terminal no topo, ele nem olha a tabela: só confere se o token é o esperado.
Quando NÃO é LL(1)
Por isso as transformações da aula 6 (eliminar recursão à esquerda, fatorar) são pré-requisitos: sem elas, a tabela quase certamente terá conflitos.
Os conflitos têm dois tipos, e vale saber dar nome a eles:
| Conflito | O que acontece na célula M[A, a] | De onde costuma vir |
|---|---|---|
| FIRST/FIRST | duas alternativas de A podem começar com a | recursão à esquerda, prefixo comum (às vezes escondido atrás de outros não-terminais), ambiguidade |
| FIRST/FOLLOW | uma alternativa de A pode sumir (deriva ε), e a, que vem depois de A, também começa outra alternativa | ε mal colocado; o else pendente é o exemplo clássico |
Na bancada abaixo, oito gramáticas: decida se cada uma é LL(1) e, se não for, que conflito ela tem. Depois da resposta, a tabela mostra a célula culpada e, quando existe, o remédio da aula 6 é aplicado na hora.
Verifique você mesmo: onde entra ε?
Para a produção E' → + T E' | ε, em quais colunas entra a produção E' → ε na tabela?
Geradores de parser LL
Ferramentas como ANTLL e bibliotecas de parser combinators usam a teoria LL. Geradores LL(1) clássicos constroem a tabela automaticamente a partir da gramática.
Enganos com FIRST/FOLLOW
Calculando com segurança
Reflita: LL(1) é o limite?
Toda linguagem livre de contexto tem uma gramática LL(1)?
Termos-chave da aula
O quadro geral das aulas 1 a 6
Esta semana fecha o primeiro bloco. Veja como tudo se conecta:
- Aulas 1-2: o panorama e as linguagens formais (Chomsky).
- Aulas 3-4: léxico — tokens, ER, autômatos (tipo 3).
- Aulas 5-6: sintaxe — GLC, ambiguidade, parsing descendente (tipo 2).
- Aula 7: FIRST/FOLLOW e LL(1) coroam o parsing preditivo. A Prova 1 cobre tudo isso.
Resumo visual
Calcule FIRST/FOLLOW automaticamente
Todas as bancadas desta aula aceitam a sua gramática: escreva na caixa de texto e tudo se recalcula. Para os conjuntos e a tabela prontos, use a mesa LL(1); para ver o cálculo acontecer, o ponto fixo rodada a rodada.
Tente: o que acontece com os conjuntos se você adicionar uma produção com ε? E se introduzir recursão à esquerda? Observe como os conjuntos mudam — e em que célula da tabela o conflito aparece.
Atividade em grupo · Mutirão de revisão (Prova 1)
Em grupos, montem um mapa de revisão das aulas 1–6.
Roteiro
- Cada integrante fica responsável por um tema: léxico, ER/autômatos, GLC, parsing descendente.
- Montem um mapa mental conectando os temas (uma página).
- Criem 2 questões originais por tema e troquem com outro grupo.
- Resolvam as questões recebidas e discutam.
Mini-quiz · Aula 7
20 questões sobre esta aula. Escolha e veja a explicação na hora.
📌 Resumo — leve isto para a prova
- A aula 6 dá um parser rápido; a aula 7 dá a garantia: sem conflito na tabela, a escolha com um token é certa para toda entrada — e o conflito aparece antes de o primeiro programa ser compilado.
- FIRST = terminais iniciais (pode conter ε); FOLLOW = terminais seguintes (contém $, nunca ε).
- LL(1) = leitura da esquerda para a direita, derivação mais à esquerda, 1 lookahead.
- A tabela preditiva sem conflitos significa gramática LL(1).
- Conflitos vêm de ambiguidade, recursão à esquerda ou falta de fatoração.
- Nem toda linguagem livre de contexto admite gramática LL(1).
- FIRST e FOLLOW se calculam por ponto fixo: repita as regras, produção por produção, até uma rodada inteira não acrescentar nada — e o FOLLOW só depois do FIRST.
- Conflito FIRST/FIRST: duas alternativas começam com o mesmo token. Conflito FIRST/FOLLOW: uma alternativa some, e o token que vem depois dela também começa outra.