Fases do compilador com exemplo, processo e etapas.

⚡ Resumo Inteligente

As fases de um compilador descrevem como ele transforma o código-fonte em código de máquina por meio de seis etapas: análise léxica, análise sintática, análise semântica, geração de código intermediário, otimização de código e geração de código, com suporte do gerenciamento da tabela de símbolos e tratamento de erros em todo o processo.

  • 🔤 Análise Lexical: A primeira fase analisa o código-fonte e agrupa os caracteres em tokens, preenchendo a tabela de símbolos.
  • ???? Análise de sintaxe: Os tokens são verificados em relação às regras gramaticais e organizados em uma árvore de análise sintática.
  • ✅ Análise Semântica: O compilador verifica a compatibilidade e o significado dos tipos usando a árvore sintática e a tabela de símbolos.
  • 🔁 Nível intermediário Code: Uma representação independente de máquina, como um código de três endereços, é gerada para facilitar a tradução.
  • ⚡ Optimization: O código redundante e inacessível é removido para tornar o programa mais rápido e menor.
  • 🖥️ Code Geração: A fase final converte o código otimizado em código de máquina alvo, alocando registradores e memória.

Quais são as fases do design do compilador?

Compilador opera em várias fases, cada fase transforma o programa fonte de uma representação para outra. Cada fase recebe entradas de seu estágio anterior e alimenta sua saída para a próxima fase do compilador.
Existem 6 fases em um compilador. Cada uma dessas fases auxilia na conversão da linguagem de alto nível em código de máquina. As fases de um compilador são:

  1. Análise léxica
  2. Análise de sintaxe
  3. Análise semântica
  4. Gerador de código intermediário
  5. Code otimizador
  6. Code gerador
Fases do compilador
Fases do compilador

Todas essas fases convertem o código-fonte dividindo-o em tokens, criando árvores de análise e otimizando o código-fonte por diferentes fases.

Fase 1: Análise Lexical

A Análise Lexical é a primeira fase em que o compilador verifica o código-fonte. Este processo pode ser feito da esquerda para a direita, caractere por caractere, e agrupar esses caracteres em tokens.
Aqui, o fluxo de caracteres do programa de origem é agrupado em sequências significativas, identificando os tokens. Ele faz a entrada dos tickets correspondentes na tabela de símbolos e passa esse token para a próxima fase.
As principais funções desta fase são:

  • Identifique as unidades lexicais em um código-fonte
  • Classifique as unidades lexicais em classes como constantes, palavras reservadas e insira-as em tabelas diferentes. Irá ignorar comentários no programa de origem
  • Identifique o token que não faz parte do idioma

Exemplo:
x = y + 10

Tokens

X identificador
= Operador de atribuição
Y identificador
+ Operador de adição
10 Sessão

Fase 2: Análise de Sintaxe

A análise de sintaxe trata da descoberta da estrutura do código. Determina se um texto segue ou não o formato esperado. O principal objetivo desta fase é garantir que o código-fonte escrito pelo programador esteja correto ou não.
A análise de sintaxe é baseada nas regras baseadas na linguagem de programação específica, construindo a árvore de análise com a ajuda de tokens. Também determina a estrutura do idioma de origem e a gramática ou sintaxe do idioma.
Aqui está uma lista de tarefas realizadas nesta fase:

  • Obtenha tokens do analisador léxico
  • Verifica se a expressão está sintaticamente correta ou não
  • Reportar todos os erros de sintaxe
  • Construa uma estrutura hierárquica conhecida como árvore de análise

Exemplo

Qualquer identificador/número é uma expressão
Se x for um identificador e y+10 for uma expressão, então x= y+10 é uma instrução.
Considere a árvore de análise para o exemplo a seguir

(a+b)*c

Exemplo de análise de sintaxe

Na árvore de análise

  • Nó interior: registro com um arquivo de operador e dois arquivos para filhos
  • Folha: registros com 2/mais campos; um para token e outras informações sobre o token
  • Garantir que os componentes do programa se encaixem de forma significativa
  • Reúne informações de tipo e verifica a compatibilidade de tipo
  • Os operandos de verificação são permitidos pelo idioma de origem

Fase 3: Análise Semântica

A análise semântica verifica a consistência semântica do código. Ele usa a árvore de sintaxe da fase anterior junto com a tabela de símbolos para verificar se o código-fonte fornecido é semanticamente consistente. Também verifica se o código está transmitindo um significado apropriado.
O Semantic Analyzer verificará incompatibilidades de tipo, operandos incompatíveis, uma função chamada com argumentos impróprios, uma variável não declarada, etc.
As funções da fase de análise semântica são:

  • Ajuda você a armazenar informações de tipo coletadas e salvá-las na tabela de símbolos ou na árvore de sintaxe
  • Permite realizar verificação de tipo
  • No caso de incompatibilidade de tipos, onde não existem regras exatas de correção de tipos que satisfaçam a operação desejada, um erro semântico é mostrado
  • Coleta informações de tipo e verifica a compatibilidade de tipo
  • Verifica se o idioma fonte permite ou não os operandos

Exemplo

float x = 20.2;
float y = x*30;

No código acima, o analisador semântico irá converter o inteiro 30 para float 30.0 antes da multiplicação

Fase 4: Intermediária Code Generation

Assim que a fase de análise semântica termina, o compilador gera um código intermediário para a máquina de destino. Este código representa um programa para algum valor absoluto.tracmáquina t.
O código intermediário está entre a linguagem de alto nível e a linguagem de máquina. Esse código intermediário precisa ser gerado de forma que seja fácil traduzi-lo no código de máquina de destino.
Funções no nível intermediário Code geração:

  • Deve ser gerado a partir da representação semântica do programa fonte
  • Contém os valores calculados durante o processo de tradução
  • Ajuda você a traduzir o código intermediário para o idioma de destino
  • Permite manter a ordem de precedência do idioma de origem
  • Ele contém o número correto de operandos da instrução

Exemplo

Por exemplo, nos

total = count + rate * 5

O código intermediário com a ajuda do método de código de endereço é:

t1 := int_to_float(5)
t2 := rate * t1
t3 := count + t2
total := t3

Fase 5: Code Operacional

A próxima fase é a otimização do código ou código intermediário. Esta fase remove linhas de código desnecessárias e organiza a sequência de instruções para acelerar a execução do programa sem desperdiçar recursos. O principal objetivo desta fase é melhorar o código intermediário para gerar um código que rode mais rápido e ocupe menos espaço.
As principais funções desta fase são:

  • Ajuda você a estabelecer uma compensação entre velocidade de execução e velocidade de compilação
  • Melhora o tempo de execução do programa alvo
  • Gera código simplificado ainda em representação intermediária
  • Removendo código inacessível e livrando-se de variáveis ​​não utilizadas
  • Removendo instruções que não são alteradas do loop

Exemplo:
Considere o seguinte código

a = intofloat(10)
b = c * a
d = e + b
f = d

Pode se tornar

b =c * 10.0
f = e+b

Fase 6: Code Generation

Code A geração é a última fase de um compilador. Ela recebe entradas das fases de otimização de código e produz o código de página ou código objeto como resultado. O objetivo desta fase é alocar espaço de armazenamento e gerar código de máquina relocável.
Também aloca locais de memória para a variável. As instruções do código intermediário são convertidas em instruções de máquina. Esta fase converte o código otimizado ou intermediário na linguagem de destino.
A linguagem alvo é o código de máquina. Portanto, todos os locais de memória e registros também são selecionados e alocados durante esta fase. O código gerado por esta fase é executado para receber entradas e gerar saídas esperadas.

Exemplo

uma = b + 60.0
Seria possivelmente traduzido para registros.

MOVF a, R1
MULF #60.0, R2
ADDF R1, R2

Gerenciamento de tabela de símbolos

Uma tabela de símbolos contém um registro para cada identificador com campos para os atributos do identificador. Este componente torna mais fácil para o compilador pesquisar o registro do identificador e recuperá-lo rapidamente. A tabela de símbolos também auxilia no gerenciamento do escopo. A tabela de símbolos e o manipulador de erros interagem com todas as fases e a tabela de símbolos é atualizada de forma correspondente.

Rotina de tratamento de erros

No processo de design do compilador, pode ocorrer erro em todas as fases fornecidas abaixo:

  • Analisador léxico: tokens escritos incorretamente
  • Analisador de sintaxe: parênteses ausentes
  • Gerador de código intermediário: operandos incompatíveis para um operador
  • Code Otimizador: Quando a instrução não é alcançável
  • Code Generator: Quando a memória está cheia ou os registros adequados não estão alocados
  • Tabelas de símbolos: erro de vários identificadores declarados

Os erros mais comuns são sequências de caracteres inválidas na varredura, sequências de tokens inválidas no tipo, erro de escopo e análise na análise semântica.
O erro pode ser encontrado em qualquer uma das fases acima. Após encontrar os erros, a fase precisa lidar com os erros para continuar com o processo de compilação. Esses erros precisam ser relatados ao manipulador de erros que trata o erro para executar o processo de compilação. Geralmente, os erros são relatados na forma de mensagem.

Perguntas Frequentes

A fase de análise (front-end) decompõe o código-fonte por meio de análises léxicas, sintáticas e semânticas. A fase de síntese (back-end) constrói o programa final por meio de geração de código intermediário, otimização e geração de código.

Um compilador traduz todo o programa fonte em código de máquina antes de executá-lo. Um interpretador traduz e executa o código linha por linha, o que é mais fácil de depurar, mas geralmente mais lento em tempo de execução.

O código de três endereços é uma representação intermediária onde cada instrução tem no máximo três operandos, como t1 = a + b. É simples de otimizar e fácil de traduzir para o código de máquina de destino.

A inteligência artificial e o aprendizado de máquina ajudam os compiladores modernos a tomar decisões de otimização mais inteligentes, como a escolha de transformações de loop, inlining e alocação de registradores. Eles preveem quais otimizações melhoram o desempenho para um determinado programa e alvo.

Sim. A IA pode explicar cada fase com exemplos. trace como uma instrução de exemplo passa de tokens para código de máquina, e responda a perguntas subsequentes. Isso facilita o aprendizado do projeto de compiladores para os alunos.

Resuma esta postagem com: