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

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

Capítulo II Gramáticas e Linguagens

Apresentações semelhantes


Apresentação em tema: "Capítulo II Gramáticas e Linguagens"— Transcrição da apresentação:

1 Capítulo II Gramáticas e Linguagens
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 numa GLC’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 é 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 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 ) )  ( ) ( ( ) ) P = {S  ( A ) | S ( A ) , A  ε | S} 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 )
 ( ) ( ( ) ) P = {S  ( A ) | S ( A ) , A  ε | S} 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} S  S ( A )  ( A ) ( A )
 ( ) ( ( ) ) 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

16 P = {S  ( A ) | S ( A ) , A  ε | S} S  S ( A )  ( A ) ( A )
 ( ) ( ( ) ) P = {S  ( A ) | S ( A ) , A  ε | S} 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 S * S, S * ( ) ( ( ) ) e S * ( ) ( A )
S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( A ) )  ( ) ( ( ) ) P = {S  ( A ) | S ( A ) , A  ε | S} 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} S  S ( A )  ( A ) ( A )
 ( ) ( ( ) ) 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 * ( )

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

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

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

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

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

26 + 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) ) ; } program Exemplo; var int i, j; real x; {i = 2; j = 3; x = 5.5 – (i + 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  = {a, b}; N = {S}; P = {S  S b S  a}
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 tem duas árvores sintáticas, a saber:
A sentença if b1 if b2 a1 else a2 tem duas árvores sintáticas, a saber: S  if B S else S  if B S  a1  a2 B  b1  b2 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ática da linguagem LAtrib, as seguintes produções são recursivas à esquerda:
ListDecl → ListDecl Declaração ListId → ListId , ID ListCmd → ListCmd CmdAtrib 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


Carregar ppt "Capítulo II Gramáticas e Linguagens"

Apresentações semelhantes


Anúncios Google