Fases do compilador com exemplo

Quais são as fases do projeto do compilador?

Compilador opera em várias fases, cada fase transforma o programa de origem 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 ajuda a converter a linguagem de alto nível em código de máquina. As fases de um compilador são:

  1. Análise lexical
  2. Análise de sintaxe
  3. Análise semântica
  4. Gerador de código intermediário
  5. Otimizador de código
  6. Gerador de código

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 em diferentes fases.

Neste tutorial, você aprenderá:

Fase 1: Análise Lexical

A análise lexical é a primeira fase quando o compilador verifica o código-fonte. Esse processo pode ser da esquerda para a direita, caractere por caractere, e agrupar esses caracteres em fichas.

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 funções principais 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 fonte
  • Identifique o token que não faz parte da linguagem

Exemplo :

x = y + 10

Tokens

Xidentificar
=Operador de atribuição
Eidentificar
+Operador de adição
10Número

Fase 2: Análise de sintaxe

A análise de sintaxe trata da descoberta da estrutura do código. Ele determina se um texto segue ou não o formato esperado. O principal objetivo desta fase é ter certeza de que o código-fonte escrito pelo programador está 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. Ele também determina a estrutura do idioma de origem e gramática ou sintaxe do idioma.

Aqui está uma lista das 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
  • Construir uma estrutura hierárquica conhecida como árvore de análise

Exemplo

Qualquer identificador / número é uma expressão

Se x é um identificador ey + 10 é uma expressão, então x = y + 10 é uma declaração.

Considere a árvore de análise para o exemplo a seguir

(a+b)*c 

Na árvore de análise

  • Nó interior: registro com um operador arquivado e dois arquivos para crianças
  • Folha: registros com 2 / mais campos; um para token e outras informações sobre o token
  • Certifique-se de que os componentes do programa se encaixam de forma significativa
  • Reúne informações de tipo e verifica a compatibilidade de tipo
  • 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. Ele também verifica se o código está transmitindo um significado apropriado.

O Semantic Analyzer verificará se há 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 a armazenar informações de tipo coletadas e salvá-las na tabela de símbolos ou árvore de sintaxe
  • Permite que você execute verificação de tipo
  • No caso de incompatibilidade de tipo, onde não há regras de correção de tipo exatas 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 de origem permite os operandos ou não

Exemplo

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

No código acima, o analisador semântico irá typecast o inteiro 30 para flutuar 30,0 antes da multiplicação

Fase 4: Geração de código intermediário

Depois que a fase de análise semântica termina, o compilador gera um código intermediário para a máquina de destino. Ele representa um programa para alguma máquina abstrata.

O código intermediário está entre a linguagem de alto nível e a linguagem de nível de máquina. Esse código intermediário precisa ser gerado de maneira que seja fácil traduzi-lo no código da máquina de destino.

Funções na geração de código intermediário:

  • 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 a traduzir o código intermediário para o idioma de destino
  • Permite que você mantenha a ordem de precedência do idioma de origem
  • Ele contém o número correto de operandos da instrução

Exemplo

Por exemplo,

total = count + rate * 5 

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

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

Fase 5: Otimização de Código

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

As funções principais desta fase são:

  • Ajuda você a estabelecer um equilíbrio entre a velocidade de execução e 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 declarações que não foram 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: Geração de Código

A geração de código é a última e última fase de um compilador. Ele obtém entradas das fases de otimização do código e produz o código da página ou o código do objeto como resultado. O objetivo desta fase é alocar armazenamento e gerar código de máquina relocável.

Ele também aloca locais de memória para a variável. As instruções no código intermediário são convertidas em instruções de máquina. Esta fase abrange o código de otimização ou intermediário na linguagem de destino.

O idioma de destino é 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 obter entradas e gerar saídas esperadas.

Exemplo:

a = b + 60,0

Possivelmente seria traduzido para registradores.

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

Gestão da 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 ajuda no gerenciamento do escopo. A tabela de símbolos e o manipulador de erros interagem com todas as fases e atualização da tabela de símbolos de forma correspondente.

Rotina de tratamento de erros:

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

  • Analisador léxico: tokens escritos incorretamente
  • Analisador de sintaxe: parêntese ausente
  • Gerador de código intermediário: operandos incompatíveis para um operador
  • Otimizador de código: quando a instrução não está acessível
  • Gerador de código: declarações inacessíveis
  • Tabelas de símbolos: Erro de vários identificadores declarados

Os erros mais comuns são sequência de caracteres inválida na varredura, sequências de token 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. Depois de 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 do erro para realizar o processo de compilação. Geralmente, os erros são relatados na forma de mensagem.

Resumo

  • O compilador opera em várias fases, cada fase transforma o programa fonte de uma representação para outra
  • Seis fases do projeto do compilador são 1) Análise lexical 2) Análise de sintaxe 3) Análise semântica 4) Gerador de código intermediário 5) Otimizador de código 6) Gerador de código
  • Análise Lexical é a primeira fase quando o compilador verifica o código-fonte
  • A análise de sintaxe trata de descobrir a estrutura do texto
  • A análise semântica verifica a consistência semântica do código
  • Assim que a fase de análise semântica terminar o compilador, gere o código intermediário para a máquina de destino
  • A fase de otimização de código remove a linha de código desnecessária e organiza a sequência de instruções
  • A fase de geração de código obtém entradas da fase de otimização de código e produz o código da página ou código do objeto como resultado
  • Uma tabela de símbolos contém um registro para cada identificador com campos para os atributos do identificador
  • A rotina de tratamento de erros lida com erros e relatórios durante muitas fases