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

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

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

Apresentações semelhantes


Apresentação em tema: "CES-41 COMPILADORES Capítulo V Análise Sintática."— Transcrição da apresentação:

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): 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 Classes de métodos de análise sintática: Classes de métodos de análise sintática: – Analisadores universais – Analisadores top-down – Analisadores bottom-up Analisadores universais: Analisadores universais: – Conseguem analisar qualquer GLC – São muito ineficientes para uso em compiladores

5 Analisadores top-down e bottom-up: Analisadores top-down e bottom-up: – Varrem o programa da esquerda para a direita, um símbolo de cada vez – 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: 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: 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 de precedência de operadores Análise LR 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 GLCs Métodos de análise sintática se aplicam a determinadas classes de GLCs Algumas gramáticas devem ser alteradas para que um método possa ser aplicado Algumas gramáticas devem ser alteradas para que um método possa ser aplicado É a busca por uma GLC equivalente à original É a busca por uma GLC equivalente à original Duas GLCs são equivalentes quando geram a mesma linguagem Duas GLCs 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 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 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: Produções típicas: Cmd IF Expr Cmd | IF Expr Cmd ELSE Cmd | c1 | c2 | c1 | c2 A sentença: IF e1 IF e2 c1 ELSE c2 tem duas árvores sintáticas: 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 A regra usual para resolver a ambiguidade é fazer o ELSE corresponder ao segundo IF Esta regra pode ser incorporada à gramática Esta regra pode ser incorporada à gramática Gramática equivalente: Gramática equivalente: Cmd CmdCasado | CmdNãoCasado CmdCasado IF Expr CmdCasado ELSE CmdCasado | c1 | c2 CmdNãoCasado IF Expr Cmd | IF Expr CmdCasado ELSE CmdNãoCasado | IF Expr CmdCasado ELSE CmdNãoCasado

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

13 Cmd CmdCasado | CmdNãoCasado CmdCasado IF Expr CmdCasado ELSE CmdCasado | c1 | c2 CmdNãoCasado IF Expr Cmd | IF Expr CmdCasado ELSE CmdNãoCasado | IF Expr CmdCasado ELSE CmdNãoCasado Essa nova gramática dificulta análise preditora: Essa nova gramática dificulta aná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 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 )* 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 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: 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) else Term ( ); } }

16 Expr ( ) { if ( func (átomos analisados e/ou futuros) == TRUE ) { Expr ( ); if (atom != +) erro (+ esperado) else Term ( ); } } Caso func (átomos analisados e/ou futuros) seja TRUE, na chamada interna de Expr, os átomos serão os mesmos Caso func (á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 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 Para aplicar um método top-down, toda recursividade à esquerda deve ser eliminada da gramática Há recursividade imediata e não-imediata à esquerda Há recursividade imediata e não-imediata à esquerda Exemplos: 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 É o caso de uma produção ser recursiva à esquerda Um caso bem simples é o das seguintes produções: Um caso bem simples é o das seguintes produções: A A A A (, (N )* e não iniciam com A) Estas produções podem ser substituídas pelas seguintes: 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 ε} {A A } {A R R R ε} Resolve muitos casos, mas não é geral 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 A m n Podem ser substituídas por: A 1 A' 2 A' n A' A' 1 A' 2 A' m A' ε Nenhum i pode ser ε

22 b) Recursividade não-imediata à esquerda: O algoritmo a seguir elimina toda recursividade à esquerda de uma gramática 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 Condições da gramática: não deve ter ciclos nem produções vazias Gramática sem ciclos: sem derivações da forma 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 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 GLCs Existem algoritmos para eliminar ciclos e produções vazias de GLCs

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

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: Renomeando os não-terminais: S = A 1, T = A 2, U = A 3 A gramática torna-se em: A gramática torna-se em: A 1 A 1 a A 2 b c A 2 A 1 d A 3 e f A 3 A 1 g A 3 h i

25 Para i = 1: Eliminação das recursividades imediatas à esquerda de A 1 : Eliminação das recursividades imediatas à esquerda de A 1 : A 1 A 2 b X c X X a X ε A A A 1 A' 2 A' A' 1 A' ε Algoritmo 5.1 A 1 A 2 b X c X X a X ε A 2 A 1 d A 3 e f A 3 A 1 g A 3 h i Novo estado das produções

26 Para i = 2, j = 1: Produções de A 2 : Produções de A 2 : A 2 A 1 d A 3 e f Produções de A 1 no momento: A 1 A 2 b X c X Produções de A 1 no momento: A 1 A 2 b X c X Substitui-se A 1 d por A 2 b X d c X d : Substitui-se A 1 d por A 2 b X d c X d : Produção da forma A 2 A 1

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

28 Para i = 3, j = 1: Produções de A 3 : Produções de A 3 : A 3 A 1 g A 3 h i Produções de A 1 no momento: A 1 A 2 b X c X Produções de A 1 no momento: A 1 A 2 b X c X Substitui-se A 1 g por A 2 b X g c X g : Substitui-se A 1 g por A 2 b X g c X g : A 3 A 2 b X g c X g A 3 h i Produção da forma A 3 A 1

29 Para i = 3, j = 2: Produções de A 3 : Produções de A 3 : A 3 A 2 b X g c X g A 3 h i Produções de A 2 no momento: A 2 c X d Y A 3 e Y f Y Produções de A 2 no momento: A 2 c X d Y A 3 e Y f Y Substitui-se A 2 b X g por Substitui-se A 2 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 A 3 A 2

30 Para i = 3: Eliminação das recursividades imediatas à esquerda de A 3 : Eliminação das recursividades imediatas à esquerda de A 3 : A 3 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 A 1 A' 2 A' 3 A' 4 A' 3 A' 4 A' A' 1 A' 2 A' ε Algoritmo 5.1

31 Novo estado das produções: Novo estado das produções: A 1 A 2 b X c X X a X ε A 2 c X d Y A 3 e Y f Y 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 A 1 A 2 b X c X A 2 c X d Y A 3 e Y f Y 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: Restaurando os nomes originais dos não-terminais: S T b X c X T c X d Y U e Y f Y 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 ε Não há mais recursividade a esquerda S = A1, T = A2, U = A3

33 5.2.3 – Fatoração à esquerda Sejam as seguintes produções do não-terminal A: Sejam as seguintes produções do não-terminal A: A A onde,, (N )* e o primeiro símbolo de é diferente do primeiro símbolo de 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 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: Pode-se atrasar a decisão, aplicando nesta gramática a seguinte transformação: A A, A A A, A

34 A A A, A A A A, A Isso ainda não garante a possibilidade de aplicação de um método preditor 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 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 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 ) 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 Essas derivações diferem no trecho marcado

36 S S(S) (S) () S S(S) S() () Na primeira, escolheu-se o não-terminal S mais à esquerda para ser expandido Na primeira, escolheu-se o não-terminal S mais à esquerda para ser expandido Na segunda, foi escolhido o não-terminal S mais à direita Na segunda, foi escolhido o não-terminal S mais à direita Simbolicamente Simbolicamente S(S) me (S) e S(S) md S() Ou seja, 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 Derivação mais à esquerda ou mais à direita: quando todas as derivações diretas forem me ou md Simbolicamente: * me ou * md Simbolicamente: * me ou * md No exemplo anterior 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 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 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 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: 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 F opmult T ( E ) opmult T E T F opmult T ( E ) opmult T ( T opad E ) opmult T ( F opad E ) opmult T ( T opad E ) opmult T ( F opad E ) opmult T ( id opad E ) opmult T ( id opad T ) opmult T ( id opad E ) opmult T ( id opad T ) opmult T ( id opad F ) opmult T ( id opad id ) opmult T ( id opad F ) opmult T ( id opad id ) opmult T ( id opad id ) opmult F opmult T ( id opad id ) opmult F opmult T ( id opad id ) opmult cte opmult T ( id opad id ) opmult cte opmult T ( id opad id ) opmult cte opmult F ( id opad id ) opmult cte opmult F ( id opad id ) opmult cte opmult ( E ) ( id opad id ) opmult cte opmult ( E ) ( id opad id ) opmult cte opmult ( T opad E ) ( id opad id ) opmult cte opmult ( T opad E ) ( id opad id ) opmult cte opmult ( F opad E ) ( id opad id ) opmult cte opmult ( F opad E ) ( id opad id ) opmult cte opmult ( id opad E ) ( id opad id ) opmult cte opmult ( id opad E ) ( id opad id ) opmult cte opmult ( id opad T ) ( id opad id ) opmult cte opmult ( id opad T ) ( id opad id ) opmult cte opmult ( id opad F ) ( id opad id ) opmult cte opmult ( id opad F ) ( id opad id ) opmult cte opmult ( id opad cte ) ( 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: Exemplo: Produção de derivações mais a direita da gramática: E T | E opad T T F | T opmult F F id | cte | ( E ) Derivação mais à direita para a expressão: ( x + y ) * 10 / ( n – 2 )

42 E T T opmult F T opmult ( E ) E T T opmult F T opmult ( E ) T opmult ( E opad T ) T opmult ( E opad F ) T opmult ( E opad T ) T opmult ( E opad F ) T opmult ( E opad cte ) T opmult ( T opad cte ) T opmult ( E opad cte ) T opmult ( T opad cte ) T opmult ( F opad cte ) T opmult ( id opad cte ) T opmult ( F opad cte ) T opmult ( id opad cte ) T opmult F opmult ( id opad cte ) T opmult F opmult ( id opad cte ) T opmult cte opmult ( id opad cte ) T opmult cte opmult ( id opad cte ) F opmult cte opmult ( id opad cte ) F opmult cte opmult ( id opad cte ) ( E ) opmult cte opmult ( id opad cte ) ( E ) opmult cte opmult ( id opad cte ) ( E opad T ) opmult cte opmult ( id opad cte ) ( E opad T ) opmult cte opmult ( id opad cte ) ( E opad F ) opmult cte opmult ( id opad cte ) ( E opad F ) opmult cte opmult ( id opad cte ) ( E opad id ) opmult cte opmult ( id opad cte ) ( E opad id ) opmult cte opmult ( id opad cte ) ( T opad id ) opmult cte opmult ( id opad cte ) ( T opad id ) opmult cte opmult ( id opad cte ) ( F opad id ) opmult cte opmult ( id opad cte ) ( F opad id ) opmult cte opmult ( id opad cte ) ( id opad id ) opmult cte opmult ( id opad cte ) ( x + y ) * 10 / ( n – 2 ) Analisadores bottom-up examinam derivações mais a direita reversas

43 ( x + y ) * 10 / ( n – 2 ) ( id opad id ) opmult cte opmult ( id opad cte ) ( id opad id ) opmult cte opmult ( id opad cte ) ( F opad id ) opmult cte opmult ( id opad cte ) ( F opad id ) opmult cte opmult ( id opad cte ) ( T opad id ) opmult cte opmult ( id opad cte ) ( T opad id ) opmult cte opmult ( id opad cte ) ( E opad id ) opmult cte opmult ( id opad cte ) ( E opad id ) opmult cte opmult ( id opad cte ) ( E opad F ) opmult cte opmult ( id opad cte ) ( E opad F ) opmult cte opmult ( id opad cte ) ( E opad T ) opmult cte opmult ( id opad cte ) ( E opad T ) opmult cte opmult ( id opad cte ) ( E ) opmult cte opmult ( id opad cte ) ( E ) opmult cte opmult ( id opad cte ) F opmult cte opmult ( id opad cte ) F opmult cte opmult ( id opad cte ) T opmult cte opmult ( id opad cte ) T opmult cte opmult ( id opad cte ) T opmult F opmult ( id opad cte ) T opmult F opmult ( id opad cte ) T opmult ( id opad cte ) T opmult ( F opad cte ) T opmult ( id opad cte ) T opmult ( F opad cte ) T opmult ( T opad cte ) T opmult ( E opad cte ) T opmult ( T opad cte ) T opmult ( E opad cte ) T opmult ( E opad F ) T opmult ( E opad T ) T opmult ( E opad F ) 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 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 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 o programa analisado Também: tentativa de achar uma derivação mais à esquerda para a sentença ou o 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 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 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 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 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 S a A d a B A b c B ccd ddc w = a c c d S 1) Início: Árvore contendo somente o símbolo inicial Cursor na raiz da árvore Cursor no primeiro átomo da sentença

48 S a A d a B A b c B ccd ddc w = a c c d S a A d 2) 1 a 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 Os cursores se casam: a = a

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

50 S a A d a B A b c B ccd ddc S a A d b w = a c c d 4) 1 a 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 Os cursores não se casam: b c

51 S a A d a B A b c B ccd ddc S a A d b w = a c c d 5) Elimina-se a subárvore da expansão anterior 2 a produção para expandir A Cursor da sentença retrocede para onde A foi expandido, ou seja, permanece onde está: Cursor da árvore avança em pré- ordem Os cursores se casam: c = c c

52 S a A d a B A b c B ccd ddc S a A d c w = a c c d Os cursores não se casam: d c 6) Os dois cursores avançam

53 S a A d a B A b c B ccd ddc S a A d c w = a c c d Os cursores se casam: a = a 7) Elimina-se a subárvore da expansão anterior Não existe outra produção para expandir A Elimina-se também a subárvore da expansão imediatamente anterior, ou seja, a de S Cursor da sentença retrocede até ao ponto em que S foi expandido 2 a produção para expandir S O cursor da árvore avança a B

54 S a A d a B A b c B ccd ddc S a B c c d w = a c c d 8) Os cursores avançam 1 a produção para expandir B Cursor da árvore avança Casamento nos três últimos movimentos dos cursores: c c d = c c d A sentença é reconhecida

55 Só se chega à conclusão de que há erro na sentença, quando não houver mais opções para expandir o não-terminal da raiz Só se chega à conclusão de que há erro na sentença, quando não houver mais opções para expandir o não-terminal da raiz Como detectar e tratar erros? Como detectar e tratar erros? No pior caso (erro na sentença), o tempo gasto na análise cresce exponencialmente com tamanho da sentença No pior caso (erro na sentença), o tempo gasto na análise cresce exponencialmente com tamanho da sentença E se a gramática tivesse recursividade à esquerda? E se a gramática tivesse recursividade à esquerda? Exemplo: S b S b O uso de backtracking é raramente necessário para analisar construções de linguagens de programação O uso de backtracking é raramente necessário para analisar construções de linguagens de programação

56 Análise sem backtracking: no momento de expansão escolhe a produção correta, dispensando tentativas desnecessárias Análise sem backtracking: no momento de expansão escolhe a produção correta, dispensando tentativas desnecessárias Nem todas as GLCs podem ser analisadas sem backtracking, mas, na prática, só ela é usada Nem todas as GLCs podem ser analisadas sem backtracking, mas, na prática, só ela é usada Existe análise sem backtracking em que o número de átomos necessários para a tomada de decisão é maior que 1 Existe análise sem backtracking em que o número de átomos necessários para a tomada de decisão é maior que 1 Ou seja, existem métodos sem backtracking também não preditores Ou seja, existem métodos sem backtracking também não preditores

57 5.4.2 – Gramáticas LL(k) e LL(1) Gramáticas LL(k): admitem analisadores sem back- tracking que: Gramáticas LL(k): admitem analisadores sem back- tracking que: Analisam as sentenças da esquerda para a direita (o primeiro L - left) Analisam as sentenças da esquerda para a direita (o primeiro L - left) Produzem derivações mais à esquerda (o segundo L) Produzem derivações mais à esquerda (o segundo L) Precisam analisar no máximo, os próximos k símbolos, para decidir que produção usar Precisam analisar no máximo, os próximos k símbolos, para decidir que produção usar Gramáticas LL(1): gramáticas LL(k) em que k = 1 Gramáticas LL(1): gramáticas LL(k) em que k = 1

58 Métodos preditores só analisam gramáticas LL(1) Métodos preditores só analisam gramáticas LL(1) Nesta disciplina serão abordados somente métodos preditores Nesta disciplina serão abordados somente métodos preditores Livro que aborda com detalhes muitos outros métodos: Livro que aborda com detalhes muitos outros métodos: Aho, A.V., Ullman, J.D. – The Theory of Parsing, Translation and Compiling – Prentice-Hall – 1972 Aho, A.V., Ullman, J.D. – The Theory of Parsing, Translation and Compiling – Prentice-Hall – 1972 É o primeiro Livro do Dragão – hoje são três É o primeiro Livro do Dragão – hoje são três

59 Espectro dos métodos top-down: Espectro dos métodos top-down: Top-down BacktrackingSem Backtracking Não PreditoresPreditores

60 5.4.3 – Análise preditora recursiva É uma análise preditora estruturada num conjunto de subprogramas recursivos É uma análise preditora estruturada num conjunto de subprogramas recursivos O método dos diagramas de transições é preditor recursivo O método dos diagramas de transições é preditor recursivo Outro método: também orienta-se por uma gramática fatorada à esquerda, mas dispensa os diagramas de transições Outro método: também orienta-se por uma gramática fatorada à esquerda, mas dispensa os diagramas de transições

61 Exemplo: seja a gramática Exemplo: seja a gramática Expressão Termo | Termo OPAD Expressão Termo Fator | Fator OPMULT Termo Fator ID | CTE | ( Expressão ) | OPNEG Fator Fatorando: Expressão Termo Eaux Eaux OPAD Expressão | ε Termo Fator Taux Taux OPMULT Termo | ε Fator ID | CTE | ( Expressão ) | OPNEG Fator A seguir: Esquema de programa analisador sintático em C

62 Programa principal: Programa principal: void main () { printf ("Digite a expressao:\n\n"); gets (expressao); printf ("\n"); ptexpr = 0; carac = NovoCarac (); NovoAtomo (); Expressao (); if (atom.tipo != ENDOFFILE) Esperado (ENDOFFILE); }

63 Expressão Termo Eaux Eaux OPAD Expressão | ε void Expressao () { Termo (); Eaux (); } void Eaux () { if (atom.tipo == OPAD) { NovoAtomo (); Expressao (); }}

64 Termo Fator Taux Taux OPMULT Termo | ε void Termo () { Fator (); Taux (); } void Taux () { if (atom.tipo == OPMULT) { NovoAtomo (); Termo (); }}

65 Fator ID | CTE | ( Expressão ) | OPNEG Fator void Fator () { switch (atom.tipo) { case CTE: NovoAtomo (); break; case ID: NovoAtomo (); break; case ABPAR: NovoAtomo (); Expressao (); if (atom.tipo != FPAR) Esperado (FPAR); NovoAtomo (); break; case OPNEG: NovoAtomo (); Fator (); break; default: NaoEsperado (atom.tipo); NovoAtomo (); break; }}

66 5.4.4 – Análise preditora não-recursiva Para melhor desempenho, é conveniente trocar uma solução recursiva por outra não-recursiva, usando pilha Para melhor desempenho, é conveniente trocar uma solução recursiva por outra não-recursiva, usando pilha Chamadas de subprogramas são consumidoras de tempo Chamadas de subprogramas são consumidoras de tempo Chamadas recursivas numa análise preditora podem ser substituídas por empilhamentos e por consultas a uma tabela de produções Chamadas recursivas numa análise preditora podem ser substituídas por empilhamentos e por consultas a uma tabela de produções

67 Um analisador não-recursivo, diante de um átomo da sentença e de um não-terminal a ser expandido, no topo da pilha, consulta uma tabela de produções para saber como expandi-lo Um analisador não-recursivo, diante de um átomo da sentença e de um não-terminal a ser expandido, no topo da pilha, consulta uma tabela de produções para saber como expandi-lo Os símbolos do lado direito da produção escolhida são então empilhados no lugar desse não-terminal Os símbolos do lado direito da produção escolhida são então empilhados no lugar desse não-terminal A próxima figura ilustra o esquema de um analisador sintático preditor não-recursivo A próxima figura ilustra o esquema de um analisador sintático preditor não-recursivo

68 Pilha: local para fazer expansões de não-terminais Pilha: local para fazer expansões de não-terminais Tabela de produções: matriz bidimensional M para indicar a produção a ser usada para expandir um não-terminal, diante de um átomo na entrada Tabela de produções: matriz bidimensional M para indicar a produção a ser usada para expandir um não-terminal, diante de um átomo na entrada

69 Funcionamento: seja X o elemento do topo da pilha e a o átomo em análise Funcionamento: seja X o elemento do topo da pilha e a o átomo em análise Se X = a = $: encerra com sucesso Se X = a $: desempilha X e avança na entrada Se X a e ambos são terminais: erro Se X é um não terminal: consulta a entrada M[X, a] da tabela M M[X, a] pode ser uma produção de X ou um erro Se, por exemplo, M[X,a] for a produção X YZW: Desempilhar X Empilhar W, Z, Y, com Y no topo Se M[X,a] for um erro: Acionar tratamento de erro M[X, a] X a

70 Algoritmo 5.3: Análise preditora não recursiva Empilhar ($); Empilhar (S) /* S é o símbolo inicial */ ; w sentença || $; p &(w[0]); Repetir { X topo da pilha; a *p; Se (X = terminal ou X = $) { Se (X = a) {Desempilhar (X); Avançar (p);} Senão Erro ( X era esperado ); } Senão { /* X é não-terminal */ Se M[X, a] = {X Y 1 Y 2 Y 3... Y k } { Desempilhar (X); Empilhar (Y k... Y 3 Y 3 Y 1 ) /* Y 1 no topo */ ; Imprimir a produção {X Y 1 Y 2 Y 3... Y k };} Senão Erro ( a não era esperado ); } } enquanto (X $)/* enquanto pilha ainda não vazia */ A saída pode ser a produção usada

71 Exemplo: seja a seguinte gramática de expressões: E T E E + T E | ε T F TT * F T | ε F ( E ) | id Seja a seguinte sentença em análise: id + id * id Seja a seguinte sentença em análise: id + id * id Supor a seguinte tabela de produções (sua construção é apresentada após o exemplo – as posições vazias são erros): Supor a seguinte tabela de produções (sua construção é apresentada após o exemplo – as posições vazias são erros):

72 Estado inicial: Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E E TE T

73 Programa analisador preditor id+ * $ Sentença de entrada $ Pilha Ação: Expandir Saída E E TE T T F T FT

74 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E TE T FT T F id E TE T FT F id

75 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Desempilhar Avançar Saída E TE T FT F id T id

76 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E TE T FT F id T E TE T FT F id T ε

77 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E TE T FT F id T ε E T + E TE T FT F id T ε E +TE

78 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Desempilhar Avançar Saída E TE T FT F id T ε E +TE T +

79 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E TE T FT F id T ε E +TE T T F E TE T FT F id T ε E +TE T FT

80 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E TE T FT F id T ε E +TE T FT T F id E TE T FT F id T ε E +TE T FT F id

81 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Desempilhar Avançar Saída E TE T FT F id T ε E +TE T FT F id T id

82 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E TE T FT F id T ε E +TE T FT F id T F * E TE T FT F id T ε E +TE T FT F id T *FT

83 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Desempilhar Avançar Saída E TE T FT F id T ε E +TE T FT F id T *FT T F *

84 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E TE T FT F id T ε E +TE T FT F id T *FT T F id E TE T FT F id T ε E +TE T FT F id T *FT F id

85 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Desempilhar Avançar Saída E TE T FT F id T ε E +TE T FT F id T *FT F id T id

86 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E TE T FT F id T ε E +TE T FT F id T *FT F id T E TE T FT F id T ε E +TE T FT F id T *FT F id T ε

87 Programa analisador preditor id+ * $ Sentença de entrada $ E Pilha Ação: Expandir Saída E TE T FT F id T ε E +TE T FT F id T *FT F id T ε E TE T FT F id T ε E +TE T FT F id T *FT F id T ε E ε

88 Programa analisador preditor id+ * $ Sentença de entrada $ Pilha Ação: Desempilhar Avançar Saída E TE T FT F id T ε E +TE T FT F id T *FT F id T ε E ε Ação: Encerrar com sucesso Derivação Resta saber como construir a tabela de produções !!!

89 E T E E + T E | ε T F T T * F T | ε F ( E ) | id Há gramáticas cujas tabelas apresentam duas ou mais produções para a mesma entrada Há gramáticas cujas tabelas apresentam duas ou mais produções para a mesma entrada Então não se pode aplicar um método preditor Então não se pode aplicar um método preditor

90 E T E E + T E | ε T F T T * F T | ε F ( E ) | id Produção de X em que o primeiro símbolo do lado direito é um terminal a: pode ser colocada na entrada [X, a] Produção de X em que o primeiro símbolo do lado direito é um terminal a: pode ser colocada na entrada [X, a] – Prepara um casamento entre pilha e entrada Exemplos: M[E, +] = E +TE M[F, (] = F (E) Exemplos: M[E, +] = E +TE M[F, (] = F (E) M[T, *] = T *FTM[F, id] = F id M[T, *] = T *FTM[F, id] = F id

91 E T E E + T E | ε T F T T * F T | ε F ( E ) | id Produção de X em que o primeiro símbolo do lado direito é um não terminal Y: Produção de X em que o primeiro símbolo do lado direito é um não terminal Y: – Para ser colocada numa entrada [X, a] é necessário ver se Y pode derivar uma forma sentencial iniciada por a É o caso das produções E TE e T FT É o caso das produções E TE e T FT

92 E T E E + T E | ε T F T T * F T | ε F ( E ) | id Produção vazia de X: Produção vazia de X: – Para ser colocada numa entrada [X, a] é necessário ver se a pode aparecer em alguma forma sentencial depois de X

93 5.4.5 – As funções Primeiro e Seguinte A construção da tabela de produções é auxiliada por duas funções: Primeiro e Seguinte A construção da tabela de produções é auxiliada por duas funções: Primeiro e Seguinte Sendo (N )*, Primeiro ( ) é o conjunto dos terminais que iniciam todas as sentenças derivadas de Sendo (N )*, Primeiro ( ) é o conjunto dos terminais que iniciam todas as sentenças derivadas de Se * ε, então ε Primeiro ( ) Se * ε, então ε Primeiro ( ) Observa-se que, se o primeiro símbolo de for um terminal qualquer a, então Primeiro ( ) = {a} Observa-se que, se o primeiro símbolo de for um terminal qualquer a, então Primeiro ( ) = {a}

94 Exemplo: seja = A a B C b c d D + + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Todas as possíveis e talvez infinitas cadeias só de terminais Eliminando-se os terminais repetidos, obtém-se Primeiro( ) Como possui terminais, * ε portanto: ε Primeiro ( )

95 Utilidade da função Primeiro ( ) em análise preditora: Sejam as produções A | Sejam as produções A | Na expansão de A diante do terminal b, a decisão por ou, depende de b pertencer a Primeiro( ) ou Primeiro( ) Na expansão de A diante do terminal b, a decisão por ou, depende de b pertencer a Primeiro( ) ou Primeiro( ) Caso b pertença aos dois conjuntos, a indecisão persiste Caso b pertença aos dois conjuntos, a indecisão persiste Caso b não pertença a nenhum dos dois conjuntos: erro Caso b não pertença a nenhum dos dois conjuntos: erro

96 Sendo A um não-terminal qualquer, Seguinte (A) é o conjunto dos terminais que podem aparecer imediatamente à direita de A, em alguma forma sentencial Sendo A um não-terminal qualquer, Seguinte (A) é o conjunto dos terminais que podem aparecer imediatamente à direita de A, em alguma forma sentencial Mais precisamente, é o conjunto dos terminais b, tais que existe uma derivação da forma S * Ab Mais precisamente, é o conjunto dos terminais b, tais que existe uma derivação da forma S * Ab (, (N )*) Se A for o símbolo mais a direita de alguma forma sentencial, então $ Seguinte (A) Se A for o símbolo mais a direita de alguma forma sentencial, então $ Seguinte (A)

97 Exemplo: sejam todas as possivelmente infinitas formas sentenciais de uma GLC S * _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Em algumas (possivelmente infinitas) o não-terminal A aparece

98 Exemplo: sejam todas as possivelmente infinitas formas sentenciais de uma GLC S * _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Colocando-se o finalizador $ em cada uma

99 Exemplo: sejam todas as possivelmente infinitas formas sentenciais de uma GLC S * _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ A _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ A _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ A $ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ A _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ A _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ $ Colocando-se os símbolos que seguem A

100 Exemplo: sejam todas as possivelmente infinitas formas sentenciais de uma GLC S * _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ A B _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ A a _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ A $ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ A b _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ A D _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ $ a, b, $ Seguinte (A)

101 Cálculo do Primeiro ( ): Seja = X 1 X 2 X 3... X n, onde X i (1 i n) é um terminal ou um não terminal: Seja = X 1 X 2 X 3... X n, onde X i (1 i n) é um terminal ou um não terminal: O cálculo do Primeiro ( ) exige o cálculo de Primeiro (X i ) O cálculo do Primeiro ( ) exige o cálculo de Primeiro (X i )

102 Algoritmo 5.4: Calcula Primeiro (X), onde X (N ) O cálculo é feito simultaneamente para todos os símbolos da gramática O algoritmo tem 2 etapas: 1. 1.Inicialização 2. 2.Processo rotativo convergente

103 Algoritmo 5.4: 1. 1.Inicialização Para todo símbolo X da gramática { Se (X é terminal) Primeiro (X) {X}; Senão se (X é uma produção) Primeiro (X) { }; Senão Primeiro (X) { }; }

104 2. 2.Processo rotativo convergente Aplicar a seguinte regra a toda produção não-vazia da gramática de modo rotativo, até que nenhum terminal ou seja acrescentado ao conjunto Primeiro de qualquer não-terminal: Para cada produção do tipo X Y 1 Y 2 Y 3... Y k (k 1) { Para (i 1; i k; i++) Se (i = 1) || ( j | (1 j i-1), Primeiro (Y j )) Acrescentar (Primeiro (Y i ) - { }) a Primeiro (X) Se ( i | (1 i k), Primeiro (Y i )) Acrescentar a Primeiro (X); }

105 Comentários: seja a produção X Y 1 Y 2 Y 3... Y k (k 1) Todo o terminal (excluído ) presente em Primeiro (Y 1 ) certamente pertence a Primeiro (X) Se Y 1 não deriva, então nada mais deve ser acrescentado a Primeiro (X) Mas se Y 1 deriva, então deve-se acrescentar a Primeiro (X) todo terminal (excluído ) contido em Primeiro (Y 2 )

106 Comentários: seja a produção X Y 1 Y 2 Y 3... Y k (k 1) Se Y 1, Y 2 e Y 3 derivam, então deve-se acrescentar a Primeiro (X) todo terminal contido em Primeiro (Y 4 ) E assim por diante Se Y 1, Y 2, Y 3,..., Y k derivam, então deve-se acrescentar a Primeiro (X)

107 Exemplo: seja a gramática: E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Inicialização do Algoritmo 5.4: Inicialização do Algoritmo 5.4: Primeiro (+) = {+}Primeiro (*) = {*} Primeiro (() = { ( }Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = Primeiro (T) = {} Primeiro (E) = Primeiro (T) = { } Primeiro (E) = Primeiro (T) = Primeiro (F) = { }

108 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, 1 a rotação: Processo rotativo do Algoritmo 5.4, 1 a rotação: Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {} Primeiro (E) = { } Primeiro (T) = {} Primeiro (T) = { } Primeiro (E) = { } Primeiro (T) = { } Primeiro (F) = { } E T E : Primeiro (T) = { } nada acontece E + T E : Primeiro (+) = {+}, então Primeiro (E) = {, +}

109 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, 1 a rotação: Processo rotativo do Algoritmo 5.4, 1 a rotação: Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = { } Primeiro (E) = { } Primeiro (T) = { } Primeiro (F) = { } T F T : Primeiro (F) = { } nada acontece T *F T : Primeiro (*) = {*}, então Primeiro (T) = {, *}

110 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, 1 a rotação: Processo rotativo do Algoritmo 5.4, 1 a rotação: Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { } Primeiro (T) = { } Primeiro (F) = { } F ( E ) : Primeiro (() = { ( }, então Primeiro (F) = { ( }

111 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, 1 a rotação: Processo rotativo do Algoritmo 5.4, 1 a rotação: Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { } Primeiro (T) = { } Primeiro (F) = { ( } F id : Primeiro (id) = { id }, então Primeiro (F) = { (, id }

112 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, final da 1 a rotação Processo rotativo do Algoritmo 5.4, final da 1 a rotação Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { } Primeiro (T) = { } Primeiro (F) = { (, id }

113 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, 2 a rotação: Processo rotativo do Algoritmo 5.4, 2 a rotação: Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { } Primeiro (T) = { } Primeiro (F) = { (, id } E T E : Primeiro (T) = { } nada acontece E + T E : Primeiro (+) = {+}, nada acontece T F T : Primeiro (F) = { (, id }, então Primeiro (T) = { (, id }

114 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, 2 a rotação: Processo rotativo do Algoritmo 5.4, 2 a rotação: Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { } Primeiro (T) = { (, id } Primeiro (F) = { (, id } T * F T : Primeiro (*) = {*}, nada acontece F ( E ) : Primeiro (() = { ( }, nada acontece F id : Primeiro (id) = { id }, nada acontece

115 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, final da 2 a rotação Processo rotativo do Algoritmo 5.4, final da 2 a rotação Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { } Primeiro (T) = { (, id } Primeiro (F) = { (, id }

116 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, 3 a rotação: Processo rotativo do Algoritmo 5.4, 3 a rotação: Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { } Primeiro (T) = { (, id } Primeiro (F) = { (, id } E T E : Primeiro (T) = { (, id } Primeiro (E) = { (, id }

117 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, 3 a rotação: Processo rotativo do Algoritmo 5.4, 3 a rotação: Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { (, id } Primeiro (T) = { (, id } Primeiro (F) = { (, id } Com as outras produções nada acontece

118 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, final da 3 a rotação Processo rotativo do Algoritmo 5.4, final da 3 a rotação Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { (, id } Primeiro (T) = { (, id } Primeiro (F) = { (, id }

119 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Processo rotativo do Algoritmo 5.4, 4 a rotação: Processo rotativo do Algoritmo 5.4, 4 a rotação: Primeiro (+) = {+} Primeiro (*) = {*} Primeiro (() = { ( } Primeiro ()) = { ) } Primeiro (id) = {id} Primeiro (E) = {, +} Primeiro (T) = {} Primeiro (T) = {, *} Primeiro (E) = { (, id } Primeiro (T) = { (, id } Primeiro (F) = { (, id } Nada acontece Ficam determinados os Primeiros de todos os símbolos

120 Algoritmo 5.5: Cálculo do Primeiro ( ), onde = X 1 X 2 X 3... X n e X i (N ), (1 i n) Primeiro ( ) { }; Para (i 1; i n; i++) Se (i = 1) || ( j | (1 j i-1), Primeiro (X j )) Acrescentar (Primeiro (X i ) - { }) a Primeiro ( ) ; Se ( i | (1 i n), Primeiro (X i )) Acrescentar a Primeiro ( ); Se ( = ) Primeiro ( ) { };

121 = X 1 X 2 X 3... X n Comentários: seja = X 1 X 2 X 3... X n Todos os terminais de Primeiro (X 1 ) devem pertencer a Primeiro ( ) Todos os terminais de Primeiro (X 1 ) devem pertencer a Primeiro ( ) Caso ( Primeiro (X 1 )), todos os terminais de Primeiro (X 2 ) devem pertencer a Primeiro ( ) Caso ( Primeiro (X 1 )), todos os terminais de Primeiro (X 2 ) devem pertencer a Primeiro ( ) Caso ( Primeiro (X 1 ) e Primeiro (X 2 )), todos os terminais de Primeiro (X 3 ) devem pertencer a Primeiro ( ) Caso ( Primeiro (X 1 ) e Primeiro (X 2 )), todos os terminais de Primeiro (X 3 ) devem pertencer a Primeiro ( ) E assim por diante E assim por diante

122 Algoritmo 5.6: Calcula Seguinte (A), onde A é um não- terminal O cálculo é feito simultaneamente para todos os não- terminais da gramática O algoritmo tem 3 etapas 1. 1.Inicialização trivial 2. 2.Inicialização não-trivial 3. 3.Processo rotativo convergente

123 Algoritmo 5.6: 1. 1.Inicialização trivial Seguinte (S) {$}; /* S é o símbolo inicial */ /* $ é marca de fim da sentença */ Inicializar Seguinte de todos os outros não-terminais com o conjunto vazio

124 Comentários: S * _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ $ S $ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ $ $ Seguinte (S)

125 2. 2.Inicialização não-trivial Para toda produção do tipo A w 1 B 1 w 2 B 2 w 3... w n B n w n+1, (n 1; w i *, 1 i n+1; B i N, 1 i n) { Para (i 1; i n; i++) { Expressão da produção: A i B i i, ( i, i (N ) * ); Acrescentar (Primeiro ( i ) - { }) a Seguinte (B i ) ; }} Pelo menos um não-terminal do lado direito

126 Comentários: seja a produção A i B i i Sendo A um não-terminal útil, haverá pelo menos uma forma sentencial do tipo Sendo A um não-terminal útil, haverá pelo menos uma forma sentencial do tipo _ _ _ _ _ _ _ _ _ _ _ _ A _ _ _ _ $ E haverá outra do tipo E haverá outra do tipo _ _ _ _ _ _ _ _ _ _ _ _ i B i i _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ i B i i _ _ _ _ $ Então (Primeiro ( i ) – { }) Seguinte (B i ) Então (Primeiro ( i ) – { }) Seguinte (B i ) i pode ser vazio ou derivar a cadeia vazia

127 3. Processo rotativo convergente Aplicar a seguinte regra a toda produção não-vazia da gramática de modo rotativo, até que nenhum terminal ou $ seja acrescentado ao conjunto Seguinte de qualquer não terminal: Seja A w 1 B 1 w 2 B 2 w 3... w n B n w n+1, a produção em questão, onde (n 1; w i *, 1 i n+1; B i N, 1 i n): Para (i 1; i n; i++) { Expressão da produção: A i B i i, ( i, i (N ) * ); Se (( i é vazia) ou ( Primeiro ( i ))) Acrescentar Seguinte (A ) a Seguinte (B i ) ; } Pelo menos um não- terminal do lado direito

128 Comentários: seja a produção A i B i i Se a, b, c, $ Seguinte (A), há formas sentenciais dos tipos Se a, b, c, $ Seguinte (A), há formas sentenciais dos tipos _ _ _ _ _ _ A a _ _ _ $ _ _ _ _ A b _ _ _ $ _ _ _ _ _ A c _ _ _ $ _ _ _ _ _ _ A $ E também dos tipos E também dos tipos _ _ _ _ _ _ i B i i a _ _ _ $ _ _ _ _ i B i i b _ _ _ $ _ _ _ _ _ i B i i c _ _ _ $ _ _ _ _ _ _ i B i i $ Se i é vazia: a, b, c, $ Seguinte (B i ) Se Primeiro ( i ), ou seja, se i * : há formas sentenciais em que a, b, c, $ aparecem imediatamente depois de B i Então, acrescentar a, b, c, $ ao Seguinte (B i ) Ou seja, acrescentar Seguinte (A) ao Seguinte (B i )

129 Exemplo: seja a mesma gramática: E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Seja a tabela dos Primeiros de seus não-terminais calculada no exemplo anterior: Seja a tabela dos Primeiros de seus não-terminais calculada no exemplo anterior:

130 Inicialização trivial do Algoritmo 5.6 Inicialização trivial do Algoritmo 5.6: Seguinte (E) = {$} Seguinte (E) = { } Seguinte (T) = { } Seguinte (F) = { }

131 Inicialização não-trivial do Algoritmo 5.6: Inicialização não-trivial do Algoritmo 5.6: Seguinte (E) = {$} Seguinte (E) = { } Seguinte (T) = { } Seguinte (F) = { } E T E: Produção E T E: Seguinte (T) = Seguinte (T) (Primeiro (E) – {ε}) = { } ({+, ε} – {ε}) = {+}

132 Inicialização não-trivial do Algoritmo 5.6: Inicialização não-trivial do Algoritmo 5.6: Seguinte (E) = {$} Seguinte (E) = { } Seguinte (T) = {+} Seguinte (T) = { } Seguinte (F) = { } E T E: Produção E T E: Seguinte (T) = Seguinte (T) (Primeiro (E) – {ε}) = { } ({+, ε} – {ε}) = {+} Seguinte (E) = Seguinte (E) (Primeiro (ε) – {ε}) = { } ({ε} – {ε}) = { }

133 Inicialização não-trivial do Algoritmo 5.6: Inicialização não-trivial do Algoritmo 5.6: Seguinte (E) = {$} Seguinte (E) = { } Seguinte (T) = {+} Seguinte (T) = { } Seguinte (F) = { } E +T E: Produção E +T E: Seguinte (T) = Seguinte (T) (Primeiro (E) – {ε}) = {+} ({+, ε} – {ε}) = {+} Seguinte (E) = Seguinte (E) (Primeiro (ε) – {ε}) = { } ({ε} – {ε}) = { }

134 Inicialização não-trivial do Algoritmo 5.6: Inicialização não-trivial do Algoritmo 5.6: Seguinte (E) = {$} Seguinte (E) = { } Seguinte (T) = {+} Seguinte (T) = { } Seguinte (F) = { } T FT: Produção T FT: Seguinte (F) = Seguinte (F) (Primeiro (T) – {ε}) = { } ({*, ε} – {ε}) = {*}

135 Inicialização não-trivial do Algoritmo 5.6: Inicialização não-trivial do Algoritmo 5.6: Seguinte (E) = {$} Seguinte (E) = { } Seguinte (T) = {+} Seguinte (T) = { } Seguinte (F) = {*} T FT: Produção T FT: Seguinte (F) = Seguinte (F) (Primeiro (T) – {ε}) = { } ({*, ε} – {ε}) = {*} Seguinte (T) = Seguinte (T) (Primeiro (ε) – {ε}) = { } ({ε} – {ε}) = { }

136 Inicialização não-trivial do Algoritmo 5.6: Inicialização não-trivial do Algoritmo 5.6: Seguinte (E) = {$} Seguinte (E) = { } Seguinte (T) = {+} Seguinte (T) = { } Seguinte (F) = {*} T *FT: Produção T *FT: Seguinte (F) = Seguinte (F) (Primeiro (T) – {ε}) = {*} ({*, ε} – {ε}) = {*} Seguinte (T) = Seguinte (T) (Primeiro (ε) – {ε}) = { } ({ε} – {ε}) = { }

137 Inicialização não-trivial do Algoritmo 5.6: Inicialização não-trivial do Algoritmo 5.6: Seguinte (E) = {$} Seguinte (E) = { } Seguinte (T) = {+} Seguinte (T) = { } Seguinte (F) = {*} F (E): Produção F (E): Seguinte (E) = Seguinte (E) (Primeiro ()) – {ε}) = {$} ({ ) } – {ε}) = {$, )}

138 Inicialização não-trivial do Algoritmo 5.6: Inicialização não-trivial do Algoritmo 5.6: Seguinte (E) = {$, )} Seguinte (E) = { } Seguinte (T) = {+} Seguinte (T) = { } Seguinte (F) = {*}

139 Final da inicialização não-trivial do Algoritmo 5.6: Final da inicialização não-trivial do Algoritmo 5.6: Seguinte (E) = {$, )} Seguinte (E) = { } Seguinte (T) = {+} Seguinte (T) = { } Seguinte (F) = {*}

140 Processo rotativo do Algoritmo 5.6, 1 a rotação: Processo rotativo do Algoritmo 5.6, 1 a rotação: Seguinte (E) = {$, )} Seguinte (E) = { } Seguinte (T) = {+} Seguinte (T) = { } Seguinte (F) = {*} E T E: () Produção E T E: (ε Primeiro (E)) Seguinte (T) = Seguinte (T) Seguinte (E) = {+} {$, )} = {+, $, )}

141 Processo rotativo do Algoritmo 5.6, 1 a rotação: Processo rotativo do Algoritmo 5.6, 1 a rotação: Seguinte (E) = {$, )} Seguinte (E) = { } Seguinte (T) = {+, $, )} Seguinte (T) = { } Seguinte (F) = {*} E T E: Produção E T E: Seguinte (T) = Seguinte (T) Seguinte (E) = {+} {$, )} = {+, $, )} Seguinte (E) = Seguinte (E) Seguinte (E) = { } {$, )} = {$, )}

142 Processo rotativo do Algoritmo 5.6, 1 a rotação: Processo rotativo do Algoritmo 5.6, 1 a rotação: Seguinte (E) = {$, )} Seguinte (T) = {+, $, )} Seguinte (T) = { } Seguinte (F) = {*} T F T: () Produção T F T: (ε Primeiro (T)) Seguinte (F) = Seguinte (F) Seguinte (T) = {*} {+, $, )} = {*, +, $, )}

143 Processo rotativo do Algoritmo 5.6, 1 a rotação: Processo rotativo do Algoritmo 5.6, 1 a rotação: Seguinte (E) = {$, )} Seguinte (T) = {+, $, )} Seguinte (T) = { } Seguinte (F) = {*, +, $, )} T F T: Produção T F T: Seguinte (F) = Seguinte (F) Seguinte (T) = {*} {+, $, )} = {*, +, $, )} Seguinte (T) = Seguinte (T) Seguinte (T) = { } {+, $, )} = {+, $, )}

144 Processo rotativo do Algoritmo 5.6, 1 a rotação: Processo rotativo do Algoritmo 5.6, 1 a rotação: Seguinte (E) = {$, )} Seguinte (T) = {+, $, )} Seguinte (F) = {*, +, $, )} T * F T: () Produção T * F T: (ε Primeiro (T)) Seguinte (F) = Seguinte (F) Seguinte (T) = {*, +, $, )} {+, $, )} = {*, +, $, )} Seguinte (T) = Seguinte (T) Seguinte (T) = {+, $, )} {+, $, )} = {+, $, )}

145 Processo rotativo do Algoritmo 5.6, 1 a rotação: Processo rotativo do Algoritmo 5.6, 1 a rotação: Seguinte (E) = {$, )} Seguinte (T) = {+, $, )} Seguinte (F) = {*, +, $, )} F ( E ): (Não se aplica a regra, pois ) Produção F ( E ): (Não se aplica a regra, pois ε Primeiro ()))

146 Final da 1 a rotação do processo rotativo do Algoritmo 5.6: Final da 1 a rotação do processo rotativo do Algoritmo 5.6: Seguinte (E) = {$, )} Seguinte (T) = {+, $, )} Seguinte (F) = {*, +, $, )}

147 Processo rotativo do Algoritmo 5.6, 2 a rotação: Processo rotativo do Algoritmo 5.6, 2 a rotação: Seguinte (E) = {$, )} Seguinte (T) = {+, $, )} Seguinte (F) = {*, +, $, )} Nada é alterado Ficam determinados os Seguintes de todos os não-terminais

148 5.4.6 – Construção da tabela de produções Seja A um não-terminal e a um terminal Seja A um não-terminal e a um terminal

149 Sejam A as produções de A Sejam A as produções de A Se a Primeiro ( ) Se a Primeiro ( ) Então: A pode expandir para, na presença de a na entrada pode gerar sub- sentenças iniciadas por a, para casar com o a na entrada

150 Sejam A as produções de A Sejam A as produções de A Se a (Primeiro ( ) e Primeiro ( ) e Primeiro ( )) Se a (Primeiro ( ) e Primeiro ( ) e Primeiro ( )) E se, e não derivarem ε Então: Erro com A na presença de a na entrada A só gera sub-sentenças não-vazias e não iniciadas por a Nunca aparecerá um a no topo da pilha para casar com o a na entrada

151 Sejam A as produções de A Sejam A as produções de A Se a (Primeiro ( ) e Primeiro ( ) e Primeiro ( )), mas se pelo menos derivar ε Se a (Primeiro ( ) e Primeiro ( ) e Primeiro ( )), mas se pelo menos derivar ε E se a Seguinte (A) E se a Seguinte (A) Então: A pode expandir para na presença de a na entrada Existe a possibilidade de haver um a abaixo do A, na pilha, ou um não- terminal que gere algo iniciado por a

152 Algoritmo 5.7: Construção da tabela de produções Para cada produção A da gramática { Para cada terminal a em Primeiro ( ) Acrescentar A a M[A, a]; Se (ε Primeiro ( )) { Para todo terminal b em Seguinte (A) Acrescentar A a M[A, b]; Se ($ Seguinte (A)) Acrescentar A a M[A, $]; }} Colocar Erro em cada posição indefinida da tabela.

153 Exemplo: seja a mesma gramática: E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Tabelas dos Primeiros e Seguintes já calculadas: Tabelas dos Primeiros e Seguintes já calculadas:

154 E T E E + T E | E T E E + T E | T F T T * F T | F ( E ) | id Tabela de produções: Tabela de produções:

155 Sejam A as produções de A Sejam A as produções de A Se a (Primeiro ( ) e Primeiro ( )) Se a (Primeiro ( ) e Primeiro ( )) Então: indecisão A pode expandir para ou, na presença de a na entrada A gramática não é LL(1), ou seja, não admite análise preditora

156 Sejam A as produções de A Sejam A as produções de A Se a (Primeiro ( ) e Seguinte (A)) Se a (Primeiro ( ) e Seguinte (A)) e se derivar ε Então: indecisão A pode expandir para ou, na presença de a na entrada A gramática não é LL(1), ou seja, não admite análise preditora Indecisão: duas ou mais produções numa posição M[A, a] da tabela

157 Exemplo: seja a gramática para if-else: S i b S S | a S e S | S i b S S | a S e S | Tabelas: Tabelas: M[S, e] tem duas produções Tipicamente decide-se por S e S O else corresponde ao último if

158 5.4.7 – Tratamento de erros Um erro é detectado quando: Um terminal no topo da pilha não casa com o próximo símbolo na entrada b era esperado O não-terminal no topo da pilha e o próximo símbolo de entrada determinam uma posição de erro na tabela de produções a não era esperado

159 O terminal no topo da pilha não casa com o próximo símbolo na entrada: Mensagem: b era esperado Mensagem: b era esperado Ação típica: desempilhar o terminal da pilha Ação típica: desempilhar o terminal da pilha Resolve o caso de esquecimento de b

160 O não-terminal no topo da pilha e o próximo símbolo de entrada determinam erro na tabela de produções: Mensagem: a não era esperado Mensagem: a não era esperado É difícil escolher a melhor ação É difícil escolher a melhor ação Uma das técnicas mais usadas é o uso de um conjunto de terminais de sincronismo Uma das técnicas mais usadas é o uso de um conjunto de terminais de sincronismo Descarta-se terminais de entrada até que se encontre um desses terminais Seja sincr a designação desse terminal

161 Terminais de sincronismo: Terminais do Seguinte (A): desempilhar A - o que estiver abaixo do A na pilha pode ser: Terminais do Seguinte (A): desempilhar A - o que estiver abaixo do A na pilha pode ser: Um terminal também pertencente a Seguinte (A) que case com sincr Um terminal também pertencente a Seguinte (A) que case com sincr Um não-terminal que expanda para uma cadeia iniciada por sincr Um não-terminal que expanda para uma cadeia iniciada por sincr

162 Terminais de sincronismo: Terminais do Primeiro (A): não desempilhar A: Terminais do Primeiro (A): não desempilhar A: Haverá uma posição sem erro na tabela Haverá uma posição sem erro na tabela Há possibilidade de retomar a análise Há possibilidade de retomar a análise

163 Ainda para não-terminal A no topo da pilha: Se houver a produção A ε, pode-se usá-la para expandir A, retardando o tratamento do erro Se houver a produção A ε, pode-se usá-la para expandir A, retardando o tratamento do erro

164 Pode-se incluir também, no conjunto de terminais de sincronismo, palavras reservadas que iniciam comandos Pode-se incluir também, no conjunto de terminais de sincronismo, palavras reservadas que iniciam comandos Consultar a literatura para mais detalhes Consultar a literatura para mais detalhes


Carregar ppt "CES-41 COMPILADORES Capítulo V Análise Sintática."

Apresentações semelhantes


Anúncios Google