Análise Descendente(Top

Propaganda
Analisador sintático: Tipos de análises sintáticas
Tanto os métodos descendentes como os ascendentes
constroem a árvore de derivação da esquerda para direita.
A escolha das regras basea-se na cadeia a ser reconhecida,
que é lida da esquerda para a direita.
Analisador sintático: Análise Sintática Ascendente
Na análise sintática ascendente a construção da árvore de
derivação para uma determinada cadeia (lexema) começa
pelas folhas da árvore e segue em direção de sua raiz.
Caso seja obtida uma árvore cuja raiz tem como rótulo o
símbolo inicial da gramática, e na qual a sequência dos
rótulos das folhas forma a cadeia dada, então a cadeia é
uma sentença da linguagem, e a árvore obtida é a sua
árvore de derivação.
Analisador sintático: Análise Sintática Ascendente
Embora a árvore de derivação seja usada para descrever os
métodos de análise, na prática ela não precisa ser
efetivamente construída.
A única estrutura de dados necessária para o processo de
análise sintática é uma pilha.
Guarda informação sobre os nós da árvore de
derivação relevantes em cada fase do processo
Analisador sintático: Análise Sintática Ascendente
Definição:
Redução de uma cadeia → partir das folhas em direção à
raiz de uma árvore de derivação.
A cada passo, procura-se reduzir uma cadeia (ou subcadeia) ao seu símbolo de origem, objetivando-se atingir o
símbolo inicial da gramática.
Analisador sintático: Análise Sintática Ascendente
Etapas da redução de uma cadeia
1) Toma-se uma determinada cadeia .
2) Procura-se por uma sub-cadeia a1,a2,...an de  que
possa ser substituída pelo seu símbolo de origem .
Ou seja,  → a1,a2,...an . Assim a1,a2,...an  b = a1 
a2.
Analisador sintático: Análise Sintática Ascendente
3) Repetir o passo (2) até que  = símbolo inicial da
gramática.
Caso isso não seja possível, tem-se que a cadeia analisada
não pertence a linguagem especificada.
Analisador sintático: Análise Sintática Ascendente
Analisador sintático: Análise Sintática Ascendente
Outro exemplo a cadeia
x = a+a*a e produção
Nesse caso, a
ordem das regras
corresponde
a uma derivação à
direita, porém de
trás para frente
Analisador sintático: Análise Sintática Ascendente
Problemas:
Os maiores problemas na análise sintática ascendente residem
na dificuldade de determinação de qual parcela da cadeia (subcadeia) que deverá ser reduzida;
Qual será a produção a ser utilizada na redução, para o caso de
existirem mais do que uma possibilidade.
Analisador sintático: Análise Sintática Descendente
Na análise sintática descendente tem-se procedimento
inverso ao da ascendente.
Aqui a análise parte da raiz da árvore de derivação e segue
em direção as folhas, ou seja,
a partir do símbolo inicial da gramática vai-se procurando
substituir os símbolos não-terminais de forma a obter nas
folhas da árvore a cadeia desejada.
Analisador sintático: Análise Sintática Descendente
Etapas da redução de uma cadeia
1) Toma-se uma determinada cadeia b e o símbolo inicial  da
gramática.
2) Procura-se por uma regra de derivação que permita derivar
 em sua totalidade ou pelo menos se aproximar desta.
3) Repetir o passo (2) até que a cadeia não apresente mais
símbolos não terminais, verificando se a cadeia obtida
coincide com .
Não havendo coincidência, a cadeia analisada não
pertence a linguagem especificada.
Analisador sintático: Análise Sintática Descendente
Exemplo
Considere a seguinte gramática
e a cadeia x = a+a*a
Analisador sintático: Análise Sintática Descendente
Analisador sintático: Análise Sintática Descendente
Problemas:
Embora apresente os mesmos problemas que a analise
sintática ascendente, implementa facilmente compiladores
para linguagens obtidas de gramáticas LL(1)
(análise da cadeia da esquerda para a direita e derivações
esquerdas observando apenas o primeiro símbolo da cadeia
para decidir qual regra de derivação será utilizada).
Gramática: Derivações e Precedência
Gramática: Ambigüidade
Definição 1
Ambigüidade refere-se geralmente a confusão na GLC
Sobrecarga (Overloading) pode criar ambigüidade f(17)
Em algumas linguagens, f pode ser uma função ou uma macro
Para eliminar ambigüidade é preciso conhecer contexto
• Requer valores de declarações
• É uma questão de tipo, uma gramática livre de contexto não é
suficiente
• Requer uma solução extra-gramatical (não em GLC)
Ambigüidade: Uma gramática que produz mais de uma árvore
de derivação para alguma sentença é considerada ambígua
Uma GLC é ambígua se permitir mais de 1
derivação mais à esquerda ou mais de 1
derivação mais à direita para a mesma sentença
Gramática: Ambigüidade
Definição 2
• Se uma gramática tem mais do que uma derivação mais à
esquerda ou a direita, então a gramática é ambígua
• Se houver mais do que uma árvore gramatical, então a gramática
é ambígua
Exemplo clássico — o problema do if-then-else
Esta ambigüidade é de natureza inteiramente gramatical
Gramática: Ambigüidade
Esta sentença tem duas derivações
producão 2,
depois
producão 1
produção 1,
depois
produção 2
Gramática: Ambigüidade
Removendo ambigüidade
Associar cada else ao then anterior mais próximo ainda não
associado if (regra de senso comum)
Com esta gramática,
o exemplo
tem apenas uma
derivação
Gramática:LL(1) e LR(1):Técnicas de parsing
Top-down parsers (LL(1) derivação mais a esquerda, recursivo
descendente)
• Inicia na raiz da árvore e cresce em direção as folhas
• Obtém uma produção e tenta associar a entrada
• Se escolha errada pode tentar retroceder (backtrack)
• Algumas gramáticas são livre de retrocesso (parsing preditivos )
• Não podem tratar com gramáticas recursivas a esquerda
Bottom-up parsers LR(1)
• L é porque a entrada é da esquerda para a direita
• R é porque é feito usando derivação mais a direita e o 1 porque
avalia um token adiante
• Inicia nas folhas e cresce até a raiz
• Inicia em um estado válido para os primeiros tokens
Gramática: Eliminações
Eliminações:
Utiliza Gramáticas Livres de Contexto (GLC) para descrever a
sintaxe das construções de linguagem de programação como
expressões e comandos
Derivações: a partir do símbolo inicial de uma regra, substitui-se um
não terminal pelo corpo de uma de suas produções
-O não terminal em cada passo é escolhido:
Em derivações mais à esquerda (lm), o não terminal mais à
esquerda em cada forma sentencial sempre é escolhido
Em derivações mais à direita (rm), o não terminal mais à direita em
cada forma sentencial sempre é escolhido
Gramática: Eliminações
Eliminação (fatoração) de recursão à esquerda
- Métodos de análise descendente não tratam recursões à
esquerda
- Eliminação de recursão à esquerda imediata:
Gramática: Eliminações
Eliminação de recursividade à esquerda
Gramática: Eliminações
Exemplo de Fatoração a Esquerda
Cmd  if Expr then Cmd else Cmd | if Expr then Cmd | Outro
A 
a
A
b
• Fatorando a esquerda:
Cmd  if Expr then Cmd else Opc | Outro
A

b
X
else Opc  if Expr then Cmd else else Opc | 
X 
a
X
|
Gramática: Eliminações
Gramática: Eliminações
Fatoração de uma gramática
• Elimina indecisão de qual produção aplicar quando duas ou
mais produções iniciam com a mesma forma sentencial. Por
exemplo
Gramática: Eliminações
Algoritmo:
- Entrada: gramática G
- Saída: gramática G, fatorada à esquerda
1) para cada não terminal A, encontrar prefixo a mais longo e
comum a duas ou mais de suas alternativas
2) Se a!=ℇ, então existe um prefixo comum não trivial,
substitua todas as produções A, A → aB1 | aB2 | ... | aBn | y, onde y
representa todas as alternativas que não começam com a, por:
- A→ aA' | y
- A‘→ B1 | B2 | ... | Bn
Gramática: Eliminações
Gramática: Eliminações
Gramática: Eliminações
Análise Descendente(Top-Down)
Análise Descendente(Top-Down)
• Como implementar um reconhecedor para uma GLC?
• Constrói-se a árvore de derivação, lendo a sentença de
esquerda para a direita, e substituindo sempre o não-terminal
mais à esquerda.
• Existe três tipos principais de parser top-down:
– Recursivo com retrocesso
– Recursivo preditivo
– Tabular preditivo.
Análise Descendente(Top-Down)
Análise Descendente(Top-Down)
Implementação do reconhecedor
• Cria-se um procedimento por não-terminal
– Ele testa a aplicação de cada produção associada ao não terminal;
– Lê no texto de entrada o próximo token
• Chama o analisador lexical (yylex()) !
• É necessário lembrar onde se fez uma escolha de uma
alternativa, para poder retroceder neste ponto.
Análise Descendente(Top-Down)
ReconheceTIPO() {
switch(token) {
case {integer, char, num}: ReconheceTIPOSIMPLES();
break;
case ^: reconhece( id) ;
break;
}
}
ReconheceTIPOSIMPLES() {
switch(token){
case integer: reconhece(integer); break;
case char: reconhece(char); break;
case num: reconhece(num); reconhece(pp); reconhece(num); break;
default: erro();
}
}
Análise Descendente(Top-Down)
Observações sobre o método recursivo com retrocesso
• É fácil de implementar.
• É necessário:
1. Que a gramática não seja recursiva à esquerda
• A  Aa se tornará
ReconheceA() { ReconheceA();... }
• Recursão infinita!
2. Que a gramática seja fatorada à esquerda
• Senão, deve-se fazer retrocesso.
3. Que os primeiros terminais deriváveis possibilitem a decisão de
uma produção a aplicar!
• Não há retrocesso sobre não-terminais...
Análise Descendente(Top-Down)
Definição: Conjuntos “First”
• First(α):
– Definição informal:
• conjunto de todos os terminais que começam
qualquer seqüência derivável de α.
Análise Descendente(Top-Down)
Condição para que se possa usar um analisador preditivo
Análise Descendente(Top-Down)
Análise Descendente(Top-Down)
O que acontece se   First(A)?
Análise Descendente(Top-Down)
Para tratar o caso do ε:
o conjunto Follow
• Follow(B):
– conjunto de terminais que podem aparecer à direita
de um não-terminal B em uma sentença válida.
– $ passa a denotar um terminal “virtual” que marca o fim da
entrada (EOF, CTRL-D,…)
•
Análise Descendente(Top-Down)
Exemplo First/Follow
SAB
Ac|
B  cbB | ca
First(A) = {c, } Follow(A) = {c}
First(B) = {c} Follow(B) = {$}
First(S) = {c} Follow(S) = {$}
Análise Descendente(Top-Down)
Análise Descendente(Top-Down)
Observações First/Follow
• Só terminais entram em First e Follow.
• O algoritmo de cálculo de First(α):
– É trivial quando α é um terminal t.
– varre as produções X → tω quando α é um não-terminal X;
– Inclui ε apenas quando X pode derivar em ε.
• O algoritmo de cálculo de Follow(X)
– É reservado aos não-terminais X
– Inclui o $ em alguns casos triviais (X == o start S)
– Varre as produções onde X aparece à direita (A → ωX ω’)
– NUNCA inclui ε
Análise Descendente(Top-Down)
Exemplo First/Follow
S  XYZ
X  aXb | 
Y  cYZcX | d
Z  eZYe | f
First(X) = {a, } Follow(X) = {c, d, b, e, f}
First(Y) = {c, d} Follow(Y) = {e, f}
First(Z) = {e, f} Follow(Z) = {$, c, d}
First(S) = {a, c, d} Follow(S) = {$}
Download