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

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

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

Apresentações semelhantes


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

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 As linguagens de programação conhecidas não são livres de contexto Exemplo: seja a linguagem Exemplo: seja a linguagem L = {w c w | w Є (a | b)*} onde ∑ = {a, b, c} Sentença típica: aababcaabab Sentença típica: aababcaabab

4 L = {w c w | w Є (a | b)*} onde ∑ = {a, b, c} Sentença típica: aababcaabab Sentença típica: aababcaabab A linguagem é uma simplificação daquelas que exigem a declaração de todo identificador antes de ser usado 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 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) 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 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 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 regulares são usadas na análise léxica Gramáticas livres de contexto são usadas na análise sintática 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 A sensibilidade ao contexto das linguagens é verificada na análise semântica Exemplo: declaração de identificadores 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 – Definição Tipicamente são usadas três especificações para se definir uma linguagem de programaçã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: 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: 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} Simbolicamente, G = {N, ∑, S, P}

10 Forma geral de uma produção: A → α 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: 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 ■ 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 ) )  ( ) ( ( ) ) 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 S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( 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 S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( 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 S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( 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 ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( A ) )  ( ) ( ( 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 S  S ( A )  ( A ) ( A )  ( ) ( A )  ( ) ( S )  ( ) ( ( 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, ‘{’, ‘}’, ‘;’, ‘,’, ‘=’, ‘+’, ‘-’, ‘(’, ‘)’} ∑ = {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} N = {Programa, Cabeçalho, Declarações, ListDecl, Declaração, Tipo, ListId, Comandos, ListCmd, CmdAtrib, Expressão, Termo} O símbolo inicial é Programa 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 }  + program ID (Exemplo) ; var Declaração Declaração { 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 ; } 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 ; } 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 ) ; }  + program ID (Exemplo) ; var int ID (i), ID (j) ; real ID (x) ; { ID (i) = Termo ; ID (j) = Termo ; ID (x) = Termo - ( Expressão + Termo ) ; } 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 (i) = Termo ; ID (j) = Termo ; ID (x) = Termo - ( Termo + 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 (i) = CTINT (2) ; ID (j) = CTINT (3) ; ID (x) = CTREAL (5.5) - (ID (i) + ID (j) ) ; 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 2.3 – GLC’s Ambíguas Uma GLC é ambígua, se uma de suas sentenças possuir 2 ou mais árvores sintáticas distintas 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: 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: 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 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 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 Exemplo: comando if-else da Linguagem CProduções: S  if B S else S  if B S  a1  a2 B  b1  b2

32 A sentença 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   )* 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: 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: 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 Existe recursividade não-imediata à esquerda Exemplo: Seja a gramática G = { , N, P, S} na qual: 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: 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: 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 "CES-41 COMPILADORES Capítulo II Gramáticas e Linguagens."

Apresentações semelhantes


Anúncios Google