domingo, 1 de junho de 2008

Mostrando o pensamento lógico de um compilador

Através do uso de metalinguagens é possível obter-se, de modo suficientemente rigoroso uma boa definição da linguagem de programação cujo compilador se deseja construir. Seja qual for a técnica empregada para tal finalidade, o resultado é sempre um programa a ser executado no computador.

Sendo um programa, o tradutor(compilador) deverá ser expresso em alguma linguagem de programçaõ disponível, para que seja possível implamtá-lo em alguma máquina existente e portanto algum compilador pode ser suposto existente para permitir a primeira tradução de um compilador para a linguagem que esta sendo desenvolvida. Este deverá, portanto, ser escrito na linguagem de programação que o compilador disponível seja capaz de traduzir.

Tem-se duas questões a solucionar: para qual máquina o compilador final deverá gerar código, e em que linguagem tal compilador deverá ser redigido.

Seja L a linguagem a ser compilada para a máquina M, ou seja, deseja-se construir um compilador da linguagem L que gere um código-objeto que seja executável na máquina M.

Com estas hipóteses, descreve-se a seguir a técnica de obtenção de compiladores ditos 'auto-compiláveis' através do método de 'bootstrapping'. Sendo que um compilador é chamado 'auto-compilável' quando a linguagem em que for desenvolvido (L') é a própria linguagem L que o compilador deve ser capaz de traduzir.

O método de 'bootstrapping' permite obter a partir de praticamente nenhuma infraestrutura uma primeira versão de um compilador auto-compilável a ser utilizado posteriormente para melhorar e aperfeiçoar, em versão subsequente, o compilador original. A técnica mencionada pode ser detalhada como segue:

  1. Escreve-se na linguagem L' um compilador capaz de traduzir a linguagem L para linguagem de máquina M' (nesta primeira versão, pode-se implementar apenas os recursos de L que sejam indispensáveis a construção deste primeiro compilador). Obtém-se assim na máquina M' um compilador auto-resistente para a linguagem L, que gera código para a própria máquina M'. Caso as linguagens L e M sejam a mesma, então o compilador obtido no passo 1 estaria disponível a priori, sendo assim desnecessário refazê-lo.
  2. De posse do compilador da linguagem L para a máquina M', reescreve-se o mesmo na própria linguagem M, eliminando-se deste modo linguagens L' diferentes, e de modo que o código-objeto que o novo compilador deve produzir se apresente na linguagem da máquina M. Utilizando-se o compilador L disponível, compila-se o novo programa obtido, obtendo-se desta maneira, para ser executado na máquina M', um compilador cruzado para a linguagem L, auto-compilável e que gera código para a máquina M. Se o compilador cruzado é o objewtivo final do desenvolvimento, eventuais aperfeiçoamentos do compilador podem ser efetuados, repetindo-se este passo até que se obtenha a versão definitiva do mesmo.
  3. Desejamos um compilador auto-residente, e considerando-se que o compilador obtido no passo 2 foi escrito na própria linguagem que é capaz de traduzir, ou seja, que é auto-compilável, pode-se utilizá-lo na máquina M', para compilar seu próprio texto-fonte. O programa-objeto assim obtido será executável na máquina M', e será um programa equivalente ao compilador que o produziu. Em outras palavras, o programa obtido será de linguagem L, capaz de traduzi-lo para a linguagem da máquina M, e que pode ser executado diretamente na máquina M, ou seja, produziu-se em M' um compilador auto-residente e auto-compilável da linguagem L para a máquina M.
  4. Transporta-se o compilador obtido para a máquina M, onde se pode, se assim for conviniente prosseguir o desenvolvimento do compilador e da linguagem, aperfeiçoando-se o programa obtido até que apresente todas as características desejadas.

Se a máquina M não comporta tal desenvolvimento, pode-se alterar o programa obtido, retornando-se ao terceiro passo tantas vezes forem necessárias , até que se obtenha o compilador desejado que é então transportado definitivamente para a máquina M. A figura abaixo mostra uma notação 'bootstrapping':

Um texto, denominado texto-fonte, é submetido ao programa representado no polígono, pela extremidade esquerda da figura.

No braço esquerdo do polígono esta indicada a linguagem em que X está escrito( linguagem fonte). O programa compilador, escrito na linguagem de desenvolvimento endicada na extremidade inferior do polígono, traduz o texto-fonte para a linguagem-objeto, indicada na extremidade direita do polígono, gerando um texto Y equivalente, denotado na linguagem-objeto.

Agora vejamos o processo de 'bootstrapping' que foi descrito anteriormente através da figura abaixo:


Assim depois do processamento chegamos no código objeto através do pensamento lógico que o compilador utiliza.

Um comentário:

dan disse...

uhhh! aê, boa kelly!
estava inspirada, heim? :D