Everton, estou aqui navegando nos teus fontes, contente feito um moleque em loja de doces. Que bacana, cara! Estou vendo os caminhos que você trilhou, as opções que você fez. É uma sensação gostosa essa.
Nem sei por onde eu começo, Everton. Se você morasse aqui perto eu ia te chamar pra tomar um café na padaria e conversar um monte.
Bom, primeiro, "Caraka, Muleke!". É grande o seu projeto, hein! Bem mais ambicioso que o meu. Vi que além do compilador você também teve a preocupação de fazer uma parte que interpretasse linha por linha. Eu confesso que nem pensei nisso. A linguagem que o seu compilador entende é maior. Os computadores de 50 anos atrás nem tinham monitor de vídeo, então não havia comando para mover o cursor na tela, por exemplo. O meu compilador não abrange isso. Já o seu compilador aceita um BASIC mais recente, mais completo, tem esses comandos e muitos outros. O meu compilador é um projeto bem mais modesto que o seu.
Vi também que você escreveu uma grande quantidade de testes, exercitando cada pedacinho do seu compilador, como manda o figurino, coisa que eu também não fiz. Eu sou preguiçoso, viu Everton, então só peguei um monte de programinhas prontos que eu achei na Internet e fui submetendo um por um ao processo de compilação pra ver no que dava. Eu tinha os cento e poucos programas do livro do David Ahl. Comecei do menorzinho e, à medida que ia resolvendo os problemas, ia caminhando em direção aos maiores. Deu certo. Só tem que, quando algo não funcionava eu tinha que vasculhar pra descobrir onde estava o problema, porque eu não tinha ideia onde procurar: se era no lexer, ou no parser, ou em qualquer outra parte. Já se eu tivesse escrito os testes direitinho, daria pra saber exatamente em qual parte estaria o problema. Bom, toda abordagem tem seus prós e contras, não é verdade?
Você sim, vai entender a minha dor. É difícil fazer a parte de leitura do código em BASIC, hein? Fiquei surpreso, eu achei que seria mais fácil. Esse BASIC antigo foi pensado pelo John Kemeny para ser bem flexível, de modo a deixar os estudantes de programação à vontade. Então o programador não era obrigado a separar as palavras, nem botar ponto-e-vírgula nos lugares certos. Junte a isso o fato que os computadores daquela época tinham uma quantidade de memória exígua e que qualquer pontuação nos fontes ocuparia um espaço precioso. Resultado: muitos programas em BASIC são difíceis de ler. É difícil pra gente e pros compiladores também. Inúmeras vezes o meu analisador léxico enroscava em alguma situação onde ele entendia que era uma coisa e na verdade era outra. Eu lembro que só pra resolver onde terminava o nome das variáveis e começava a parte seguinte eu apanhei bastante.
Quando o meu analisador léxico já estava conseguindo engolir todos os programas em BASIC sem engasgar eu comecei a trabalhar no parser, o analisador sintático. Pensei que seria mais fácil. Ah, tolinho! Aí foi que a porca torceu o rabo. Sempre que eu resolvia um problema eu pensava "agora sim. Agora vai funcionar pra todos." Que nada. Resolvia uma situação e se enroscava já no programa seguinte.
Quando o lexer e o parser estavam funcionando eu brinquei um bocado. Vi que você fez o mesmo. Eu também coloquei contadores para fazer uma estatística de quantas vezes aparecia cada uma das situações nos fontes analisados. O que mais me surpreendia era que tudo que eu pensava que não seria possível, que não seria permitido, era. Sempre tinha um programador que ia lá e fazia o que não devia, só pra atrapalhar a minha vida. "O quê? Dois FOR usando o mesmo NEXT? Tá maluco? Pode." "GOTO pra uma linha que não existe? Pode." Que raiva! Esse Kemeny era um louco! 8^)
Depois que brinquei muito de analisar as estatísticas comecei a escrever o gerador de código. Eu resolvi que cada nó da árvore sintática deveria saber como gerar o código para a sua parte. Então, por exemplo, o nó astLit tinha um método "generateC" que gerava a string no formato de um fonte em C, o nó cmdFor gerava o código em C para o comando FOR, e assim por diante. Ajudou por um lado e atrapalhou por outro. Ajudou porque ficava fácil de encontrar onde estava o método que gerava o código errado. Atrapalhou porque o gerador de código na verdade estava espalhado por todo lado! No fim eu resolvi fazer uma mudança grande e juntei todos estes pedacinhos dentro de um módulo só, o genC.go . Deu trabalho.
Olha, eu devo confessar que foi muito divertido. É emocionante saber que aqueles programas de 50 anos atrás estão rodando ali na sua máquina porque você resolveu cada um dos problemas. Uma sensação muito boa. Foi trabalhoso, mas o resultado valeu. E você, meu novo amigo Everton, sabe exatamente do que estou falando.
Obrigado por compartilhar o seu projeto. Estou lendo aqui, me deliciando.
Um grande abraço!