1 linguagens formais e tradutores análise sintática - 1 prof. andré luis meneses silva...

Post on 17-Apr-2015

115 Views

Category:

Documents

8 Downloads

Preview:

Click to see full reader

TRANSCRIPT

1

Linguagens Formais e Tradutores

Análise Sintática - 1

Prof. André Luis Meneses Silvaalms@ufs.br

www.dsi.ufs.br

2

Análise Sintática (parsing) Verificar se um programa é

sintaticamente válido Reconhecer a estrutura

sintática do programa Produzir uma representação

abstrata dos programas (sintaxe abstrata)

Produzir mensagens de erros. Se recuperar.

analisadorléxico

parser

Tokens

Programa fonte

AnalisadorSemântico

Árvore Abstrata

3

Especificação da Sintaxe Definições regulares não têm o poder de expressão

suficiente Gramáticas livres de contexto = def. regulares

+ recursão Uma GLC G é definida por

um conjunto de produções (ou regras) simbolo → simbolo simbolo ....

simbolo Cada símbolo pode ser terminal ou não terminal O símbolo à esquerda de → é um não terminal Existe um símbolo destacado: símbolo inicial

4

Especificação da Sintaxe ExemploE → E+E ouE → E+EE → E*E | E*EE → num | num

E → (E) | (E) Derivação

E E+E E + E + E num + E + E num + E + num num + num + num

5

Árvore de derivação

E

E E+

E E+

num num

num

yield

6

Derivação mais à esquerdaE E+E E + E + E num + E + E num + num + E num + num + num Gramática é ambígua

sse

existe mais de uma árvore de derivação para uma mesma sentença (yield)sseexiste mais de uma derivação mais à esquerda

7

E

E E+

E E+

num num

E

E E+

E E+

num num

num

num

8

Gramáticas ambíguas

Problemáticas para compilação Qual é a estrutura gramatical escolhida?

Como lidar Adicionar regras extra-gramaticais

precedência de operadores, associatividade, else opcional, ...; ou

Usar GLC não ambígua equivalente com a original

9

Gramáticas ambíguas Precedência e associatividade podem ser

codificadas dentro da GLC

E → E+T | E-T | TT → T*F | T/F | FF → id | num | (E)

Regras recursivas à esq. associatividade à

esquerda Camada mais alta precedência mais baixa

10

Gramática por camadas - exemplo

E → E + T | E - T | TT → T * F | T / F | FF → -F | +F | VV → V . id | V [ E ] | AA → id | num | (E)

11

else opcionalS if E then S else S | if E then S | outro

Qual é a árvore deif E1 then if E2 then S1 else S2 ?

12

else opcionalS if E then S else S | if E then S | outro

Qual é a árvore deif E1 then if E2 then S1 else S2 ?

LPs adotam: else sempre casa com o if mais próximo.Podemos codificar isto numa GLC, assim:

S S' | S"S' if E then S' else S' | outroS" if E then S | if E then S' else S"

13

Métodos de Análise Métodos universais são ineficientes (CYK e outros) Top Down (recursivos-descendentes)

Constroem a árvore de deriv. em pré-ordem Caso particular: parser preditivos (LL(n))

Decidem que produção usar olhando n tokens de lookahead

LL(1) são adequados para implementação manual Servem para a maioria das linguagens Exigem transformações na gramática original

Bottom Up (pós-ordem) Cobrem uma classe mais ampla de gramáticas Menos transformações Usualmente construídos com ferramentas

14

Parser Recursivo Descendente Pode envolver retrocesso (Backtracking)

L → c A d

A → ab | a

O parser de cad exige retrocesso

Ineficiente para ser usado na prática Em geral, LPs não precisam de retrocesso

15

Análise preditivo Não precisam de retrocesso Porém, só servem para um tipo de gramáticas -- LL(n)

não permitem recursão à esquerda LL(1): Se queremos expandir A e temos a na entrada

Só deve ser possível usar uma única produção a é chamado de lookahead

Exemplo: Sintaxes com palavras reservadas como

S if E then S else S | while E do S | begin L end

Em gramáticas LL(n) usa-se n símbolos de lookahead

16

Parser preditivo

S if E then S else S | begin S L | print E

L end | ; S LE num = num

void S( ) { switch(tok) { case IF: proxToken( ); E( ); reconhecer(THEN); S( ); reconhecer(else); S( ); break; case BEGIN: proxToken( ); S( ); L( ); break; case PRINT: proxToken( ); E( ); break; default: erro( ); } }

Um procedimento para cada não terminal Um switch com um caso para cada produção

17

void L( ) { switch(tok) { case END: proxToken( ); break; case SEMICOLON: proxToken( ); S( ); L( ); break; default: erro( ); } }

void E( ) { switch(tok) { case NUM: proxToken( ); reconhecer(EQ); reconhecer(NUM); break; default : erro( ); } }

void proxToken( ) { tok = scanner.proximoToken( ).codigo; }

void reconhecer(int t) { if (t!=tok) erro( ); else tok = scanner.proximoToken( ).codigo; }

18

Gramáticas não LLV V [ E ] | id

O procedimento V( ) chama recursivamente V( ) sem consumir nenhum token. Entra em loop.

E num + E | num * E | num | (E)Com num inicialmente scaneado, que produção escolho?Porém, ela é LL(2).

E T + E | T T F * T | FF num | (E)

Não é LL(2). (num)+(num)

“( num” não determina a produção a escolher

19

Primeiro e Seguinte Primeiro()={a | * a} { | * } Seguinte(A)={a | S * Aa}

Permitem ver se a gramática é LL(1) Permitem construir a tabela sintática preditiva

c/entrada contém a produção a ser aplicada para um par lookahead – terminal

ExemploZ d Y X Y W b | X Y W Z | c | a

Primeiro(Z)=?

20

Algoritmo para Primeiro Inicializar Primeiro(a)={a}, para todo terminal a

Se X , adicionar a Primeiro(X)Repetir até não poder adicionar mais

Se X Y1Y2...Yk, Primeiro(Y1), ... , Primeiro(Yi-1)

(i.e., Y1Y2..Yi-1 ), ea Primeiro(Yi)então adicionar a a Primeiro(X)

Primeiro(X1X2...Xn) = Primeiro(X1), se Primeiro(X1);Primeiro(X1X2...Xn) = Primeiro(X1)...Primeiro(Xi+1) - {} se Primeiro(Xk), para k =1...i , e Primeiro(Xi+1); ePrimeiro(X1X2...Xn) = Primeiro(X1) ... Primeiro(Xn) se Primeiro(Xk), para k = 1...n

21

Z d Y X Y W b | X Y W Z | c | a

abcdXYZW

a

b

c

d

, a, c

, c

a, b, c, d

b

Primeiro

22

Seguinte - Algoritmo Seguinte(A)={a | S * Aa} Colocar $ em Seguinte(S)

Repetir até não poder adicionar mais Se existir AB

adicionar Primeiro()-{ε} a Seguinte(B)

Se existir AB ouAB e Primeiro()

adicionar Seguinte(A) a Seguinte(B)

23

Z d Y X Y W b | X Y W Z | c | a

XYZW

c, b

c, b

$

a, b, c, d

Seguinte

S Z $

24

Tabela sintática preditiva

Z d Y X Y W b | X Y W Z | c | a

X a X Y X Y

Y Y cY

W b

Z X Y W Z Z X Y W Z Z X Y W ZZ d

Z X Y W Z

X

Y

WZ

a b c d

A é uma entrada para (A,a) na tabela sse:– Se A e a Primeiro() – Se A, Primeiro() e a Seguinte(A)

25

G é LL(1) sse a sua tabela sintática preditiva é determinística

LL(n): Com n lookaheads as entradas para as colunas serão cadeias de tamanho n

Gramáticas não LL: Nenhuma G ambígua é LL Nenhuma G com recursão à esquerda é LL

V V [ E ] | idid Primeiro(V[E])

26

Eliminando recursão à Esquerda• E → E+T | E-T | T

Podemos escrever sem recursão à esquerda, assimE → T E'E'→ + T E' |

Em geral, se temosA → A1 | A2 |...| An

| 1 | 2 |...| m

EscrevemosA → 1A' | 2A' |...| mA'A' → 1A' | 2A' |...| nA' |

Dificuldades futuras Árvore de derivação associativa à direita Geração de árvore abstrata exige tratamento especial

27

Tabela preditiva da gramática de expressões anterior

S → E $E → T E'E'→ + T E' |

28

Tirando em evidência (fatoração) à esquerda

• A → | |...podemos escrever

A → A' |... A' → |

Por exemploD → int Id ; | int Id ( A ) ; | outro

pode ser re-escrito comoD → int Id D' | outroD' → ; | ( A ) ;

Pequena dificuldade: A estrutura gramatical foi mudada

29

Exemplos de fatoração

E id E' | num

E' (E) | [e] |

E id(E) |id[e] |id |num

30

• S if E then S else S | if E then S | outro

Pode ser escrito comoS if E then S X

| outroX else S |

Porém, neste caso, a fatoração não é suficiente pois a nova gramática ainda é ambígua

Em (X,else), a tabela vai ter duas entradas:

Xelse S e X Solução ad-hoc: (adotada pela javacc, por ex.)

Escolher sempre a primeira regra (neste caso, o else associa com o if mais próximo, como esperado).

Não há prescrição geral.

31

Recuperação de erros em Parsers preditivos

Quando acontecem?– A( ) foi chamado com o lookahead a e a entrada (A,a)

na tabela preditiva é vazia; ou Ao reconhecer(a) o lookahead é diferente de a

Desespero trabalha bem Pular todos os tokens até achar um de sincronização Heurísticas para o conjunto de sincronização Ajustes por tentativa e erro

Outros métodos Substituir o token. Exemplo:

lookahead = "," e Reconhecer(";") falha Inserindo tokens (inseguro, pode entrar em loop)

Inserir ";” quando detectar sua falta

32

Modalidade de despero -- Heurísticas

• A( ) foi chamado com lookahead a Ponto de partida: sincronização = Seguinte(A) e A( )

é resumido Acrescentar como sincronização as palavras chaves de

construções mais altas ou da mesma altura (se houver seqüências). Por ex.

Se faltar “;” e começar depois um while, o while poderia ser ignorado sem esta heurística

Expressões estão dentro de comandos Usar produção vazia (ou que gera vazio) como default

Ao reconhecer token Ignorar token (apagar) – sincroniza com todos

33

Resumo Análise Sintática Gramáticas

Ambigüidade Classificação dos métodos de análise Análise top-down

Análise preditivo – Gramáticas LL Tabela sintática preditiva Fatoração e eliminação da recursão á esquerda Recuperação de erros

34

Bibliografia Seções 4.1-4.6 do livro do Dragão Seções 3.1 e 3.2 do livro do Tigre

top related