CP 5017.9 Prof. Msc.. Carlos de Salles 1 - EMENTA O Processo de Compilação. Deteção e Recuperação de Erros. Introdução à geração de Código Intermediário. Geração de Código de Máquina. Otimização. Uma visão sobre alguns compiladores. A construção de um compilador. 2 - O PROCESSO DE COMPILAÇÃO 2.1 - Introdução 2.2 - Aspectos do Processo de Compilação 3 - DEFINIÇÃO DE LINGUAGEM 3.1 - Introdução 3.2 - Sintaxe e Semântica 3.3 - Gramáticas - Definição Formal de Linguagem de Programação 3.4 - O Problema da Análise 4 - ANÁLISE LÉXICA 4.1 - Introdução 4.2 - Construção Manual de Analisadores 4.3 - Construção Sistemática de Analisadores 4.4 - Saídas do Analisador Léxico 4.5 - Implementação 4.6 - Erros 5 - GRAMÁTICAS LIVRES DO CONTEXTO 5.1 - Sintaxe e Semântica 5.2 - Gramáticas - Definição Formal de Linguagens de Programação 5.3 - Gramáticas Livres do Contexto Slide 1
Ementa (continuação) CP 5017.9 Prof. Msc.. Carlos de Salles 6 - ANÁLISE SINTÁTICA DESCENDENTES 6.1 - Formalização 6.2 - Análise com Recuperação 6.3 - Análise sem Recuperação 6.3.1 - Analisadores Recursivos 6.3.2 - Analisadores Preditivos 7 - ANÁLISE SNTÁTICA ASCENDENTE 7.1 - Formalização 7.2 - Analisadores de Precedência 8 - TRADUÇÃO DIRIGIDA POR SINTAXE 8.1 - Esquemas da Tradução Dirigida por Sintaxe 8.2 - Implementação de Tradutores Dirigidos por Sintaxe 9 - TABELA DE SÍMBOLOS 9.1 - Os Conteúdos da Tabela de Símbolo 9.2 Organizações de Tabelas de Símbolos 10 - ORGANIZAÇÃO DE MEMÓRIA 11 - CONSTRUÇÃO AUTOMÁTICA DE ANALISADORES EFICIENTES Bibliografia GRUNE, DICK et al. Projeto Moderno de Compiladores. Editora Campus. AHO, Alfred; SETHI, Ravi; ULLMAN, Jeffrey D. Compiladores Princípios, Técnicas e Ferramentas. Editora Guanabara. Editora LTC. Slide 2
Paradigma análise/síntese código fonte interface de vanguarda código intermediário gerador de código código alvo Estrutura básica de um compilador Slide 3
Interface de vanguarda do compilador Engloba as fases de análise Gera uma representação semântica intermediária Análise léxica Converte uma seqüência de caracteres no(s) arquivo(s) de entrada com o código fonte em uma seqüência de tokens equivalente; Cada token representa um elemento atômico da linguagem; Análise sintática Transforma a seqüência de tokens em uma árvore sintática que representa o código fonte; É dividido em dois grupos de métodos: os top-down e os bottom-up; Tratamento de contexto Avalia erros de tipagem e nos identificadores; Baseia-se em informações coletadas numa estrutura chamada tabela de símbolos. Slide 4
Geração de código X Interpretação Geração de código Transforma a representação semântica intermediária em código executável em uma linguagem alvo; Características: Processamento considerável; A forma intermediária resultante, que é de código binário específico da máquina, é de baixo-nível; O mecanismo de interpretação é o próprio hardware da CPU; A execução do programa é relativamente rápida; Interpretação Ao invés de traduzir para uma linguagem alvo, realiza as ações semânticas diretamente; Vantagens: Geralmente um interpretador é escrito em uma linguagem de mais alto nível, portanto irá rodar em várias máquinas diferentes. Um gerador de código é voltado para uma máquina específica; Escrever um interpretador exige esforço bem menor; Executar as ações diretamente da representação semântica permite tanto uma melhor verificação quanto informação de erros; Melhor segurança (explorado por Java) Características: O processamento do programa é de mínimo a moderado; A forma intermediária resultante, alguma estrutura de dados específica de sistema, de médio a alto nível; O mecanismo de interpretação é um programa; A execução do programa é relativamente lenta. Slide 5
Por que estudar Compiladores? Estruturação eficaz do problema Compiladores analisam sua entrada, constroem uma representação semântica intermediária e sintetizam sua saída a partir disso; Esse paradigma análise-síntese é muito poderoso e amplamente aplicável; Usando a mesma representação semântica intermediária, um compilador pode ser escrito para L linguagens e M máquinas, bastando escrever as L interfaces de vanguarda diferentes e os M sintetizadores diferentes; Uso eficiente de formalismos Expressões regulares análise léxica Gramáticas livres de contexto análise sintática Gramáticas de atributo tratamento de contexto e extensão para geração de código e interpretação Casamento de padrões e técnicas de programação dinâmica geração de código Uso de ferramentas de geração de programas A entrada para um gerador de programas é de um nível de abstração mais alto que de uma linguagem de programação; Flexibilidade e mutabilidade ampliadas; Código pré-construído pode ser incluído em um programa gerado, aumentando seu poder a quase nenhum custo; Uma descrição formal pode ser usada para gerar mais de um tipo de programa; Exemplo: Flex/Bison; Lex/Yacc. Slide 6
Por que estudar Compiladores? A construção de compiladores tem uma ampla aplicabilidade; O uso de técnicas de construção de compiladores são aplicadas em outros escopos Exemplos: Conversão de formatos diferentes de arquivos; Leituras de arquivos HTML ou PostScript. Compiladores são baseados em algoritmos gerais úteis As estruturas de dados e algoritmos implementados são didaticamente importantes Exemplos: Árvores sintáticas; Tabelas hash; Tabelas pré-processadas ; Coletor de lixo; Programação dinâmica, etc. Enfim, estudar compiladores é solidificar o conhecimento de programação! Slide 7
Propriedades de um bom compilador Gerar código correto; De que adianta um compilador que erra uma vez a cada um milhão; Estar de acordo com a especificação da linguagem; Nada de super ou sub-conjuntos da linguagem; Ser escalável, ou seja, ser capaz de tratar códigos fonte de tamanhos arbitrários; Atualmente isso é muito mais simples já que a quantidade de memória disponível é cada vez maior; Velocidade de compilação não é mais importante; Nada mais de cartões compilar agora é rápido; Algoritmos desejavelmente lineares O(n); Não é interessante a existência de algoritmos nãolineares no processo de compilação; Problema: a otimização de código não é linear; Outras características importantes: Portabilidade do compilador; Portabilidade do código alvo; Slide 8
Slide 9 Histórico de compiladores 1945 1960: Geração de Código Linguagens sendo desenvolvidas lentamente; O uso de compiladores era chamado de programação automática ; Linguagens de alto nível não eram bem vistas; Se o compilador gerava código inferior àquele gerado manualmente com assemblers, para que uma linguagem de alto nível? 1960 1975: Parsing Proliferação de novas linguagens; Nasce a idéia que é melhor ter ferramentas para gerar um compilador rapidamente que gerar código mais eficiente; Mudança no paradigma: maior enfoque na análise que na síntese; Aparecimento de técnicas formais notadamente voltadas para a geração de parsers; 1975 dias atuais: Geração e Otimização de Código; Novos Paradigmas Número de novas linguagens e de novas máquinas caem; Demanda por interfaces com o usuário mais amigáveis (nascimento dos IDEs); Novos paradigmas de programação, como linguagens funcionais e lógicas e programação distribuída; A ênfase agora é o que compilar e não mais como compilar.