Fiz um compilador de brainfuck em lua

Por incrível que pareça, isso é considerado uma linguagem de programação criada como uma espécie de piada. O funcionamento dela é bem simples:

Símbolo Função
> Desloca o ponteiro para a direita.
< Desloca o ponteiro para a esquerda.
+ Soma 1 ao valor do ponteiro atual.
- Subtraí 1 ao valor do ponteiro atual.
. Imprime o valor do ponteiro atual no console.
, Lê uma tecla do usuário e passa para o ponteiro atual.
[…] Repete tudo o que está dentro do bloco enquanto o valor do ponteiro atual for diferente de 0.

Por exemplo, vou escrever “Teste!” (em ASCII: [84, 101, 115, 116, 101, 33]) no console:

++++++++++[>++++++++>++++++++++>+++++++++++>++++++++++++>++++++++++>+++<<<<<<-]>++++.>+.>+++++.>----.>+.>+++.

OUTPUT: Teste!

Aqui está o script:

local memory = {}
local pointer = 0
local offset = 1
local loop = 0
local canRead = true

local output = {}
local source = "++++++++++[>++++++++>++++++++++>+++++++++++>++++++++++++>++++++++++>+++<<<<<<-]>++++.>+.>+++++.>----.>+.>+++."

-- Definir os tokens
local tokens = {
    ["+"] = function()
		if canRead then
			memory[pointer] = (memory[pointer] + 1) % 256
		end
    end,
    
    ["-"] = function()
		if canRead then
			memory[pointer] = (memory[pointer] - 1) % 256
		end
    end,
    
    [">"] = function()
		if canRead then
			pointer = pointer + 1
		end
    end,
    
    ["<"] = function()
		if canRead then
			pointer = pointer - 1
		end
    end,
    
    ["."] = function()
        if canRead then
            table.insert(output, string.char(memory[pointer]))
        end
    end,
	
    ["["] = function()
        loop = offset - 1
        canRead = memory[pointer] > 0
    end,
    
    ["]"] = function()
        offset = canRead and loop or offset
        canRead = true
    end
}

-- Inicializar a memória
for i = pointer, 1024 do
    memory[i] = 0
end

-- Ler cada um dos caracteres 
while offset <= source:len() do
    local character = source:sub(offset, offset)
    local token = tokens[character]
    
    if token then
        token()
    end
    
    offset = offset + 1
end

-- Escrever a output
print(table.concat(output))

Link da wikipedia a respeito: https://pt.wikipedia.org/wiki/Brainfuck
Código no pastebin: https://pastebin.com/Jk6yAG60

Explicando o código

Vou tentar dar uma explicação para esse código que eu escrevi:

++++++++++[>++++++++>++++++++++>+++++++++++>++++++++++++>++++++++++>+++<<<<<<-]>++++.>+.>+++++.>----.>+.>+++.

O ponteiro atual (que passará a ser chamado de P[0]) tem o valor zero.
P[0] = 0

++++++++++ - Somou 10 ao valor do ponteiro atual.
P[0] = 10

[ - Abriu o loop, ele vai ficar repetindo tudo dentro do bloco enquanto P != 0.
>++++++++ - Deslocou o ponteiro para 1 e somou 8.
P[1] = 8

>++++++++++ - Deslocou o ponteiro para 2 e somou 10.
P[2] = 10

>+++++++++++ - Deslocou o ponteiro para 3 e somou 11.
P[3] = 11

>++++++++++++ - Deslocou o ponteiro para 4 e somou 12.
P[4] = 12

>++++++++++ - Deslocou o ponteiro para 5 e somou 10.
P[5] = 10

>+++ - Deslocou o ponteiro para 6 e somou 3.
P[6] = 3

<<<<<<- - Deslocou o ponteiro de volta para o 0 e subtaiu 1.
P[0] = 9.

Esse processo será repetido mais 9 vezes (no total 10) até que P[0] = 0. No fim, os valores finais dos ponteiros serão:
P[0] = 0
P[1] = 80
P[2] = 100
P[3] = 110
P[4] = 120
P[5] = 100
P[6] = 30

>++++. - Desloca o ponteiro para 1, soma 4 e escreve no console: (P[1] = 80 + 4 = 84, “T”)
>+. - Desloca o ponteiro para 2, soma 1 e escreve no console: (P[2] = 100 + 1 = 101, “e”)
>+++++. - Desloca o ponteiro para 3, soma 5 e escreve no console: (P[3] = 110 + 5 = 115, “s”)
>----. - Desloca o ponteiro para 4, subtraí 4 e escreve no console: (P[4] = 120 - 4 = 116, “t”)
>+. - Desloca o ponteiro para 5, soma 1 e escreve no console: (P[2] = 100 + 1 = 101, “e”)
>+++. - Desloca o ponteiro para 6, soma 3 e escreve no console: (P[2] = 30 + 3 = 33, “!”)

Saída: “Teste!”

2 Curtidas

Wow, acho que entendi o porque deram esse nome pra linguagem kkkkkkkkkkkkkkk

Mas falando sério, sua explicação foi muito boa, eu entendi praticamente tudo.

Uma pergunta, o que é o offset atual?

1 Curtida

É o valor em byte que o ponteiro atual está apontando na memória. Vou até editar porque ficou meio confuso.

1 Curtida

Aaaaaata, acho que entendi. Obrigado!

Depois de quebrar muito a cabeça, consegui escrever “Olá” ([ 79, 108, 225 ])

++++++++++ [
 > ++++++++
 > ++++++++++
 >> ++++++++++++++++++++
  <<<<-
]
 
> -.
> ++++++++.

> ++++++++++ [
  > ++
    <-
]

> +++++.

OUTPUT: Olá

Vou tentar mostrar o que eu fiz:

++++++++++ (10) [
 > ++++++++  -> Adicionando 8 no segundo ponterio (vai ficar 80)
 > ++++++++++  -> Adicionando 10 no terceiro ponteiro (vai ficar 100)
 >> ++++++++++++++++++++  -> Adicionando 20 no quinto ponteiro (vai ficar 200  /  adicionei no quinto porque usei o quatro como loop)
  <<<<-
]
> -.  -> Removendo 1 e printando (79)
> ++++++++.  -> Adicionando 8 e printando (108)

O objetivo aqui é fazer o quinto ponteiro chegar a 20 (total 220), usando o quarto ponteiro para o loop (estava com preguiça de escrever manualmente e queria testar)

> ++++++++++ [
  > ++
    <-
]

Por fim, adicionando 5 para chegar em 225 e printando:

> +++++.



Enquanto escrevia isso, percebi que podia poupar o segundo loop, adicionando mais dois valores no terceiro ponteiro, no primeiro loop. Ficou assim:
++++++++++ [
 > ++++++++
 > ++++++++++
 > ++++++++++++++++++++++
  <<<-
]
 
> -.
> ++++++++.
> +++++.

OUTPUT: Olá
1 Curtida