Ir ao conteúdo

Como o compilador pega o código-fonte e transforma em binário

Atualizado pela última vez em 26 de outubro de 2023

Acredito que depois do último artigo, você se convenceu que “Programar é conversar com o computador. Apenas Conversar!”. Para que essa conversa ocorra, como falei, entra cena um programa (ou conjunto de programas) para fazer a tradução da linguagem humana para a linguagem do computador(ou  linguagem de máquina, que são os famosos zeros e uns). Existe uma escala que determina se uma linguagem é mais próxima da linguagem humana do que da de máquina. Vamos nos ater as  linguagens de baixo nível e linguagens de alto nível. Resumidamente, as de alto nível se aproximam da linguagem humana e as de baixo nível da linguagem de máquina. Isso significa que as linguagens de baixo nível, conseguem ter acessos muito mais próximos dos recursos da máquina do computador.

Cada linguagem de programação tem as suas particularidades em sua “forma de escrita”. Essa forma de escrita chama-se sintaxe.  Veja a diferença de duas instruções que resultam no mesmo resultado utilizando uma linguagem de alto nível e outra de baixo nível:

sintaxe linguagens programação para explicar sobre compiladores

Do lado esquerdo tem um script feito em linguagem Assembly e do outro lado um feito com a linguagem Python. O objetivo desses programas são apenas exibir “Olá Walmir Silva!”. Vale ressaltar que existem diversas linguagens de programação e cada uma vai ter as suas particularidades de sintaxe. Você vai aprender mais sobre linguagens de programação no artigo “O que são linguagens de programação?”.

Como os compiladores transformam esses códigos-fonte de modo que o computador entenda?

Esse assunto normalmente é desprezado por programadores iniciantes, porém, saber como os programas são compilados, é um conhecimento fundamental. Resumidamente, funciona assim: os compiladores pegam o código-fonte que escrevemos em nossos programas, e na hora de fazer a compilação, ele vai efetuar algumas análises em uma sequência e gerar um código de máquina.

Análise Léxica (Tokenization)

Em primeiro lugar, o compilador vai analisar as pequenas partes do que você escreveu no programa para verificar se pertence ao “alfabeto da linguagem de programação”. Ou seja, ele vai quebrar em palavras, conhecidas como tokens. Por exemplo, veja essa pequena parte de código:

instruções linguagem programação

Ele vai analisar essa sequência (\n = quebra de linha e <eof> é End of File, final do arquivo do programa):

tekenização linguagem computador

Caso algum caractere não pertença ao alfabeto da linguagem, vai ser gerado um erro léxico.

Análise Sintática (Parsing)

O compilador vai analisar se o que você escreveu em seu código está de acordo com a forma de escrita (sintaxe) da linguagem utilizada.  Ou seja, a análise sintática tem como objetivo validar a gramática do programa. Nessa etapa, a sequência de token vai ser varrida para ver se está de acordo. Exemplo:

exemplo verificação compilação

Nesse exemplo, o compilador vai analisar que você colocou “fi” ao invés de “if” e gerar uma notificação de erro de sintaxe. Outro exemplo é verificar se você esqueceu de abrir e/ou fechar parênteses, ou aspas, etc. Para ser feito esta análise sintática, o compilador cria uma árvore sintática. Esse tema é bem mais profundo que esse resumo que estou fazendo aqui. Estou focando em passar os conceitos fundamentais, assim como venho fazendo, por exemplo, no artigo “O mínimo que você precisa saber para iniciar em programação”. 

Análise Semântica

O passo seguinte é a procura de relações entre os tokens, se estão de acordo com o esperado para a linguagem. Ele analisa se os tipos de dados são adequados em cada lugar, se uma operação é possível, se não faltou alguma coisa necessária para completar uma operação, etc. Caso ele encontre alguma discrepância, o compilador gerará um erro semântico

Entre a análise léxica e a semântica, temos o uso da tabela de símbolos

A tabela de símbolos serve como um banco de dados para o processo de compilação. Seu principal conteúdo são informações sobre tipos e atributos de cada nome definido pelo usuário no programa. Essas informações são colocadas na tabela de símbolos pelos analisadores léxico e sintático, e usadas pelo analisador semântico e pelo gerador de código. Parece confuso, mas logo mais você vai compreender tudo.

Um banco de dados é uma coleção organizada de informações – ou dados – estruturadas.

Resumidamente, o processo de compilação se inicia com o analisador léxico que varre todo o código-fonte e transforma o texto em um fluxo de tokens, e nessa fase é criada a tabela de símbolos. Logo em seguida vem a análise sintática que lê o fluxo de tokens e valida a estrutura do programa criando a árvore sintática. A terceira fase é a análise semântica que é responsável por garantir as regras. Após essa análise, o código-fonte é gerado em código intermediário que vai ser otimizado e gerado em código objeto. 

diagrama passos compilador

Essa fase de código Intermediário, eventualmente pode não acontecer e ir direto para a geração de código objeto. A grande diferença entre o código intermediário e o código objeto é que o intermediário não especifica detalhes da máquina alvo, tais como quais  registradores serão usados, quais endereços de memória serão referenciados, entre outros detalhes físicos da máquina alvo. Essa parte é um pouco mais técnica, mas não se preocupe. Em algum momento no futuro quando você estiver em um estágio mais avançado, vamos voltar nesse tema e tudo vai ficar mais claro. Não se sinta mal se algum detalhe não ficar claro agora. Foque no conceito! 

Resumidamente, código objeto é a conversão do código-fonte em linguagem de máquina

A linguagem máquina ou código-máquina é um sistema de instruções e dados codificados em código binário (zeros e uns) que podem entender os microprocessadores (tema para futuros artigos kkkk).

Chegamos ao objetivo do artigo! Foi legal esses conceitos, não foi? No decorrer de sua jornada em programação, você vai se deparar com situações de análises de erros de sintaxes, erros semânticos, etc. É muito importante você compreender quais são os passos para a compilação de um programa. Existem três métodos básicos de abordagem na tradução de linguagem de alto nível para linguagem de máquina: interpretador, compilador e tradutor. Hoje só vimos sobre o compilador kkkk, futuramente vamos abordar os demais métodos. Até lá!

Confiança Sempre!

Fontes:

Olá! Sou Walmir, engenheiro de software com MBA em Engenharia de Software e o cérebro por trás do GrowthCode e autor do livro "Além do Código". Se você acha que programação é apenas sobre escrever código, prepare-se para expandir seus horizontes. Aqui, nós vamos além do código e exploramos as interseções fascinantes entre tecnologia, negócios, artes e filosofia. Você está em busca de crescimento na carreira? Quer se destacar em um mercado competitivo? Almeja uma vida mais rica em conhecimento e realização? Então você chegou ao lugar certo. No GrowthCode, oferecemos insights profundos, estratégias comprovadas e um toque de sabedoria filosófica para catalisar seu crescimento pessoal e profissional.

Publicado emProgramação

Seja o primeiro a comentar

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *