Capítulo II Gramáticas e Linguagens

Slides:



Advertisements
Apresentações semelhantes
FAPE - Curso de Ciência da Computação
Advertisements

Software Básico Silvio Fernandes
Tópicos em Compiladores
Capítulo II – Algoritmos e Programas
5.5 – Análise Bottom-Up Tentativa de construir uma árvore sintática para a sentença analisada, começando das folhas, indo em direção à raiz (pós-ordem.
Compiladores Claudio Benossi
Compiladores I Cristiano Damiani Vasconcellos
Linguagem de Montagem Visão geral.
Prof. Yandre Maldonado e Gomes da Costa
Teoria da Computação FIC– Ciência da Computação
Deyvisson, Rafael M.P., Renato, Robson C.F., Rodolfo
Software Básico Silvio Fernandes
Compiladores Prof. Yandre Maldonado Compiladores - Prof. Yandre - 1.
Introdução à Compilação Prof. Leandro Magno Slides adaptados a partir do material cedido pelos professores Heloise Manica Paris Teixeira, Yandre M. G.
Prof. Heloise Manica Paris Teixeira
Análise Sintática - Continuação
Análise Sintática - Continuação
Linguagens Livres de Contexto
Linguagens Livre de Contexto
Identificando Linguagens Não Regulares
Curso Sistemas de Informação Disciplina: Arquitetura de Software
YACC.
Análise Sintática Ascendente
Relações em uma Gramática
Análise Léxica Supondo o trecho de programa abaixo:
Construção de Compiladores
Construção de Compiladores
Construção de Compiladores
5.6 – Complementos de Yacc – Usando Yacc com gramáticas ambíguas
Prof. Msc. Raul Paradeda Aula 3 Fundamentos
Prof. Bruno Moreno Aula 4 – 11/03/2011
Análise léxica e sintática
Aula prática - análise contextual
Compiladores, Aula Nº 5 João M. P. Cardoso
Compiladores, Aula Nº 9 João M. P. Cardoso
Gramáticas Livres de Contexto
Sintaxe e Semântica Prof.: Gláucya Carreiro Boechat
Análises léxica e sintática
Expressões Regulares e Gramáticas
Analise sintática aula-07-analise-sintática.pdf.
Esquemas L-atribuídos
Capítulo VIII Ambientes de Execução
Análises léxica e sintática
Analise Semântica aula-10-analise-semântica.pdf.
Compiladores.
Análise Sintática Prof. Alexandre Monteiro
Tradução Dirigida por Sintaxe
CES-41 COMPILADORES Aulas Práticas Capítulo II A Ferramenta Yacc.
CES-41 COMPILADORES Aulas Práticas
Linguagens Livres de Contexto
Compiladores Análise Sintática
Faculdade Pernambucana - FAPE Setembro/2007
COMPILADORES 04 Prof. Marcos.
Uma Infraestrutura para a
Fundamentos de linguagens de programação
Semântica de Linguagens de Programação
CES-10 INTRODUÇÃO À COMPUTAÇÃO
Programação de Computadores - 1
Engenharia/Ciência da Computação
Sintaxe de uma Linguagem
SISTEMAS DE INFORMAÇÃO
tópicostópicos itens 01. Terminologia 02. Operações básicas 03. Representação de linguagens 04. Formalização de gramáticas 05. Processo de derivação 06.
Analisador sintático: Tipos de análises sintáticas
Compilador Software que traduz o texto (linguagem fonte) que representa um programa para código máquina(linguagem alvo) capaz de ser executado pelo.
Faculdade Pernambuca - FAPE Compiladores Abril/2007 Compiladores Abril/2007.
Informática Teórica Engenharia da Computação. Teoria da Computação Contexto do que vamos começar a estudar As linguagens também podem ser definidas formalmente.
COMPILADORES 03 Prof. Marcos.
Análise Contextual Mauro Araújo Teoria e Implementação de Linguagens Computacionais - IF688 Centro de Informática – CIn Universidade Federal de Pernambuco.
Transcrição da apresentação:

Capítulo II Gramáticas e Linguagens 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 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

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

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

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)

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

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

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}

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

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 γ

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

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

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 }

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

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

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

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 * ( )

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

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

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

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

+ 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);}

+ 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);}

+ 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);}

+ 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);}

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

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

 = {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:

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

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

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

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)

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

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

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