Análise Sintática Descendente

Propaganda
FACULDADE ANGLO AMERICANO – FOZ DO IGUAÇU
Curso de Ciência da Computação – 7º Periodo
Disciplina: Compiladores
Prof. Erinaldo Sanches Nascimento
Análise Sintática Descendente
Recursivo com retrocesso
Recursivo preditivo
Tabular preditivo
Definição
• Esse método constroi a árvore de derivação
para a cadeia de entrada de cima para baixo.
– Da raiz para as folhas.
– Cria nós em pré-ordem (da esquerda para a
direita).
– Produz uma derivação mais à esquerda para uma
cadeia de entrada.
http://erinaldosn.wordpress.com
2
• Analisadores sintáticos descendentes
– Com retrocesso (backtracking)
– Preditivos
• Algoritmos
– Descendentes recursivos
– LL(1)
http://erinaldosn.wordpress.com
3
Exemplo
• Gramática
http://erinaldosn.wordpress.com
4
• Análise sintática descendente para a entrada id+id*id
http://erinaldosn.wordpress.com
5
http://erinaldosn.wordpress.com
6
http://erinaldosn.wordpress.com
7
Análise Sintática Descendente Recursiva
• Consiste em um conjunto de procedimentos,
um para cada não-terminal da gramática.
• Pode exigir retrocesso (voltar atrás no
reconhecimento)
• A regra gramatical para um A não-terminal é
vista como uma definição de procedimento
para reconhecer um A.
• O lado direito da regra gramatical especifica a
estrutura do código para esse procedimento.
http://erinaldosn.wordpress.com
8
• Considere a regra gramatical para um fator na
gramática de expressões:
void fator(){
switch (marca)
case ‘(‘ :
casamento(();
exp;
casamento());
case numero :
casamento(numero);
default
erro;
}
http://erinaldosn.wordpress.com
9
• Procedimento casamento que casa a marca
seguinte com seu parâmetro.
void casamento(marcaEsperada){
if marca = marcaEsperada
capturaMarca;
else
erro;
}
http://erinaldosn.wordpress.com
10
• Funcionamento de um analisador descendente com retrocesso.
– Considere a sentença [a] derivada a partir da
gramática abaixo, a qual gera listas:
S  a | [L]
L  S; L | S
http://erinaldosn.wordpress.com
11
• O reconhecimento de [
é bem sucedido.
• A derivação de L é
efetuada usando S ; L.
• S é expandido novamente, obtendo-se sucesso.
http://erinaldosn.wordpress.com
12
• A comparação seguinte (]
com ;) falha.
• O analisador deve retroceder para o ponto em
que estava por ocasião da
opção pela primeira alternativa de L.
• É aplicada a segunda
alternativa, L  S.
• A derivação final é obtida
aplicando-se a produção
Sa.
http://erinaldosn.wordpress.com
13
Pseudocódigo
• Programa principal
main(){
token = Letoken();
if S
if token = ‘$’
write (‘Sucesso’);
else
write (‘Erro’);
}
http://erinaldosn.wordpress.com
14
•
Função S
S(){
if token = ‘a’{
token = Letoken(); return true;
}
else if token = ‘[‘{
token = Letoken();
if L
if token = ‘]’{
token = Letoken(); return true;
}
else
return false;
else
return false
}
else
return false;
}
http://erinaldosn.wordpress.com
15
•
Função L.
L(){
Marca_Ponto();
if S
if token = ‘;’{
token = Letoken();
if L
return true;
else
return false;
}
else {
Retrocede();
if S
return true;
else
return false;
}
else
return false;
}
http://erinaldosn.wordpress.com
16
• A função Letoken() retorna um token lido
a partir da sentença de entrada.
• Marca_Ponto() marca, na sentença de
entrada, um ponto de possível reinício da
análise.
• Retrocede() volta o ponteiro de leitura
para o último ponto marcado.
http://erinaldosn.wordpress.com
17
• Função L sem backtracking (retrocesso)
L(){
if S
if token = ‘;’{
if L
return true;
else
return false;
}
else
return true;
else
return false;
}
http://erinaldosn.wordpress.com
18
Exercício
• Considere a gramática:
ScAd
Aab|a
• Construa uma árvore de derivação
descendente para a cadeia w = cad
• Crie um algoritmo para reconhecimento dessa
gramática.
• Implemente o algoritmo em C, Java ou Pascal.
http://erinaldosn.wordpress.com
19
FIRST e FOLLOW
• Conjunto de verificação à frente Primeiro e de
Sequência.
• Permitem escolher qual produção aplicar, com
base no próximo símbolo da entrada.
http://erinaldosn.wordpress.com
20
FIRST( )
•
é qualquer cadeia de símbolos da gramática
– Conjunto de símbolos terminais que iniciam as
cadeias derivadas de .
• Se
* , então a palavra vazia também faz
parte do conjunto.
http://erinaldosn.wordpress.com
21
• Considere as duas produções-A:
A |
• Onde FIST( ) e FIRST( ) são conjunto disjuntos
• Podemos escolher uma dessas alternativas de
A examinando o próximo símbolo de entrada
a, desde que a só possa estar em FIRST( ) ou
FIRST( )
http://erinaldosn.wordpress.com
22
FOLLOW(A)
• É definida para símbolos não-terminais.
• A é um não-terminal.
• FOLLOW(A) é o conjunto de terminais a que
podem aparecer imediatamente à direita de A
em alguma forma sentencial
– O conjunto de terminais a, tal que existe uma
derivação da forma S
* Aa para
e
quaisquer.
http://erinaldosn.wordpress.com
23
Algoritmo para calcular FIRST(X)
Para calcular o FIRST(X) de todos os símbolos S
da gramática, aplique as regras a seguir até que
não haja mais terminais ou que possam ser
acrescentados a algum dos conjuntos FIRST.
http://erinaldosn.wordpress.com
24
1. Se X é um símbolo terminal, então FIRST(X)={X}.
2. Se X é um símbolo não-terminal e X Y1Y2...Yk é
uma produção para algum k 1, então
acrescente a a FIRST(X) se, para algum i, a
estiver em FIRST(Yi), e estiver em todos os
FIRST(Yi),...,FIRST(Yi-1). Se
está em FIRST(Yj)
para todo j=1,2,...,k, então adicione a FIRST(X).
3. Se X
é uma produção, então acrescente a
FIRST(X).
http://erinaldosn.wordpress.com
25
for (cada não-terminal A)
First(A) = {};
while houver alterações em algum FIRST(A){
for (cada escolha de produção A X1,X2...Xn){
k = 1;
continue = true;
while (continue == true && k<=n){
acrescente First(Xk)-{ } a First(A);
if ( não pertencer a First(Xk){
continue = false;
k = k+1;
}
}
if (continue = true)
acrescente
a First(A);
http://erinaldosn.wordpress.com
26
• Algoritmo simplificado
for (cada não-terminal A)
First(A) = {};
while (houver alterações em algum First(A))
for (cada escolha de produção A X1X2...Xn)
acrescente FIRST(X1) a First(A);
http://erinaldosn.wordpress.com
27
Algoritmo para calcular FOLLOW(X)
Para calcular o FOLLOW(X) para todos os nãoterminais A, aplique as regras a seguir até que
nada possa ser acrescentado a nenhum dos
conjuntos FOLLOW.
http://erinaldosn.wordpress.com
28
1. Coloque $ em FOLLOW(S), onde S é o símbolo
inicial da gramática, e $ é o marcador de fim da
entrada ou fim de arquivo.
2. Se houver uma produção X
B , então tudo
em FIRST( ) exceto está em FOLLOW(A).
3. Se houver uma produção X
B, ou uma
produção X
B , onde FIRST( ) contém ,
então inclua FOLLOW(X) em FOLLOW(A).
http://erinaldosn.wordpress.com
29
• Algoritmo para computação de conjuntos FOLLOW.
Follow(símbolo-inicial) = {$};
for (cada não-terminal S # símbolo-inicial)
Follow(S) = {};
while (houver alterações em algum conjunto Follow)
for(cada produção S A1A2...An)
for (cada Xi não-terminal){
adicione First(Ai+1aAi+2...An) – { } a Follow(A)
if ( estiver em First(Ai+1Ai+2...An))
adicione Follow(S) a Follow(A)
}
http://erinaldosn.wordpress.com
30
Observe
• A palavra vazia jamais fará parte de algum
conjunto FOLLOW.
• Os conjuntos FOLLOW são formados apenas
por símbolos terminais
• não é símbolo terminal.
http://erinaldosn.wordpress.com
31
Download