Capítulo 5 – Análise sintáticacbarrico/Disciplinas/Compiladores/Downloads/Capitulo... ·...
Transcript of Capítulo 5 – Análise sintáticacbarrico/Disciplinas/Compiladores/Downloads/Capitulo... ·...
Análise sintática
Capítulo 5 – Análise sintática
1. Objetivo
2. Estratégias gerais de parsing
3. Análise sintática descendente (top-down)
3.1. Analisador sintático com retrocesso (backtracking)
3.2. Analisador sintático predicativo recursivo
3.3. Analisador sintático predicativo não recursivo – Parser LL
3.4. Construção de tabelas sintáticas predicativas (Tabelas Oráculo)
4. Análise sintática ascendente (bottom-up)
4.1. Parser por transição-redução (método geral)
4.2. Parser LR
4.3. Parser SLR
4.4. Parser LALR
Processamento de Linguagens: DI-UBI 2017/2018 1/183
Análise sintática Objetivo
Objetivo
Processamento de Linguagens: DI-UBI 2017/2018 2/183
Análise sintática Objetivo
Gramáticada linguagem
árvore desintaxe
Sequênciade símbolos
PARSER Aceitaçãoou Erro
Dado
- uma gramática livre do contexto G
- uma sequência a de símbolos terminais (frase)
pretende-se
- verificar se a é uma frase válida de L(G)
- reconhecer a forma da frase (identificar as produções de G).
Processamento de Linguagens: DI-UBI 2017/2018 3/183
Análise sintática Objetivo
Em cada momento do processo,
a a a a
em que:
a → sequência já percorrida
a → próximo símbolo a analisar (token)
a → sequência por analisar
a é uma frase de L(G) se e só se
*S a
Processamento de Linguagens: DI-UBI 2017/2018 4/183
Análise sintática Objetivo
Em cada momento do processo,
- ou existe uma derivação
*S m a d , com m T* e d (S T)*
onde m a . { Fase de possível aceitação }
- ou não existe nenhuma derivação que aceite a a. { ERRO: não é frase de L(G) }
Processamento de Linguagens: DI-UBI 2017/2018 5/183
Análise sintática Estratégias gerais de parsing
Estratégias gerais de parsing
Processamento de Linguagens: DI-UBI 2017/2018 6/183
Análise sintática Estratégias gerais de parsing
Existem duas estratégias gerais de parsing:
- reconhecimento descendente (“top-down”)
- reconhecimento ascendente (“bottom-up”).
Reconhecimento descendente (“Top-Down”)
- A árvore é construída da raiz para as folhas
- Em cada vértice (com um símbolo não terminal A):
- selecionar uma produção com A à esquerda e construir os vértices filhos de A
com os símbolos à direita nessa produção;
- selecionar o vértice onde continuar.
- Termina quando todas as folhas são símbolos terminais.
- A aceitação é obtida se a sequência a for esgotada.
- As decisões são tomadas por observação de a, chamado “lookahead” símbolo.
Processamento de Linguagens: DI-UBI 2017/2018 7/183
Análise sintática Estratégias gerais de parsing
Reconhecimento ascendente (“Bottom-up”)
- A árvore é construída das folhas para a raiz.
- Os símbolos de a são associados até se reconhecer o lado direito de uma produção.
- A aceitação é obtida se,
esgotada a sequência a, o símbolo inicial estiver na raiz da árvore.
Processamento de Linguagens: DI-UBI 2017/2018 8/183
Análise sintática Análise sintática descendente (top-down)
Análise sintática
descendente (top-down)
Processamento de Linguagens: DI-UBI 2017/2018 9/183
Análise sintática Análise sintática descendente (top-down)
Dada uma frase a, a análise descendente pode ser vista como uma tentativa de se,
- encontrar uma derivação mais à esquerda para a,
- construir uma árvore gramatical para a a partir da raiz,
criando os nós em pré-ordem.
Desta forma,
- a frase a é percorrida da esquerda para a direita,
- vão-se identificando derivações esquerdas,
- enquanto a árvore de sintaxe vai sendo construída.
Processamento de Linguagens: DI-UBI 2017/2018 10/183
Análise sintática Análise sintática descendente (top-down)
1. Análise sintática descendente com retrocesso (backtracking)
O reconhecimento é feito por expansão de regras sintáticas, substituindo
- símbolos não-terminais do lado esquerdo de produções,
- pelos símbolos do lado direito das produções.
Depois, a expansão das regras sintáticas é confirmada
- por emparelhamento
- dos símbolos da frase de entrada (a)
- com os símbolos terminais das regras sintáticas.
- se não emparelhar,
então terá que haver retrocesso no processo (“backtracking”).
O retrocesso (“backtrack”) é resultado da existência de várias produções com o mesmo
símbolo no lado esquerdo.
Processamento de Linguagens: DI-UBI 2017/2018 11/183
Análise sintática Análise sintática descendente (top-down)
Algoritmo:
Entrada: Uma gramática G e uma frase a
Saída: Árvore de derivação
1. Criar um nó com o símbolo inicial da gramática.
2. Substituir o símbolo não-terminal situado mais à esquerda da árvore de derivação pelos
símbolos do lado direito da produção cujo lado esquerdo é o símbolo substituído.
Este passo termina quando o primeiro símbolo da produção for um símbolo terminal.
3. Se o primeiro símbolo ainda não processado de a não emparelhar com o primeiro símbolo da
produção selecionada no passo anterior, recuar para o passo 2 e pesquisar outra alternativa
(“backtrack”); se não existir outra alternativa, o algoritmo termina sem sucesso.
4. Emparelhar, da esquerda para a direita, os símbolos de a com os símbolos terminais nas
folhas da árvore de derivação, até que aconteça uma das três hipóteses:
- o emparelhamento de símbolos falha terminar sem sucesso;
- é detetada na folha da árvore um símbolo não-terminal regressar ao passo 2;
- todos os símbolos de a foram emparelhados e todas as folhas da árvore contêm apenas
símbolos terminais que foram emparelhados com símbolos de a terminar com sucesso.
Processamento de Linguagens: DI-UBI 2017/2018 12/183
Análise sintática Análise sintática descendente (top-down)
Vantagens:
- simplicidade de implementação do algoritmo que lhe está associado.
Processamento de Linguagens: DI-UBI 2017/2018 13/183
Análise sintática Análise sintática descendente (top-down)
Desvantagens:
- Não aceita gramáticas recursivas à esquerda; por ex., numa entrada com erro, o
analisador entra em ciclo infinito de expansão duma produção recursiva à esquerda
- A ordem da escolha das alternativas determina a linguagem aceite pelo analisador;
por ex., a frase aa é aceite pelo analisador se for expandida em primeiro a produção
S ® B, o que não acontece se a primeira produção a ser expandida for S ® aA, pois
o primeiro símbolo da entrada, a, emparelha com o primeiro símbolo terminal da
produção S ® aA, mas o segundo símbolo de entrada, a, não pode ser derivado a
partir de A.
- Em caso de entrada com erro, não é possível identificar as causas de erro, pois não
há distinção entre retrocesso por erro e por necessidade de pesquisa de alternativas
- A operação de retrocesso é muito demorada, degradando o desempenho
(“performance”) da análise sintática.
Processamento de Linguagens: DI-UBI 2017/2018 14/183
Análise sintática Análise sintática descendente (top-down)
2. Analisador sintático predicativo recursivo
Definição:
Um Parser recursivo-descendente diz-se profético (ou predicativo) quando:
- a análise do a, ou lookahead, determina univocamente a produção a utilizar;
- a execução de um procedimento simula a sequência de símbolos do lado direito
dessa produção.
Um Parser predicativo é caracterizado por tomar sempre decisões irrevogáveis, isto é,
sem backtracking.
Para se construir um analisador predicativo, é preciso:
- dado o lookahead a (a = a) e o símbolo não terminal A a ser expandido,
- conhecer qual das alternativas da produção A ® b1 | b2 | … | bn é a única que deriva
uma cadeia que começa por a.
Processamento de Linguagens: DI-UBI 2017/2018 15/183
Análise sintática Análise sintática descendente (top-down)
Ou seja, a alternativa adequada precisa ser detetável examinando-se apenas o primeiro
símbolo da cadeia que a mesma deriva.
Algoritmo:
{ X Î T } Reconhecer_X:
Se (X = a) Então
avançar (a) { reconhecimento parcial }
Senão ERRO
{ X Î S } Reconhecer_X:
{ em função de a, escolher uma produção p : X ® X1 X2 ... Xn }
Reconhecer_X1
Reconhecer_X2
...
Reconhecer_Xn
Processamento de Linguagens: DI-UBI 2017/2018 16/183
Análise sintática Análise sintática descendente (top-down)
Partindo do símbolo inicial (S) e do início de a:
Parser_RD:
Avançar (a);
Reconhecer_S ;
Se ( a = e) Então
RECONHECIMENTO
Senão ERRO
Para a construção de um Parser predicativo é necessário estabelecer um método que,
- conhecidos o lookahead (a) e o símbolo a reconhecer,
- determine univocamente a produção a utilizar.
Uma das formas é utilizar uma tabela sintática (Tabela Oráculo), M[X,a] = p, que
significa: a produção p será aplicada se pretender-se expandir o símbolo não terminal
X e o lookahead for um símbolo terminal a (a = a).
Processamento de Linguagens: DI-UBI 2017/2018 17/183
Análise sintática Análise sintática descendente (top-down)
Pretende-se elaborar um Parser predicativo que seja:
- independente da gramática;
- constituído por uma única função, onde o símbolo é passado como parâmetro;
- eficiente;
Reconhecer(X):
Se (X Î T) Então
Se (X = a) Então
Da_Simbolo (a)
Senão ERRO
Senão np ¬ Oráculo(X, a)
Se (np ¹ ERRO) Então
Para cada Y Î Produção[np]
Reconhecer (Y)
Senão ERRO
Processamento de Linguagens: DI-UBI 2017/2018 18/183
Análise sintática Análise sintática descendente (top-down)
- ainda é recursivo;
- mas é mais cómodo e mais independente da linguagem: a informação relativa à
linguagem está guardada em duas estruturas de dados.
Otimização da Função Oráculo:
ORÁCULO : (S È T) x T ® { skip, np, erro }
(X, a) ® ação
Se (X Î T e X = a) Então
ação = skip { o reconhecedor léxico reconhece um símbolo terminal }
* Se (X Î T e X ¹ a) ou (X Î S e $ p : X a ) Então
ação = erro
* Se (X Î S e $1 p : X a ) Então
pação = np
Processamento de Linguagens: DI-UBI 2017/2018 19/183
Análise sintática Análise sintática descendente (top-down)
Nota:* *
Se (X Î S e $ p', p'' : X a e X a ) Entãop' p''
Situação de conflito
Reconhecer (X):
ação ¬ ORÁCULO (X, a)
Caso (ação) Seja
erro : ERRO
skip : Da_Simbolo(a)
np : Para (" Y Î Produção[np]) Fazer
Reconhecer (Y)
Em cada momento continua a haver apenas dois casos possíveis:
- ERRO
- Possível reconhecimento.
Processamento de Linguagens: DI-UBI 2017/2018 20/183
Análise sintática Analisador sintático predicativo não recursivo
Analisador sintático
predicativo não recursivo
Processamento de Linguagens: DI-UBI 2017/2018 21/183
Análise sintática Analisador sintático predicativo não recursivo
Pode-se construir um analisador predicativo usando uma pilha (sem recursividade).
Um analisador sintático predicativo não recursivo é composto por:
- uma frase de entrada,
- uma pilha,
- uma tabela sintática, e
- um fluxo de saída.
Frase de entrada a + b $
PilhaPrograma de AnáliseSintática PredicativaX Saída
YZ$
Tabela Sintática M
Processamento de Linguagens: DI-UBI 2017/2018 22/183
Análise sintática Analisador sintático predicativo não recursivo
A frase de entrada é seguida por um $ à direita (indica o fim da sequência de símbolos)
A pilha Z:
- contém uma sequência de símbolos gramaticais,
- com $ a indicar o fundo da pilha;
- inicialmente, a pilha contém o símbolo inicial da gramática acima de $.
A tabela sintática é um “array” bidimensional M[A, a] onde,
- A é um símbolo não terminal, terminal ou $,
- a é um símbolo terminal ou $.
O analisador sintático é um programa que se comporta da seguinte forma:
- considera o símbolo do topo da pilha X e o lookahead a (estes dois símbolos
determinam a ação do analisador).
Processamento de Linguagens: DI-UBI 2017/2018 23/183
Análise sintática Analisador sintático predicativo não recursivo
Existem três possibilidades:
1. Se X = $, o analisador pára a análise com sucesso, se a = $.
2. Se X = a (a é terminal), o analisador sintático remove X da pilha e avança o
apontador da entrada para o próximo símbolo (próximo lookahead), a = a.
3. Se X é um não terminal, o programa consulta a entrada M[X, a] da tabela
sintática M, que será uma produção-X (X ® a) da gramática ou ERRO.
Por ex., se M[X,a] = { X ® UVW } substitui-se X no topo da pilha por WVU (com
U no topo); se M[X, a] = erro chama-se uma rotina de recuperação de erros.
Algoritmo: Análise sintática predicativa não recursiva
Entrada: Uma frase a e uma tabela sintática M para a gramática G = (S, T, P, S).
Saída: Uma derivação mais à esquerda (se a L(G)) ou uma indicação de erro.
Método:
Introduzir os símbolos $ e S na pilha Z (S é o símbolo inicial de G) ¾ Topo(Z) = S
a = primeiro símbolo de a
Processamento de Linguagens: DI-UBI 2017/2018 24/183
Análise sintática Analisador sintático predicativo não recursivo
Repetir
Se (Topo(Z) Î T) Então
Se (Topo(Z) = a) Então
Pop(Z)
Da_Simbolo(a)
Senão ERRO
Senão
Se (Topo(Z) Î S) Então
Se M[Topo(Z), a] = { X ® Y1Y2 … Yn } Então
Pop(Z)
Para i desde n até 1 Fazer
Push(Z, Yi)
Senão ERRO
Até (Topo(Z) = $)
Processamento de Linguagens: DI-UBI 2017/2018 25/183
Análise sintática Analisador sintático predicativo não recursivo
Resumindo, temos que sendo
a : sequência de símbolos terminais já analisados
Z : sequência de símbolos terminais e não terminais a reconhecer,
mantém-se invariante:
* S a Z
no início : a = e e Z = S
e no fim : a = a e Z = e { se tudo correr bem }
Deste modo:
- não é necessário construir a árvore de derivação
- nem guardar a
- Z funciona como uma pilha,
- portanto, é possível construir um algoritmo iterativo.
Processamento de Linguagens: DI-UBI 2017/2018 26/183
Análise sintática Analisador sintático predicativo não recursivo
A este analisador sintático dá-se o nome de Parser LL (scan input from Left to right and
construct Leftmost derivation).
Falta apenas incluir uma ação de aceitação:
Ação = { skip, np, erro, ac }.
A aceitação ocorre quando:
(Z = $) e (a = $)
pois não há símbolo para reconhecer nem falta analisar nenhum símbolo.
Processamento de Linguagens: DI-UBI 2017/2018 27/183
Análise sintática Analisador sintático predicativo não recursivo
ParserLL (algoritmo LL):
Push(Z, $)
Push(Z, S)
Da_Simbolo(a)
Repetir
Acção ¬ Oráculo(Topo(Z), a);
Pop(Z);
Caso Acção Seja
erro : Erro;
ac : ;
skip : Da_Simbolo(a);
np : Para i desde n até 1 Fazer { X ® Y1Y2 … Yn }
Push(Z, Yi);
Até Ação = ac;
Processamento de Linguagens: DI-UBI 2017/2018 28/183
Análise sintática Construção de tabelas sintáticas predicativas (Tabelas Oráculo)
Construção de tabelas sintáticas
predicativas (Tabelas Oráculo)
Processamento de Linguagens: DI-UBI 2017/2018 29/183
Análise sintática Construção de tabelas sintáticas predicativas (Tabelas Oráculo)
A ideia subjacente ao algoritmo associado à construção destas tabelas é a seguinte:
- suponha-se que A ® a é uma produção e que a Î First(a);
- logo, o analisador sintático irá expandir A através de a quando o símbolo de
entrada corrente (lookahead) for a (a = a).
A única complicação ocorre quando a = e ou a e.
Neste caso, deve-se expandir A de novo através de a se:
- a Î Follow(A) ou
- $ (na entrada) foi atingido e $ Î Follow(A).
Processamento de Linguagens: DI-UBI 2017/2018 30/183
Análise sintática Construção de tabelas sintáticas predicativas (Tabelas Oráculo)
Algoritmo:
Entrada : Gramática G
Saída : Tabela Oráculo M[X, Y] em que,
X (S T { $ }) e
Y (T { $ })
Descrição do método:
1. Para cada produção A ® a de G, executar os passos 2 e 3.
2. Para cada símbolo terminal a Î First(a), fazer M[A, a] = A ® a.
3. Se e Î First(a), então para cada b Î Follow(A), fazer M[A, b] = A ® a.
Se e Î First(a) e $ Î Follow(A), fazer M[A, $] = A ® a.
4. Fazer a cada entrada da tabela M do tipo M[x, x] = SKIP, em que x T.
5. Fazer à entrada da tabela M, M[$, $] = AC.
6. Fazer a cada entrada indefinida da tabela M, M[k, j] = ERRO.
Os passos 2 e 3 podem ser substituídos pelo seguinte único passo:
2-3. Para cada símbolo terminal a Î Lookhead(A ® a), fazer M[A, a] = A ® a.
Processamento de Linguagens: DI-UBI 2017/2018 31/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
Exemplo de um analisador sintático
predicativo não recursivo
Processamento de Linguagens: DI-UBI 2017/2018 32/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
Considere a seguinte gramática G = (Σ, T, P, S), em que
Σ = { S, A, B, C, D },
T = { a, b, c, d, e, f },
P = {
1) S DC;→
2) A → a;
3) A → Cb;
4) B → e;
5) B c; →
6) B dA; →
7) C e→ ;
8) C → f;
9) D A→ B
}
Processamento de Linguagens: DI-UBI 2017/2018 33/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
First (a) = { a }
First (b) = { b }
First (c) = { c }
First (d) = { d }
First (e) = { e }
First (f) = { f }
First (S) = { a, e, f }
First (A) = { a, e, f }
First (B) = { ε, c, d }
First (C) = { e, f }
First (D) = { a, e, f }
Follow (S) = { $ }
Follow (A) = { c, d, e, f }
Follow (B) = { e, f }
Follow (C) = { $, b }
Follow (D) = { e, f }
Processamento de Linguagens: DI-UBI 2017/2018 34/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
1) S DC→
First(S DC) = First(D) = { a, e, f }→ (e First(D))
M[S, a] = M[S, e] = M[S, f] = 1
Oráculo $ a b c d e f
S 1 1 1
A
B
C
D
$
a
b
c
d
e
f
Processamento de Linguagens: DI-UBI 2017/2018 35/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
2) A → a
First(A a) = First(a) = { a }→
M[A, a] = 2
Oráculo $ a b c d e f
S 1 1 1
A 2
B
C
D
$
a
b
c
d
e
f
Processamento de Linguagens: DI-UBI 2017/2018 36/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
3) A → Cb
First(A Cb) = First(C) = { e, f }→ (e First(C))
M[A, e] = M[A, f] = 3
Oráculo $ a b c d e f
S 1 1 1
A 2 3 3
B
C
D
$
a
b
c
d
e
f
Processamento de Linguagens: DI-UBI 2017/2018 37/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
4) B → e
Como e First(e), M[B, x] = 4, para x Follow(B) = { e, f }
M[B, e] = M[B, f] = 4
Oráculo $ a b c d e f
S 1 1 1
A 2 3 3
B 4 4
C
D
$
a
b
c
d
e
f
Processamento de Linguagens: DI-UBI 2017/2018 38/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
5) B c→
First(B c) = First(c) = { c }→
M[B, c] = 5
Oráculo $ a b c d e f
S 1 1 1
A 2 3 3
B 5 4 4
C
D
$
a
b
c
d
e
f
Processamento de Linguagens: DI-UBI 2017/2018 39/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
6) B dA→
First(B dA) = First(d) = { d }→
M[B, d] = 6
Oráculo $ a b c d e f
S 1 1 1
A 2 3 3
B 5 6 4 4
C
D
$
a
b
c
d
e
f
Processamento de Linguagens: DI-UBI 2017/2018 40/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
7) C e→
First(C e) = First(e) = { e }→
M[C, e] = 7
Oráculo $ a b c d e f
S 1 1 1
A 2 3 3
B 5 6 4 4
C 7
D
$
a
b
c
d
e
f
Processamento de Linguagens: DI-UBI 2017/2018 41/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
8) C → f
First(C f) = First(f) = { f }→
M[C, f] = 8
Oráculo $ a b c d e f
S 1 1 1
A 2 3 3
B 5 6 4 4
C 7 8
D
$
a
b
c
d
e
f
Processamento de Linguagens: DI-UBI 2017/2018 42/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
9) D A→ B
First(D AB) = First(A) = { a, e, f }→ (e First(A))
M[D, a] = M[D, e] = M[D, f] = 9
Oráculo $ a b c d e f
S 1 1 1
A 2 3 3
B 5 6 4 4
C 7 8
D 9 9 9
$
a
b
c
d
e
f
Processamento de Linguagens: DI-UBI 2017/2018 43/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
M[x, x] = SKIP, para x T M[$, $] = AC
Oráculo $ a b c d e f
S 1 1 1
A 2 3 3
B 5 6 4 4
C 7 8
D 9 9 9
$ AC
a SKIP
b SKIP
c SKIP
d SKIP
e SKIP
f SKIP
Processamento de Linguagens: DI-UBI 2017/2018 44/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
M[X, Y] = E (Erro), para as entradas vazias
Oráculo $ a b c d e f
S E 1 E E E 1 1
A E 2 E E E 3 3
B E E E 5 6 4 4
C E E E E E 7 8
D E 9 E E E 9 9
$ AC E E E E E E
a E SKIP E E E E E
b E E SKIP E E E E
c E E E SKIP E E E
d E E E E SKIP E E
e E E E E E SKIP E
f E E E E E E SKIP
Processamento de Linguagens: DI-UBI 2017/2018 45/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Push(Z, $)
Push(Z, S)
S$
Oraculo(Topo(Z), a) = Oraculo(S, e) = 1
Processamento de Linguagens: DI-UBI 2017/2018 46/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Push(Z, C)
Push(Z, D)
DC$
Oraculo(Topo(Z), a) = Oraculo(D, e) = 9
Processamento de Linguagens: DI-UBI 2017/2018 47/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Push(Z, B)
Push(Z, A)
ABC$
Oraculo(Topo(Z), a) = Oraculo(A, e) = 3
Processamento de Linguagens: DI-UBI 2017/2018 48/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Push(Z, b)
Push(Z, C)
CbBC$
Oraculo(Topo(Z), a) = Oraculo(C, e) = 7
Processamento de Linguagens: DI-UBI 2017/2018 49/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Push(Z, e)
ebBC$
Oraculo(Topo(Z), a) = Oraculo(e, e) = SKIP
Processamento de Linguagens: DI-UBI 2017/2018 50/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Da_Simbolo(a)
bBC$
Oraculo(Topo(Z), a) = Oraculo(b, b) = SKIP
Processamento de Linguagens: DI-UBI 2017/2018 51/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Push(Z, e)
Da_Simbolo(a)
BC$
Oraculo(Topo(Z), a) = Oraculo(B, d) = 6
Processamento de Linguagens: DI-UBI 2017/2018 52/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Push(Z, A)
Push(Z, d)
dAC$
Oraculo(Topo(Z), a) = Oraculo(d, d) = SKIP
Processamento de Linguagens: DI-UBI 2017/2018 53/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Da_Simbolo(a)
AC$
Oraculo(Topo(Z), a) = Oraculo(A, f) = 3
Processamento de Linguagens: DI-UBI 2017/2018 54/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Push(Z, b)
Push(Z, C)
CbC$
Oraculo(Topo(Z), a) = Oraculo(C, f) = 8
Processamento de Linguagens: DI-UBI 2017/2018 55/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Push(Z, f)
fbC$
Oraculo(Topo(Z), a) = Oraculo(f, f) = SKIP
Processamento de Linguagens: DI-UBI 2017/2018 56/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Da_Simbolo(a)
bC$
Oraculo(Topo(Z), a) = Oraculo(b, b) = SKIP
Processamento de Linguagens: DI-UBI 2017/2018 57/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Da_Simbolo(a)
C$
Oraculo(Topo(Z), a) = Oraculo(C, e) = 7
Processamento de Linguagens: DI-UBI 2017/2018 58/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Push(Z, e)
e$
Oraculo(Topo(Z), a) = Oraculo(e, e) = SKIP
Processamento de Linguagens: DI-UBI 2017/2018 59/183
Análise sintática Exemplo de um analisador sintático predicativo não recursivo
e b d f b e $
Pop(Z)
Da_Simbolo(a)
$
Oraculo(Topo(Z), a) = Oraculo($, $) = AC
FIM.
A frase pertence à linguagem gerada pela gramática G, L(G).
Processamento de Linguagens: DI-UBI 2017/2018 60/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Análise Sintática
Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 61/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1. Princípios gerais
O objetivo da análise sintática ascendente é a construção da árvore de derivação, a
partir das folhas, em direção à raiz.
A árvore de derivação é construída percorrendo a sequência a de símbolos de entrada
(frase) da esquerda para a direita (e armazenada numa string s): esta operação é
designada por deslocamento (“shift”) da posição do analisador sintático.
Quando é detetada uma sequência de símbolos gramaticais idêntica ao lado direito de
uma produção, esses símbolos são substituídos pelo símbolo não-terminal do lado
esquerdo da produção: esta operação é designada por redução (“reduce”).
Processamento de Linguagens: DI-UBI 2017/2018 62/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Exemplo: Considere-se a gramática com as seguintes 6 produções :
1) S ® A B c 2) S B A c
3) A ® a 4) A a A
5) B ® b 6) B b B
A frase abbc pode ser reduzida até ao símbolo inicial da gramática S em 4 etapas:
S Þ A B c Þ A b B c Þ A b b c Þ a b b c
Etapa Sequência deSímbolos Gramaticais
Regra GramaticalReduzida
1 a b b c 3
2 A b b c 5
3 A b B c 6
4 A B c 1
5 S
O procedimento corresponde a uma sequência de derivação à direita.
Processamento de Linguagens: DI-UBI 2017/2018 63/183
Análise sintática Análise Sintática Ascendente (bottom-up)
2. Método geral: parser por transição-redução
s = m b e p : A b s = m A Redução de b em A pela produção p
Cada redução corresponde a uma subida de nível na árvore de derivação.
p : A ® X Y … Z A
m X Y … Z
depois disso, se :
s = m A = f d A e p : B d A s = f B B
A
f d X Y … Z
Sequência reconhecida: ao atingir a raiz da árvore (s = S) não restam símbolos em .
Processamento de Linguagens: DI-UBI 2017/2018 64/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
Um parser “bottom-up” é caracterizado por dois tipos de operações básicas:
Redução: s = m b s = m A
Transição: s = m a e Avançar( )
No início do processo: s = e e = a
No fim do processo: s = S e = e { Aceitação }
Num parser “top-down”:
No início do processo: s = S e = a
No fim do processo: s = e e = e { Aceitação }
Processamento de Linguagens: DI-UBI 2017/2018 65/183
a
a
a
a
a
Análise sintática Análise Sintática Ascendente (bottom-up)
Em qualquer momento de parsing “bottom-up”:
- Ou existe uma derivação: { estado possível de aceitação }
- Ou não existe nenhuma derivação a efetuar: estado de erro.
Assumindo (por enquanto) que todas as decisões podem ser tomadas apenas em
função dos valores de S e de a, define-se:
ORÁCULO : (T È S)* x T ® { shift, reduce, ac, erro }
(s, a) ação
Processamento de Linguagens: DI-UBI 2017/2018 66/183
S s a b
Análise sintática Análise Sintática Ascendente (bottom-up)
Parser_Trans_Red:
Inicializar(s) ;
Da_Simbolo(a) ;
Repetir
ação ¬ ORÁCULO(s, a) ;
Caso ação Seja
erro: ERRO ;
ac: ;
shift: s ¬ s a ;
Da_Simbolo(a) ;
reduce: s ¬ s - b ; { p : A ® b }
s ¬ s A ;
Até ac ;
Processamento de Linguagens: DI-UBI 2017/2018 67/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Exemplo:
Dada a gramática G com as seguintes produções:
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
analisar a expressão: a + (b * c) $
Processamento de Linguagens: DI-UBI 2017/2018 68/183
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
E
Processamento de Linguagens: DI-UBI 2017/2018 69/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
Processamento de Linguagens: DI-UBI 2017/2018 70/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
Processamento de Linguagens: DI-UBI 2017/2018 71/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
Processamento de Linguagens: DI-UBI 2017/2018 72/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
Processamento de Linguagens: DI-UBI 2017/2018 73/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Reduce p4
Processamento de Linguagens: DI-UBI 2017/2018 74/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Reduce p4
E + ( E * c ) $ Shift
Processamento de Linguagens: DI-UBI 2017/2018 75/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Reduce p4
E + ( E * c ) $ Shift
E + ( E * c ) $ Shift
Processamento de Linguagens: DI-UBI 2017/2018 76/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Reduce p4
E + ( E * c ) $ Shift
E + ( E * c ) $ Shift
E + ( E * c ) $ Reduce p4
Processamento de Linguagens: DI-UBI 2017/2018 77/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Reduce p4
E + ( E * c ) $ Shift
E + ( E * c ) $ Shift
E + ( E * c ) $ Reduce p4
E + (E * E ) $ Reduce p2
Processamento de Linguagens: DI-UBI 2017/2018 78/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Reduce p4
E + ( E * c ) $ Shift
E + ( E * c ) $ Shift
E + ( E * c ) $ Reduce p4
E + (E * E ) $ Reduce p2
E + ( E ) $ Shift
Processamento de Linguagens: DI-UBI 2017/2018 79/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Reduce p4
E + ( E * c ) $ Shift
E + ( E * c ) $ Shift
E + ( E * c ) $ Reduce p4
E + (E * E ) $ Reduce p2
E + ( E ) $ Shift
E + ( E ) $ e Reduce p3
Processamento de Linguagens: DI-UBI 2017/2018 80/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Reduce p4
E + ( E * c ) $ Shift
E + ( E * c ) $ Shift
E + ( E * c ) $ Reduce p4
E + (E * E ) $ Reduce p2
E + ( E ) $ Shift
E + ( E ) $ e Reduce p3
E + E $ e Reduce p1
Processamento de Linguagens: DI-UBI 2017/2018 81/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
p1 : E E + E→ p2 : E E * E→ p3 : E ( E )→ p4 : E id →
s a Ação
a + ( b * c ) $ Shift
a + ( b * c ) $ Reduce p4
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Shift
E + ( b * c ) $ Reduce p4
E + ( E * c ) $ Shift
E + ( E * c ) $ Shift
E + ( E * c ) $ Reduce p4
E + (E * E ) $ Reduce p2
E + ( E ) $ Shift
E + ( E ) $ e Reduce p3
E + E $ e Reduce p1
E $ e ac
Processamento de Linguagens: DI-UBI 2017/2018 82/183
a
Análise sintática Análise Sintática Ascendente (bottom-up)
3. Parser LR
Os analisadores sintáticos LR apresentam diversas vantagens:
- Reconhecem praticamente todos os construtores de linguagens de programação
estruturadas em blocos, expressas em gramáticas independentes do contexto.
- São mais gerais que outros analisadores sintáticos e revelam o mesmo grau de
eficiência.
- Podem detetar cedo erros sintáticos, quando tal é possível, ao pesquisar a entrada
da esquerda para a direita.
Maior inconveniente destes analisadores:
- a complexidade da sua implementação.
No entanto, a existência de ferramentas que geram automaticamente analisadores
sintáticos (tal como o YACC) eliminou este problema.
Processamento de Linguagens: DI-UBI 2017/2018 83/183
Análise sintática Análise Sintática Ascendente (bottom-up)
O analisador sintático LR:
“Left-scan”, leitura da frase da esquerda para a direita,
“Rightmost derivation”, derivação da direita para a esquerda,
- pesquisa os elementos da frase da esquerda para a direita (tal como os
analisadores descendentes) e
- constrói uma derivação à direita, invertida.
Processamento de Linguagens: DI-UBI 2017/2018 84/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Arquitetura do analisador sintático LR
Entrada Frase$
Pilha Reconhecedor Saída
Ações
Saltos
Processamento de Linguagens: DI-UBI 2017/2018 85/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Tabelas do analisador sintático LR
As duas tabelas do analisador sintático ascendente LR são designadas por:
- tabela de ações (“actions”) e
- tabela de saltos (“goto”).
A tabela de ações A[estado, entrada] é indexada pelo estado e pelo símbolo de entrada
(terminal), e possui um dos quatro valores :
1. Desloca s (“shift”), na qual s é um estado.
2. Reduz n (“reduce”), na qual n é a referência a uma produção X → a.
3. Aceita (“accept”).
4. Erro.
Processamento de Linguagens: DI-UBI 2017/2018 86/183
Análise sintática Análise Sintática Ascendente (bottom-up)
A tabela de saltos G[estado, símbolo]:
- é indexada pelo estado e pelo símbolo não-terminal,
- possui, nalgumas células, uma indicação da referência a um estado.
A construção das tabelas pode ser efetuada utilizando três metodologias distintas:
1. SLR (“Simple LR”) — é o método mais simples, mas também o menos poderoso,
porque não é possível construir as tabelas para algumas gramáticas.
2. LR canónico — é o método mais poderoso e, em simultâneo, o mais complexo,
sendo aquele que mais memória necessita para armazenar a tabela.
3. LALR (“LookAhead LR”) — este método é um compromisso entre os métodos
SLR e LR canónico, e funciona para a maior parte das linguagens de programação.
Processamento de Linguagens: DI-UBI 2017/2018 87/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Reconhecimento de uma frase
Um parser LR implementa o autómato determinístico de pilha, capaz de reconhecer
uma dada gramática do tipo LR(k), onde:
- os estados do autómato “representam” valores da string s
- cada transição: s s a
corresponde à determinação do próximo estado, em função do atual e de a T∈
- cada redução:
s s − b determina o estado anterior quando do atual se retira b (∈ S T)*,∪
s s A determina o próximo estado em função do atual e de A ∈ S
- transições são implementadas por uma tabela chamada Oráculo_T ou Ação:
Oráculo_T : Q × T { shift, reduce, ac, erro } × (Q P) ∪
(q, a) ( ação, q’ np )∨
Processamento de Linguagens: DI-UBI 2017/2018 88/183
Análise sintática Análise Sintática Ascendente (bottom-up)
- os estados anteriores são recuperados se, numa pilha F de estados forem
efetuados Pop’s em número igual ao dos símbolos em β
- mudanças de estado por redução são implementadas por um Oráculo_S ou Goto:
Oráculo_S : Q × S Q
(q, A) q’
Processamento de Linguagens: DI-UBI 2017/2018 89/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Algoritmo:
Proc Parser_LR:
Inicializar(F) ;
Da_Simbolo(a) ;
Repetir
acção Oráculo_T(Topo(F), a) ;
Caso ação Seja
erro: ERRO ; ac: ; shift: q ação.estado ;
Push(F, q) ;
Da_Simbolo(a) ;
reduce: np ação.Num_prod ;
(A, nsd) Prod[np] ;
Para i desde 1 até nsd Fazer
Pop(F) ;
q Oráculo_S(Topo(F), A) ;
Push(F, q) ;
Até ac ;
Processamento de Linguagens: DI-UBI 2017/2018 90/183
Análise sintática Análise Sintática Ascendente (bottom-up)
- Como associar estados a valores de s ?
- Como construir os Oráculos ?
- Será sempre possível ?
Cada passo do processo LR é caracterizado por :
( s, a ) CONFIGURAÇÃO LR
Cada decisão é tomada em função de:
A d .b produção em reconhecimento e ponto (.) de decisão;
w o prefixo de s, com s = w d;
m o contexto direito de A.
Processamento de Linguagens: DI-UBI 2017/2018 91/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Ao conjunto destes três elementos chama-se:
Item LR [ w, A d .b , m ]
Uma configuração ( s, a ) satisfaz a condição não-erro LR se :
* b m a
A cada configuração não-erro, está associado um e um só item LR.
No início : (e, a) [ e, Z .S$, e ]
No fim : (S, $) [ e, Z S.$, e ]
Processamento de Linguagens: DI-UBI 2017/2018 92/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Só existem três formas de itens LR (a que correspondem três tipos de ações):
1) [ ω, A d .ab , m ]
a que corresponde a transição:
(wd , ar) (wda, r)s
2) [ ω, A d .Bb , m ]
a ação a tomar depende de B, e virá a ser tomada em função de
[ wd , B .g , bm ]
3) [ w, A d .e , m ]
a que corresponde a redução
(wd , m) (wA, m)r
A cada configuração (s, a ) está associado um item [ w, A d .b , m ] que determina
de forma única a ação a executar, sendo necessário verificar que a é derivável de bm.
Processamento de Linguagens: DI-UBI 2017/2018 93/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Construção do autómato
Para um dado item LR [ w, A d .b , m ] chama-se item LR(k) a
[ A d .b , First(k, m) ]
Os estados de um autómato LR(k) são constituídos por itens LR(k).
Num autómato LR(0) os estados são [ A d .b ].
Exemplo:
Construir o autómato não determinístico LR(0) para a gramática G com as seguintes
produções:
1) Z S $→
2) S a→
3) S b A A→
4) A ε→
5) A A a→
Processamento de Linguagens: DI-UBI 2017/2018 94/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 95/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 96/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 97/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 98/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 99/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 100/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 101/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 102/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 103/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 104/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 105/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 106/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 107/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 108/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 109/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 110/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Algoritmo para construir o autómato determinístico:
Alfabeto : S T ∪
Estado inicial : [ Z . S $, e ]
Cada estado é formado por :
- Um item LR(k) : [ A d . b , n ]
- Pelo seu fecho, isto é, todos os itens da forma
[ B . g, m ] sempre que b = B r, com m = First(k, r n)
- E pelo fecho de cada um desses itens.
A função de transição :
D = Q × (T ∪ S) Q
para cada item LR(k) associado ao estado q
[ A → d . B r, n ] B T ∀ ∈ ∪ S
D (q, B) = q’ com q’ = [ A d B . r, n ]
Exemplo: construir o autómato determinístico LR(0) para a gramática G anterior.
Processamento de Linguagens: DI-UBI 2017/2018 111/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 112/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 113/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 114/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 115/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 116/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 117/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 118/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 119/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 120/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 121/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 122/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 123/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 124/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 125/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 126/183
Análise sintática Análise Sintática Ascendente (bottom-up)
NOTAS:
- Uma redução corresponde a recuar no grafo (com o conhecimento da produção).
{ redução por S → bAA }
- Num parser LR(0), a redução é feita qualquer que seja o a; basta que tenha
acabado o reconhecimento da produção atual.
Processamento de Linguagens: DI-UBI 2017/2018 127/183
Análise sintática Análise Sintática Ascendente (bottom-up)
- Neste parser LR(0) podem ocorrer duas situações de conflito :
{ redução por A → e } { redução por S → bAA }
{ redução por A → Aa }
Por exemplo, ao estado 5 estão associados:
[ A → e, m ] e [ A → A.a, a ]
Se a First(∈ m) é impossível decidir:
redução por A → e, ou
transição para [ A → Aa., a ].
Para fazer o reconhecimento basta conhecer:
- A identificação (número) de cada estado;
- Transições ou reduções definidas para esse estado.
Processamento de Linguagens: DI-UBI 2017/2018 128/183
Análise sintática Análise Sintática Ascendente (bottom-up)
A partir do autómato determinístico A constroem-se as Tabelas Oráculo, da seguinte
forma:
- q Q, X S
Oráculo_S (q, X) = sq', se (q, q')X A
Oráculo_S (q, X) = erro, caso contrário
- q Q, t T
Oráculo_T (q, t) = sq', se (q, q')t A
Oráculo_T (q, t) = rp, se [ A → a ., n ] : t First(k, n)
Oráculo_T (q, t) = erro, caso contrário
q [ Z → S.$, e ] e t = $
Oráculo_T (q, t) = AC
Processamento de Linguagens: DI-UBI 2017/2018 129/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Tabela Oráculo (exemplo anterior):
a
a b $ S A
e
s
t
a
d
o
s
1 s3 s4 erro s2 erro
2 erro erro AC erro erro
3 r2 r2 r2 erro erro
4 r4 r4 r4 erro s5
5 s7/r4 r4 r4 erro s6
6 s7/r3 r3 r3 erro erro
7 r5 r5 r5 erro erro
Oráculo_T Oráculo_S
{ 2 conflitos redução/transição não é LR(0) }
Processamento de Linguagens: DI-UBI 2017/2018 130/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Construir o autómato determinístico LR(1) para a mesma gramática:
First(S) = { a, b }
First(A) = { a, e }
Follow(S) = { $ }
Follow(A) = { a, $ }
Processamento de Linguagens: DI-UBI 2017/2018 131/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ]
Processamento de Linguagens: DI-UBI 2017/2018 132/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ]
[ S .a, $ ] First($e) = { $ }
[ S .bAA, $ ] First($e) = { $ }
Processamento de Linguagens: DI-UBI 2017/2018 133/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC ( = $)
[ S .a, $ ]
[ S .bAA, $ ]
Processamento de Linguagens: DI-UBI 2017/2018 134/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC ( = $)
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
Processamento de Linguagens: DI-UBI 2017/2018 135/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b
4 [ S b.AA, $ ]
Processamento de Linguagens: DI-UBI 2017/2018 136/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b
4 [ S b.AA, $ ]
[ A . , a/$ ] First(A$) = { a, $ }
[ A .Aa, a/$ ] First(A$) = { a, $ }
red#4( = a/$)
Processamento de Linguagens: DI-UBI 2017/2018 137/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b5 [ S bA.A, $ ]
4 [ S b.AA, $ ] A [ A A.a, a/$ ]
[ A . , a/$ ]
[ A .Aa, a/$ ]
red#4( = a/$)
Processamento de Linguagens: DI-UBI 2017/2018 138/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b5 [ S bA.A, $ ]
4 [ S b.AA, $ ] A [ A A.a, a/$ ]
[ A . , a/$ ] red#4 [ A . , $ ] First($) = { $ }
[ A .Aa, a/$ ] ( = $) [ A .Aa, $ ] First($) = { $ }
red#4( = a/$)
Processamento de Linguagens: DI-UBI 2017/2018 139/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b5 [ S bA.A, $ ]
4 [ S b.AA, $ ] A [ A A.a, a/$ ]
[ A . , a/$ ] red#4 [ A . , $ ] First($) = { $ }
[ A .Aa, a/$ ] ( = $) [ A .Aa, $ ] First($) = { $ }
red#4( = a/$)
red#4( = a)
[ A . , a ]
[ A .Aa, a ]
First(a$) = { a }
First(a$) = { a }
Processamento de Linguagens: DI-UBI 2017/2018 140/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b5 [ S bA.A, $ ]
4 [ S b.AA, $ ] A [ A A.a, a/$ ]
[ A . , a/$ ] red#4 [ A . , a/$ ]
[ A .Aa, a/$ ] (= a/$) [ A .Aa, a/$ ]
red#4( = a/$)
Processamento de Linguagens: DI-UBI 2017/2018 141/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b5 [ S bA.A, $ ]
4 [ S b.AA, $ ] A [ A A.a, a/$ ]
[ A . , a/$ ] red#4 [ A . , a/$ ]
[ A .Aa, a/$ ] (= a/$) [ A .Aa, a/$ ]
red#4( = a/$)
a
6 [ A Aa., a/$ ] red#5 ( = a/$)
Processamento de Linguagens: DI-UBI 2017/2018 142/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b5 [ S bA.A, $ ] A
7 [ S bAA., $ ]
4 [ S b.AA, $ ] A [ A A.a, a/$ ] [ A A.a, a/$ ]
[ A . , a/$ ] red#4 [ A . , a/$ ] red#3 ( = $)
[ A .Aa, a/$ ] (= a/$) [ A .Aa, a/$ ]
red#4( = a/$)
a
6 [ A Aa., a/$ ] red#5 ( = a/$)
Processamento de Linguagens: DI-UBI 2017/2018 143/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b5 [ S bA.A, $ ] A
7 [ S bAA., $ ]
4 [ S b.AA, $ ] A [ A A.a, a/$ ] [ A A.a, a/$ ]
[ A . , a/$ ] red#4 [ A . , a/$ ] red#3 ( = $)
[ A .Aa, a/$ ] (= a/$) [ A .Aa, a/$ ] a
red#4( = a/$)
a
6 [ A Aa., a/$ ] red#5 ( = a/$)
Processamento de Linguagens: DI-UBI 2017/2018 144/183
Análise sintática Análise Sintática Ascendente (bottom-up)
1 [ Z .S$, ] S 2 [ Z S.$, ] AC
[ S .a, $ ]
[ S .bAA, $ ] a 3 [ S a., $ ] red#2 ( = $)
b5 [ S bA.A, $ ] A
7 [ S bAA., $ ]
4 [ S b.AA, $ ] A [ A A.a, a/$ ] [ A A.a, a/$ ]
[ A . , a/$ ] red#4 [ A . , a/$ ] red#3 ( = $)
[ A .Aa, a/$ ] (= a/$) [ A .Aa, a/$ ] a
red#4( = a/$)
a
6 [ A Aa., a/$ ] red#5 ( = a/$)
Os Follow's são apenas utilizados para decidir quando devem ser feitas reduções.
Processamento de Linguagens: DI-UBI 2017/2018 145/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Tabela Oráculo LR(1) (exemplo anterior):
a
a b $ S A
e
s
t
a
d
o
s
1 s3 s4 erro s2 erro
2 erro erro AC erro erro
3 erro erro r2 erro erro
4 r4 erro r4 erro s5
5 s6 erro r4 erro s7
6 r5 erro r5 erro erro
7 s8 erro r3 erro erro
8 erro erro r5 erro erro
Oráculo_T Oráculo_S
{ não existem conflitos é LR(1) }
Processamento de Linguagens: DI-UBI 2017/2018 146/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Conflito redução/transição
Resumindo e concluindo:
- Um item LR(k) da forma
[ A → a.Xb , m ]
determina uma transição por X
- Um item LR(k) da forma
[ A → a., m ]
determina uma redução por A → a para todo o a First(k, ∈ m).
As possíveis situações de conflito são
- Conflito redução-transição
ao mesmo estado estão associados 2 itens LR(k) da forma:
[ A → a .ab , m ]
e [ B → d ., n ], com a First(k, ∈ n)
Processamento de Linguagens: DI-UBI 2017/2018 147/183
Análise sintática Análise Sintática Ascendente (bottom-up)
- Conflito redução-redução
ao mesmo estado estão associados 2 itens LR(k) da forma:
[ A → a., m ]
e [ B → b ., n ]
com First(k, m) First(k, n) ≠ .
- Uma dada gramática satisfaz a condição LR(k) se não provocar conflitos em nenhum
dos estados.
Processamento de Linguagens: DI-UBI 2017/2018 148/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Exercício:
Verificar se a gramática não-ambígua de expressões é LR(0) ou LR(1).
Produções:
p1: Z S $→
p2: S E→
p3: E E + T→
p4: E T→
p5: T ( E )→
p6: T id→
Processamento de Linguagens: DI-UBI 2017/2018 149/183
Análise sintática Análise Sintática Ascendente (bottom-up)
{ conflito redução/transição no estado 5 não é LR(0) }
Processamento de Linguagens: DI-UBI 2017/2018 150/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Construção do autómato LR(1):
First(S) = First(E) = First(T) = { (, id }
Follow(S) = { $ }
Follow(E) = Follow(T) = { +, ), $ }
Processamento de Linguagens: DI-UBI 2017/2018 151/183
Análise sintática Análise Sintática Ascendente (bottom-up)
- As transições possíveis a partir do estado 1 são:
- (Action) símbolos terminais :First(S) ou First(E) ou First(T) = { (, id }→
- (Goto) símbolos não-terminais: S, E, T→
-Não ocorrem reduções no estado 1
- First(k, rn) servem apenas para identificar reduções
Processamento de Linguagens: DI-UBI 2017/2018 152/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 153/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Observações
- O autómato LR(0) contem informação insuficiente para resolver os conflitos que
surgem na maioria das linguagens.
- As exigências de memória destes autómatos são aceitáveis.
- O autómato LR(1) contem informação suficiente para resolver os conflitos na maioria
das linguagens.
- A memória necessária neste autómatos é impraticável.
- No entanto, existem soluções de compromisso, como sejam: SLR(1) e LALR(1).
Processamento de Linguagens: DI-UBI 2017/2018 154/183
Análise sintática Análise Sintática Ascendente (bottom-up)
4. Parser SLR(1) — Simple LR(1)
- Os seus estados são basicamente os mesmos que os do autómato LR(0)
- A certos items é associada informação “necessária” para identificar reduções
- A cada item LR(0) da forma:
[ A → a . ] é associado o Follow(A)
Haverá redução por A → a se a Follow(A)
- O correspondente item LR(1) seria:
[ A → a ., m ], com m Follow(A), mas não todo o Follow(A).
Processamento de Linguagens: DI-UBI 2017/2018 155/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Exemplo:
Verificar se a gramática G = ( { S, A }, { a, b, c }, S, P ) é SLR(1), em que P contém
as seguintes produções:
p0: Z S$→
p1: S Sb→
p2: S bAa→
p3: A aSc→
p4: A aSb→
p5: A a→
Follow(S) = { $, b, c } Follow(A) = { a }
Serão resolvidos os dois conflitos LR(0):
No estado 6 : conflito redução/transição
No estado 10: conflito redução/redução
Processamento de Linguagens: DI-UBI 2017/2018 156/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 157/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Processamento de Linguagens: DI-UBI 2017/2018 158/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Tabela Oráculo SLR(1):
a
a b c $ S A
e
s
t
a
d
o
s
1 erro s3 erro erro s2 erro
2 erro s4 erro AC erro erro
3 s6 erro erro erro erro s5
4 erro r1 r1 r1 erro erro
5 s7 erro erro erro erro erro
6 r5 s3 erro erro s8 erro
7 erro r2 r2 r2 erro erro
8 erro s10 s9 erro erro erro
9 r3 erro erro erro erro erro
10 r4 r1 r1 r1 erro erro
Oráculo_T Oráculo_S
Processamento de Linguagens: DI-UBI 2017/2018 159/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Conclusão:
O método SLR(1) resolve conflitos LR(0) quando
Conflito redução-transição:
quando a Ï Follow(B)
[ A ® a.ab ]
[ B ® d . ]
Conflito redução-redução:
quando Follow(A) Follow(B) = Æ
[ A ® a. ]
[ B ® b . ]
Processamento de Linguagens: DI-UBI 2017/2018 160/183
Análise sintática Análise Sintática Ascendente (bottom-up)
5. Parser LALR(1) — LookAhead LR(1)
- Ainda os mesmos estados que os autómatos LR(0).
- Com mais informação associada a cada item
- Cada item LR(0) da forma [ A ® a. ] do estado q é substituído por
[ A ® a., n ], onde n = L (q, A ® a.)
- Cada item LR(0) da forma [ A ® a.Xb ] do estado q é substituído por
[ A ® a.Xb , n ], onde n = L (q, A ® a.Xb)
- Deste modo, a redução num estado com o item
[ A ® a., n ]
só será efetuada se a Î n.
Processamento de Linguagens: DI-UBI 2017/2018 161/183
Análise sintática Análise Sintática Ascendente (bottom-up)
- O método LALR(1) resolve conflitos LR(0) quando:
Conflito redução-transição:
[ A ® a .ab ]
[ B ® d . ]
resolvido quando a Ï L(q, B ® d)
Conflito redução-redução:
[ A ® a . ]
[ B ® b . ]
resolvido quando L(q, A ® a) Ç L(q, B ® b) = Æ
Processamento de Linguagens: DI-UBI 2017/2018 162/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Cálculo dos L() LALR(1):
Regra 1: Propagação por transição de estados :
L(q’, A → aX.b) = È L(q, A → a.Xb)[A →a .Xb ] Î q
Uma transição de q para q’ pelo símbolo X, propaga o L() do
item [A → a.Xb] para o item [A → aX.b].
Regra 2: Concatenação por cálculo do fecho
[A → a .Br]-------------------------------
[B → .d]
L(q, B → .d) = È First(r L(q, A →a.Br))[A →a .Br ] Î q
O L() de cada item do fecho de [A → a .Br] obtém-se concatenando
r com L(q, A →a.Br) e calculando o First da cadeia obtida.
Processamento de Linguagens: DI-UBI 2017/2018 163/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Regra 3: Estado inicial q0 e estado final qf
L(q0, Z → .S$) = { e }
L(qf, Z →S.$) = { $ }
As regras são aplicadas por travessias iterativas do autómato.
Processamento de Linguagens: DI-UBI 2017/2018 164/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Exemplo:
Verificar se a gramática G = ( { S, L, R }, { id, =, * }, S, P ) é LALR(1), em que
P contém as seguintes produções:
p0: Z S$→ (não faz parte de G)
p1: S L=R→
p2: S R→
p3: L *R→
p4: L id→
p5: R L→
O método LALR(1) vai eliminar o conflito redução/transição no estado 4, que ocorreria por
LR(0) e SLR(1).
Processamento de Linguagens: DI-UBI 2017/2018 165/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LR(0) com conflito redução/transição no estado 4:
Processamento de Linguagens: DI-UBI 2017/2018 166/183
Análise sintática Análise Sintática Ascendente (bottom-up)
SLR(1) com conflito redução/transição no estado 4:
Processamento de Linguagens: DI-UBI 2017/2018 167/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 168/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 169/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 170/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 171/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 172/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 173/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 174/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 175/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 176/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
Processamento de Linguagens: DI-UBI 2017/2018 177/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Tabela Oráculo LALR(1):
a
id = * $ S L R
e
s
t
a
d
o
s
1 s5 erro s6 erro s2 s4 s3
2 erro erro erro AC erro erro erro
3 erro erro erro r2 erro erro erro
4 erro s7 erro r5 erro erro erro
5 erro r4 erro r4 erro erro erro
6 s5 erro s6 erro erro s9 s10
7 s5 erro s6 erro erro s9 s8
8 erro erro erro r1 erro erro erro
9 erro r5 erro r5 erro erro erro
10 erro r3 erro r3 erro erro erro
Oráculo_T Oráculo_S
Processamento de Linguagens: DI-UBI 2017/2018 178/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Relação entre LL(k), LR(k), SLR(k) e LALR(k):
- LL(k) é o parser mais simples e, consequentemente, o com mais problemas, pos
nem todas as gramáticas podem ser tratadas com este parser (as recursivas)
- As fraquezas do parser LL(k) são superadas pelo parser LR(k)
- O parser SLR(1) – LR(1) simples; aumenta o poder de análise do LR(0)
- O parser LR(1) aumenta o poder de análise do SLR(1), pois ajuda a resolver
conflitos redução-redução e redução-transição
- O parser LALR(1) aumenta o poder de análise de LR(1); diminui o AFD e a tabela
de “parsing” do LR(1)
Processamento de Linguagens: DI-UBI 2017/2018 179/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Construção do AFD LALR(1) a partir do AFD LR(1):
Seja a gramática com as seguintes produções:
A ( A )→
A a→
Processamento de Linguagens: DI-UBI 2017/2018 180/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LR(1):
Processamento de Linguagens: DI-UBI 2017/2018 181/183
Análise sintática Análise Sintática Ascendente (bottom-up)
LALR(1):
(Fazer também o LALR(1) a partir do LR(0) e verificar se são iguais)
Processamento de Linguagens: DI-UBI 2017/2018 182/183
Análise sintática Análise Sintática Ascendente (bottom-up)
Otimização das Tabelas de Parsing:
- São geralmente matrizes esparsas
- Tentativas de compactação.
…....
Processamento de Linguagens: DI-UBI 2017/2018 183/183