Вы находитесь на странице: 1из 40

Compiladores

Análise Sintática – Parte II


Estratégias de Análise Descendente

Prof.: MSc. Ayslânya J. Wanderley

ayslanyawanderley@fiponline.edu.br
1
Métodos de Análise

• Existem métodos universais de análise sintática, como o


algoritmo de Cocke-Younger-Kasami e o de Earley, que
trabalham com qualquer tipo de gramática livre de
contexto;

• Mas são ineficientes para se usar na produção de


compiladores, pois são de ordem de O(n3), com n sendo
o tamanho da cadeia de tokens.

Compiladores ayslanyawanderley@fiponline.edu.br 2
Métodos de Análise
• Os métodos Top-Down e Bottom-Up mais eficientes e
interessantes são determinísticos (O(n)).

• Eles trabalham somente com subclasses de GLCs, mas muitas


dessas subclasses, por exemplo, as gramáticas LL(k) e LR(k) são
bastante expressivas para descrever a maioria das linguagens
de programação.

• Duas delas são de interesse imediato:


– LL(1): Left to right scan, Left-most derivation, 1 token look-
ahead
– LR(1): Left to right scan, Right-most derivation, 1 token
look-ahead

Compiladores ayslanyawanderley@fiponline.edu.br 3
Análise Sintática Descendente
• Uma tentativa de construir uma árvore de derivação da
esquerda para a direita;

• Cria a raiz e, a seguir, cria as subárvores filhas;

• Produz uma derivação mais à esquerda da sentença em


análise.

• Constrói a árvore de derivação para a cadeia de entrada


de cima para baixo (top-down).

Compiladores ayslanyawanderley@fiponline.edu.br 4
Métodos de Análise Descendentes
• Veremos 3 estratégias de A.S.D. :

• A.S.D. Recursiva com Retrocesso (tentativa e erro na escolha


de produção)

• Parsers Preditivos:
– Com procedimentos recursivos: são mais adequados para serem escritos
manualmente; um símbolo look ahead determina a produção a ser
escolhida.

– Dirigidos por tabela: fazem uso de uma pilha explícita para guardar o lado
direito das produções; mais adequado para serem implementados
automaticamente pela pré-computação da Tabela de Análise

Compiladores ayslanyawanderley@fiponline.edu.br 5
A. S. D. recursiva com retrocesso
• Analisador sintático com retrocesso
– Testa diferentes possibilidades de análise sintática de
entrada, retrocedendo se alguma possibilidade
falhar.
– São mais poderosos.
– São mais lentos.

Compiladores ayslanyawanderley@fiponline.edu.br 6
A. S. D. recursiva com retrocesso
• Consiste em um conjunto de procedimentos, um para cada não
terminal da gramática.

• A execução começa com a ativação do procedimento referente


ao símbolo inicial da gramática, que para e anuncia sucesso se o
seu corpo conseguir expandir toda a cadeia da entrada.

• Pode exigir retrocesso, voltar atrás no reconhecimento, fazendo


repetidas leituras sobre a entrada.
– Raramente presentes nas linguagens de programação.
– Não é muito eficiente.
– Os preferidos são os baseados em tabelas, como o algoritmo de
programação dinâmica.
Compiladores ayslanyawanderley@fiponline.edu.br 7
A. S. D. recursiva com retrocesso
• Pseudocódigo típico para um não terminal;

void A() { Escolha uma produção-A, A → x1 x2 ... xk


for (i = 1 até k) { if (xi é um não terminal) ativa
procedimento xi ();
else if (xi igual ao símbolo de entrada a)
avance na entrada para o próximo símbolo terminal;
else /* ocorreu um erro */; }
}

• Esse pseudocódigo é não determinista, pois escolhe a


produção-A a ser aplicada de uma maneira arbitrária.
Compiladores ayslanyawanderley@fiponline.edu.br 8
A. S. D. recursiva com retrocesso
• Análise recursiva com retrocesso.

• Considere a sentença [ a ] derivada a partir da gramática


abaixo:

S → a | [L]
L → S;L|S

Compiladores ayslanyawanderley@fiponline.edu.br 9
A. S. D. recursiva com retrocesso
• Reconhecimento da sentença [ a ]

Compiladores ayslanyawanderley@fiponline.edu.br 10
A. S. D. recursiva com retrocesso
• Reconhecimento da sentença [ a ]

Compiladores ayslanyawanderley@fiponline.edu.br 11
A. S. D. recursiva com retrocesso
• Exercício: Considere a gramática:
S → cAd
A → ab | a

Realize o passo a passo da ASDR com retrocesso para a


cadeia w = cad.

Compiladores ayslanyawanderley@fiponline.edu.br 12
Funções First e Follow
• Funções associativas a uma gramática G.

• Permitem escolher qual produção aplicar, com


base no próximo símbolo da entrada.

• Durante a recuperação de erro, conjuntos de


tokens produzidos por FOLLOW podem ser
usados como tokens de sincronismo.

Compiladores ayslanyawanderley@fiponline.edu.br 13
Funções First e Follow
• Funções que auxiliam a construção de analisadores
sintáticos;

• First
– Define o conjunto de símbolos que iniciam derivações a partir
de uma sequência de símbolos terminais e não terminais
– c está em First(A)
• Follow
– Define o conjunto de símbolos que se pode seguir a derivar
após um dado símbolo não terminal
– a está em Follow(A) ... :

Compiladores ayslanyawanderley@fiponline.edu.br 14
Funções First e Follow

• FIRST(a), onde a é qualquer cadeia de símbolos da


gramática, como sendo o conjunto de símbolos
terminais que iniciam as cadeias derivadas de a.

• As regras abaixo definem esse conjunto:

1) Se a * ε então ε é um elemento de FIRST(a);

2) Se a * aδ então a é um elemento de FIRST(a),


sendo a um símbolo terminal e δ uma forma sentencial
qualquer, podendo ser vazia.
Compiladores ayslanyawanderley@fiponline.edu.br 15
Funções FIRST - Regras
• Para calcular FIRST(X) de todos os símbolos X da
gramática, as seguintes regras devem ser aplicadas até
que não haja mais terminais ou ε:
– Se X é um símbolo terminal, então FIRST(X)={X}
– Se X é um símbolo não terminal e X::= Y1Y2...Yk é uma produção
p/ 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(Y ),... FIRST(Yi- ).
1 1

• adicione ε se ε está em FIRST(Yj) para todo j = 1,2,...k


• Se Y1 não derivar ε, nada mais deve ser acrescentado a
FIRST(X)
– Se X::= ε é uma produção, então acrescente ε a FIRST(X)
Compiladores ayslanyawanderley@fiponline.edu.br 16
Função FOLLOW - Regras
• Para calcular FOLLOW(A) de todos os não terminais A,
as seguintes regras devem ser aplicadas até que nada
mais possa ser acrescentado a nenhum dos conjuntos
FOLLOW:
– Coloque $ em FOLLOW(S), onde $ é o marcador de fim da entrada

– Se houver uma produção A::αBβ, então tudo em FIRST(β) exceto ε


está em FOLLOW(B)

– Se houver uma produção A::= αB, ou uma produção A::= αBβ, onde
o FIRST(β) contém ε, então inclua o FOLLOW(A) em
FOLLOW(B)

Compiladores ayslanyawanderley@fiponline.edu.br 17
Exemplo
• Seja a Gramática
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) = {$}

Compiladores ayslanyawanderley@fiponline.edu.br 18
Exercícios
• Exercícios: A partir da gramática a seguir:

S > cAd
A>b|a

Calcule:
First(S):
First(A):
Follow(S):
Follow(A):

Compiladores ayslanyawanderley@fiponline.edu.br 19
Exercícios
• Exercícios: A partir da gramática a seguir:

COMAND > COND | ITER | ATRIB


COND > if EXPR then COMAND
ITER > repeat LISTA until EXPR | while EXPR do COMAND
ATRIB> id := EXPR

Calcule:
First(ATRIB):
First(ITER):
First(COND):
First(COMAND):
Compiladores ayslanyawanderley@fiponline.edu.br 20
A. S. D. Preditiva Recursiva

• O símbolo sobre o cabeçote de leitura determina


exatamente qual produção deve ser aplicada na
expansão de cada nãoterminal;

• Deve ser possível determinar, dado um símbolo a, qual


não terminal deve ser derivado.

Compiladores ayslanyawanderley@fiponline.edu.br 21
A. S. D. Preditiva Recursiva
• Exemplo:
COMANDO → if EXPR then COMANDO | while EXPR do
COMANDO | repeat LISTA until EXPR | id := EXPR

• Se as produções de COMANDO fossem escritas assim:


COMANDO → CONDICIONAL | ITERATIVO | ATRIBUIÇÃO
CONDICIONAL → if EXPR then COMANDO
ITERATIVO → repeat LISTA until EXPR | while EXPR do
COMANDO
ATRIBUIÇÃO → id := EXPR

Compiladores ayslanyawanderley@fiponline.edu.br 22
A. S. D. Preditiva Recursiva
• Ainda assim continuaria sendo possível determinar
univocamente a produção a ser usada.

• Porém, seria necessário determinar quais terminais


iniciam as sentenças deriváveis a partir de
CONDICIONAL, ITERATIVO e ATRIBUIÇÃO:
– CONDICIONAL → if EXPR then COMANDO
– ITERATIVO → repeat LISTA until EXPR | while EXPR do
COMANDO
– ATRIBUIÇÃO → id := EXPR

Compiladores ayslanyawanderley@fiponline.edu.br 23
A. S. D. Preditiva Recursiva
• Dado um símbolo não terminal A definido por várias
alternativas.

– Se A → β1 | β2 | ... | βN. A implementação de um


reconhecedor recursivo preditivo para A exige que os
conjuntos FIRST de β1 | β2 | ... | βN sejam disjuntos dois a
dois
• Exemplo:

Compiladores ayslanyawanderley@fiponline.edu.br 24
A. S. D. Preditiva Recursiva
Implementação do recursivo preditivo

Para o não terminal COMANDO:


SE token = “if‟ ENTÃO
INVOCA CONDICIONAL
SENÃO SE token = “while‟ OU token = “repeat” ENTÃO
INVOCA ITERATIVO
SENÃO SE token = ‘id’ ENTÃO
INVOCA ATRIBUIÇÃO
SENÃO RETORNA FALSE

Compiladores ayslanyawanderley@fiponline.edu.br 25
A. S. D. Preditiva Recursiva
Exigem que:

(1) A gramática não tenha recursividade à esquerda;

(2) A gramática esteja fatorada à esquerda;

(3) Os não terminais com mais de uma regra de produção


possuam conjunto PRIMEIROS capazes de identificar
univocamente.

Compiladores ayslanyawanderley@fiponline.edu.br 26
A. S. D. Preditiva Tabular
• A A.S.D. Preditiva Tabular ou Análise Sintática LL,
implementa o descendente recursivo utilizando
explicitamente uma pilha.

• A ideia é a seguinte:
– O analisador sintático recebe uma sequência de entrada (a
sentença a ser analisada);
– Manipula uma estrutura de dados tipo pilha (onde monta a
ADS);
– Para cada símbolo de entrada, consulta uma tabela de análise
sintática para saber que regra aplicar;
– Emite uma sequência de saída (regras que estão sendo
aplicadas).
Compiladores ayslanyawanderley@fiponline.edu.br 27
A. S. D. Preditiva Tabular
• Entrada do analisador:
– Sentença a ser analisada, seguida por um símbolo delimitador
($).
– Pilha: contém uma sequência de símbolos da gramática,
precedida pelo indicador de base de pilha ($).
– Tabela de análise sintática: é uma matriz M[A, a], onde 'A' é
um não terminal e 'a' é um terminal ou cifrão ($).

• Saída do analisador:
– Constará das produções aplicadas a partir do símbolo inicial
(S), na geração da sentença.

Compiladores ayslanyawanderley@fiponline.edu.br 28
Algoritmo para construir a tabela
• Calcular os conjuntos First e Follow

• Para cada produção A → α


1. Para cada a ∈ First(α)
– incluir a produção A → α em M[A,a]
2. Se ε ∈ First(α)
– incluir a produção A → α em M[A,b] para cada b em Follow(A)
3. Se ε ∈ First(α) e $ ∈ Follow(A)
– incluir A → α to M[A,$]
• Todas entradas não definidas são erros.

Compiladores ayslanyawanderley@fiponline.edu.br 29
A tabela preditiva M(X, t)
• Tabela Bi-dimensional:
– Dimensão 1: Não terminal X
– Dimensão 2: Caractere da entrada (terminal) t
– A entrada (X,t) contém a regra de produção a aplicar

Compiladores ayslanyawanderley@fiponline.edu.br 30
A tabela preditiva M(X, t)
• Tabela Bi-dimensional:
– Dimensão 1: Não terminal X
– Dimensão 2: Caractere da entrada (terminal) t
– A entrada (X,t) contém a regra de produção a aplicar

Compiladores ayslanyawanderley@fiponline.edu.br 31
A tabela preditiva M(X, t)
• Tabela Bi-dimensional:
– Dimensão 1: Não-terminal X
– Dimensão 2: Caractere da entrada (terminal) t
– A entrada (X,t) contém a regra de produção a aplicar

Compiladores ayslanyawanderley@fiponline.edu.br 32
A tabela preditiva M(X, t)
• Tabela Bi-dimensional:
– Dimensão 1: Não-terminal X
– Dimensão 2: Caractere da entrada (terminal) t
– A entrada (X,t) contém a regra de produção a aplicar

Compiladores ayslanyawanderley@fiponline.edu.br 33
A tabela preditiva M(X, t)
• Tabela Bi-dimensional:
– Dimensão 1: Não-terminal X
– Dimensão 2: Caractere da entrada (terminal) t
– A entrada (X,t) contém a regra de produção a aplicar

Compiladores ayslanyawanderley@fiponline.edu.br 34
A tabela preditiva M(X, t)
• Tabela Bi-dimensional:
– Dimensão 1: Não-terminal X
– Dimensão 2: Caractere da entrada (terminal) t
– A entrada (X,t) contém a regra de produção a aplicar

Compiladores ayslanyawanderley@fiponline.edu.br 35
A tabela preditiva M(X, t)
• Tabela Bi-dimensional:
– Dimensão 1: Não-terminal X
– Dimensão 2: Caractere da entrada (terminal) t
– A entrada (X,t) contém a regra de produção a aplicar

Compiladores ayslanyawanderley@fiponline.edu.br 36
Funcionamento do parser
• Seja X o símbolo no topo da pilha
• Seja a o símbolo de entrada (terminal!) a analisar

1. Se X = $ e a = $ : para e reconheceu uma sentença.


2. Se X = a != $ : desempilha X e avança de um símbolo na
entrada.
3. Se X é não terminal: Consulta a tabela M(X, a)
4. Se for vazia: ERRO
5. Se contém X -> UVW, então substitui na pilha X por
UVW (U no topo).
Compiladores ayslanyawanderley@fiponline.edu.br 37
Usando a tabela
• String: “cbca”

Compiladores ayslanyawanderley@fiponline.edu.br 38
Exercício
FIRST(E) = FIRST(T) = FIRST(F) = {¬, id}
E → T E’ FIRST(E’) = {v, ε }
E’ → v T E’ | ε FIRST(T’) = {&, ε}
T → F T’ FOLLOW(E) = {$}
T’ → & F T’ | ε FOLLOW(E’) = {$}
FOLLOW(T) = {v,$}
F → ¬ F | id FOLLOW(T’) = {v,$}
FOLLOW(F) = {&, v, $}

Construa a tabela preditiva e analise a sentença:


id v id & id
Compiladores ayslanyawanderley@fiponline.edu.br 39
Referências
• Aho, A. V.; Sethi, R. e Ullman, J. D. Compiladores:
Princípios, Técnicas e Ferramentas. Pearson, 2008.

Compiladores ayslanyawanderley@fiponline.edu.br 40

Вам также может понравиться