Jonesforth para Macintosh Intel

O jonesforth-macintel é um port que fiz para Macintosh Intel (32 bits) do jonesforth, um interpretador FORTH escrito em Assembly i386 para Linux. O projeto está hospetado no GitHub em ruda / jonesforth-macintel.

De volta aos anos 80, a maioria dos computadores de 8 bits da época iniciavam com o interpretador BASIC, por ser uma linguagem fácil de aprender. O BASIC entretanto, era uma linguagem muito limita e o uso da linguagem assembly, principalmente dos processadores Z-80 e 6509, era necessário para o desenvolvimento de programas mais interessantes.

Um interpretador FORTH parecia ser mais adequado a esses sistemas de recursos modestos, por estar mais próximo do nível da máquina; mas a verdade é que FORTH nunca pegou nessas computadores de 8 bits. Foi somente nos anos 90, com o OpenFirmware é que FORTH ganhou espaço nas workstations Unix, como as da Sun Microsystems.

Falo de brincadeira aos meus amigos que gostaria de construir uma máquina do tempo e reescrever a história, para fazer com que FORTH conseguisse ser a linguagem padrão das máquinas de 8 bits, removendo os danos causados por aprender BASIC :)

Enquanto isso não for possível de acontecer, eu resolvi aproveitar uma implementação de FORTH simples e de bom entendimento para o meu Macintosh, e esta é a razão do port do jonesforth para o Macintel: celebrar o passado mas pensando no presente.

Como Utilizar o jonesforth?

Compile o interpretador diretamente com o GCC (requer a instalação do XCode) através do comando:

$ gcc -m32 -nostdlib jonesforth-macintel.s -o jonesforth

Para executar o interpretador é necessário incluir as palavras adicionais (WORDs) definidas no jonesforth.f e também a entrada padrão, necessário para receber os comandos do usuário, como em:

$ cat jonesforth.f - | ./jonesforth 
JONESFORTH VERSION 47
OK
." Hello World!" 
Hello World!
1 2 + .
3 
BYE

Perdido em FORTH? Eu recomendo ler o artigo (em Inglês) Simple Forth que é um ótimo tutorial sobre a linguagem.

Considerações sobre o Port

A parte fácil do port é que a arquitetura é a mesma, Intel x86. Seria mais difícil portar para uma arquitetura diferente, como as RISCs PowerPC ou ARM, devido as mudanças de opcodes, registradores e demais idiossincrasias de arquitetura.

O Linux utiliza o GNU assembler, enquanto o Macintosh utiliza um assembler Mach-O, que se assemelha com o GNU Assembler, o que ajudou no processo do port. Tive que ler o manual de ambos os assemblers para entender as semelhantes e diferenças – ainda bem que haviam mais semelhanças.

O processo de port pode ser divido em três grandes frases: a primeira fase foi fazer com que o port compilasse no meu Mac. A segunda fase consistiu em remover as primeiras falhas de segmentações e core dumps básicos. A terceira fase foi o polimento do interpretador, permitindo que ele se comportasse igual a versão Linux.

Em todas as fases do processo eu pude contar com o depurador GDB, que foi a ferramenta importantíssima para que o port tivesse êxito, particularmente gostei do comando x, que faz um dump ou exame de uma região de memória/registradores e do comando info reg, que exibe o estado de todos os registradores da máquina.

A diferença fundamental entre a versão Linux e Mac é maneira com que se faz as chamadas de sistema (syscalls). No Linux os parâmetros pra syscall são postos em registradores, e no Macintosh (que segue os BSDs) são postos na pilha. Eu escrevi um um artigo que explica as chamadas de sistema no Macintosh: Chamadas de Sistema (syscalls) no Mac OS X.

Ports relacionados: