Etapas do processo de compilação
A estrutura de um compilador é classicamente dividida em duas grandes partes: o front-end e o back-end.
- O front-end é responsável por analisar o código-fonte para compreender sua estrutura e significado, sendo dependente da linguagem-fonte.
- O back-end utiliza a representação gerada pelo front-end para gerar e otimizar o código para uma máquina-alvo específica.
Front-end
O front-end valida a sintaxe e a semântica do código, sendo independente da arquitetura da máquina de destino.
1. Arquivo-fonte
É o código escrito pelo programador em uma linguagem de alto nível.
Saída: fluxo de caracteres
2. Analisador Léxico
Sua função é ler o fluxo de caracteres do código-fonte e agrupá-los em unidades léxicas chamadas tokens.
Por exemplo, var nota = 10;
seria quebrado nos tokens var
, nota
, =
, 10
, ;
.
Saída: fluxo de tokens
3. Analisador Sintático
Esta etapa verifica se a sequência de tokens obedece às regras gramaticais da linguagem por meio de expressões regulares e máquina de estados.
Ele organiza os tokens em uma estrutura hierárquica, geralmente uma Árvore de Sintaxe Abstrata (AST), que representa a estrutura do código.
Saída: Árvore de sintaxe
4. Analisador Semântico
Verifica o significado do código para garantir que as operações são lógicas e coerentes, realizando, por exemplo, a checagem de tipos.
Nesta fase, a árvore de sintaxe é anotada com informações de tipo e outras informações semânticas.
Saída: Árvore de Sintaxe Anotada
Back-end
O back-end utiliza a estrutura gerada pelo front-end para construir o código executável para uma arquitetura específica.
5. Gerador de Código Intermediário
Cria uma representação do programa em uma linguagem de baixo nível, mas que ainda é independente da máquina-alvo. Essa representação simplifica o processo de otimização e a geração do código final.
Note
Representação intermediário é o código de 3 endereços.
Saída: Representação Intermediária (RI)
6. Otimizador de Código
Analisa a representação intermediária e a transforma em uma versão semanticamente equivalente, porém mais eficiente (menor ou mais rápida).
Note
Esta é uma etapa opcional, mas presente na maioria dos compiladores modernos.
Saída: Representação Intermediária Otimizada
7. Gerador de Código Final
Traduz a representação intermediária otimizada para a linguagem de máquina da arquitetura-alvo, como a linguagem Assembly.
Esta fase envolve a seleção de instruções e a alocação de registradores do processador.
Saída: Código em Linguagem Assembly
8. Arquivo Objeto
É o resultado final do processo, contendo o código de máquina que pode ser ligado a outras bibliotecas e executado pelo sistema operacional.
Componentes auxiliares
Duas estruturas interagem com quase todas as fases do processo:
- Tabela de Símbolos: Armazena informações sobre os identificadores (variáveis, funções, etc.) usados no programa, como tipo, escopo e endereço de memória. É consultada e atualizada por diversas fases.