1 / 36

CES-41 COMPILADORES

CES-41 COMPILADORES. Capítulo II Gramáticas e Linguagens. Capítulo II – Gramáticas e Linguagens. 2.1 – Gramáticas e linguagens de programação 2.2 – Gramáticas livres de contexto 2.3 – GLC’s ambíguas 2.4 – GLC’s recursivas à esquerda. 2.1 – Gramáticas e Linguagens de Programação.

Download Presentation

CES-41 COMPILADORES

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

E N D

Presentation Transcript


  1. CES-41 COMPILADORES Capítulo II Gramáticas e Linguagens

  2. Capítulo II – Gramáticas e Linguagens 2.1 – Gramáticas e linguagens de programação 2.2 – Gramáticas livres de contexto 2.3 – GLC’s ambíguas 2.4 – GLC’s recursivas à esquerda

  3. 2.1 – Gramáticas e Linguagens de Programação • As linguagens de programação conhecidas não são livres de contexto • Exemplo: seja a linguagem L = {w c w | w Є (a | b)*} onde ∑ = {a, b, c} • Sentença típica: aababcaabab

  4. L = {w c w | w Є (a | b)*} onde ∑ = {a, b, c} • Sentença típica: aababcaabab • A linguagem é uma simplificação daquelas que exigem a declaração de todo identificador antes de ser usado • A primeira ocorrência de aabab representa sua declaração e a segunda, seu uso • A letra c representa a separação entre declarações e comandos executáveis

  5. L = {w c w | w Є (a | b)*} onde ∑ = {a, b, c} • Sentença típica: aababcaabab • A Teoria de Linguagens Formais demonstra que tais linguagens não podem ser geradas por gramáticas livres de contexto (GLC’s) • Ou seja, apresentam sensibilidade ao contexto • No entanto não se usam gramáticas sensíveis ao contexto (GSC’s) para analisar programas escritos em linguagens de programação

  6. Gramáticas regulares são usadas na análise léxica • Gramáticas livres de contexto são usadas na análise sintática • A sensibilidade ao contexto das linguagens é verificada na análise semântica • Exemplo: declaração de identificadores • Um identificador é colocado na tabela de símbolos quando de sua declaração • Sua presença nessa tabela é verificada, quando de seu uso (teste semântico)

  7. 2.2 – Gramáticas Livres de Contexto 2.2.1 – Definição • Tipicamente são usadas três especificações para se definir uma linguagem de programação: • Especificações sintáticas, feitas através de uma GLC • Especificações léxicas, usando expressões regulares • Especificações semânticas, usando restrições às construções sintáticas

  8. Em compilação, para a maioria das linguagens de programação,há uma simplificação tal que: • GLC’s são usadas para guiar toda a fase de análise e a geração do código intermediário (todo o front-end do compilador) • O analisador sintático é fundamentado numaGLC’s • Ele tem como escravo o analisador léxico • Ele tem como recheio o analisador semântico e o gerador do código intermediário

  9. GLC é uma entidade G contendo quatro componentes: • Um conjunto finito N de símbolos não-terminais • Um alfabeto, ou seja, um conjunto finito ∑ de símbolos terminais, também chamados de átomos • A designação de um dos não-terminais de N para ser o símbolo inicial, referenciado muitas vezes por S • Um conjunto P de produções • Simbolicamente, G = {N, ∑, S, P}

  10. Forma geral de uma produção: A → α • A é um não-terminal, ou seja, A Є N, e é chamado de lado-esquerdo • α é um conjunto de zero ou mais terminais e/ou não-terminais, ou seja, αЄ (N  ∑)*, e é chamado de lado-direito

  11. De passagem, produção com sensibilidade ao contexto: βA γ → βαγ • A é um não-terminal, ou seja, A Є N • α,β,γ são conjuntos de zero ou mais terminais e/ou não-terminais, ou seja, α,β,γЄ (N  ∑)* • Pelo menos um entre β e γ não é vazio • A pode ser substituído por α, se estiver entre β e γ

  12. 2.2.2 – Construção de um programa ou sentença • Seja a seguinte gramática G = {N, ∑, S, P} N = {S, A} ∑ = {(, )} P = {S  ( A ) | S ( A ) , A ε | S} Símbolo inicial: S • O símbolo inicial S é o embrião • A construção se inicia substituindo-se o símbolo inicial, pelo lado direito de uma de suas produções: S  S ( A ) • Tem início a formação do feto do programa

  13. P = {S  ( A ) | S ( A ) , A ε | S} • A seguir, lados esquerdos de produções que fazem parte desse feto vão sendo substituídos pelos lados direitos S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( A ) )  ( ) ( ( ) ) A construção termina quando todos os não-terminais tiverem sido substituídos O símbolo inicial e cada estado do feto são formas sentenciais do programa ou da sentença Sentença é uma forma sentencial sem não-terminais

  14. P = {S  ( A ) | S ( A ) , A ε | S} S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( A ) )  ( ) ( ( ) ) A linguagem gerada por G, é o conjunto de todas as sentenças geradas por G Simbolicamente L(G) = { w *  S * w }

  15. P = {S  ( A ) | S ( A ) , A ε | S} Definição recursiva de forma sentencial de uma gramática: 1) O símbolo inicial S é uma forma sentencial 2) Seja A um não-terminal e sejam α, β, γ cadeias de símbolos terminais e/ou não terminais 3) Se βAγ for uma forma sentencial e A → α uma produção, então β α γ é também uma forma sentencial S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( A ) )  ( ) ( ( ) )

  16. P = {S  ( A ) | S ( A ) , A ε | S} S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( A ) )  ( ) ( ( ) ) Derivação direta é a substituição, numa forma sentencial, de um não-terminal pelo lado direito de uma de suas produções O processo ao lado apresenta 6 derivações diretas

  17. P = {S  ( A ) | S ( A ) , A ε | S} S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( A ) )  ( ) ( ( ) ) Derivação de uma forma sentencial é uma sequência de zero ou mais derivações diretas para produzir essa forma, começando do símbolo inicial Simbolicamente: S * S, S * ( ) ( ( ) ) e S * ( ) ( A ) Outro símbolo: +: sequência de uma ou mais derivações diretas

  18. P = {S  ( A ) | S ( A ) , A ε | S} As definições de derivação e derivação direta e os símbolos , * e + podem ser aplicados a - Não-terminais diferentes do símbolo inicial - Sub-cadeias de sentenças - Sub-cadeias de formas sentenciais Exemplos: A  S  ( A )  ( ) A +( A ) A *( ) S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( A ) )  ( ) ( ( ) )

  19. Exemplo: produção de um programa na linguagem LAtrib, com as seguintes características: • Programas têm só o módulo principal • Esse módulo tem cabeçalho, declarações e comandos de atribuição • As variáveis podem ser inteiras e reais, escalares • Operadores de expressões: soma e subtração • Expressões podem ter parêntesis

  20. Gramática para LAtrib: • ∑ = {program, var, int, real, ID, CTINT, CTREAL, ‘{’, ‘}’, ‘;’, ‘,’ , ‘=’ , ‘+’ , ‘-’ , ‘(’, ‘)’} • Os átomos literais em negrito são palavras reservadas • N = {Programa, Cabeçalho, Declarações, ListDecl, Declaração, Tipo, ListId, Comandos, ListCmd, CmdAtrib, Expressão, Termo} • O símbolo inicial é Programa

  21. Seja o programa Exemplo: program Exemplo; var int i, j; real x; { i = 2; j = 3; x = 5.5–(i+j); } Produções da Gramáticapara LAtrib: Programa → Cabeçalho Declarações Comandos Cabeçalho → program ID ; Declarações → ε | varListDecl ListDecl → Declaração | ListDecl Declaração Declaração → Tipo ListId; Tipo → int | real ListId → ID | ListId, ID Comandos→ {ListCmd} ListCmd → ε | ListCmdCmdAtrib CmdAtrib → ID =Expressão; Expressão → Termo | Expressão+Termo | Expressão-Termo Termo → ID | CTINT | CTREAL | (Expressão) Seja a construção do programa Exemplo

  22. program Exemplo; var int i, j; real x; {i = 2; j = 3; x = 5.5 – (i + j);} ProgramaCabeçalho Declarações Comandos +program ID(Exemplo) ; varListDecl{ListCmd} +program ID(Exemplo) ; var ListDecl Declaração {ListCmdCmdAtrib} +program ID(Exemplo) ; var Declaração Declaração {ListCmdCmdAtribCmdAtrib} +program ID(Exemplo) ; var Declaração Declaração {ListCmdCmdAtribCmdAtribCmdAtrib}

  23. program Exemplo; var int i, j; real x; {i = 2; j = 3; x = 5.5 – (i + j);} +program ID(Exemplo) ; var Declaração Declaração {CmdAtribCmdAtribCmdAtrib} +program ID(Exemplo) ; var Tipo ListId;Tipo ListId; { ID(i)=Expressão; ID(j)=Expressão; ID(x)=Expressão;} +program ID(Exemplo) ; var intListId, ID(j);real ID(x); { ID(i)=Termo; ID(j)=Termo; ID(x)=Expressão-Termo;}

  24. program Exemplo; var int i, j; real x; {i = 2; j = 3; x = 5.5 – (i + j);} +program ID(Exemplo) ; var int ID(i) , ID(j) ; real ID(x) ; { ID(i) = Termo ; ID(j) = Termo ; ID(x) = Termo - ( Expressão ) ; } +program ID(Exemplo) ; var int ID(i) , ID(j) ; real ID(x) ; { ID(i) = Termo ; ID(j) = Termo ; ID(x) = Termo - ( Expressão + Termo ) ; }

  25. program Exemplo; var int i, j; real x; {i = 2; j = 3; x = 5.5 – (i + j);} +program ID(Exemplo) ; var int ID(i) , ID(j) ; real ID(x) ; { ID(i) = Termo ; ID(j) = Termo ; ID(x) = Termo - ( Termo + Termo ) ; }

  26. program Exemplo; var int i, j; real x; {i = 2; j = 3; x = 5.5 – (i + j);} +program ID(Exemplo) ; var int ID(i) , ID(j) ; real ID(x) ; { ID(i) = CTINT(2) ; ID(j) = CTINT(3) ; ID(x) = CTREAL(5.5) - (ID(i)+ ID(j) ) ; }

  27. 2.2.3 – Árvores sintáticas • Árvore sintática é uma representação gráfica de uma derivação • Exemplo: árvore sintática de S * ( ) ( ( ) )

  28. Árvore sintática do programa Exemplo program Exemplo; var int i, j; real x; { i = 2; j = 3; x = 5.5–(i+j); }

  29. 2.3 – GLC’s Ambíguas • Uma GLC é ambígua, se uma de suas sentenças possuir 2 ou mais árvores sintáticas distintas • Exemplo: Seja a gramática G = {, N, P, S} tal que:  = {a, b}; N = {S}; P = {S  S b S  a} • G é ambígua pois a sentença ababa tem duas árvores sintáticas:

  30. Exemplo: a Língua Portuguesa sem pontuação teria sérias ambiguidades • A frase matar o rei não é pecado teria dois sentidos: 1) matar o rei não é pecado 2) matar o rei não é pecado

  31. Em compilação, as gramáticas devem ser não-ambíguas, ou então, deve-se acrescentar regras para resolver ambiguidades • Exemplo: comando if-else da Linguagem C Produções: S  if B S else S  if B S  a1  a2 B  b1  b2

  32. S  if B S else S  if B S  a1  a2 B  b1  b2 • A sentença if b1 if b2 a1 else a2 tem duas árvores sintáticas, a saber: Regra de solução: fazer o else corresponder ao último if

  33. 2.4 – GLC’s Recursivas à Esquerda • Uma GLC é recursiva à esquerda, se tiver um não-terminal A tal que haja uma derivação A + A, onde  (N )* • Exemplo: Na gramática G = {, N, P, S} tal que:  = {a, b}; N = {S}; P = {S  S b S  a} tem-se S  S b S (recursividade imediata à esquerda)

  34. Exemplo: Na gramáticada linguagem LAtrib, as seguintes produções são recursivas à esquerda: ListDecl → ListDecl Declaração ListId → ListId, ID ListCmd → ListCmdCmdAtrib Expressão → Expressão+Termo | Expressão-Termo

  35. Existe recursividade não-imediata à esquerda • Exemplo: Seja a gramática G = {, N, P, S} na qual:  = {a, b, c, d}; N = {S, A}; P = {S Aa b , A  Sc  d } Essa gramática é não-imediatamente recursiva à esquerda pois: S  A a S c a

  36. Análise sintática top-down- grande grupo de métodos muito populares de análise sintática: • Não consegue tratar gramáticas recursivas à esquerda • Tais gramáticas devem então ser transformadas em outras equivalentes não-recursivas à esquerda • Essa transformação será vista no Capítulo V • Análise sintática bottom-up- outro grande grupo de métodos muito populares de análise sintática: • Trabalha mais eficientemente com gramáticas recursivas à esquerda • Yacc usa análise bottom-up

More Related