Você está na página 1de 8

Lembrando: construir a tabela

de análise LL(1)
• Como fazer ?
– Re-escrever gramática para satisfazer condições de LL(1)
– Calcular conjuntos First e Follow
Compiladores – Para cada produção A → α
1. Para cada a ∈First(α)
– incluir A → α em M[A,a]
Análise sintática (4) 2. Se ε ∈ First(α)
Análise ascendente – incluir A → α em M[A,b] para cada b em Follow(A)
Autômatos Empilhar/Reduzir 3. Se ε ∈ First(α) e $ ∈ Follow(A)
– incluir A → α to M[A,$]
– Todas entradas não definidas são erros

Plano da aula Top-Down x Bottom Up


Gramática: S → A B Entrada:
• Transformação de Gramática
A→c|ε ccbca
• Análise bottom-up (ascendente):
princípios gerais B → cbB | ca
– Vocabulário Top-Down/Esquerda Bottom-Up/Direita
– Exemplos S ⇒ AB S→AB ccbca ⇐ Acbca A→c
• Analisador com pilha (reduz/empilha) ⇒ cB A→c ⇐ AcbB B→ca
• Gramática LR ⇒ ccbB B→cbB ⇐ AB B→cbB
– Tabelas LR. ⇒ ccbca B→ca ⇐S S→AB

Redução – exemplo 1 Redução – exemplo 1

S → aABe abbcde S → aABe abbcde


A → Abc | b A → Abc | b aAbcde
B→d B→d

Redução = substituição do lado direito de uma


produção pelo não terminal correspondente
(lado esquerdo)

1
Redução – exemplo 1 Redução – exemplo 1
S → aABe abbcde S → aABe abbcde
A → Abc | b aAbcde A → Abc | b aAbcde
B→d B→d aAde

handle = seqüência de símbolos do lado direito da


produção, tais que suas reduções levam, no final, ao
símbolo inicial da gramática

Redução – exemplo 1 Redução – exemplo 1


S → aABe abbcde S → aABe abbcde
A → Abc | b aAbcde A → Abc | b aAbcde
B→d aAde B→d aAde
aABe

Redução – exemplo 1 Redução – exemplo 2


S → aABe abbcde E→E+E
E→E*E id + id * id
A → Abc | b aAbcde
E → (E) | id
B→d aAde
aABe
S

2
Redução – exemplo 2 Redução – exemplo 2
E→E+E E→E+E
E→E*E id + id * id E→E*E id + id * id
E → (E) | id E + id * id E → (E) | id E + id * id
E + E * id

Redução – exemplo 2 Redução – exemplo 2


E→E+E E→E+E
E→E*E id + id * id E→E*E id + id * id
E → (E) | id E + id * id E → (E) | id E + id * id
E + E * id E + E * id
E * id E * id
E*E

Redução – exemplo 2 Ações bottom-up (empilha-reduz)


• A análise Bottom-Up vai necessitar:
E→E+E – De uma pilha para guardar os símbolos
– De um buffer de entrada para a sentença w a ser reconhecida.
E→E*E id + id * id
E → (E) | id E + id * id • Operações lícitas:
– empilha (shift):
E + E * id • coloca no topo da pilha o símbolo que está sendo lido e avança o
cabeçote de leitura na string
E * id – reduz (reduce):
• substitui o handle no topo da pilha pelo não terminal
E*E correspondente
– aceita:
E • reconhece que a sentença foi gerada pela gramática
– erro:
• ocorrendo erro de sintaxe, chama uma subrotina de atendimento a
erros

3
Ações bottom-up: 3 problemas Ações bottom-up: 3 problemas
• Problema 1: Como decidir qual lado • Problema 1: Como decidir qual lado
direito de produção trocar pelo lado direito de produção trocar pelo lado
esquerdo (redução) ? esquerdo (redução) ?
– Ler entrada da esquerda para direita
– Em algumas situações uma escolha
aparece:
1. ler mais um caractere da entrada
ou Análise Entrada Ação
2. aplicar redução $ abc$ Ler
a$ bc$ Ler
ab$ c$ Ler

S → abc | a abc$ Redução


S$ $ Aceitar

Ações bottom-up: 3 problemas E → E + E | E * E | (E) | id


• Problema 1: Como decidir qual lado direito de Pilha Entrada Ação
produção trocar pelo lado esquerdo (redução)? $ id + id * id shift
- conflito reduce/reduce
$id + id * id Reduce E → id
• Problema 2: Como escolher entre ler ou aplicar $E + id * id shift
a redução? $E+ id * id shift
– Conflito Shift / Reduce $E+id * id Reduce E → id
$E+E * id Reduce E → E + E
• Problema 3: Como guardar o substring que $E * id shift
está sendo analisando?
$E* id shift
– Pode ser uma combinação de 1 ou mais símbolos
(terminais ou não-terminais) $E*id $ Reduce E → id
– Pilha $E*E $ Reduce E → E * E
$E $ aceita!

Ações em Parsing Empilha-Reduz Várias soluções para o parsing Bottom-Up


• Reduz
– Se: • O parsing bottom-up é mais poderoso do que o
• γα está na pilha parsing Top-Down
• A→ α
– Regras aplicadas em reverso
• existe um β ∈T* tal que S ⇒* γA β ⇒ γ α β
– Então: – Pode “adiar decisões” de reduções
• Pode-se remover o “handle” α; • Pode usar mais de um símbolo na entrada para tomar a
• Reduz-se γ β para γ A na pilha decisão.
– γα é um prefixo viável • Vários algoritmos para o parsing Shift-Reduce
• Ele pode derivar numa seqüência de terminais (empilha-reduz):
– LR(0) Hoje
• Shift (empilha) – SLR(1)
– Empilhar o terminal, avançar entrada Próxima aula
– LR(1)
• Erro
– LALR(1)
• Aceitar

4
Parsing LR Tabela Ação/Transição (LR)
• Parser baseado em tabelas • Ação: A partir de um estado s e de um terminal t,
Estruturas de dados:
– Lê a entrada de esquerda para direita
(L) Pilha de estados {s} e símbolos Ação[s, t] indica:
– Cria derivações mais a direita (R) Tabela de ações: Action[s,t]; t ∈T – Se se faz um shift S (empilha) ou um Reduce R (reduz) ao ler o
Tabela de transições: Goto[s,X]; X ∈N símbolo ‘a’ na entrada.
• Usa um autômato finito com pilha – Caso S: indica também o estado a empilhar;
– Cada estado representa produções da • Fazer:
gramática – empilhar o estado e avançar na leitura.
– Transições são feitas a cada
terminal/não terminal – Caso R: indica também a regra a reduzir e, a seguir, aplica uma
0 * 1 0 $ Buffer de entrada Transição.
• Fazer:
t – depilhar tantos estados como símboloS reduzidoS;
– empilhar o estado alvo do Goto(topo Pilha, Símbolo reduzido).
Pilha s Parser LR Saída
$ • Transição (goto): a partir de um estado s e de um não-
terminal X, Goto[s, X] indica o próximo estado a
empilhar.
Tabela
Ação Goto

Exemplo de uso de tabela Ação/Transição Tabela Ações/Transições


Ações Goto
• Gramática usada:
* ( ) id $ E T F
S→T 0 S5 S8 2 1
T→F|T*F 1 R1 R1 R1 R1 R1
F → id | ( T ) 2 S3 Ok!
3 S5 S8 4
4 R2 R2 R2 R2 R2
5 S5 S8 6 1
6 S3 S7
7 R4 R4 R4 R4 R4
8 R3 R3 R3 R3 R3

Tabela Ações/Transições Tabela Ações/Transições


Ações Terminais Goto Não-Terminais Ações Terminais Goto Não-Terminais

* ( ) id $ E T F * ( ) id $ E T F
0 S5 S8 2 1 0 S5 S8 2 1
Estados 1 R1 R1 R1 R1 R1 Estados 1 R1 R1 R1 R1 R1
2 S3 Ok! 2 S3 Ok!
3 S5 S8 4 3 S5 S8 4
4 R2 R2 R2 R2 R2 4 R2 R2 R2 R2 R2 Shift e empilha 8
5 S5 S8 6 1 5 S5 S8 6 1
6 S3 S7 6 S3 S7
7 R4 R4 R4 R4 R4 7 R4 R4 R4 R4 R4
8 R3 R3 R3 R3 R3 8 R3 R3 R3 R3 R3

5
Tabela Ações/Transições Análise de “(id)*id” (1/2)
Ações Terminais Goto Não-Terminais
Stack Input Action
* ( ) id $ E T F 0 ( id ) * id $ Shift S5
0 S5 S8 2 1 05 id ) * id $ Shift S8
Estados 1 R1 R1 R1 R1 R1 058 ) * id $ Reduz 3 F→→id,
pop 8, goto [5,F]=1
2 S3 Ok! Productions
051 ) * id $ Reduz 1 T→→ F,
3 S5 S8 4 1 T→F pop 1, goto [5,T]=6
4 R2 R2 R2 R2 R2 Shift e empilha 8 2 T → T*F 056 ) * id $ Shift S7
5 S5 S8 6 1 0567 * id $ Reduz 4 F→→ (T),
3 F → id
pop 7 6 5, goto [0,F]=1
6 S3 S7
4 F → (T) 01 * id $ Reduz 1 T → F
7 R4 R4 R4 R4 R4 Reduce a 4a regra pop 1, goto [0,T]=2
8 R3 R3 R3 R3 R3

Análise de “(id)*id” (2/2) Construindo tabelas LR


• Para montar as tabelas, precisa-se:
– Definir os estados,
Stack Input Action – Definir os Gotos/Ações

01 * id $ Reduz 1 T→→F,
• Os estados devem capturar o andamento na análise de
pop 1, goto [0,T]=2 quais símbolos podem ser reduzidos.
02 * id $ Shift S3 – Vai-se dever calcular quais conjuntos de símbolos podem ser
023 id $ Shift S8 considerados como handles.
– Noção de ponto / fechamento.
0238 $ Reduz 3 F→→id,
pop 8, goto [3,F]=4
• Os gotos e as açoes vão ser definidos graças ao cálculo
0234 $ Reduz 2 T→→T * F das transições entre os estados.
pop 4 3 2, goto [0,T]=2 – Tendo analisado que tenho um handle, quais símbolos podem
02 $ Aceitar aparecer depois?
– Sucessor(.)

Cálculo dos conjuntos


de itens canônicos LR Cálculo dos conjuntos
• A tabela pre-calcula todas as derivações possíveis a partir de um
dado ponto de análise Left -> Right da entrada.

• Parte de noção de configuração ou ítem LR(0) associado a uma • Propriedade de Fechamento:


regra (ou conjunto de regras) – Se T → X1 … Xi • Xi+1 … Xn está em um conjunto, e Xi+1 é um
= uma regra da gramática com um ‘ponto’ em algum lugar à direita. não-terminal que deriva em α (i.e.: existe a regra Xi+1 → α),
então também entra no conjunto:
• Exemplo: a regra T → T * F possui quatro ítens: Xi+1 → • α
T → •T * F
T→T•*F – Itera-se essa operação
conjunto canônico de ítens
T→T*•F • Calcula-se o conjunto como um ponto fixo
T→T*F•
– O ponto • representa até onde foi feita a análise • Ponto inicial:
• Quer-se calcular os conjuntos canônicos de ítens – Acrecenta-se um não-terminal S’ à gramática
= todos os ítens alcançáveis a partir de um conjunto de regras da
gramática. – Adiciona-se uma produção S’ → S
• Cada conjunto será um estado do parser LR – Conjunto de ítens Inicial é:
• Similar à conversão de AFND para AFD fechamento(S’ → • S)

6
Exemplo: fechamento(S’ → • T) Sucessor(C,X)
S’ → T • É o segundo procedimento útil para montar a tabela
T→F|T*F S’ → • T –
LR
Pega em argumento um conjunto de ítens C e um símbolo X
F → id | ( T ) T→• F – Retorna um conjunto de ítens
T→• T*F – Informalmente: “mover o ponto pelo símbolo X”

• Cálculo do sucessor a partir do estado e0 ao ler X:


F → • id 1. mover ponto para direita em todos os ítens de e0 onde o
F→• (T) •
ponto precede X
Para todas as regras A → α • X β em C,
retorna A → α X • β
Estado 0 2. Calcular o fechamento deste conjunto de ítens.
3. Esse novo estado será sucessor(e0,X)

Exemplo de Sucessor Construção dos Conjuntos de Ítens


e0 = Estado 0 =
{S’ → • T, T → • F, T → • T * F, F → • id, • Família de conjuntos de ítens
– Cada conjunto será um estado do parser
F→• (T)}
S’ → T
Sucessor(e0, “(“)) = ? T→F|T*F
Fechamento(F → ( • T )) F → id | ( T ) proc items(G’)
={ F→(• T) C = fechamento({S’ → • S});
do foreach I ∈ C do
T → • F,
foreach X ∈ (N ∪ T) do
T → • T * F, C = C ∪ Sucessor(I, X);
F → • id, while C é modificado;
}
F→• (T)

* ( ) id $ T F
Productions
Reduz 1 F 0 S5 S8 Reduz
2 11
F
1 T→F
F 1: T → F • 1 R1 R1 F R1
R1 1:R1T → F •
2 T → T*F 2 S3 A
3 F → id $ Aceitar Reduz 2 3 S5 S8 4 $ Aceitar Reduz 2
4 F → (T) 2: S’ → T • 4: T → T * F • 4 R2 R2 R2 R2 R2 2: S’ → T • 4: T → T * F •
T→T• *F 5 S5 S8 6T →1 T • * F

0: S’ → • T T Reduz 3 → • T S7
6 S3
0: S’ T Reduz 3
id * F id * F
T→• F 8: F → id • T7 → • F
R4 R4 R4 R4 R4
8: F → id •
8 R3 R3 R3 R3 R3
T→• T*F 3: T → T * • F T→• T*F 3: T → T * • F
id id
F → • id F → • id id F → • *id ( ) id $ FT →F • id id
F→• (T) F→• (T) ( 5: F → ( • T ) F →0 • ( TS5) S8
F2 →1 • ( T ) ( 5: F → ( • T )
1 R1 R1 R1 R1 R1
T→• F T→• F
7: F → ( T ) • 7: F → ( T ) •
2 S3 A
) * T→• T*F ) * T→• T*F
3 S5 S8 4
( F → • id ( F → • id
Reduz 4 4 Reduce 4
R2 R2 R2 R2 R2
6: F → ( T • ) T 6: F → ( T • ) T
F→• (T) 5 S5 S8 6 1 F→• (T)
T→T• *F 6 S3 S7
T→T• *F
( 7 R4 R4 R4 R4 R4
(
8 R3 R3 R3 R3 R3

7
Construção Tabela LR(0) Observações
1. Construir F = {I0, I1, …In}
• I0 é o estado inicial
• LR(0) sempre reduz se
2. a) Se {S’ → S••} ∈Ii {A → α••} ∈Ii, sem lookahead
então ação[i,$] = aceitar • Ítens Shift e Reduce podem estar no
b) Se {A → α••} ∈Ii e A != S’ mesmo conjunto de configurações
então ação[i,_] = reduzir A → α • Pode haver mais de um ítem reduce por
c) Se {A → α••aβ} ∈Ii e Sucessor(Ii,a)=Ij conjunto
então ação[i,a] = shift j
• Problema com A → Є
3. Se Sucessor(Ii,A) == Ij então goto[i,A] = j
4. Todas as entradas não definidas são erros

LR(0) é fraco, considere: Sumário


S’ → T 5: F → id • • A análise bottom-up usa:
T→F|T*F F → id • = T
– Handles, para determinar qual cadeia reduzir;

F → id | ( T ) – Tabelas LR (Goto/Transições) para determinar quais
F → id = T Conflito Shift/reduce! reduções e shifts efetuar.
T → id 2: F → id •
• Usa-se um autômato de estados finitos, com
uma pilha, para reconhecer uma sentença.
T → id •… – Construído a partir dos itens canônicos
Conflito Reduce/Reduce! • Fechamento + propagação
• Vimos o LR(0) que é limitado.
– Como melhorar o algoritmo?

Você também pode gostar