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

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

Capítulo V Análise Sintática

Apresentações semelhantes


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

1 Capítulo V Análise Sintática
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 Classes de 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 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 GLC equivalente à 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 Expr Cmd | IF Expr Cmd ELSE Cmd | c1 | c2 A sentença: IF e1 IF e2 c1 ELSE c2 tem duas árvores sintáticas:

11 Esta regra pode ser incorporada à gramática Gramática equivalente:
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 Expr CmdCasado ELSE CmdCasado | c1 | c2 CmdNãoCasado  IF Expr Cmd | IF Expr CmdCasado ELSE CmdNãoCasado

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

13 Essa nova gramática dificulta análise preditora:
Cmd  CmdCasado | CmdNãoCasado CmdCasado  IF Expr CmdCasado ELSE CmdCasado | c1 | c2 CmdNãoCasado  IF Expr Cmd | IF Expr CmdCasado ELSE CmdNãoCasado 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

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”) 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 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 (,   (N  )* e não iniciam com A)
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 Transformação da gramática:
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 i pode 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 Eliminação das recursividades imediatas à esquerda de A1:
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 Produções de A1 no momento: A1  A2 b X  c X
Para i = 2, j = 1: Produções de A2: A2  A1 d  A3 e  f Produções de A1 no 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 Eliminação das recursividades imediatas à esquerda de A2:
Para i = 2: Eliminação das recursividades imediatas à esquerda de A2: Algoritmo 5.1 A  A1  1  2  3 A  1 A'  2 A'  3 A' A'  1 A'  ε A2  c X d Y  A3 e Y  f Y Y  b X d Y  ε 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 Produções de A1 no momento: A1  A2 b X  c X
Para i = 3, j = 1: Produções de A3: A3  A1 g  A3 h  i Produções de A1 no 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 c X d Y b X g  A3 e Y b X g  f Y b X g :
Para i = 3, j = 2: Produções de A3: A3  A2 b X g  c X g  A3 h  i Produções de A2 no momento: A2  c X d Y  A3 e Y  f Y 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 Eliminação das recursividades imediatas à esquerda de A3:
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  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 Restaurando os nomes originais dos não-terminais:
A1  A2 b X  c X A2  c X d Y  A3 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: 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 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) me (S) e S(S) md S()
S  S(S)  (S)  () S  S(S)  S()  () 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 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: *me ou *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 ( x + y ) * 10 / ( n – 2 ) E  T  F opmult T  ( 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 F ) opmult T  ( id opad id ) opmult T  ( id opad id ) opmult F opmult T  ( id opad id ) opmult cte opmult T  ( id opad id ) opmult cte opmult F  ( id opad id ) opmult cte opmult ( 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 ( id opad E )  ( 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 cte ) ( x + y ) * / ( n – ) 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 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 ) 
T opmult ( E opad T )  T opmult ( E opad F )  T opmult ( E opad cte )  T opmult ( T opad cte )  T opmult ( F opad cte )  T opmult ( id opad cte )  T opmult F opmult ( id opad cte )  T opmult cte opmult ( id opad cte )  F opmult cte opmult ( id opad cte )  ( E ) 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 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 )  ( id opad id ) opmult cte opmult ( id opad cte ) ( x y ) * / ( n – ) Analisadores bottom-up examinam derivações mais a direita reversas

43 ( E ) opmult cte opmult ( id opad cte ) 
( x y ) * / ( n – ) ( id 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 )  ( E opad id ) 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 ) opmult cte opmult ( id opad cte )  F opmult cte opmult ( id opad cte )  T opmult cte opmult ( id opad cte )  T opmult F opmult ( id opad cte )  T opmult ( id opad cte )  T opmult ( F 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 )  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 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

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 S w = a c c d S  a A d  a B A  b  c B  ccd  ddc 1) Início:
Árvore contendo somente o símbolo inicial Cursor na raiz da árvore Cursor no primeiro átomo da sentença S w = a c c d

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

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

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

51 Os cursores se casam: c = c
S  a A d  a B A  b  c B  ccd  ddc 5) Elimina-se a subárvore da expansão anterior 2a 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 S a A d b c w = a c c d Os cursores se casam: c = c

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

53 Os cursores se casam: a = a
S  a A d  a B A  b  c B  ccd  ddc 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 2a produção para expandir S O cursor da árvore avança S a A d c a B w = a c c d Os cursores se casam: a = a

54 S a B c c d w = a c c d S  a A d  a B A  b  c B  ccd  ddc
8) Os cursores avançam 1a 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 w = a c c d

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 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 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

56 Análise sem backtracking: no momento de expansão escolhe a produção correta, dispensando tentativas desnecessárias Nem todas as GLC’s 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 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: Analisam as sentenças da esquerda para a direita (o primeiro L - left) 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 Gramáticas LL(1): gramáticas LL(k) em que k = 1

58 Métodos preditores só analisam gramáticas LL(1)
Nesta disciplina serão abordados somente métodos preditores 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 É o primeiro Livro do Dragão – hoje são três

59 Espectro dos métodos top-down:
Backtracking Sem Backtracking Não Preditores Preditores

60 5.4.3 – Análise preditora recursiva
É uma análise preditora estruturada num conjunto de subprogramas recursivos 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

61 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 | ε A seguir: Esquema de programa analisador sintático em C

62 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); }

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 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

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 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

68 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

69 Se X = a = $: encerra com sucesso
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] X a Se M[X,a] for um erro: Acionar tratamento de erro Se, por exemplo, M[X,a] for a produção XYZW: Desempilhar X Empilhar W, Z, Y, com Y no topo M[X, a] pode ser uma produção de X ou um erro

70 A saída pode ser a produção usada
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Y1Y2Y3 ... Yk} { Desempilhar (X); Empilhar (Yk ... Y3Y3Y1) /* Y1 no topo */ ; Imprimir a produção {XY1Y2Y3 ... Yk};} 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 T’ T’  * F T’ | ε F  ( E ) | 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):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

89 Então não se pode aplicar um método preditor
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 Então não se pode aplicar um método preditor

90 Prepara um casamento entre pilha e entrada
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] Prepara um casamento entre pilha e entrada Exemplos: M[E’, +] = E’  +TE’ M[F, (] = F  (E) M[T’, *] = T’  *FT’ M[F, id] = F  id

91 É o caso das produções E  TE’ e T  FT’
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: 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’

92 E  T E’ E’  + T E’ | ε T  F T’ T’  * F T’ | ε F  ( E ) | id
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 Sendo   (N  )*, Primeiro () é o conjunto dos terminais que iniciam todas as sentenças derivadas de  Se  * ε, então ε  Primeiro () 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 Como  possui terminais,  * ε portanto: ε  Primeiro () Eliminando-se os terminais repetidos, obtém-se Primeiro()

95 Utilidade da função Primeiro () em análise preditora:
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() Caso b pertença aos dois conjuntos, a indecisão persiste 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 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)

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

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

99 Exemplo: sejam todas as possivelmente infinitas formas sentenciais de uma GLC
_ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ 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
_ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ A B _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ A a _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ _ A $ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ A b _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ A D _ $ a, b, $  Seguinte (A)

101 Cálculo do Primeiro ():
Seja  = X1 X2 X3 ... Xn, onde Xi (1  i  n) é um terminal ou um não terminal: O cálculo do Primeiro () exige o cálculo de Primeiro (Xi)

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: Inicialização Processo rotativo convergente

103 Algoritmo 5.4: 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 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  Y1Y2Y3 ... Yk (k  1) { Para (i  1; i  k; i++) Se (i = 1) || (j | (1  j  i-1),   Primeiro (Yj )) Acrescentar (Primeiro (Yi ) - {}) a Primeiro (X) Se (i | (1  i  k),   Primeiro (Yi )) Acrescentar  a Primeiro (X); }

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

106 Comentários: seja a produção X  Y1Y2Y3 ... Yk (k  1)
Se Y1, Y2 e Y3 derivam , então deve-se acrescentar a Primeiro (X) todo terminal contido em Primeiro (Y4) E assim por diante Se Y1, Y2 , Y3, ... , Yk derivam , então deve-se acrescentar  a Primeiro (X)

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

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

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

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

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

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

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

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

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

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

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

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

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

120 Algoritmo 5.5: Cálculo do Primeiro (),
onde  = X1 X2 X3 ... Xn e Xi  (N  ), (1  i  n) Primeiro ()  { }; Para (i  1; i  n; i++) Se (i = 1) || (j | (1  j  i-1),   Primeiro (Xj )) Acrescentar (Primeiro (Xi ) - {}) a Primeiro () ; Se (i | (1  i  n),   Primeiro (Xi )) Acrescentar  a Primeiro (); Se ( = ) Primeiro ()  {};

121 Comentários: seja  = X1 X2 X3 ... Xn
Todos os terminais de Primeiro (X1) devem pertencer a Primeiro () Caso (  Primeiro (X1)), todos os terminais de Primeiro (X2 ) devem pertencer a Primeiro () Caso (  Primeiro (X1) e   Primeiro (X2)), todos os terminais de Primeiro (X3) devem pertencer a Primeiro () 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 Inicialização trivial Inicialização não-trivial Processo rotativo convergente

123 Algoritmo 5.6: 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 * $  Seguinte (S) _ _ _ _ _ _ _ _ _ _ _ _ _ _ $
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ $ _ _ _ _ _ _ _ _ _ _ _ _ $ S $ _ _ _ _ _ _ _ _ _ _ _ _ _ $ $  Seguinte (S)

125 Inicialização não-trivial Para toda produção do tipo
A  w1 B1 w2 B2 w3 ... wn Bn wn+1, (n  1; wi  *, 1  i  n+1; Bi  N, 1  i  n) { Para (i  1; i  n; i++) { Expressão da produção: A  i Bi i, (i, i  (N  )*); Acrescentar (Primeiro (i ) - {}) a Seguinte (Bi) ; } Pelo menos um não-terminal do lado direito

126 Comentários: seja a produção A  i Bi i
Sendo A um não-terminal útil, haverá pelo menos uma forma sentencial do tipo _ _ _ _ _ _ _ _ _ _ _ _ A _ _ _ _ $ E haverá outra do tipo _ _ _ _ _ _ _ _ _ _ _ _ i Bi i _ _ _ _ $ Então (Primeiro (i) – {})  Seguinte (Bi) 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  w1 B1 w2 B2 w3 ... wn Bn wn+1, a produção em questão, onde (n  1; wi  *, 1  i  n+1; Bi  N, 1  i  n): Para (i  1; i  n; i++) { Expressão da produção: A  i Bi i, (i, i  (N  )*); Se ((i é vazia) ou (  Primeiro (i))) Acrescentar Seguinte (A ) a Seguinte (Bi) ; } Pelo menos um não-terminal do lado direito

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

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

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

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

132 Inicialização não-trivial do Algoritmo 5.6:
Seguinte (E) = {$} Seguinte (E’) = { } Seguinte (T) = {+} Seguinte (T’) = { } Seguinte (F) = { } 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:
Seguinte (E) = {$} Seguinte (E’) = { } Seguinte (T) = {+} Seguinte (T’) = { } Seguinte (F) = { } 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:
Seguinte (E) = {$} Seguinte (E’) = { } Seguinte (T) = {+} Seguinte (T’) = { } Seguinte (F) = { } Produção T  FT’: Seguinte (F) = Seguinte (F)  (Primeiro (T’) – {ε}) = { }  ({*, ε} – {ε}) = {*}

135 Inicialização não-trivial do Algoritmo 5.6:
Seguinte (E) = {$} Seguinte (E’) = { } Seguinte (T) = {+} Seguinte (T’) = { } Seguinte (F) = {*} 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:
Seguinte (E) = {$} Seguinte (E’) = { } Seguinte (T) = {+} Seguinte (T’) = { } Seguinte (F) = {*} 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:
Seguinte (E) = {$} Seguinte (E’) = { } Seguinte (T) = {+} Seguinte (T’) = { } Seguinte (F) = {*} Produção F  (E): Seguinte (E) = Seguinte (E)  (Primeiro (‘)’) – {ε}) = {$}  ({ ) } – {ε}) = {$, )}

138 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:
Seguinte (E) = {$, )} Seguinte (E’) = { } Seguinte (T) = {+} Seguinte (T’) = { } Seguinte (F) = {*}

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

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

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

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

144 Processo rotativo do Algoritmo 5.6, 1a rotação:
Seguinte (E) = {$, )} Seguinte (E’) = {$, )} Seguinte (T) = {+, $, )} Seguinte (T’) = {+, $, )} Seguinte (F) = {*, +, $, )} 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, 1a rotação:
Seguinte (E) = {$, )} Seguinte (E’) = {$, )} Seguinte (T) = {+, $, )} Seguinte (T’) = {+, $, )} Seguinte (F) = {*, +, $, )} Produção F ( E ): (Não se aplica a regra, pois ε  Primeiro (‘)’))

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

147 Processo rotativo do Algoritmo 5.6, 2a rotação:
Seguinte (E) = {$, )} Seguinte (E’) = {$, )} Seguinte (T) = {+, $, )} Seguinte (T’) = {+, $, )} Seguinte (F) = {*, +, $, )} Nada é alterado Ficam determinados os Seguinte’s 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

149 Sejam A       as produções de A 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
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
Se a  (Primeiro () e Primeiro () e Primeiro ()), mas se pelo menos  derivar ε 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’ |  T  F T’ T’  * F T’ |  F  ( E ) | id Tabelas dos Primeiro’s e Seguinte’s já calculadas:

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

155 Sejam A     as produções de A 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 Se a  (Primeiro () e Seguinte (A))
e se  derivar ε Indecisão: duas ou mais produções numa posição M[A, a] da tabela 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

157 Exemplo: seja a gramática para if-else: S  i b S S’ | a S’  e S | 
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 Ação típica: desempilhar o terminal da pilha Resolve o caso de esquecimento de b

160 Mensagem: a não era esperado É difícil escolher a melhor ação
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 É difícil escolher a melhor ação 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: Um terminal também pertencente a Seguinte (A) que case com 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: Haverá uma posição sem erro na tabela 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

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


Carregar ppt "Capítulo V Análise Sintática"

Apresentações semelhantes


Anúncios Google