A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

1 Linguagens Formais e Tradutores Análise Sintática - 1 Prof. André Luis Meneses Silva

Apresentações semelhantes


Apresentação em tema: "1 Linguagens Formais e Tradutores Análise Sintática - 1 Prof. André Luis Meneses Silva"— Transcrição da apresentação:

1 1 Linguagens Formais e Tradutores Análise Sintática - 1 Prof. André Luis Meneses Silva

2 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. analisador léxico parser Tokens Programa fonte Analisador Semântico Árvore Abstrata

3 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 4 Especificação da Sintaxe Exemplo E E+E ou E E+E E E*E | E*E E num | num E (E) | (E) Derivação E E+E E + E + E num + E + E num + E + num num + num + num

5 5 Árvore de derivação E E E + E E + num yield

6 6 Derivação mais à esquerda E 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) sse existe mais de uma derivação mais à esquerda

7 7 E E E + E E + num E E E + E E +

8 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 9 Gramáticas ambíguas Precedência e associatividade podem ser codificadas dentro da GLC E E+T | E-T | T T T*F | T/F | F F id | num | (E) Regras recursivas à esq. associatividade à esquerda Camada mais alta precedência mais baixa

10 10 Gramática por camadas - exemplo E E + T | E - T | T T T * F | T / F | F F -F | +F | V V V. id | V [ E ] | A A id | num | (E)

11 11 else opcional S if E then S else S | if E then S | outro Qual é a árvore de if E1 then if E2 then S1 else S2 ?

12 12 else opcional S if E then S else S | if E then S | outro Qual é a árvore de if 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' | outro S" if E then S | if E then S' else S"

13 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 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 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 16 Parser preditivo S if E then S else S | begin S L | print E L end | ; S L E 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 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 18 Gramáticas não LL V 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 | F F num | (E) Não é LL(2). ( num )+( num ) ( num não determina a produção a escolher

19 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 Exemplo Z d Y X YW b | X Y W Z | c | a Primeiro(Z)=?

20 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 Y 1 Y 2... Y k, Primeiro( Y 1 ),..., Primeiro( Y i - 1 ) (i.e., Y 1 Y 2.. Y i - 1 ), e a Primeiro(Y i ) então adicionar a a Primeiro( X ) Primeiro( X 1 X 2... X n ) = Primeiro( X 1 ), se Primeiro( X 1 ); Primeiro( X 1 X 2... X n ) = Primeiro( X 1 )... Primeiro( X i+1 ) - { } se Primeiro( X k ), para k =1...i, e Primeiro( X i+1 ); e Primeiro( X 1 X 2... X n ) = Primeiro( X 1 )... Primeiro( X n ) se Primeiro( X k ), para k = 1...n

21 21 Z d Y X YW b | X Y W Z | c | a abcdXYZWabcdXYZW a b c d, a, c, c a, b, c, d b Primeiro

22 22 Seguinte - Algoritmo Seguinte(A)={a | S * Aa } Colocar $ em Seguinte( S ) Repetir até não poder adicionar mais Se existir A B adicionar Primeiro( )-{ε} a Seguinte( B ) Se existir A B ou A B e Primeiro( ) adicionar Seguinte( A ) a Seguinte( B )

23 23 Z d Y X YW b | X Y W Z | c | a XYZWXYZW c, b $ a, b, c, d Seguinte S Z $

24 24 Tabela sintática preditiva Z d Y X YW b | X Y W Z | c | a X a X Y Y Y c Y W b Z X Y W Z Z d Z X Y W Z XYWZXYWZ ab c d A é uma entrada para ( A,a) na tabela sse: –Se A e a Primeiro( ) –Se A, Primeiro( ) e a Seguinte( A )

25 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 ] | id id Primeiro( V[E] )

26 26 Eliminando recursão à Esquerda E E+T | E-T | T Podemos escrever sem recursão à esquerda, assim E T E' E' + T E' | Em geral, se temos A A 1 | A 2 |...| A n | 1 | 2 |...| m Escrevemos A 1 A' | 2 A' |...| m A' A' 1 A' | 2 A' |...| n A' | Dificuldades futuras Árvore de derivação associativa à direita Geração de árvore abstrata exige tratamento especial

27 27 Tabela preditiva da gramática de expressões anterior S E $ E T E' E' + T E' |

28 28 Tirando em evidência (fatoração) à esquerda A | |... podemos escrever A A' |... A' | Por exemplo D int Id ; | int Id ( A ) ; | outro pode ser re-escrito como D int Id D' | outro D' ; | ( A ) ; Pequena dificuldade: A estrutura gramatical foi mudada

29 29 Exemplos de fatoração E id E' |num E' (E) |[e] | E id(E) |id[e] |id |num

30 30 S if E then S else S | if E then S | outro Pode ser escrito como S if E then S X | outro X 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: X else 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 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 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 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 34 Bibliografia Seções do livro do Dragão Seções 3.1 e 3.2 do livro do Tigre


Carregar ppt "1 Linguagens Formais e Tradutores Análise Sintática - 1 Prof. André Luis Meneses Silva"

Apresentações semelhantes


Anúncios Google