1 / 164

CES-41 COMPILADORES

CES-41 COMPILADORES. Capítulo V Análise Sintática. Capítulo V – Análise Sintática. 5.1 – Classificação dos analisadores sintáticos 5.2 – Tratamento de gramáticas 5.3 – Escolha de uma derivação 5.4 – Análise top-down 5.5 – Análise bottom-up 5.6 – Complementos de Yacc.

Download Presentation

CES-41 COMPILADORES

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CES-41 COMPILADORES Capítulo V Análise Sintática

  2. Capítulo V – Análise Sintática 5.1 – Classificação dos analisadores sintáticos 5.2 – Tratamento de gramáticas 5.3 – Escolha de uma derivação 5.4 – Análise top-down 5.5 – Análise bottom-up 5.6 – Complementos de Yacc

  3. 5.1 – Classificação dos Analisadores Sintáticos • Papel do analisador sintático (visto anteriormente): • Verificar a estrutura sintática de um programa • Detectar, sinalizar e tratar erros sintáticos • Servir de esqueleto para o front-end

  4. Classesde métodos de análise sintática: • Analisadores universais • Analisadores top-down • Analisadores bottom-up • Analisadores universais: • Conseguem analisar qualquer GLC • São muito ineficientes para uso em compiladores

  5. Analisadores top-down e bottom-up: • Varrem o programa da esquerda para a direita, um símbolo de cada vez; alguns deles por vezes precisam voltar da direita para a esquerda • Englobam os métodos mais comumente usados em compiladores • Os métodos mais eficientes trabalham apenas com subclasses de gramáticas • Várias dessas subclasses (gramáticas LL e LR, descritas mais adiante) conseguem descrever a maioria das construções sintáticas das linguagens de programação

  6. Analisadores top-down: • Caminham pela árvore sintática dos programas, da raiz para as folhas • Trabalham com gramáticas LL (Left-Left) • Englobam os métodos preditores, dentre os quais, os diagramas de transições • As implementações manuais utilizam métodos top-down

  7. Analisadores bottom-up: • Caminham pela árvore sintática dos programas, das folhas para a raiz • Trabalham com gramáticas LR (Left-Right) • Englobam importantes métodos: • Análise de precedência de operadores • Análise LR • São muito usados na geração automática de analisadores sintáticos

  8. 5.2 – Tratamento de Gramáticas • Métodos de análise sintática se aplicam a determinadas classes de GLC’s • Algumas gramáticas devem ser alteradas para que um método possa ser aplicado • É a busca por uma GLCequivalente à original • Duas GLC’s são equivalentes quando geram a mesma linguagem

  9. 5.2.1 – Eliminação de ambiguidades • Alguns métodos de análise sintática exigem que a gramática seja não-ambígua • Outros métodos mantém a ambiguidade das gramáticas e usam regras para eliminar árvores sintáticas indesejáveis

  10. Exemplo: comando IF-ELSE da Linguagem C • Produções típicas: Cmd IF ExprCmd| IF ExprCmd ELSE Cmd |c1 | c2 • A sentença: IF e1 IF e2 c1 ELSE c2 tem duas árvores sintáticas:

  11. A regra usual para resolver a ambiguidade é fazer o ELSE corresponder ao segundo IF • Esta regra pode ser incorporada à gramática • Gramática equivalente: CmdCmdCasado|CmdNãoCasado CmdCasado IF ExprCmdCasadoELSE CmdCasado | c1 | c2 CmdNãoCasado IF ExprCmd | IF ExprCmdCasadoELSE CmdNãoCasado

  12. CmdCmdCasado|CmdNãoCasado CmdCasado IF ExprCmdCasadoELSE CmdCasado | c1 | c2 CmdNãoCasado IF ExprCmd | IF ExprCmdCasadoELSE CmdNãoCasado • CmdCasado nunca produz IF sem ELSE • Esta gramática impede o aparecimento de comandos não-casados entre Expr e ELSE

  13. CmdCmdCasado|CmdNãoCasado CmdCasado IF ExprCmdCasadoELSE CmdCasado | c1 | c2 CmdNãoCasado IF ExprCmd | IF ExprCmdCasadoELSE CmdNãoCasado • Essa nova gramática dificultaanálise preditora: • Em Cmd, se aparecer um IF, qual das duas produções tomar? • Cada tipo de ambiguidade deve ser eliminada mediante um tratamento particular

  14. 5.2.2 – Eliminação de recursividade à esquerda • Uma GLC é recursiva à esquerda, se tiver um não-terminal A tal que haja uma derivação A + A, onde  (N )* • Os métodos de análise top-down não conseguem trabalhar com gramáticas recursivas à esquerda

  15. Exemplo: sejam as produções ExprTermExpr + Term • Num método top-down típico, há um procedimento para cada um dos não-terminais Expr e Term: Expr ( ) { if ( func (átomos analisados e/ou futuros) == TRUE ) { Expr ( ); if (atom != ‘+’) erro (“+ esperado”) elseTerm ( ); } elseTerm ( ); }

  16. Expr ( ) { if ( func (átomos analisados e/ou futuros) == TRUE ) { Expr ( ); if (atom != ‘+’) erro (“+ esperado”) elseTerm ( ); } elseTerm ( ); } • Casofunc (átomos analisados e/ou futuros) seja TRUE, na chamada interna de Expr, os átomos serão os mesmos • O valor de func se repete, resultando em infinitas chamadas recursivas

  17. Para aplicar um método top-down, toda recursividade à esquerda deve ser eliminada da gramática • Há recursividade imediata e não-imediata à esquerda • Exemplos: Imediata: S  S b S  a Não-imediata: S Aa b , A  Sc  d

  18. a) Recursividade imediata à esquerda: • É o caso de uma produção ser recursiva à esquerda • Um caso bem simples é o das seguintes produções: A  A (,  (N )* e não iniciam com A) • Estas produções podem ser substituídas pelas seguintes: A R RR ε que geram as mesmas formas sentenciais que as originais, conforme o próximo slide

  19. {A  A} {A R RR ε} • Resolve muitos casos, mas não é geral

  20. Exemplo: seja a seguinte gramática, com duas produções contendo recursividade imediata à esquerda: Expr Expr+ Termo  Termo Termo  Termo * Fator  Fator Fator  ( Expr)  ID Transformação da gramática: Expr Termo Eaux Eaux + Termo Eaux ε Termo  Fator Taux Taux * Fator Taux ε Fator  ( Expr) | ID {A  A} {A R R R ε} Nas produções de Expr, substituindo: A por Expr  por + Termo  por Termo R por Eaux De modo análogo, na produção de Termo

  21. Generalização: várias produções do mesmo não-terminal, com recursividade a esquerda Algoritmo 5.1: As seguintes produções: A  A 1  A 2  - - -  A m  1  2  - - -  n Podem ser substituídas por: A  1 A'  2 A'  - - -  n A' A'  1 A'  2 A'  - - -  m A'  ε Nenhum ipode ser ε

  22. b) Recursividade não-imediata à esquerda: • O algoritmo a seguir elimina toda recursividade à esquerda de uma gramática • Condições da gramática: não deve ter ciclos nem produções vazias • Gramática sem ciclos: sem derivações da forma A + A • Gramática sem produções vazias: a única produção vazia permitida é S  (S: símbolo inicial) e S não aparece do lado direito de qualquer produção • Existem algoritmos para eliminar ciclos e produções vazias de GLC’s

  23. Algoritmo 5.2: eliminação de recursividade à esquerda Arranjar os não-terminais numa ordem A1, A2, ... , An Para (i = 1; i <= n; i++) { Para (j = 1; j <= i-1; j++) { Sendo Aj  1  2  - - - m as produções de Aj, no momento, Substituir cada produção da forma Ai  Aj  pelas produções Ai  1   2   - - - m  } Eliminar as recursividades imediatas a esquerda entre as produções de Ai; }

  24. Exemplo: Eliminar as recursividades à esquerda da gramática: S  S a  T b  c T  S d  U e  f U  S g  U h  i • Renomeando os não-terminais: S = A1, T = A2, U = A3 • A gramática torna-se em: A1  A1 a  A2 b  c A2  A1 d  A3 e  f A3  A1 g  A3 h  i

  25. Para i = 1: • Eliminação das recursividades imediatas à esquerda de A1: A1  A2 b X  c X X  a X  ε Algoritmo 5.1 A  A1  1  2 A  1 A'  2 A' A'  1 A'  ε A1  A2 b X  c X X  a X  ε A2  A1 d  A3 e  f A3  A1 g  A3 h  i Novo estado das produções

  26. Para i = 2, j = 1: • Produções de A2: A2  A1 d  A3 e  f • Produções de A1no momento: A1  A2 b X  c X • Substitui-se A1 d por A2 b X d  c X d: Produção da forma A2  A1 

  27. Para i = 2: • Eliminação das recursividades imediatas à esquerda de A2: Algoritmo 5.1 A2 c X d Y  A3 e Y  f Y Y  b X d Y ε A  A1  1  2  3 A  1 A'  2 A'  3 A' A'  1 A'  ε A1  A2 b X  c X X  a X  ε A2 c X d Y  A3 e Y  f Y Y  b X d Y ε A3  A1 g  A3 h  i Novo estado das produções

  28. Para i = 3, j = 1: • Produções de A3: A3  A1 g  A3 h  i • Produções de A1no momento: A1  A2 b X  c X • Substitui-se A1 g por A2 b X g  c X g : A3  A2 b X g  c X g  A3 h  i Produção da forma A3  A1 

  29. Para i = 3, j = 2: • Produções de A3: A3  A2 b X g  c X g  A3 h  i • Produções de A2no momento: A2 c X d Y  A3 e Y  fY • Substitui-se A2 b X g por c X d Y b X g  A3 e Y b X g  f Y b X g : Produção da forma A3  A2 

  30. Para i = 3: • Eliminação das recursividades imediatas à esquerda de A3: A3 c X d Y b X g Z  f Y b X g Z  c X g Z  i Z Z  e Y b X g Z  h Z  ε A  A1  A2 1  2  3  4 A  1 A'  2 A'  3 A'  4 A' A'  1 A'  2 A' ε Algoritmo 5.1

  31. Novo estado das produções: A1  A2 b X  c X X  a X  ε A2 c X d Y  A3 e Y  fY Y  b X d Y ε A3  c X d Y b X g Z  f Y b X g Z  c X g Z  i Z Z  e Y b X g Z  h Z  ε

  32. A1  A2 b X  c X A2 c X d Y  A3 e Y  fY A3  c X d Y b X g Z  f Y b X g Z  c X g Z  i Z X  a X  ε Y  b X d Y ε Z  e Y b X g Z  h Z  ε • Restaurando os nomes originais dos não-terminais: S  T b X  c X T  c X d Y  U e Y  fY U  c X d Y b X g Z  f Y b X g Z  c X g Z  i Z X  a X  ε Y  b X d Y ε Z  e Y b X g Z  h Z  ε S = A1, T = A2, U = A3 Não há mais recursividade a esquerda

  33. 5.2.3 – Fatoração à esquerda • Sejam as seguintes produções do não-terminal A: A  onde , ,  (N )* e o primeiro símbolo de é diferente do primeiro símbolo de  • Para um método preditor, não é claro qual produção usar para expandir A • Pode-se atrasar a decisão, aplicando nesta gramática a seguinte transformação: A  A’ , A’ 

  34. A  A  A’ , A’  • Isso ainda não garante a possibilidade de aplicação de um método preditor • O primeiro símbolo de  e pode ser um não-terminal, permanecendo a indecisão • Fatoração é apenas um passo para adequar gramáticas a um método preditor

  35. 5.3 – Escolha de uma Derivação • Mesmo numa GLC não-ambígua, a sequência de derivações diretas para produzir uma sentença pode variar • Exemplo: seja a gramática S ε | S ( S ) A sentença ( ) pode ser gerada pelas seguintes derivações: S  S(S)  (S)  () S  S(S)  S()  () • Essas derivações diferem no trecho marcado

  36. S  S(S)  (S)  () S  S(S)  S()  () • Na primeira, escolheu-se o não-terminal Smais à esquerda para ser expandido • Na segunda, foi escolhido o não-terminal Smais à direita • Simbolicamente S(S) me (S) e S(S) md S() • Ou seja, S(S) deriva diretamente mais à esquerda (S) S(S) deriva diretamente mais à direita S()

  37. Derivação mais à esquerda ou mais à direita: quando todas as derivações diretas forem me ou md • Simbolicamente: *meou *md • No exemplo anterior { S *me ( ) } = { S  S(S)  (S)  ( ) } { S *md ( ) } = { S  S(S)  S( )  ( ) }

  38. Qualquer árvore sintática tem uma única derivação mais à esquerda e uma única derivação mais à direita • Gramática ambígua – outra definição: produz mais de uma derivação mais à esquerda ou mais à direita para pelo menos uma de suas sentenças • Os analisadores sintáticos mais conhecidos analisam derivações mais à esquerda ou mais à direita dos programas

  39. Exemplo: Produção de derivações mais a esquerda da gramática: E  T | T opad E T  F | F opmult T F  id | cte | ( E ) Derivação mais à esquerda para a expressão: ( x + y ) * 10 / ( n – 2 )

  40. ETFopmult T  ( E ) opmult T  ( Topad E ) opmult T  ( Fopad E ) opmult T  ( id opadE ) opmult T  ( id opadT ) opmult T  ( id opadF ) opmult T  ( id opad id ) opmultT ( id opad id ) opmultFopmult T  ( id opad id ) opmultcteopmultT ( id opad id ) opmultcteopmultF ( id opad id ) opmultcteopmult ( E )  ( id opad id ) opmultcteopmult ( Topad E )  ( id opad id ) opmultcteopmult ( Fopad E )  ( id opad id ) opmultcteopmult ( id opadE )  ( id opad id ) opmultcteopmult ( id opadT )  ( id opad id ) opmultcteopmult ( id opadF )  ( id opad id ) opmultcteopmult ( id opadcte ) ( x + y ) * 10 / ( n – 2 ) Analisadores preditores examinam derivações mais a esquerda

  41. Exemplo: Produção de derivações mais a direita da gramática: E  T | E opad T T  F | T opmultF F id | cte | ( E ) Derivação mais à direita para a expressão: ( x + y ) * 10 / ( n – 2 )

  42. ET T opmultF T opmult ( E )  T opmult ( E opadT )  T opmult ( E opadF )  T opmult ( Eopadcte )  T opmult ( Topadcte )  T opmult ( Fopadcte ) Topmult ( id opadcte )  T opmultFopmult ( id opadcte )  Topmultcteopmult ( id opadcte )  Fopmultcteopmult ( id opadcte )  ( E ) opmultcteopmult ( id opadcte )  ( E opadT ) opmultcteopmult ( id opadcte )  ( E opadF ) opmultcteopmult ( id opadcte )  ( Eopad id ) opmultcteopmult ( id opadcte )  ( Topad id ) opmultcteopmult ( id opadcte )  ( Fopad id ) opmultcteopmult ( id opadcte )  ( id opad id ) opmultcteopmult ( id opadcte ) ( x + y ) * 10 / ( n – 2 ) Analisadores bottom-up examinam derivações mais a direita reversas

  43. ( x + y ) * 10 / ( n – 2 ) ( idopad id ) opmultcteopmult ( id opadcte )  ( Fopad id ) opmultcteopmult ( id opadcte )  ( Topad id ) opmultcteopmult ( id opadcte )  ( Eopadid ) opmultcteopmult ( id opadcte )  ( E opadF ) opmultcteopmult ( id opadcte )  ( E opad T ) opmultcteopmult ( id opadcte )  ( E )opmultcteopmult ( id opadcte )  Fopmultcteopmult ( id opadcte )  T opmultcteopmult ( id opadcte )  T opmult Fopmult ( id opadcte )  T opmult ( idopadcte ) T opmult ( Fopadcte )  T opmult ( Topadcte ) T opmult ( E opadcte )  T opmult ( E opadF ) T opmult ( E opad T )  T opmult( E )T opmult FTE Em negrito, lados direitos a serem reduzidos

  44. 5.4 – Análise Top-Down • Tentativa de construir uma árvore sintática para a sentença analisada, começando da raiz, indo em direção às folhas e criando os nós em pré-ordem Exemplo:

  45. 5.4 – Análise Top-Down • Tentativa de construir uma árvore sintática para a sentença analisada, começando da raiz, indo em direção às folhas e criando os nós em pré-ordem • Também: tentativa de achar uma derivação mais à esquerda para a sentença ou programa analisado • Análise preditora: os átomos são analisados linearmente da esquerda para a direita, sem a necessidade de observar átomos futuros e de caminhar de volta, da direita para a esquerda, sobre a sequência de átomos

  46. 5.4.1 – Análise backtracking • Por vezes, a produção escolhida para produzir uma derivação direta mais à esquerda não leva à árvore sintática da sentença analisada • Então, o analisador é obrigado a voltar para a esquerda na sequência de átomos e a eliminar uma subárvore da árvore em construção, substituindo-a por outra • Exemplo: seja a gramática S  a A d  a B A  b  c B ccdddc A seguir, análise da sentença: w = a c c d

  47. 1) Início: Árvore contendo somente o símbolo inicial Cursor na raiz da árvore Cursor no primeiro átomo da sentença S S  a A d  a B A  b  c B ccdddc w = a c c d

  48. 2) 1a produção para expandir S Liga-se S ao átomo da sentença apontado pelo cursor, pois é diante dele que ocorreu a expansão Cursor da árvore avança em pré-ordem S a A d S  a A d  a B A  b  c B ccdddc w = a c c d Os cursores se casam: a = a

  49. 3) Os dois cursores avançam S a A d S  a A d  a B A  b  c B ccdddc w = a c c d

  50. 4) 1a produção para expandir A Liga-se A ao átomo da sentença apontado pelo cursor, pois é diante dele que ocorreu a expansão Cursor da árvore avança em pré-ordem S a A d b S  a A d  a B A  b  c B ccdddc w = a c c d Os cursores não se casam: b ≠ c

More Related