Compiladores

Parsing LL(1)

Professor: Gabriel Soares Baptista

O problema

Hoje queremos responder a uma pergunta simples.

  • Como o parser escolhe a produção certa sem voltar atrás?
  • Como ele usa apenas um símbolo de olhar adiante?
  • O que precisa estar pronto antes da tabela funcionar?

LL(1)

Ideia central

LL(1) lê da esquerda para a direita, constrói derivação mais à esquerda e decide com um símbolo de lookahead.

  • L: left-to-right
  • L: leftmost derivation
  • 1: um símbolo de lookahead

Os três componentes

  • Buffer de entrada: a cadeia termina em $.
  • Pilha de análise: começa com $ e o símbolo inicial.
  • Tabela LL(1): decide qual produção usar.
LL1FlowentradaBuffer de entrada... a b c $lookaheadSímbolo atualda entradaaentrada->lookaheadpilhaPilha de análise$ / símbolo inicialtopoTopo da pilhaXpilha->topotabelaTabela LL(1)M[A, a]decisaoExpandir, casarou errotabela->decisaotopo->tabelalookahead->tabela

FIRST

O FIRST(A) responde a pergunta:

  • com que símbolo uma derivação de $A$ pode começar?
  • pode começar com vazio?

$$ A \to a \mid \epsilon $$

$$ FIRST(A) = \{a, \epsilon\} $$

  • a entra porque pode aparecer primeiro.
  • \epsilon entra porque $A$ pode desaparecer.

FOLLOW

O FOLLOW(A) responde a pergunta:

  • o que pode aparecer logo depois de $A$?
  • se $A$ desaparecer, quem ocupa o lugar dele?
  • \epsilon não entra em FOLLOW.
  • \$ entra em FOLLOW(S), onde $S$ é o símbolo inicial.

$$ \begin{split} S &\to AB \\ A &\to a \\ B &\to b \end{split} $$

$$ FOLLOW(S)=\{\$\},\quad FOLLOW(A)=\{b\},\quad FOLLOW(B)=\{\$\} $$

Exemplo 1

FIRST e FOLLOW completos

Gramática:

$$ \begin{split} S &\to ABCD \\ A &\to a \mid \epsilon \\ B &\to b \mid \epsilon \\ C &\to c \mid \epsilon \\ D &\to d \mid \epsilon \end{split} $$
$$ \begin{split} FIRST(A) &= \{a, \epsilon\} \\ FIRST(B) &= \{b, \epsilon\} \\ FIRST(C) &= \{c, \epsilon\} \\ FIRST(D) &= \{d, \epsilon\} \\ FIRST(S) &= \{a, b, c, d, \epsilon\} \end{split} $$
$$ \begin{split} FOLLOW(S) &= \{\$\} \\ FOLLOW(A) &= \{b, c, d, \$\} \\ FOLLOW(B) &= \{c, d, \$\} \\ FOLLOW(C) &= \{d, \$\} \\ FOLLOW(D) &= \{\$\} \end{split} $$

Exemplo 2

Follow em cadeia

Gramática:

$$ \begin{split} S &\to A B c \\ A &\to a \mid \epsilon \\ B &\to b \mid \epsilon \end{split} $$
$$ \begin{split} FIRST(A) &= \{a, \epsilon\} \\ FIRST(B) &= \{b, \epsilon\} \\ FIRST(S) &= \{a, b, c\} \end{split} $$
$$ \begin{split} FOLLOW(S) &= \{\$\} \\ FOLLOW(B) &= \{c\} \\ FOLLOW(A) &= \{b, c\} \end{split} $$
  • Se $B$ some, c passa a ficar logo depois de $A$.
  • Se $B$ não some, o que começa B também pode seguir A.

Montando a tabela

Antes de preencher qualquer célula, feche FIRST e FOLLOW.

Regra:

  1. coloque $A \to \alpha$ nas células de $FIRST(\alpha)$ exceto $\epsilon$
  2. se $\epsilon \in FIRST(\alpha)$, coloque a produção nas colunas de $FOLLOW(A)$
Não existe coluna de vazio
\epsilon não vira coluna da tabela. Ele só diz que precisamos usar o contexto de FOLLOW(A).

Exemplo 3

Tabela curta

Gramática:

$$ \begin{split} S &\to aA \mid b \\ A &\to c \mid \epsilon \end{split} $$
$$ \begin{split} FIRST(S) &= \{a, b\} \\ FIRST(A) &= \{c, \epsilon\} \\ FOLLOW(S) &= \{\$\} \\ FOLLOW(A) &= \{\$\} \end{split} $$
$$ \begin{array}{c|ccc} & a & b & c \\ \hline S & S \to aA & S \to b & \\ A & & & A \to c \end{array} $$

Exemplo 4

Parênteses

Gramática:

$$ S \to (S) \mid \epsilon $$
$$ \begin{split} FIRST(S) &= \{(, \epsilon\} \\ FOLLOW(S) &= \{\$, )\} \end{split} $$
$$ \begin{array}{c|ccc} & ( & ) & \$ \\ \hline S & S \to (S) & S \to \epsilon & S \to \epsilon \end{array} $$

Exemplo 4

Entrada de (())

Passo Pilha Entrada Ação
1 [$, S] (())\$ Consulta $M[S, (]$
2 [$, ), S, (] (())\$ Expande $S \to (S)$
3 [$, ), S] (())\$ Faz match de (
4 [$, ), S] ())\$ Consulta $M[S, (]$
5 [$, ), ), S, (] ())\$ Expande $S \to (S)$
6 [$, ), ), S] ())\$ Faz match de (
7 [$, ), )] ))\$ Consulta $M[S, )]$
8 [$, ), )] ))\$ Expande $S \to \epsilon$
9 [$, )] ))\$ Faz match de )
10 [$] )\$ Faz match de )
11 [$] $ Sucesso

Exemplo 5

Expressões

Gramática clássica:

$$ \begin{split} E &\to T E' \\ E' &\to + T E' \mid \epsilon \\ T &\to F T' \\ T' &\to * F T' \mid \epsilon \\ F &\to (E) \mid id \end{split} $$
$$ \begin{split} FIRST(E) &= FIRST(T) = \{(, id\} \\ FIRST(E') &= \{+, \epsilon\} \\ FIRST(T) &= FIRST(F) = \{(, id\} \\ FIRST(T') &= \{*, \epsilon\} \\ FIRST(F) &= \{(, id\} \end{split} $$
$$ \begin{split} FOLLOW(E) &= \{\$, )\} \\ FOLLOW(E') &= \{\$, )\} \\ FOLLOW(T) &= \{+, \$, )\} \\ FOLLOW(T') &= \{+, \$, )\} \\ FOLLOW(F) &= \{*, +, \$, )\} \end{split} $$

Exemplo 5

Tabela e leitura

$$ \begin{array}{c|cccccc} & id & + & * & ( & ) & \$ \\ \hline E & E \to T E' & & & E \to T E' & & \\ E' & & E' \to + T E' & & & E' \to \epsilon & E' \to \epsilon \\ T & T \to F T' & & & T \to F T' & & \\ T' & & T' \to \epsilon & T' \to * F T' & & T' \to \epsilon & T' \to \epsilon \\ F & F \to id & & & F \to (E) & & \end{array} $$

Exemplo 5

Trace curto

Passo Pilha Entrada Ação
1 [$, E] id$ Consulta $M[E, id]$
2 [$, E', T] id$ Expande $E \to T E'$
3 [$, E', T', F] id$ Expande $T \to F T'$
4 [$, E', T', id] id$ Expande $F \to id$
5 [$, E', T'] $ Faz match de id
6 [$, E'] $ Expande $T' \to \epsilon$
7 [$] $ Expande $E' \to \epsilon$
8 [$] $ Sucesso

Quando não é LL(1)

Três causas comuns:

  • Ambiguidade: duas árvores para a mesma cadeia
  • Recursão à esquerda: o parser volta ao mesmo não terminal antes de consumir entrada
  • Falta de fatoração: duas produções começam igual e o lookahead não basta

Prefixo comum

$$ A \to ab \mid ac $$
  • com lookahead só em a, a decisão ainda não está pronta.
  • a solução é fatorar o prefixo comum.

Recursão à esquerda

$$ E \to E + T \mid T $$
  • o parser tenta expandir E e volta para E antes de consumir qualquer coisa.
  • isso causa loop em parser top-down.

Ambiguidade

$$ E \to E + E \mid id $$
  • para id + id + id, mais de uma árvore continua possível.
  • a tabela não consegue esconder um conflito que já existe na gramática.

Pŕoximos Passos

Na próxima aula, vamos fazer uma revisão para consolidar esses conceitos. Depois disso, o próximo passo será a geração de código na parte sintática.