Compiladores

Parsing LR(0)

Professor: Gabriel Soares Baptista

De LL(1) para LR(0)

Na aula anterior, o parser era descendente.

  • começava pelo símbolo inicial
  • expandia não terminais
  • usava FIRST, FOLLOW e um símbolo de lookahead
  • tentava prever a estrutura da entrada

A troca de perspectiva

Hoje o parser será ascendente.

  • começa pela entrada
  • empilha símbolos e estados
  • reconhece pedaços já lidos
  • reduz esses pedaços para não terminais
Ideia central

LR(0) lê da esquerda para a direita e reconstrói uma derivação mais à direita ao contrário.

Retomada LL(1)

Considere:

$$ S \to aS \mid b $$

Essa gramática gera:

  • b
  • ab
  • aab
  • aaab

Tabela LL(1)

$$ FIRST(S)=\{a,b\} $$

$$ FOLLOW(S)=\{\$\} $$

Não terminal a b $
S $S \to aS$ $S \to b$ erro

Simulação LL(1)

Entrada: aab$

Pilha Entrada Ação
$ S a a b $ usa $S \to aS$
$ S a a a b $ casa a
$ S a b $ usa $S \to aS$
$ S a a b $ casa a
$ S b $ usa $S \to b$
$ b b $ casa b
$ $ aceita

O movimento do LR(0)

O LR(0) faz o movimento oposto.

  • o LL(1) expande o símbolo inicial até chegar à entrada
  • o LR(0) reduz a entrada até chegar ao símbolo inicial
$$ \begin{split} S &\Rightarrow aS \Rightarrow aaS \Rightarrow aab \\ aab &\Rightarrow aaS \Rightarrow aS \Rightarrow S \end{split} $$

O que significa LR(0)

  • L: left-to-right, leitura da esquerda para a direita
  • R: rightmost derivation in reverse, derivação mais à direita ao contrário
  • 0: nenhuma informação de lookahead para decidir reduções
Consequência

LR(0) é simples, mas restritivo. Muitas gramáticas precisam de SLR, LR(1) ou LALR.

Operações do parser

Operação Notação Ideia
Shift sN consome um terminal e vai para o estado N
Reduce rK reduz pelo corpo da produção K
Goto N desvia após reconhecer um não terminal
Accept acc aceita a entrada

Por que estados?

Se a pilha guardasse apenas símbolos, o parser não saberia em que ponto da gramática está.

  • estados representam progresso dentro das produções
  • a pilha guarda estados e símbolos reconhecidos
  • cada estado é um conjunto de itens LR(0)

Gramática aumentada

Antes de construir o autômato, adicionamos uma nova produção inicial.

Gramática original:

$$ S \to a $$

Gramática aumentada:

$$ S' \to S $$

Por que aumentar?

A produção aumentada cria o estado de aceitação.

$$ S' \to S \cdot $$
Quando o parser chega a esse item e a entrada está no fim, a análise aceita.
Intuição

O parser reconheceu um S completo e não sobrou entrada real.

Itens LR(0)

Um item LR(0) é uma produção com um ponto.

$$ A \to XYZ $$

$$ \begin{split} A &\to \cdot XYZ \\ A &\to X \cdot YZ \\ A &\to XY \cdot Z \\ A &\to XYZ \cdot \end{split} $$

Como ler o ponto

Item Leitura
$A \to \cdot XYZ$ ainda não reconheci nada
$A \to X \cdot YZ$ reconheci X, falta YZ
$A \to XY \cdot Z$ reconheci XY, falta Z
$A \to XYZ \cdot$ reconheci tudo, posso reduzir

Closure

Closure completa um conjunto de itens.

Regra:

Se existe $A \to \alpha \cdot B \beta$ e B é não terminal, adicionamos todos os itens $B \to \cdot \gamma$.

Em palavras: se agora posso precisar reconhecer um B, preciso considerar todas as formas pelas quais B pode começar.

Closure: exemplo

Gramática aumentada:

$$ \begin{split} S' &\to S \\ S &\to aS \mid b \end{split} $$

Começamos com:

$$ S' \to \cdot S $$

Closure: resultado

Como o ponto está antes de S, adicionamos as produções de S com ponto no início.

$$ I_0 = \left\{ \begin{array}{l} S' \to \cdot S \\ S \to \cdot aS \\ S \to \cdot b \end{array} \right\} $$

Goto

Goto(I, X) responde:

se estou no estado I e reconheço o símbolo X, para onde vou?

Procedimento:

  • mova o ponto sobre X
  • aplique Closure ao resultado

Goto: exemplo

Estado inicial:

$$ I_0 = \left\{ \begin{array}{l} S' \to \cdot S \\ S \to \cdot aS \\ S \to \cdot b \end{array} \right\} $$

Vamos calcular $Goto(I_0, a)$.

Goto: movendo o ponto

O item com a depois do ponto é:

$$ S \to \cdot aS $$

Depois de reconhecer a:

$$ S \to a \cdot S $$

Goto: aplicando Closure

Agora o ponto ficou antes de S.

Como S é não terminal, entram todas as produções de S com ponto no início.
$$ Goto(I_0, a)=\left\{ \begin{array}{l} S \to a \cdot S \\ S \to \cdot aS \\ S \to \cdot b \end{array} \right\} $$

Tabela LR(0)

A tabela tem duas partes.

Parte Colunas Conteúdo
ACTION terminais e $ shift, reduce, accept, erro
GOTO não terminais próximo estado

Regras da tabela

  • transição por terminal vira shift
  • transição por não terminal vira goto
  • item completo vira reduce
  • item $S' \to S \cdot$ vira accept em $
LR(0) puro

Reduções comuns entram em todas as colunas de ACTION.

Exemplo 1

Gramática mínima

$$ S \to a $$

Gramática aumentada:

$$ \begin{array}{rcl} (0) & S' & \to S \\ (1) & S & \to a \end{array} $$

Exemplo 1

Estados

$$ I_0 = \left\{ \begin{array}{l} S' \to \cdot S \\ S \to \cdot a \end{array} \right\} $$

$$ I_1 = \{S' \to S \cdot\} \qquad I_2 = \{S \to a \cdot\} $$

Exemplo 1

Transições

Origem Símbolo Destino
I0 S I1
I0 a I2

Exemplo 1

Tabela

Estado ACTION a ACTION $ GOTO S
0 s2 1
1 acc
2 r1 r1

r1: $S \to a$

Exemplo 1

Simulação de a$

Pilha Entrada Ação
0 a $ s2
0 a 2 $ r1: $S \to a$
0 S 1 $ acc

Exemplo 2

Vários a antes de b

$$ S \to aS \mid b $$

Gramática aumentada:

$$ \begin{array}{rcl} (0) & S' & \to S \\ (1) & S & \to aS \\ (2) & S & \to b \end{array} $$

Exemplo 2

Estado inicial

$$ I_0 = \left\{ \begin{array}{l} S' \to \cdot S \\ S \to \cdot aS \\ S \to \cdot b \end{array} \right\} $$

Exemplo 2

Transições principais

Origem Símbolo Destino
I0 S I1
I0 a I2
I0 b I3
I2 S I4
I2 a I2
I2 b I3

Exemplo 2

Estados finais

$$ \begin{split} I_1 &= \{S' \to S \cdot\} \\ I_3 &= \{S \to b \cdot\} \\ I_4 &= \{S \to aS \cdot\} \end{split} $$

I3 reduz por $S \to b$.

I4 reduz por $S \to aS$.

Exemplo 2

Tabela LR(0)

Estado ACTION a ACTION b ACTION $ GOTO S
0 s2 s3 1
1 acc
2 s2 s3 4
3 r2 r2 r2
4 r1 r1 r1

Exemplo 2

Simulação de aab$

Pilha Entrada Ação
0 a a b $ s2
0 a 2 a b $ s2
0 a 2 a 2 b $ s3
0 a 2 a 2 b 3 $ r2: $S \to b$
0 a 2 a 2 S 4 $ r1: $S \to aS$
0 a 2 S 4 $ r1: $S \to aS$
0 S 1 $ acc

Exemplo 2

O que aconteceu?

O parser reconstruiu a cadeia de baixo para cima.

$$ b \Rightarrow S $$
$$ aS \Rightarrow S $$
$$ aS \Rightarrow S $$

Exemplo 3

Recursão à esquerda

$$ E \to E + n \mid n $$

  • em parser descendente direto, isso causa loop
  • em LR(0), isso é natural
  • o parser primeiro lê n, depois reduz para E

Exemplo 3

Gramática aumentada

$$ \begin{array}{rcl} (0) & E' & \to E \\ (1) & E & \to E + n \\ (2) & E & \to n \end{array} $$

Estado inicial:

$$ I_0=\left\{ \begin{array}{l} E' \to \cdot E \\ E \to \cdot E + n \\ E \to \cdot n \end{array} \right\} $$

Exemplo 3

Estados

$$ \begin{split} I_1 &= \left\{ \begin{array}{l} E' \to E \cdot \\ E \to E \cdot + n \end{array} \right\} \\ I_2 &= \{E \to n \cdot\} \\ I_3 &= \{E \to E + \cdot n\} \\ I_4 &= \{E \to E + n \cdot\} \end{split} $$

Exemplo 3

Transições

Origem Símbolo Destino
I0 E I1
I0 n I2
I1 + I3
I3 n I4

Exemplo 3

Tabela LR(0)

Estado ACTION n ACTION + ACTION $ GOTO E
0 s2 1
1 s3 acc
2 r2 r2 r2
3 s4
4 r1 r1 r1

Exemplo 3

Simulação de n+n$

Pilha Entrada Ação
0 n + n $ s2
0 n 2 + n $ r2: $E \to n$
0 E 1 + n $ s3
0 E 1 + 3 n $ s4
0 E 1 + 3 n 4 $ r1: $E \to E + n$
0 E 1 $ acc

Quando LR(0) falha

Nem toda gramática é LR(0).

Conflitos comuns:

Conflito Significado
shift/reduce o estado quer empilhar e reduzir
reduce/reduce o estado quer reduzir por duas produções

Shift/reduce

O conflito aparece quando um estado contém ao mesmo tempo:

  • um item que ainda pode avançar com terminal
  • um item completo que manda reduzir
Como LR(0) não usa lookahead, a redução entra em todas as colunas de ACTION.

LL(1) vs LR(0)

Aspecto LL(1) LR(0)
Direção top-down bottom-up
Derivação mais à esquerda mais à direita ao contrário
Pilha símbolos esperados estados e símbolos reconhecidos
Decisão FIRST, FOLLOW, lookahead itens e estados
Recursão à esquerda problema natural

Roteiro LR(0)

  1. Aumente a gramática.
  2. Numere as produções.
  3. Calcule Closure do item inicial.
  4. Aplique Goto até fechar os estados.
  5. Preencha ACTION e GOTO.
  6. Simule uma cadeia.

Exercício 1

Construa a tabela LR(0) para:

$$ S \to c $$

Depois simule:

$$ c\$ $$

Exercício 2

Construa a tabela LR(0) para:

$$ S \to aS \mid c $$

Depois simule:

$$ aac\$ $$

Exercício 3

Construa a tabela LR(0) para:

$$ E \to E * n \mid n $$

Depois simule:

$$ n*n\$ $$

Exercício 4

Considere:

$$ \begin{split} S &\to A \\ A &\to aA \mid b \end{split} $$

Faça:

  1. gramática aumentada
  2. coleção canônica de itens
  3. tabela LR(0)
  4. simulação de aab$

Resumo

  • LR(0) é bottom-up
  • itens indicam progresso nas produções
  • Closure expande possibilidades antes de não terminais
  • Goto cria as transições entre estados
  • ACTION decide shift, reduce e accept
  • GOTO move entre estados após uma redução

Encerramento

O mais importante é dominar a construção da tabela.

Depois que a tabela está pronta, a execução é mecânica:

  • consultar estado atual
  • olhar próximo símbolo da entrada
  • aplicar ação
  • atualizar a pilha