Se você quer desenvolver um programa de computador do zero, primeiro você deve desenvolver a sua linguagem de programação.

Você alguma vez já se questionou sobre como os programas de computador são feitos?

Eles estão disponíveis no seu computador, facilitando suas tarefas, dando a impressão de que fazem parte do Sistema Operacional, como mágica. Com um clicar de botões o seu pensamento está escrito na tela e em seguida postado na web.

Mas ele foi desenvolvido por uma pessoa como você, o programador. Sua função é desenvolver o programa, mas não podemos esquecer que, para que este cumpra este objetivo, foi necessário que outras grandes mentes viessem antes dele e desenvolvessem as suas ferramentas, as linguagens de programação e os compiladores.

O desenvolvimento de uma linguagem de programação não é algo simples de se fazer e seguem alguns passos. Passos esses originários de estudos das linguagens naturais (a língua falada e escrita pelos diferentes povos).

Primeiramente uma linguagem de programação deve possuir uma especificação léxica. Em linguagens de programação o termo léxico é utilizado para definir todas as palavras e símbolos pertencentes a linguagem de programação.

Por exemplo, “public”, “private”, “protected”,  “static”,  da Linguagem Java. “enum”, ”extern”, “register” de C. Além dos símbolos “(”, “)”, “{”, “}”, “+”, “-”, “=” que podem ser comuns a maioria das linguagens.

Ou seja, aqui devemos definir com o que escreveremos os nossos programas. Também devem ser descritos os símbolos que podemos utilizar para escrever essas palavras.

Enquanto que nas linguagens naturais, se você escrever uma palavra de forma “errada” (ou diferente do formal), ela ainda pode ser entendida pelo receptor, em linguagens de programação ,o compilador não entenderá qual a função daquela palavra.

O segundo passo é definir a especificação gramatical da linguagem. Aqui descreveremos formalmente a gramática da linguagem de programação, ou seja, como as palavras devem ser posicionadas.

Por exemplo a soma: Para realizar uma soma, primeiramente definimos uma variável (que deve ter a sua estrutura léxica definida) para receber o resultado, seguido do símbolo de igualdade ou atribuição e em seguida os operandos e a operação.

Y = X + 1

Se a operação de soma for descrita dessa forma, todas as operações de soma devem ser escritas da mesma maneira, ou simplesmente não funcionarão. Aqui descrevemos somente a estrutura das operações.

O terceiro passo é definir a estrutura semântica da linguagem. É aqui que daremos significado a isso tudo. Descreveremos como as operações serão realizadas.

Por exemplo a soma, novamente: Na estrutura semântica deve ser descrita como essa soma deve ser realizada. Primeiramente lemos o valor da variável X e realizamos a soma desta com a constante 1 para em seguida atribuir este resultado à variável Y.

Aqui definimos como a operação de soma deve ser realizada, do início ao fim.

Tendo em mãos estas três estruturas da linguagem, podemos então utilizar um programa tradutor para analisar o programa escrito. O tradutor irá verificar se o programa está escrito de forma correta e então gerará, ao final, um programa executável (no caso do compilador) ou o resultado da execução do programa (caso interpretador).

Não, não é assim que desenvolvemos um aplicativo.

O compilador/interpretador deve ser construído tendo em mãos todas essas estruturas da linguagem de programação mencionadas anteriormente.

Tendo em mãos a estrutura léxica da linguagem, ele realiza a analise léxica do programa, verificando palavras e símbolos não definidos.

Com a estrutura gramatical, ele realiza a análise sintática. Verificando se as palavras ou símbolos lidos eram esperados no dado momento.

Com a estrutura semântica, ele realiza a análise semântica do programa. Verificando se as operações definidas podem ser realizadas.

Caso em algum momento seja encontrado um erro no programa, ele é retornado para o programador, utilizando o tratador de erros. Eles então serão analisados e corrigidos pelo programador.

Após a análise semântica, o programa desenvolvido deve estar correto para ser executado, mas antes disso, outros passos são realizados.

O primeiro deles é a geração de código intermediário, aqui será gerado uma versão do programa em uma linguagem mais fácil de ser tratado pelo tradutor. Esse tratamento irá otimizar o programa, para que o menor número de operações possíveis seja executado. Quanto menor o número de operações, mais rápido o programa é executado.

O interpretador irá somente até esse passo. Mas o compilador ainda possuirá os passos abaixo.

O compilador, após a otimização, gera um código em linguagem objeto.

Fases de um compilador. Divididas em duas etapas. A etapa de análise e a etapa de síntese podem ser vistas aqui.

A linguagem objeto é a linguagem objetivo da tradução. Ela pode ser uma linguagem que tornará mais fácil a execução pela máquina a qual se destina. Ela pode ser, também, a linguagem na qual o compilador foi desenvolvido. Se o compilador foi desenvolvido em C, a linguagem objeto pode ser C.

Por último é gerado o programa objeto, que é o programa executável. Quando um programa é desenvolvido, utilizando as linguagens de programação C# ou Delphi, o compilador dessas linguagens gera um programa com extensão “.exe”, destinada ao Sistema Operacional Windows. Quando um programa é desenvolvido utilizando a linguagem Java, o compilador de Java gera um programa com extensão “.jar”, destinada a máquina virtual Java.

No caso dos interpretadores, o código objeto e o programa objeto não são gerados. O próprio arquivo no qual o programa foi desenvolvido é executado. Um exemplo disso são as páginas web.

Você já deve ter visitado uma página que termina com a extensão “.php” ou “.asp”. Isso quer dizer que são páginas que foram desenvolvidas com a linguagem de programação PHP ou ASP, respectivamente. Quando uma requisição de acesso a estas páginas é realizada pelo navegador, o servidor web, instalado no servidor, acessa esses arquivos e envia o resultado ao navegador. A própria página é executada, e nesse momento ela também é analisada. Se o programa está correto, a execução da página é realizada e o resultado é mostrado para você no navegador.

Uma captura de tela do compilador GCC. Um programa simples está sendo compilado e então executado. Veja aqui.

Mas o compilador ou interpretador são programas de computador também. Por isso eles também devem ser construídos utilizando uma linguagem de programação. A linguagem Java, por exemplo, possui diversos compiladores, escritos em diversas linguagens. Mas se você for olhar o programa executável desse compilador, eles possuirão a extensão “.exe”, por exemplo, indicando que foram desenvolvidos utilizando uma linguagem desenvolvida para a plataforma Windows.

O Sistema Operacional também é um programa de computador e foi desenvolvido utilizando uma linguagem de programação, em um compilador.

A evolução da computação acompanha a evolução das linguagens de programação. Hoje em dia temos linguagens mais fáceis de serem utilizadas do que tínhamos há alguns anos e, muito provavelmente, teremos linguagens mais avançadas surgindo nos próximos anos. Linguagens que serão mais fáceis de serem utilizadas, que utilizem o hardware de maneira mais proveitosa, ou desenvolvidas para um fim específico.

Se quiser saber mais sobre compiladores, desenvolvimento de linguagens de programação ou tirar dúvidas, comente. Converse conosco.

Menção honrosa aqui a Bjarne Stroustrup que recebeu, em 20 de Fevereiro de 2018, o prêmio Charles Stark Draper Prize for Engineering por desenvolver a linguagem C++. Linguagem esta que beneficia bilhões de pessoas indiretamente. Desde ferramentas de pesquisa do Google, Smartphones, sistemas de telecomunicações utilizam o C++ em algum nível.