Professional Documents
Culture Documents
Analise Ascendente
Analise Ascendente
Instituto de Informática
Universidade Federal de Goiás
6 de outubro de 2009
Alavanca
As formas sentenciais sublinhadas que aparecem em uma
redução são denominadas alavancas, pois elas “alavancam” um
nível acima na árvore devido à substituição delas por um
não-terminal colocado no nível superior da árvore.
Uma alavanca é uma forma sentencial que corresponde a um
lado direito de uma produção e que aparece na derivação mais
à direita de alguma forma sentencial.
No exemplo anterior, b, Abc, d, aABe são alavancas.
Alavanca
Formalmente, uma alavanca de uma forma sentencial mais à
direita γ é uma produção A →β e uma posição dentro de γ
onde a cadeia β pode ser encontrada e substituida por A de
forma a produzir a forma sentencial à direita anterior numa
derivação mais à direita de γ.
No exemplo anterior: dado γ = aAbcde, β = Abc é uma
alavanca de γ, mas β = b não é.
Exemplo
Considere a gramática: E → E + E, E → E ∗ E, E → (E),
E → id,
e a cadeia: Id1 + id2 ∗ id3
e a derivação mais à direita:
E ⇒ E+E ⇒ E+E∗E ⇒ E+E∗id ⇒ E+id∗id ⇒ id+id∗id
Exemplo
A Pilha
Um $ é usado para marcar o fundo da pilha e o fim da cadeia
de entrada. Inicialmente:
Pilha: $
Buffer: w$, onde w é a cadeia de entrada.
Se a cadeia for aceita:
Pilha: S$
Buffer: $
Ações Possíveis
Empilhar (shift): desloca o próximo símbolo da entrada para
o topo da pilha.
Reduzir: substitui a alavanca no topo da pilha pelo lado
esquerdo (não-terminal) de alguma produção.
Detectar erro: erro sintático ocorrido.
Aceitar: o símbolo inicial é o único na pilha e o buffer de
entrada se encontra vazio.
O Funcionamento do Analisador
Repare na última tabela que é possível ver o reverso de uma
derivação mais à direita lendo-se a tabela de baixo para cima,
e em cada linha, começando a leitura na pilha e continuando
no buffer de entrada.
O método utilizado deve garantir que a alavanca apareça no
topo da pilha.
Parsers LR
Podem ser construídos para reconhecer qualquer estrutura
sintática de linguagens de programação que podem ser geradas
por uma gramática livre de contexto.
A classe de gramáticas que podem ser analisadas com o
método LR é um superconjuto próprio das gramáticas LL(k).
Podem detectar erros no início, em uma varredura da entrada
a partir da esquerda.
Parsers LR
Devem ser automatizados (muito difícil implementar um
analisador manualmente).
LR Parser
Possui um programa que usa o estado no topo da pilha e o
próximo símbolo(lookahead symbol) da entrada como índices
para a tabela de ação.
A pilha contém dois tipos de símbolos: símbolos gramaticais e
estados. Cada estado representa o prefixo de uma alavanca
que está na pillha abaixo dele. Estes prefixos são denominados
prefixos viáveis
Tabela de ação A
É indexada por um par <estado, terminal>
Se A[sm , ai ] = shif t s - o parser desloca ai para o topo da
pilha e empilha o estado s. O próximo símbolo na entrada
passa a ser ai+1 .
Se A[sm , ai ]= acc - a cadeia de entrada é valida e deve ser
aceita
Se A[sm , ai ] = error - ocorreu um erro sintático. Iniciar a
recuperação de erro.
Tabela de ação A
Se A[sm , ai ] = reduz(B → β) - o parser desemplilha 2 × |β|
elementos da pilha (estados e símbolos de β). Utiliza o estado
s que aparece no topo da pilha e o não terminal B para
indexar a tabela de desvio D, então, empilha B e, em seguida,
o estado indicado por D[s, B]. Neste caso, o próximo símbolo
na entrada não é modificado.
Exemplo
Considere a gramática:
G = {VN , VT , P, E 0 }, onde VN = {E 0 , E, T, F },
VT = {id, +, ×, (, )},
P = { E 0 → E,
E → E + T,
E → T,
T → T × F,
T → F,
F → (E),
F → id
}
Figura: Analisador LR
Estados na Pilha
O estado no topo da pilha contém a informação sobre um
prefixo viável na pilha. Ele indica o prefixo de uma alanca que
está sendo formada (ou que já se formou) na pilha e pode ser
interpretado como estado de um autômato finito capaz de
reconhecer prefixos viáveis na pilha.
Um estado representa um conjunto de itens gramaticais que
mostram para cada produção, o que já foi reconhecido e o que
falta reconhecer da produção.
Itens LR(0)
Um item LR(0), ou simplesmente item, de uma gramática é
uma produção da com um ponto (•) em alguma posição do
lado direito da produção.
O ponto colocado à direita de um símbolo indica que foi
reconhecida na entrada uma subcadeia derivada daquele
símbolo.
Colocado à esquerda, indica que esperamos reconhecer uma
subcadeia derivada do símbolo.
Exemplo de Item
Ex.: F → (•E) - significa que o analisador sintático está em um
estado em que ele já reconheceu um “(” e que espera reconhecer na
entrada uma subcadeia derivada de E e, após reconhecer está
subcadeia, ele espera reconhecer um “)”. Um item corresponde a
um estado que mostra o tanto de um prefixo viável que já foi
reconhecido e o tanto que falta reconhecer.
Gramática Estendida
Para a construção dos estados do Autômato formado por itens
LR(0) utiliza-se uma gramática estendida, acrescentando-se a
produção S 0 → S.
O objetivo é caracterizar duas situações através dos itens:
S 0 → •S - indica o estado inicial do analisador sintático em
que ele espera reconhecer uma cadeia derivada de S.
S 0 → S• - indica uma situação de aceitação da cadeia.
f echamento({E 0 → •E})
O que fizemos para construir o estado inicial I0 foi aplicar
intuitivamente a operação fechamento no conjunto inicial de itens
{E 0 → •E }:
f echamento({E 0 → •E}) = {E 0 → •E,
f echamento({E 0 → •E})
O que fizemos para construir o estado inicial I0 foi aplicar
intuitivamente a operação fechamento no conjunto inicial de itens
{E 0 → •E }:
f echamento({E 0 → •E}) = {E 0 → •E,
E → •E + T , E → •T
f echamento({E 0 → •E})
O que fizemos para construir o estado inicial I0 foi aplicar
intuitivamente a operação fechamento no conjunto inicial de itens
{E 0 → •E }:
f echamento({E 0 → •E}) = {E 0 → •E,
E → •E + T , E → •T
T → •T × F , T → •F
f echamento({E 0 → •E})
O que fizemos para construir o estado inicial I0 foi aplicar
intuitivamente a operação fechamento no conjunto inicial de itens
{E 0 → •E }:
f echamento({E 0 → •E}) = {E 0 → •E,
E → •E + T , E → •T
T → •T × F , T → •F
F → •(E), F → •id
}
Tabelas SLR
SLR (Simple LR) o método mais simples da classe LR e
também o menos poderoso (pode ser utilizado com um
número reduzido de gramáticas.
A tabela sintática (de ação e desvio) criada por esse método é
denominada tabela SLR.
A tabela sintática é construída tomando como base o
autômato LR(0) de uma gramática SLR.
Definições Preliminares
O analisador SLR utiliza o autômato LR(0) para derivar as
ações da tabela sintática.
Duas definições preliminares são necessárias para descrever
como a tabela pode ser criada a partir dos estados do
autômato:
Conjunto Primeiro de um símbolo.
Conjunto Seguinte de um símbolo.
Conjunto Primeiro
O conjunto primeiro de um símbolo X é utilizado para se
saber todos os terminais a que iniciam cadeias de terminais
derivadas de X.
Construção:
Se X é um terminal (token) então X está em primeiro(X).
∗
Se X ⇒ ε, então ε está em primeiro(X).
Se X for não-terminal e X → Y1 Y2 . . . Yn , para algun n ≥ 1
então:
se para algum i, a ∈ primeiro(Yi ) e ∈ primeiro(Yj ) para
todo j < i, inclua a em primeiro(X);
se ∈ primeiro(Yi ), para 1 ≤ i ≤ n, inclua em
primeiro(X).
Conjunto Seguinte
O cojunto seguinte de um não-terminal A é formado pelo
conjunto de terminais a que aparecem à direita de A em
alguma forma sentencial derivada pela gramática, isto é, se
∗
existir αAaβ, tal que S ⇒ αAaβ para algum α e β.
Conjunto Seguinte
Construção:
Inserir o token terminador de cadeia ($) em seguinte(S), onde
S é o símbolo inicial.
Se existe A → αBβ, então todo token em primeiro(β),
exceto ε deve ser inserido em seguinte(B).
Se existir uma produção A → αB ou uma produção
A → αBβ, onde primeiro(β) contém ε, então tudo em
seguinte(A) deve ser inserido em seguinte(B).
Erros e Conflitos
1 Todas as entradas que ficaram vazias ao fim do processo