Aula 11: Análise Sintática Ascendente (LR)

Data de Publicação

25/03/2026

Data de Modificação

08/03/2026

Objetivos

Ao final desta aula, você será capaz de:

  • Descrever o paradigma bottom-up (ascendente): construção da árvore das folhas para a raiz.
  • Explicar a mecânica shift-reduce: pilha, buffer de entrada, ações Shift, Reduce, Accept e Error.
  • Identificar o handle (substring a ser reduzida) e a relação com as produções da gramática.
  • Relacionar parsers LR com ferramentas (Bison/Yacc) e com o projeto Mini-Pascal.

Motivação

Parsers ascendentes (LR) são a base de muitos compiladores industriais porque:

  • Aceitam uma classe maior de gramáticas do que parsers LL (incluindo recursão à esquerda).
  • Lidam naturalmente com gramáticas escritas de forma “natural” para expressões e listas.
  • São gerados por ferramentas (Bison/Yacc, ANTLR em modo LR), produzindo parsers eficientes e mantíveis.

Visão geral: Top-Down vs Bottom-Up

flowchart LR
  subgraph LL [Top-Down LL]
    A1[Raiz] --> A2[Expandir]
    A2 --> A3[Folhas]
  end
  subgraph LR [Bottom-Up LR]
    B1[Folhas] --> B2[Reduzir]
    B2 --> B3[Raiz]
  end
  • Top-Down (LL): começa pelo símbolo inicial e “expande” produções até obter os tokens; a árvore cresce da raiz para as folhas.
  • Bottom-Up (LR): começa pelos tokens e “reduz” sequências ao lado direito de produções, substituindo pelo não terminal do lado esquerdo; a árvore é construída das folhas para a raiz.

Conteúdo

1. Mecânica Shift-Reduce

O parser mantém:

  • Uma pilha de símbolos (terminais e não terminais).
  • Um buffer de entrada com os tokens restantes (da esquerda para a direita).

Configuração em um instante: (conteúdo da pilha, entrada restante). O parser repete ações até Accept ou Error.

As quatro ações possíveis:

Ação Descrição
Shift Remover o próximo token da entrada e empilhá-lo no topo da pilha.
Reduce Escolher uma produção \(A \to \beta\); os \(|\beta|\) símbolos no topo da pilha formam exatamente \(\beta\) (da ordem topo → base). Desempilhar esses símbolos e empilhar \(A\). (Construir nó da árvore associado a \(A\) com filhos \(\beta\).)
Accept A pilha contém apenas o símbolo inicial \(S\) e a entrada está vazia. Parsing concluído com sucesso.
Error Nenhuma ação (Shift, Reduce ou Accept) é aplicável. Erro de sintaxe; reportar e, se houver estratégia de recuperação, aplicá-la.

A decisão de qual ação tomar em cada configuração é feita por uma tabela de parsing (ou equivalente), construída a partir da gramática (LR(0), SLR, LR(1), LALR). O próximo token da entrada (lookahead) e o estado atual (que resume o conteúdo da pilha) indexam a tabela.

2. Handle

O handle é uma substring no topo da pilha que é o lado direito de alguma produção \(A \to \beta\) e que deve ser reduzida nesse passo. Ou seja, é o \(\beta\) que o parser escolhe para a ação Reduce.

Em gramáticas adequadas para LR, em cada configuração há no máximo um handle (e a decisão é determinística com o lookahead). O algoritmo LR garante que o handle correto seja identificado no momento certo.

3. Exemplo passo a passo

Gramática simplificada:

\[E \to E + T \mid T\] \[T \to T * F \mid F\] \[F \to \texttt{id}\]

Entrada: id + id.

Passo Pilha Entrada Ação
1 \(\varepsilon\) id + id Shift id
2 id + id Reduce \(F \to \texttt{id}\)
3 F + id Reduce \(T \to F\)
4 T + id Reduce \(E \to T\)
5 E + id Shift +
6 E + id Shift id
7 E + id \(\varepsilon\) Reduce \(F \to \texttt{id}\)
8 E + F \(\varepsilon\) Reduce \(T \to F\)
9 E + T \(\varepsilon\) Reduce \(E \to E + T\)
10 E \(\varepsilon\) Accept

A pilha evolui até conter apenas \(E\) com entrada vazia; nesse momento Accept.

4. Diagrama do ciclo do parser LR

flowchart TD
  Início([Início]) --> Estado[Estado atual + lookahead]
  Estado --> Decisão{Consulta tabela}
  Decisão -->|Shift| Shift[Empilhar token]
  Decisão -->|Reduce| Reduce[Desempilhar beta, empilhar A]
  Decisão -->|Accept| Fim([Sucesso])
  Decisão -->|Vazio/Error| Erro([Erro])
  Shift --> Estado
  Reduce --> Estado

O “estado atual” em um parser LR por tabela é um estado do autômato LR (conjunto de itens LR), não apenas o conteúdo literal da pilha; a pilha pode armazenar símbolos e estados. O diagrama acima é conceitual: a cada passo consulta-se a tabela e aplica-se Shift, Reduce, Accept ou Error.

5. Recursão à esquerda

Parsers LL (top-down) têm dificuldade com recursão à esquerda (risco de loop). Parsers LR (bottom-up) não têm esse problema: a redução ocorre após os tokens terem sido empilhados, então a ordem das produções com recursão à esquerda é tratada naturalmente pela tabela. Por isso gramáticas com expressões escritas como \(E \to E + T \mid T\) são comuns em geradores LR (Bison/Yacc).

Conexões com ferramentas e projeto

  • Bison/Yacc geram parsers baseados em LALR(1) (ou LR(1)); a máquina de estados e a tabela ACTION/GOTO são construídas a partir da gramática. Entender shift-reduce ajuda a interpretar conflitos (shift/reduce, reduce/reduce) e a ajustar a gramática ou as regras de precedência.
  • No projeto Mini-Pascal você usa parser LL nas etapas 3 e 4; mesmo assim, conhecer LR ajuda a ler documentação de compiladores, a analisar ambiguidades e a entender como ferramentas industriais funcionam.

Resumo

  • Bottom-up: árvore construída das folhas para a raiz; o parser reduz sequências ao lado direito de produções.
  • Shift: empilha token; Reduce: desempilha \(\beta\), empilha \(A\) para \(A \to \beta\); Accept: pilha = \(S\), entrada vazia; Error: nenhuma ação aplicável.
  • O handle é o \(\beta\) no topo da pilha escolhido para reduzir.
  • Parsers LR lidam bem com recursão à esquerda e são a base de geradores como Bison.

Perguntas de reflexão

  • Em que situações você consideraria migrar de um parser LL manual para um parser LR gerado por ferramenta?
  • Que informação extra (além da pilha de símbolos) o parser LR mantém para decidir entre Shift e Reduce? (Dica: estado do autômato LR, lookahead.)

Referências

  • Aho et al. (2006). Compilers: Principles, Techniques, and Tools. Cap. 4 (parsing LR).
  • Cooper & Torczon (2011). Engineering a Compiler.

Materiais da aula

Última atualização: 08/03/2026

De volta ao topo