Compiladores: fases, componentes e otimização

Classificado em Computação

Escrito em em português com um tamanho de 6,22 KB

Compiladores: visão geral

Definição

Compilador: programa que lê um programa escrito em uma linguagem (fonte) e o traduz para outra linguagem (destino), reportando erros quando eles ocorrem.

Fluxo de tradução

Programa fonte > tradutor > programa intermediário > máquina virtual > Saída
Sistema de processamento de uma linguagem > processador > programa fonte modificado > Compilador > Assembler > código objeto > link/loader > executável

Programas auxiliares do processo de compilação

Existem ferramentas que apoiam o processo de compilação, entre as quais se destacam:

Reprocessadores

  • Processam macros
  • Includes
  • Extensão de linguagens

Assemblers

Abstração da arquitetura da máquina de destino.

Carregadores (loaders)

Resolvem referências externas e fazem o linking (linkers / linkeditores).

Análise e Síntese

Análise: quebra o código-fonte em suas partes e cria uma representação intermediária do programa. Verifica erros e constrói a tabela de símbolos.

Síntese: constrói o programa-destino a partir da representação intermediária.

Fases de um compilador

  • Stream de caracteres
  • Analisador léxico
  • Stream de tokens
  • Analisador sintático
  • Árvore sintática
  • Analisador semântico
  • Árvore sintática (anotada)
  • Gerador de código intermediário
  • Representação intermediária
  • Otimizador de código
  • Representação intermediária otimizada
  • Gerador de código
  • Código de máquina

Front-end (Análise)

A análise corresponde ao front end do compilador (até a geração do código intermediário) e inclui:

  • Analisador léxico
  • Analisador sintático
  • Analisador semântico

Back-end (Síntese)

A síntese corresponde ao back end do compilador e inclui:

  • Geradores de código intermediário
  • Otimizador de código
  • Gerador de código

Análise léxica

A análise léxica converte uma sequência de caracteres em tokens.

Exemplo: p = i + R * 60

<= >  <+>  <*>
Ou
(entradas possíveis e tokens correspondentes)

Análise sintática

A análise sintática agrupa tokens em uma estrutura hierárquica com significado (árvore sintática).

Análise semântica

A análise semântica verifica se os componentes de um programa se encaixam de forma a ter um significado adequado.

Resumo: análise

Análise: quebra o código-fonte em suas partes e cria uma representação intermediária do programa. Verifica erros e constrói a tabela de símbolos.

Resumo: síntese

Síntese: constrói o programa-destino a partir da representação intermediária.

Análise do programa-fonte (detalhes)

  • Análise léxica – lê a sequência de caracteres e a organiza como tokens (sequências de caracteres com algum significado).
  • Análise sintática – agrupa caracteres ou tokens em uma estrutura hierárquica com significado.
  • Análise semântica – verifica se os componentes de um programa têm significado adequado quando combinados.

Código intermediário

  • Idealmente deve ser fácil de produzir e também de traduzir para a linguagem-destino.
  • Na prática, costuma-se gerar código para uma máquina abstrata.
  • Por exemplo, three-address code: usa três operandos por instrução, cada um como se fosse um registrador.

Otimização de código

  • Realiza transformações no código visando melhorar sua performance em tempo de execução, uso de memória, tamanho do executável etc.

Geração de código

  • Realiza a alocação de registradores (quando necessária) e a tradução do código intermediário para a linguagem-destino.

Classificações por paradigma

  • Imperativo – "como": conceito de estado e comandos que mudam o estado (ex.: C, C++, C#, Java).
  • Declarativo – "o quê": ex.: Haskell, Prolog.

Tempo de ligação

  • Estático: em tempo de compilação.
  • Dinâmico: em tempo de execução.

Árvore sintática

Representação hierárquica (AST) construída pelo analisador sintático e anotada pelo analisador semântico.

Objetivos dos compiladores

  • Gerar código corretamente.
  • Ser capaz de tratar programas de qualquer tamanho.
  • A velocidade da compilação não é a característica principal em muitos casos.
  • O tamanho do compilador já não é mais um problema relevante.
  • Usabilidade (user-friendliness): medida pela qualidade das mensagens de erro.
  • A importância da velocidade e do tamanho do código gerado depende do propósito do compilador; em muitos casos, a velocidade do código vem em primeiro lugar.

Modelo de compilação

Dois grandes passos:

  • Análise: interpreta o programa-fonte e cria uma representação intermediária do mesmo.
  • Síntese: a partir da representação intermediária, produz o programa-alvo.

Por que estudar compilação?

Várias aplicações e necessidades atuais:

  • Validação de arquiteturas diferenciadas de computadores.
  • Aceitação de novas linguagens de programação.
  • Otimização de código para celulares, sistemas embarcados e novas arquiteturas.
  • Teste de falhas/erros em software.
  • Busca por brechas/falhas de segurança em sistemas.
  • Efetividade do paralelismo (ambientes multicore).
  • Melhor uso de memória (registradores, caches, RAM).
  • Tradução entre sistemas diferentes; síntese de hardware (da especificação para o modelo).
  • Interpretação de linguagens especiais: SQL, por exemplo.
  • Etc.
24,>,>,>,>,>,>,>*>,>+>,>=>,>

Entradas relacionadas: