5 Computação com Máquinas de Registradores
Meu objetivo é mostrar que a máquina celestial não é uma espécie de ser divino e vivo, mas uma espécie de mecanismo de relojoaria (e aquele que acredita que um relógio tem alma atribui a glória do criador à obra), na medida em que quase todos os múltiplos movimentos são causados por uma força muito simples e material, assim como todos os movimentos do relógio são causados por um único peso.
— Johannes Kepler, letter to Herwart von Hohenburg, 1605
Começamos este livro estudando processos e descrevendo processos em termos de funções escritas em JavaScript. Para explicar os significados dessas funções, usamos uma sucessão de modelos de avaliação: o modelo de substituição do capítulo 1, o modelo de ambiente do capítulo 3, e o avaliador metacircular do capítulo 4. Nosso exame do avaliador metacircular, em particular, dissipou muito do mistério de como linguagens semelhantes ao JavaScript são interpretadas. Mas mesmo o avaliador metacircular deixa questões importantes sem resposta, porque ele falha em elucidar os mecanismos de controle em um sistema JavaScript. Por exemplo, o avaliador não explica como a avaliação de uma subexpressão consegue retornar um valor para a expressão que usa esse valor. Além disso, o avaliador não explica como algumas funções recursivas podem gerar processos iterativos (ou seja, serem avaliadas usando espaço constante) enquanto outras funções recursivas gerarão processos recursivos.1 Este capítulo aborda ambas essas questões.
Descreveremos processos em termos da operação passo a passo de um computador tradicional. Tal computador, ou máquina de registradores, executa sequencialmente instruções que manipulam o conteúdo de um conjunto fixo de elementos de armazenamento chamados registradores. Uma instrução típica de máquina de registradores aplica uma operação primitiva ao conteúdo de alguns registradores e atribui o resultado a outro registrador. Nossas descrições de processos executados por máquinas de registradores se parecerão muito com programas em "linguagem de máquina" para computadores tradicionais. No entanto, em vez de focar na linguagem de máquina de qualquer computador específico, examinaremos várias funções JavaScript e projetaremos uma máquina de registradores específica para executar cada função. Assim, abordaremos nossa tarefa da perspectiva de um arquiteto de hardware em vez da de um programador de computador em linguagem de máquina. Ao projetar máquinas de registradores, desenvolveremos mecanismos para implementar construções de programação importantes, como recursão. Também apresentaremos uma linguagem para descrever projetos de máquinas de registradores. Na seção 5.2 implementaremos um programa JavaScript que usa essas descrições para simular as máquinas que projetamos.
A maioria das operações primitivas de nossas máquinas de registradores são muito simples. Por exemplo, uma operação pode adicionar os números obtidos de dois registradores, produzindo um resultado a ser armazenado em um terceiro registrador. Tal operação pode ser realizada por hardware facilmente descrito. No entanto, para lidar com estruturas de lista, também usaremos as operações de memória head, tail e pair, que requerem um mecanismo elaborado de alocação de armazenamento. Na seção 5.3 estudamos sua implementação em termos de operações mais elementares.
Na seção 5.4, após termos acumulado experiência formulando funções simples como máquinas de registradores, projetaremos uma máquina que executa o algoritmo descrito pelo avaliador metacircular da seção 4.1. Isso preencherá a lacuna em nosso entendimento de como programas JavaScript são interpretados, fornecendo um modelo explícito para os mecanismos de controle no avaliador. Na seção 5.5 estudaremos um compilador simples que traduz programas JavaScript em sequências de instruções que podem ser executadas diretamente com os registradores e operações da máquina de registradores do avaliador.