Compiladores Introduo Guilherme Amaral Avelino gavelinogmail com O

  • Slides: 22
Download presentation
Compiladores - Introdução Guilherme Amaral Avelino gavelino@gmail. com

Compiladores - Introdução Guilherme Amaral Avelino gavelino@gmail. com

O que é um Compilador? “Um compilador é um programa que lê um programa

O que é um Compilador? “Um compilador é um programa que lê um programa escrito em uma linguagem (linguagem fonte) e a traduz em um programa equivalente em outra linguagem (linguagem alvo). ” Aho, Sethi, Ullman.

O que é um Compilador? �Nesse processo de tradução, há duas tarefas básicas a

O que é um 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 �Análise léxica, sintática e semântica ◦ 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

�É possível representar completamente a sintaxe de uma LP através de uma gramática sensível

�É possível representar completamente a sintaxe de uma LP através de uma gramática sensível ao contexto. �Mas como não existem algoritmos práticos para tratar essas gramáticas, a preferência recai em usar gramáticas livres 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.

�A implementação de reconhecedores de linguagens regulares (autômatos finitos) é mais simples e mais

�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 LP, 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.

Compiladores – Separando em partes � modelos possíveis para a Um Umdos modelos possíveis

Compiladores – Separando em partes � modelos possíveis para a Um Umdos modelos possíveis construção para a de compiladores faz a separação total entre o construção de compiladores faz a e o Front-end frontend, encarregado da fase de análise, back-end, encarregado da o geração de código, de separação total entre front-end, forma que encarregado da fase de análise, e o ◦ O front-end e back-end se comunicam apenas back-end, encarregadointermediária da geração de através da representação código, de forma ◦ O front-end dependeque exclusivamente. Core. Printer da ◦ linguagem O front-endfonte; e back-end se comunicam ◦ O back-end depende exclusivamente da apenas através da representação Gerador GHC linguagem destino. Phx. STGCompiler intermediária Gerador de IL � Simplifica a implementação de novos compiladores ◦◦ O front-end depende exclusivamente da Front-end específico para cada linguagem Assembler / Assembly MSIL ILDASM linguagem fonte; Compilador C ◦ Back-end específico para a arquitetura alvo Arquivo Haskell ' Parser Verificador de Tipos Desugarer Otimizações Sintaxe Core. To. STG Arquivo Core Código Assembly / Código C Haskell. NET GHC Nativo Sintaxe STG Código MSIL (Texto) JIT ◦ O back-end depende exclusivamente da Back-end linguagem objeto. Código Nativo

Compiladores - Fases �Conjunto código fonte de alterações feitas no Analisador código as quais

Compiladores - Fases �Conjunto código fonte de alterações feitas no Analisador código as quais léxico são responsáveis por uma atividade Analisador específica do processo sintático de compilação Analisador Gerador tabela de◦ símbolos Análise ◦ ◦ Léxica semântico (scanner) de Análise Sintática. Gerador (parser) código intermediário Análise Semântica Otimizador de código Otimização Gerador de Geração de código alvo Tratador de erros

Análise Léxica �Também chamada de scanner � Agrupa caracteres em símbolos tokens) � Entrada:

Análise Léxica �Também chamada de scanner � Agrupa caracteres em símbolos tokens) � Entrada: fluxo de caracteres � Saída: fluxo de símbolos � Símbolos são: (ou ◦ Palavras reservadas, identificadores de variáveis e procedimentos, operadores, pontuação, . . . �Uso de expressões regulares no reconhecimento �Lex/Flex são ferramentas que geram scanners.

Análise Léxica Dado os caracteres da instrução montante : = saldo + taxa_de_juros *

Análise Léxica Dado os caracteres da instrução montante : = saldo + taxa_de_juros * 30; São identificados os seguintes tokens: �Identificador montant �Símbolo de atribuição : = �Identificador saldo �Símbolo de adição + �Identificador taxa_de_juros �Símbolo de multiplicação * �Número 30

Análise Sintática �Também chamada de parser �Agrupa símbolos em unidades sintáticas �Ex. : os

Análise Sintática �Também chamada de parser �Agrupa símbolos em unidades sintáticas �Ex. : os 3 símbolos A+B podem ser agrupados em uma estrutura chamada de expressão. �Expressões depois podem ser agrupados para formar comandos ou outras unidades. �Saída: representação árvore de parse do programa �Gramática livre de contexto é usada para definir a estrutura do programa reconhecida por um parser �Yacc/Bison são ferramentas para gerar parsers

Análise Sintática Comando : = Identificado r montante Expressã o + Expressã o Identificado

Análise Sintática Comando : = Identificado r montante Expressã o + Expressã o Identificado r saldo Árvore gerada para: Expressã o * Expressã o o Identificado Número r taxa_de_juro 60 s montante : = saldo + taxa_de_juros * 60

Análise Semântica � Verifica se estruturas sintáticas, embora corretas sintaticamente, têm significado admissível na

Análise Semântica � Verifica se estruturas sintáticas, embora corretas sintaticamente, têm significado admissível na linguagem. � Por exemplo, não é possível representar em uma gramática livre de contexto uma regra como “todo identificador deve ser declarado antes de ser usado“ � Um importante componente é checagem de tipos. � Utiliza informações coletadas anteriormente e armazenadas na tabela de símbolos � Considerando “A + B”, quais os possíveis problemas semânticos? � Saída: árvore de parse anotada

Análise Semântica * montante saldo * + montante * taxa_de_juro 60 s saldo +

Análise Semântica * montante saldo * + montante * taxa_de_juro 60 s saldo + * taxa_de_juro inttoreal s Conversão de inteiro para real inserida pela análise semântica

Gerador de Código Intermediário �Usa as estruturas produzidas pelo analisador sintático e verificadas pelo

Gerador de Código Intermediário �Usa as estruturas produzidas pelo analisador sintático e verificadas pelo analisador semântico para criar uma seqüência de instruções simples (código intermediário) �Está entre a linguagem de alto nível e a linguagem de baixo nível

Gerador de Código Intermediário �Considere que temos um único registrador acumulador. � Considere o

Gerador de Código Intermediário �Considere que temos um único registrador acumulador. � Considere o comando de atribuição x : = a + b * c pode ser traduzido em: �t 1: =b*c �t 2: =a+t 1 �x: =t 2 �Pode-se fazer um gerador de código relativamente simples usando regras como:

Gerador de Código Intermediário Toda operação aritmética (binária) gera 3 instruções. Para b*c �

Gerador de Código Intermediário Toda operação aritmética (binária) gera 3 instruções. Para b*c � 1. 2. 3. Carga do primeiro operando no acumulador load b Executa a operação correspondente com o segundo operando, deixando o resultado no acumulador mult c Armazena o resultado em uma nova variável temporária store t 1 Um comando de atribuição gera sempre duas instruções. Para x: = t 2 � 1. ◦ Carrega o valor da expressão no acumulador load t 2 Armazena o resultado na variável store x

Para o comando de atribuição x : = a + b * c; é

Para o comando de atribuição x : = a + b * c; é gerado o código intermediário: 1. Load b { t 1 : = b * c } 2. Mult c 3. Store t 1 4. Load a { t 2 : = a + t 1 } 5. Add t 1 6. Store t 2 7. Load t 2 8. Store x { x : = t 2 }

Otimizador de Código � Independente da máquina � Melhora o código intermediário de modo

Otimizador de Código � Independente da máquina � Melhora o código intermediário de modo que o programa objeto seja menor (ocupe menos espaço de memória) e/ou mais rápido (tenha tempo de execução menor) � A saída do otimizador de código é um novo código intermediário

Otimizador de Código 1. 1. 2. 2. 3. 3. 4. 4. 5. 6. 7.

Otimizador de Código 1. 1. 2. 2. 3. 3. 4. 4. 5. 6. 7. 8. Loadbb Multcc Add a t 1 Store Load xa Add t 1 Store t 2 Load t 2 Store x

Otimizador de Código

Otimizador de Código

Gerador de Código �Produz o código objeto final � Toma decisões com relação à:

Gerador de Código �Produz o código objeto final � Toma decisões com relação à: ◦ Alocação de espaço para os dados do programa; ◦ Seleção da forma de acessá-los; ◦ Definição de quais registradores serão usados, etc. �Projetar um gerador de código que produza programas objeto eficientes é uma das tarefas mais difíceis no projeto de um compilador

Gerador de Código �Várias considerações têm que ser feitas: ◦ Há vários tipos de

Gerador de Código �Várias considerações têm que ser feitas: ◦ Há vários tipos de instruções correspondendo a vários tipos de dados e a vários modos de endereçamento; ◦ Há instruções de soma específicas, por exemplo para incrementar/decrementar de 1; ◦ Algumas somas não foram especificadas explicitamente: ◦ Cálculo de endereço de posições em vetores; ◦ Incremento/decremento registrador de topo pilha ◦ Local onde armazenar variáveis; ◦ Alocação de registradores