• Nenhum resultado encontrado

apr-comp-05

N/A
N/A
Protected

Academic year: 2021

Share "apr-comp-05"

Copied!
84
0
0

Texto

(1)

Compiladores

(2)

Análise Sintática

Segunda fase

Função: verificar se as construções

usadas no programa estão

gramaticalmente corretas.

Dada uma GLC e um programa fonte, o

objetivo é verificar se o programa pertence

a linguagem gerada pela gramática.

(3)

Recebe uma seqüência de tokens do AL e

produz uma árvore de derivação, se a

seqüência é válida

ou relata o erro encontrado.

Estratégias:

Top-down

(4)
(5)
(6)
(7)

Árvore a) corresponde a derivação

S=>cAd

Para A existem duas alternativas:

Neste ponto o analisador deve escolher uma

das alternativas

Mas deverá se lembrar das próximas

alternativas

(8)

Escolhendo a primeira alternativa

Árvore b)

S=>cabd

Falha: sentença gerada não corresponde a

sentença de entrada

Analisador deverá efetuar o retrocesso

Voltar ao último ponto de escolha

(9)

Na segunda alternativa

Árvore c)

S=>cad

Sentença reconhecida pela gramática

Problema:

O processo de backtracking é ineficiente

Difícil de identificar com precisão o local do erro

(10)

Outro exemplo:

 S → a | [ L ]

 L → S;L | S

Implementação:

 Para cada símbolo não terminal da gramática é desenvolvida uma função que explora todas as derivações.

 Pontos de recursão (marcas) são utilizados para sinalizar possível ponto de reinício.

Exemplo:

 Considere a sentença: [ a ]

(11)
(12)
(13)

LETOKEN: retorna o 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.

(14)
(15)
(16)

O símbolo sob o cabeçote de leitura

determina exatamente qual produção

deve ser aplicada na expansão de cada

não-terminal.

Dado um símbolo a sob o cabeçote de leitura e

o não-terminal A a ser derivado, qual das

produções alternativas de A é a que deve ser

derivada, unicamente, a seqüência iniciada por

(17)

Exemplo: analisador sintático recursivo para reconhecer expressões aritméticas envolvendo identificadores, valores inteiros e reais.

(18)
(19)
(20)
(21)

Análise Sintática Descendente Tabular

Não recursivo

Utilizam pilha ao invés de chamadas recursivas

Implementa um autômato de pilha controlado por tabela

de análise

O lado direito irá substituir o símbolo não-terminal que

se encontra no topo da pilha.

O analisador busca a produção a ser aplicada na tabela

de análise, levando em conta o não-terminal no topo da

pilha e o token sob o cabeçote de leitura.

(22)
(23)

A fita: contém a sentença a ser analisada,

seguida de $, símbolo que marca o fim da

sentença.

A pilha, inicialmente, contém $, que marca sua

base, seguido do símbolo inicial da gramática.

A tabela de análise é uma matriz M com n linhas

e t+1 colunas:

n – número de símbolos não-terminais

(24)

Construção da Tabela Sintática

Maior dificuldade em construir o AS.

É necessário computar duas funções

associadas à gramática:

FIRST

(25)
(26)
(27)
(28)
(29)
(30)
(31)
(32)
(33)
(34)

Se:

Cada entrada da tabela existe apenas uma

produção

Gramática que originou a tabela é do tipo LL(1)

• Sentenças geradas pela gramática são passíveis de serem analisadas da esquerda para a direita

(35)

O analisador é controlado por um

programa que considera:

X, o símbolo no topo da pilha,

e a é um símbolo terminal da entrada.

Estes dois símbolos determinam a ação

do analisador.

(36)

Há três possibilidades então:

1) Se X = a = $, o analisador encerra o

reconhecimento, com sucesso.

2) Se X = a ≠ $, o analisador desempilha X da pilha e

avança o ponteiro de entrada ao próximo símbolo de

entrada.

3) Se X é um não-terminal, o programa consulta a

entrada M[X,a] da tabela de derivação M. Esta

entrada pode ser uma produção de X ou um erro. Se,

por exemplo, M[X,a] = { X=>UVW }, o analisador

substitui X no topo da pilha por WVU (com U no

topo).

(37)

Algoritmo de análise sintática preditiva

tabular

Entrada: para uma gramática G

uma cadeia w

(38)
(39)
(40)

Gramática LL(1)

Uma gramática não recursiva à esquerda

é LL(1) se, e somente se:

Sempre que A → α, A → β são produções,

ocorrer que:

1) a interseção dos conjuntos FIRST(α) e FIRST(β) é

vazia;

2) no máximo um dos dois, α ou β , deriva a palavra

vazia;

Se β =>* ε, então a interseção de FIRST(α) COM

FOLLOW(A) é vazia.

(41)
(42)
(43)

A → α, A → β serão usadas para preencher a

linha A da matriz.

Se as interseções não fossem vazias

(44)

Exercício 1

Para a gramática abaixo calcule FIRST,

FOLLOW. Depois gere a Tabela de Análise

Preditiva e faça a seqüência de movimentos do

analisador para a seguinte sentença id+id*id$

(45)

Exercício 2

Para a gramática abaixo calcule FIRST,

FOLLOW. Depois gere a Tabela de Análise

Preditiva e faça a seqüência de movimentos do

analisador para a seguinte sentença id+id*id$

(46)

Solução Exercício 1

(47)
(48)

TABELA

(49)
(50)
(51)

Solução Exercício 2

(52)
(53)
(54)
(55)

Análise Sintática Redutiva (Bottom-Up)

A análise Bottom-up tenta construir uma árvore

gramatical para uma cadeia de entrada

começando pelas folhas, e trabalhando árvore

acima em direção à raiz.

A cada passo de redução, uma sub-cadeia

particular que reconheça o lado direito de uma

produção, é substituída pelo símbolo à

esquerda daquela produção.

(56)

Como funciona?

Configuração inicial do analisador: fita de entrada

contém a sentença a ser analisada seguida de um

$, e a pilha contém apenas o marcador de base $.

Analisador sintático empilha zero ou mais símbolos

na pilha até que um handle (lado direito de uma

produção) surja no topo da pilha. Este então é

substituído por seu lado esquerdo. Este ciclo é

repetido até termos uma entrada vazia e o símbolo

inicial no topo da pilha.

(57)
(58)

Duas classes de analisadores do tipo

empilha-reduz:

1) analisadores de precedência de operadores,

muito eficientes no reconhecimento de expressões

aritméticas e lógicas;

2 ) analisadores LR, que reconhecem a maior parte

das linguagens livres do contexto.

(59)

Analisadores de Precedência de Operadores

Esses analisadores operam sobre a classe das

gramáticas de operadores.

Nessas gramáticas, os não-terminais aparecem sempre separados por símbolos terminais (isto é, nunca

aparecem dois não-terminais adjacentes) e, além disso, as produções não derivam a palavra vazia (ex: nenhum lado direito de produção é "ε").

Por exemplo, a gramática:

E → E O E | ( E ) I id

O → + I - I * I / I **

 não é de precedência de operadores

lado direito E O E contém três não-terminais consecutivos.

(60)

Desvantagens: dificuldade em lidar com operadores iguais que tenham significados distintos

• por exemplo, o operador "-", que pode ser binário ou unário.

Para identificar o handle, os analisadores de precedência de operadores baseiam-se em relações de precedência existentes entre os tokens (operandos e operadores).

São três as relações de precedência entre os terminais:

• < , > e =.

Sendo a e b símbolos terminais, tem-se que:

a < b significa que a tem precedência menor que b;

(61)

A utilidade dessas relações na análise de uma

sentença é a identificação do handle :

< identifica o limite esquerdo do handle;

= indica que os terminais pertencem ao mesmo handle;

> identifica o limite direito do handle.

Esses analisadores são guiados por uma tabela de

precedência, cujas relações definem o movimento

que o analisador deve fazer:

• empilhar, reduzir, aceitar ou chamar uma rotina de atendimento a erro.

(62)

Tabela de precedência para operações lógicas: id v & ( ) $ id > > > > v < > < < > > & < > > < > > ( < < < < = ) > > > > $ < < < < E → E v E | E & E | (E) | id

(63)

A tabela é uma matriz quadrada que relaciona todos

os terminais da gramática mais o marcador $.

Desses terminais, poucos são realmente operadores

(neste exemplo, os operadores reais são apenas v e

& ).

É importante saber que, na tabela. os terminais nas

linhas representam terminais no topo da pilha, e os

terminais nas colunas representam terminais sob o

(64)

Basicamente, um analisador de precedência

funciona da seguinte maneira:

• Seja a o terminal mais ao topo da pilha e b o terminal sob o cabeçote de leitura:

I) se a < b ou a = b então empilha;

2) se a > b procura o handle na pilha (o qual deve estar delimitado pelas relações < e > ) e o substitui pelo nãc-terminal correspondente.

Na pilha. o handle vai desde o topo até (inclusive) o

primeiro terminal x que tem abaixo de si um terminal y tal que y < x.

Mais ao topo porque no topo pode estar um não-terminal.

Na verdade, os analisadores de precedência desconsideram os não-terminais da gramática, levando em conta apenas a presença dos mesmos (suas

(65)

Movimentos de um analisador de precedência de operadores:

Pilha Relação Entrada Ação Handle

$ < id v id & id $ Empilha id

$ id > v id & id $ Reduz id

$ E < v id & id $ Empilha v

$ E v < id & id $ Empilha id

$ E v id > & id $ Reduz id

$ E v E < & id $ Empilha &

$ E v E & < id $ Empilha id

$ E v E & id > $ Reduz id

$ E v E & E > $ Reduz E & E

$ E v E > $ Reduz E v E

(66)

Algoritmo:

Entrada: matriz de relações de precedência e a sentença a ser analisada s$.

Resultado: a sequência de produções aplicadas no reconhecimento de s, caso s pertença a L(G), caso contrário, uma indicação de erro.

Método: repita

se $S é o topo da pilha e $ está sob o cabeçote de leitura então aceita e pára

senão /* seja a o terminal mais ao topo da pilha e b o terminal sob o cabeçote */ se a < b ou a = b

então empilha b e avança o cabeçote senão se a > b

então repita /* reduzir */ desempilha

até encontrar a relação < entre o terminal do topo e o último desempilhado;

empilha o não-terminal correspondente imprime a produção aplicada

(67)

Construção da tabela de precedência de operadores

• Maior dificuldade

• Dois métodos:

 Intuitivo: vamos ver!

(68)

Método intuitivo:

• Este método obtém as relações de precedência a partir do conhecimento da associatividade e da precedência dos operadores da gramática.

• Considere dois operadores Θ1 e Θ2.

1) Se o operador Θ1 tem maior precedência que o

operador Θ2, então Θ1 (na pilha) > Θ2 (na entrada), e Θ2 (pilha) < Θ1 (entrada). Por exemplo, o operador de multiplicação * tem maior precedência que o operador +, logo, * > +. e + < *.

(69)

2) Se Θ1 e Θ2 têm igual precedência (ou são iguais) e

são associativos à esquerda, então Θ1 > Θ2, e Θ2 > Θ1; se são associativos à direita. então Θ1 < Θ2 e Θ2 < Θ1.

• Por exemplo:

os operadores * e / têm a mesma precedência e são associativos à esquerda, portanto, * > /, e / > *.

 o operador de exponenciação ** é associativo à direita, logo ** < **.

(70)

Θ < id Θ < ( Θ > ) Θ > $

id > Θ ( < Θ ) > Θ $ < Θ

3) As relações entre os operadores e os demais tokens

(operandos e delimitadores) são fixas. Para todos os operadores Θ, tem-se:

4) As relações entre os tokens que não são operadores

também são fixas:

( < ( ) > ) id > ) $ < (

( = ) ) > $ id > $ $ < id

( < id

(71)

Exemplo:

Dada a gramática:

• E → E + E | E * E | E ** E | ( E ) | id

tem-se os seguintes níveis de precedência e

associatividade entre os operadores:

• ** tem maior precedência e é associativo à direita;

• * tem precedência intermediária e é associativo à esquerda;

(72)

+ * ** ( ) id $ + > < < < > < > * > > < < > < > ** > > < < > < > ( < < < < = < ) > > > > > id > > > > > $ < < < < < Aceita

(73)

Analisadores LR(k)

K => número de símbolos de exame na entrada

(lookahead)

R => right-most derivation (derivação mais à direita)

L => left to right scanning (direção de leitura da

cadeida de entrada)

(74)

Vantagens:

• Analisadores LR servem para reconhecer a maior parte das construções de linguagens de programação.

• O método de análise LR é o mais genérico dentre os métodos de empilhar-reduzir sem retrocesso.

• Um analisador LR pode detectar um erro sintático tão cedo quanto possível numa varredura da entrada da esquerda p/ direita.

Desvantagem:

• Implementação manual bastante trabalhosa, mas

adequado para ser usado por geradores automáticos de parsers (eg, yacc/bison).

(75)
(76)

 A combinação entre símbolo de estado e o símbolo da entrada é usada para indexar uma tabela sintática e determinar o

funcionamento do analisador.

 A tabela sintática é dividida em duas partes funcionais: ação (action) e desvio (goto).

 A partir de Sm (estado no topo da pilha) e ai (símbolo da entrada), consultamos a célula ação[sm, ai] que pode ter os seguintes

valores:

empilhar s, no qual s é um estado

• reduzir utilizando a produção A → B

• aceitar

• erro

 A função desvio toma um estado e um símbolo gramatical como argumento e produz um novo estado como saída.

 O algoritmo de análise LR é utilizado na implementação de diversos tipos de analisadores: LR(0), SLR, LR(1) e LALR(1).

(77)

Algoritmo de análise sintática LR:

Entrada: uma cadeia de entrada w e uma tabela sintática LR

Saída: Se w estiver em L(G), produz uma decomposição ascendente (bottom-up) para w, caso contrário indica um erro.

Método:

 Inicialmente o analisador sintático possui s0 (estado incial) na pilha e w$ no buffer de entrada.

 O analisador sintático executa o algoritmo a seguir até que uma ação de aceitação ou de erro seja atingida.

(78)
(79)

O analisador funciona basicamente como segue:

Seja Em, o estado do topo da pilha e ai o token sob o

caheçote de leitura. O analisador consulta a tabela AÇÃO[Em, ai]. que pode assumir um dos valores:

 a) empilha E,: causa o empilhamento de "ai Em";

 b) reduz n (onde n é o número da produção A → β): causa o desempilhamento de 2 * r símbolos. onde r = | β |, e o empilhamento de "AEy" onde Ey resulta

da consulta à tabela de TRANSIÇÃO[Em-r, A ];

 c) aceita: O analisador reconhece a sentença como válida;

(80)
(81)
(82)
(83)

Exercício:

• Dada a gramática abaixo e a tabela de transição, verifique os passos do analisador para a cadeia de entrada id * id + id

(84)

Referências

Documentos relacionados

Neste caso, embora possam existir nestes locais, forrageiras de alta qualidade, como o capim-de-capivara (Hymenachne amplexicaulis), a disponibilidade de recursos forrageiros vai

alimentares: de crianças menores de seis meses: Aleitamento Materno Exclusivo (AME): nenhum outro alimento é oferecido à criança, além do leite materno; Aleitamento Materno

No projeto, o levantamento florístico identificou mais de 130 espécies medicinais dentro da área de estudo (Estações Ecológica e Experimental de Itirapina).. Para o Guia Ilustrado

ao final do processamento da mesma, a pilha estiver vazia, independentemente do estado em que o AP se encontra;. P

Outras atividades como essa questão podem ser propostas, mas lembramos que não interessa tanto, nesse caso, a realização de muitos cálculos, quanto, por exemplo,

O tratamento controle negativo aumentou o consumo de ração e piorou o ganho de peso e a conversão alimentar em comparação com o controle positivo e comparado ao tratamento controle

Em Atendimento às disposições estabelecidas pela Pró-Reitoria de Pesquisa e Pós-Graduação (http://www.prppg.ufrpe.br), por meio da Coordenadoria Geral dos Programas

10 unidades.. Meios de Comunicação | 12 unidades.. Animais Diversos para Colorir | 100. 20 unidades.. Meios de Transportes Animados | 009 12 unidades. interativo) 28