Compilador Software que traduz o texto (linguagem fonte) que representa um programa para código máquina(linguagem alvo) capaz de ser executado pelo.

Slides:



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

Tópicos em Compiladores
gerador de código intermediário
Compiladores Claudio Benossi
II – Análise léxica DEI Papel do analisador léxico.
II – Análise léxica DEI lex: linguagem de especificação para analisadores léxicos Implementação de simuladores de autómatos finitos Bibliografia aconselhada:
Compiladores I Cristiano Damiani Vasconcellos
Introdução à Programação uma Abordagem Funcional Programação I Prof.ª Claudia Boeres CT VII - Sala 32 Departamento de Informática Centro.
Linguagem de Montagem Visão geral.
Seminários de Compiladores
Deyvisson, Rafael M.P., Renato, Robson C.F., Rodolfo
Análise Léxica (Parte 2)
Software Básico Silvio Fernandes
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
Linguagens Livres de Contexto
Identificando Linguagens Não Regulares
Curso Sistemas de Informação Disciplina: Arquitetura de Software
YACC.
Lex e Yacc.
Relações em uma Gramática
Linguagem de Prog. e Programas
Autômatos Finitos Determinísticos
Análise Léxica Supondo o trecho de programa abaixo:
Construção de Compiladores
Construção de Compiladores
Tradutores de Linguagens
André Luis Meneses Silva
O Portal do Estudante de Computação
Prof. Bruno Moreno Aula 4 – 11/03/2011
Análise léxica e sintática
Aula prática - análise contextual
Ferramentas para a Construção de Compiladores: Lex & Yacc
Compiladores, Aula Nº 5 João M. P. Cardoso
Compiladores, Aula Nº 9 João M. P. Cardoso
Gramáticas Livres de Contexto
Compiladores Prof. Claudio Benossi.
Sintaxe e Semântica Prof.: Gláucya Carreiro Boechat
Análises léxica e sintática
Análise Léxica Primeira fase de um compilador
Análise Léxica.
Capítulo II Gramáticas e Linguagens
Analise sintática aula-07-analise-sintática.pdf.
Geração de Código aula-12-geração-de-código.pdf.
Análises léxica e sintática
Analise Semântica aula-10-analise-semântica.pdf.
Projeto de Linguagens de Programação
Análise Sintática Prof. Alexandre Monteiro
Tradução Dirigida por Sintaxe
Back-End Compilação aula-11-back-end.pdf.
Mas para que serve um analisador sintático? Verificar se a estrutura gramatical do programa está correta Escrito de outra forma: O texto segue as regras.
CES-41 COMPILADORES Aulas Práticas
Compiladores Análise Sintática
Revisão Compiladores – AP1
Faculdade Pernambucana - FAPE Setembro/2007
COMPILADORES 04 Prof. Marcos.
Geradores de analisadores léxicos
Compiladores – IF688 Professor: André Santos
Computabilidade e Linguagens Formais
Sintaxe de uma Linguagem
SISTEMAS DE INFORMAÇÃO
Faculdade Pernambuca - FAPE
PLP – JavaCC Java Compiler Compiler
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
Compiladores Análise Léxica
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.
Transcrição da apresentação:

Compilador Software que traduz o texto (linguagem fonte) que representa um programa para código máquina(linguagem alvo) capaz de ser executado pelo computador

Compilador Nesse processo de tradução, há duas tarefas básicas a serem executadas por um compilador: análise, em que o texto de entrada (na linguagem fonte) é examinado, verificado e compreendido síntese, ou geração de código, em que o texto de saída (na linguagem objeto) é gerado, de forma a corresponder ao texto de entrada.

Compilador A fase de análise normalmente se subdivide em: análise léxica, análise sintática e análise semântica. É possível representar completamente a sintaxe de uma Linguagem de Programação através de uma gramática livre de contexto. Deixa-se para a análise semântica a verificação de todos os aspectos da linguagens que não se consegue exprimir de forma simples usando gramáticas livres de contexto.

front-end back-end Pré-processador Analisador Léxico Analisador Sintático Analisador Semântico Gerador de Código (intermediário) Otimizador back-end Gerador de Código

Analisador Léxico Analisador Sintático final = (nota1 + nota2) / 2; Analisador Léxico Id1 = (Id2 + Id3) / 2 Analisador Sintático = Id1 / + Id2 Id3 2 Tabela de Símbolos Id1 final double ... Id2 nota1 Id3 nota2

Analisador Semântico = Id1 / + Id2 Id3 intToDouble(2) Gerador de Código (intermediário) Tabela de Símbolos Id1 final double ... Id2 nota1 Id3 nota2 temp1 = intToDouble(2) temp2 = Id3 * temp1 temp3 = Id2 / temp2 Id1 = temp3

Otimizador de Código Temp1 = id3 *2.0 Id1 = id2 / temp1 MOVF ID3, R2 Gerador de Código MOVF ID3, R2 MULF #2.0, R2 MOVF ID2, R1 DIVF R2, R1 MOVF R1, ID1 Tabela de Símbolos Id1 final double ... Id2 nota1 Id3 nota2

Fases de um Compilador Gerenciamento da tabela de símbolos: uma estrutura de dados contendo um registro para cada identificador, com os campos contendo os atributos do identificador. Quando o analisador léxico detecta um identificador, instala-o na tabela de símbolos. A estrutura de dados permite encontrar rapidamente cada registro e armazenar ou recuperar dados do mesmo.

Fases de um Compilador Um compilador não deve parar quando encontrar algum erro e sim continuar para detectar todos. A análise léxica substituir a estrutura por tokens e acrescenta na tabela de símbolos A análise sintática transforma um texto na entrada em uma estrutura de dados, em geral uma árvore, o que é conveniente para processamento posterior e captura a hierarquia implícita desta entrada A análise semântica verifica os erros semânticos, (por exemplo, uma multiplicação entre tipos de dados diferentes) no código fonte e coleta as informações necessárias para a próxima fase da compilação que é a geração de código objeto

Compilador simples de uma passagem Uma linguagem de programação pode ser definida pela descrição da aparência de seus programas (a sintaxe da linguagem) e do que os mesmos significam (a semântica da linguagem) Para especificar a sintaxe de uma linguagem, apresentamos uma notação amplamente aceita, chamada gramática livre de contexto ou BFN (Forma Backus-Naur) Para especificar a semântica de uma linguagem usaremos descrições informais e exemplos sugestivos.

Gramáticas Uma linguagem consiste essencialmente de uma seqüência de strings ou símbolos com regras para definir quais seqüências de símbolos são válidas na linguagem, ou seja, qual a sintaxe da linguagem. A interpretação do significado de uma seqüência válida de símbolos corresponde à semântica da linguagem. Existem meios formais para definir a sintaxe de uma linguagem - a definição semântica é um problema bem mais complexo. A sintaxe de linguagens é expressa na forma de uma gramática, que será introduzida na seqüência.

Estrutura da vanguarda de um compilador Tradutor dirigido pela sintaxe Fluxo de tokens Fluxo de caracteres de entrada Representação intermediária Analisador léxico

Definição da Sintaxe Uma gramática descreve a estrutura hierárquica de muitas construções das linguagens de programação. O comando if tem a estrutura em C If (expressão) comando else comando O comando é if, um parêntese à esquerda, uma expressão, um parêntese à direita, um comando, a palavra else e outro comando cmd -> if (expr) cmd else cmd

Gramáticas Um conjunto de regras de produção, é um símbolo de partida. Uma regra de produção tem o formato   , onde  representa o nome da construção sintática e  representa uma forma possível dessa construção: <expressão>  <expressão> + <expressão>

Definição da Sintaxe A regra é chamada de produção If e parênteses são tokens As variáveis expr e cmd são sequências de tokens e não terminais

Elementos de uma gramática livre de contexto Conjunto de tokens (símbolos terminais) Conjunto não-terminais Conjunto de produções, onde a produção consiste em um não-terminal, chamado de lado esquerdo da produção, uma seta e uma sequência de tokens e/ou não- terminais, chamado de lado direito da produção Uma designação a um dos não terminais como símbolo de partida

Gramáticas <expr>  <expr> + <expr> | <const> <const>  <const><const> | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9

Derivação A verificar se uma frase faz parte da linguagem gerada pela gramática, envolve sucessivas substituições da cadeia de símbolos que ocorre do lado esquerdo da produção pela sua construção sintática correspondente, partindo do símbolo inicial. Essa substituição é chamada derivação sendo normalmente denotada pelo símbolo .

Derivação ... <expressão>  <expr> + <expr>  (<expr> - <expr>) + <expr>  (<const> - <expr>) + <expr>  (<const><const> - <expr>) + <expr>  (1<const> - <expr>) + <expr>  (10 - <expr>) + <expr>  (10 - <const>) + <expr> ...  (10 - 2) + 3

Árvore Gramatical (10 – 2) + 3 <expr> <expr> + <expr> (<expr>) <const> <expr> - <expr> <const> <const> 10 2 3

Gramática Ambíguas 10 – 2 + 3 <expr> <expr> 10 2 3 <expr> <expr> - <expr> <expr> + <expr> 10 2 3

Precedência de Operadores Como saber quem precede entre * e +. Para tal criamos mais dois não terminais

Precedência de Operadores <expr>  <expr> + <termo> | <expr> - <termo> | <termo> <termo>  (<expr>) | <const> <expr> <expr> + <termo> <expr> - <termo> + <termo> <termo> - <termo> + <termo> 10 – 2 + 3 <expr> <expr> + <termo> <expr> - <termo> 10 2 3

Precedência de Operadores <expr>  <expr> + <termo> | <expr> - <termo> | <termo> <termo>  <termo> * <fator> | <termo> / <fator> | <fator> <fator>  (<expr>) | <const> <expr> 1 + 2 * 3 <expr> + <termo> <termo> * <fator> 3 2 3

Gramática 1 + 2 * 3 <expr> <termo> <expr>  <expr> + <termo> | <expr> - <termo> | <termo> <termo>  <termo> * <fator> | <termo> / <fator> | <fator> <fator>  (<expr>) | <const> 1 + 2 * 3 <expr> <termo> <termo> * <fator>

Tradução Dirigida pela Sintaxe Programa Fonte Analisador Léxico Tabela de Símbolos ... token Solicita token Analisador Sintático Analisador Semântico Código Intermediário

Notação Posfixa (9-5)+2 => 95-2+ 9-(5+2) => 952+- Os parênteses são desnecessários na notação posfixa porque a posição e a aridade (número de argumentos) dos operadores permitem somente um decodificação de uma expressão posfixa

Definição dirigida pela Sintaxe A definição dirigida pela sintaxe usa gramática livre de contexto para especificar a estrutura sintática de entrada. Cada símbolo da gramática associa um conjunto de atributos e cada produção associa um conjunto de regras semânticas para computar os valores dos atributos associados aos símbolos que figuram naquela produção.

Atributos Sintetizados O valor em um nó da árvore gramatical é determinado a partir dos valores dos atributos dos filhos daquele nó. Os atributos sintetizados possuem a desejável propriedade de que podem ser avaliados durante um único caminhamento bottom-up (final para início) da árvore gramatical

Análise Léxica O Analisador Léxico (scanner) examina o programa fonte caractere por caractere agrupando-os em conjuntos com um significado coletivo (tokens): palavras chave (if, else, while, int, etc), operadores (+, -, *, /, ^, &&, etc), constantes (1, 1.0, ‘a’, 1.0f, etc), literais (“Projeto Mono”), símbolos de pontuação (; , {, }), labels.

Token Tokens, ou lexemas, é uma sequência de caracteres que podem ser tratados como uma unidade na gramática de uma linguagem de programação

Análise Léxica Entrada: arquivo texto Saída: sequência de tokens Conta número de linhas Remove espaços em branco e comentários Apresenta símbolos ilegais Produz a tabela de símbolos

Por que análise léxica? Simplifica a análise sintática Simplifica a definição da linguagem Modularidade Reusabilidade Eficiência

Análise Léxica constanteInt  digito digito* constanteDouble  digito digito*. digito* digito  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} X* Representa uma seqüência de zero ou mais X.

Autômatos Finitos Autômatos finitos, ou máquina de estados finitos autômatos finitos determinísticos autômatos finitos não-determinísticos

Compiladores A implementação de reconhecedores de linguagens regulares (autômatos finitos) é mais simples e mais eficiente do que a implementação de reconhecedores de linguagens livres de contexto (autômatos de pilha). Nesse caso, é possível usar expressões regulares para descrever a estrutura de componentes básicos das Linguagens de Programação, tais como identificadores, palavras reservadas, literais numéricos, operadores e delimitadores, etc. Essa parte da tarefa de análise (análise léxica) é implementada separadamente, pela simulação de autômatos finitos.

Autômato Finito Determinístico Definição. Um autômato finito determinístico é uma quíntupla M = (K, Σ, *, s, F), onde K é um conjunto finito de estados Σ é um alfabeto s € K é o estado inicial F está contido K é o conjunto de estados finais é a função de transição, K x Σ para K

Exemplo de um AFD q   (q, ) q0 a b q1 Exemplo. Seja M o autômato finito determinístico (K, Σ, *, s, F), onde K = {q0, q1} Σ = {a,b} s = q0 F = K {q0} q   (q, ) q0 a b q1

Valido no AFD (q0, aabba) (q0, abba) (q0, bba) (q1, ba) (q0, a) T T T T q   (q, ) q0 a b q1 T Portanto, (q0, aabba) é aceita por M

Autômato Finito Não-Determinístico Definição. Um autômato finito não- determinístico é uma quíntupla M = (K, Σ, ), s, F), onde K é um conjunto finito de estados Σ é um alfabeto s € K é o estado inicial F está contido K é o conjunto de estados finais é a função de transição, K x (Σ c {,}) para K

Exemplo de um AFND q   (q, ) Exemplo. Seja M o autômato finito não- determinístico (K, Σ, ), s, F), onde K = {q0, q1, q2, q3, q4} Σ = {a,b} s = q0 F = K {q4} q   (q, ) q0 a b q1 q2 q3 € q4

Entrada para um AFND (q0, bababab) (q1, ababab) (q3 babab) (q4, abab) Portanto, (q0, bababab) é aceita por M

Análise Sintática Verifica se as frases obedecem as regras sintáticas da linguagem: Por exemplo, uma expressão pode ser definida como: expressão + expressão expressão – expressão (expressão) constante

Gramáticas Um conjunto de regras de produção, é um símbolo de partida. Uma regra de produção tem o formato   , onde  representa o nome da construção sintática e  representa uma forma possível dessa construção: <expressão>  <expressão> + <expressão>

Gramáticas <expr>  <expr> + <expr> | <const> <const>  <const><const> | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9

Derivação A verificar se uma frase faz parte da linguagem gerada pela gramática, envolve sucessivas substituições da cadeia de símbolos que ocorre do lado esquerdo da produção pela sua construção sintática correspondente, partindo do símbolo inicial. Essa substituição é chamada derivação sendo normalmente denotada pelo símbolo .

Derivação ... <expressão>  <expr> + <expr>  (<expr> - <expr>) + <expr>  (<const> - <expr>) + <expr>  (<const><const> - <expr>) + <expr>  (1<const> - <expr>) + <expr>  (10 - <expr>) + <expr>  (10 - <const>) + <expr> ...  (10 - 2) + 3

Árvore Sintática (10 – 2) + 3 <expr> <expr> + <expr> (<expr>) <const> <expr> - <expr> <const> <const> 10 2 3

Linguagens Regulares Gerada a partir de uma gramática regular. Pode ser representada através de uma expressão regular. Pode ser reconhecida por um Autômato Finito. Considerando linguagens compostas por símbolos 0 e 1 podemos afirmar: a linguagem L01 ={0n1n| n  1} não é regular; a linguagem L01 ={0n1m | n  1, m  1} é regular;