Transcript
Page 1: Compiladores - Introdução

Compiladores - IntroduçãoCompiladores - Introdução

Guilherme Amaral [email protected]

Page 2: Compiladores - Introdução

O que é um Compilador?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.

Page 3: Compiladores - Introdução

O que é um Compilador?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

Page 4: Compiladores - Introdução

É 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.

Page 5: Compiladores - Introdução

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.

Page 6: Compiladores - Introdução

Compiladores – Separando Compiladores – Separando em partesem partesUm dos modelos possíveis para a construção

de compiladores faz a separação total entre o frontend, encarregado da fase de análise, e o back-end, encarregado da geração de código, de forma que◦ O front-end e back-end se comunicam

apenas através da representação intermediária

◦ O front-end depende exclusivamente da linguagem fonte;

◦ O back-end depende exclusivamente da linguagem destino.

Simplifica a implementação de novos compiladores◦ Front-end específico para cada linguagem◦ Back-end específico para a arquitetura alvo

Um dos modelos possíveis para a construção de compiladores faz a separação total entre o front-end, encarregado da fase de análise, e o back-end, encarregado da geração de código, de forma que◦O front-end e back-end se comunicam

apenas através da representação intermediária

◦O front-end depende exclusivamente da linguagem fonte;

◦O back-end depende exclusivamente da linguagem objeto.

Verificador de TiposVerificador de Tipos

ParserParser

DesugarerDesugarer

Sintaxe Core

CoreToSTGCoreToSTG

Sintaxe STG

Gerador de ILGerador de IL

Código MSIL (Texto)

ILDASMILDASM

Gerador GHCGerador GHC

Código Assembly / Código C

Assembler / Compilador C

Assembler / Compilador C

Código Nativo

CorePrinterCorePrinter

Arquivo Core

PhxSTGCompilerPhxSTGCompiler

JITJIT

Código Nativo

Arquivo Haskell '

Otimizações

Assembly MSIL

Front-end

Back-end

Page 7: Compiladores - Introdução

Compiladores - FasesCompiladores - FasesConjunto de alterações feitas no

código as quais são responsáveis por uma atividade específica do processo de compilação◦Análise Léxica (scanner)◦Análise Sintática (parser)◦Análise Semântica◦Otimização◦Geração de código

Analisador léxico

Analisador sintático

Analisador semântico

Gerador de código

intermediário

Otimizador de código

Gerador de código

código fonte

código alvo

Tratador de erros

Gerador tabela de símbolos

Page 8: Compiladores - Introdução

Análise LéxicaAnálise LéxicaTambém chamada de scanner Agrupa caracteres em símbolos (ou

tokens) Entrada: fluxo de caracteres Saída: fluxo de símbolos Símbolos são:

◦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.

Page 9: Compiladores - Introdução

Análise LéxicaAnálise LéxicaDado os caracteres da instrução

montante := saldo + taxa_de_juros * 30;

São identificados os seguintes tokens:Identificador montantmontantSímbolo de atribuição :=:=Identificador saldosaldoSímbolo de adição ++Identificador taxa_de_jurostaxa_de_jurosSímbolo de multiplicação **Número 3030

Page 10: Compiladores - Introdução

Análise SintáticaAnálise SintáticaTambém chamada de parserAgrupa símbolos em unidades sintáticasEx.: 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

Page 11: Compiladores - Introdução

Análise SintáticaAnálise SintáticaComand

o

Expressão

Identificador

Expressão

Expressão

Expressão

Expressão

:=

+

*

Identificador

Identificador

montante

saldo

taxa_de_juros

Número

60

Árvore gerada para: montante := saldo + taxa_de_juros * 60

Page 12: Compiladores - Introdução

Análise SemânticaAnálise SemânticaVerifica 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

Page 13: Compiladores - Introdução

Análise SemânticaAnálise Semântica

montante

+

*

saldo

taxa_de_juros

*

60

montante

+

*

saldo

taxa_de_juros

*

inttorealinttoreal

Conversão de inteiro para real inserida pela análise semântica

Page 14: Compiladores - Introdução

Gerador de Código Gerador de Código IntermediárioIntermediárioUsa 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

Page 15: Compiladores - Introdução

Gerador de Código Gerador de Código IntermediárioIntermediárioConsidere que temos um único

registrador acumulador. Considere o comando de atribuição

x := a + b * c pode ser traduzido em:

t1:=b*ct2:=a+t1x:=t2Pode-se fazer um gerador de código

relativamente simples usando regras como:

Page 16: Compiladores - Introdução

Gerador de Código Gerador de Código IntermediárioIntermediário Toda operação aritmética (binária) gera 3

instruções. Para b*c1. Carga do primeiro operando no acumulador

load b2. Executa a operação correspondente com o segundo

operando, deixando o resultado no acumuladormult c

3. Armazena o resultado em uma nova variável temporáriastore t1

Um comando de atribuição gera sempre duas instruções. Para x:= t2

1. Carrega o valor da expressão no acumuladorload t2

◦ Armazena o resultado na variávelstore x

Page 17: Compiladores - Introdução

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

é gerado o código intermediário:1. Load b { t1 := b * c }2. Mult c3. Store t14. Load a { t2 := a + t1 }5. Add t16. Store t27. Load t28. Store x { x := t2 }

Page 18: Compiladores - Introdução

Otimizador de CódigoOtimizador 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

Page 19: Compiladores - Introdução

Otimizador de CódigoOtimizador de Código1. Load b2. Mult c3. Store t14. Load a5. Add t16. Store t27. Load t28. Store x

1. Load b2. Mult c3. Add a4. Store x

Page 20: Compiladores - Introdução

Otimizador de CódigoOtimizador de Código

Page 21: Compiladores - Introdução

Gerador de CódigoGerador de CódigoProduz 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

Page 22: Compiladores - Introdução

Gerador de CódigoGerador de CódigoVá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


Recommended