brainlang is an esoteric programming language developed in the early 90s. its essentially 1 giant 30,000 cell tape, and a pointer pointing to the current cell you’re on, whose max value is 255. cells wrap around 256 (mod 256), and the pointer wraps around 30000. BF has 8 functions:
+ adds 1 to the current cell
- subtracts 1
> shifts to the right
< shifts to the left
[ begins a loop
] ends a loop
. adds the current cells ascii to the output
, takes in an input
what I’ve done is made it compatible with Roblox functions. i believe most things in Lua are possible in the bf i made. i added a couple features for debugging as well. honestly just let your imagination roam wild- at work i made a bf interpreter in office script and found it really enjoyable programming my own draw function to draw lines and skulls w/ different colors. it was a time-killer and extremely challenging but engaging. and i encourage you to try it out, try experimenting and coming up w equations, and do something unprecedented- its completely useless, but its not like there’s anything more useful than brainfuck.
also its cross compatible as long as you don’t use the custom symbols i added.
=
basically toggles the stack output flag. when its true, everything printed using .
will be pushed into an array called the stack output. ?
prints this array, and /
clears it. there’s also _
which makes it so that anything printed with .
will be added to a string- its also a toggle.
for debugging, $ prints the value of the cell w/o ascii, and @ prints the address of it.
for functions
#
puts the most recent stacked output item (w/o removing it) into an array called the stack index
*
removes the top stack index item.
%
does the same thing as #
except for an array called the stack function arguments
same with ~
^
connects everything in the stacked index array, and calls it with the stack function arguments
and lastly |
(the absolute value symbol) yields for 10ms
if you want to leave feedback, or you find any bugs, or you want me to add anything that doesnt go against the nature of BF, leave a comment.
-- ilucere
local brainfog = {}
brainfog.__index = brainfog
local instructionCodes = {
-- you should know these
['+'] = 1,
['-'] = 2,
['<'] = 3,
['>'] = 4,
['['] = 5,
[']'] = 6,
[','] = 7,
['.'] = 8,
-- STRINGS
['='] = 9, -- STACK OUTPUT FLAG (two blocks on top of each other)
['?'] = 10, -- PRINT STACKED OUTPUT (what is our output?)
['/'] = 11, -- CLEAR STACKED OUTPUT (slash it out of here)
['_'] = 12, -- TOGGLE STRING MODE ON OUTPUT (missing character....)
-- DEBUGGING
['$'] = 13, -- PRINT CELL VALUE (money has value)
['@'] = 14, -- PRINT CELL INDEX (at what index)
-- FUNCTIONS
['#'] = 15, -- STACK INDEXING [basically puts your recent STACKED OUTPUT in an array so you can do workspace.Object for example]
['*'] = 16, -- REMOVE RECENT STACK INDEXING (* makes the most sense to me for a clear. dont remember why)
['%'] = 17, -- SET STACKED OUTPUT AS FUNCTION ARG (two objects next to each other)
['~'] = 18, -- REMOVE RECENT FUNCTION ARGS ITEM
['^'] = 19, -- CALL STACKED INDICES AS FUNCTION
-- QOL
['|'] = 20, -- HALT. stop for 10ms
}
-- v 0-0-1
-- stdBFTapeCells
-- if true, the tape is 30,000 cells, and each cell has a max of 255. if false, the max tape size is 100,000
local stdCellMax, stdTapeMax = 256, 30
local customTapeMax = 100000
function brainfog.New(stdBFTapeCells)
return setmetatable({
stdBFTapeCells=stdBFTapeCells,
tapeMax=stdBFTapeCells and (stdTapeMax) or (customTapeMax),
tape=stdBFTapeCells and (table.create(stdTapeMax, 0)) or (table.create(customTapeMax, 0)),
env=0,
argTape={},
stackOutputTape={},
stackIndexTape={},
}, brainfog)
end
function brainfog:Tokenization(text)
if (type(text) ~= 'string') then
error('not a string')
end
local instructions = {}
local loops = {}
local loopStack = {}
local index, maxLength = 1, string.len(text)
local position = 0
while (index <= maxLength) do
local character = string.sub(text, index, index)
if (character == ':') then
index += 1
while (string.sub(text, index, index) ~= '\n' and index <= maxLength) do
index += 1
end
continue
end
local characterCode = instructionCodes[character]
if (characterCode) then
position += 1
local repetitions = 0
if (character == '[') then
repetitions = 1
index += 1
table.insert(loopStack, position)
elseif (character == ']') then
repetitions = 1
index += 1
local insertion = table.remove(loopStack, #loopStack)
loops[insertion] = position
loops[position] = insertion
else
while (string.sub(text, index, index) == character) do
repetitions += 1
index += 1
end
end
table.insert(instructions, {characterCode, repetitions, position})
else
index += 1
end
end
if (#loopStack ~= 0) then
error('unbalanced loops')
end
self.loops = loops
self.instructions = instructions
return self
end
--[1] add
function brainfog._stdBFAdd(initial, count)
return (initial + count) % stdCellMax
end
function brainfog._nccBFAdd(initial, count)
return (initial + count)
end
--[2] subtract
function brainfog._stdBFSub(initial, count)
return (initial - count) % stdCellMax
end
function brainfog._nccBFSub(initial, count)
return (initial - count)
end
--[3] left
function brainfog._stdBFLeft(ptr, count)
return (ptr - count) % stdTapeMax
end
function brainfog._nccBFLeft(ptr, count)
return (ptr - count) % customTapeMax
end
--[4] right
function brainfog._stdBFRight(ptr, count)
return (ptr + count) % stdTapeMax
end
function brainfog._nccBFRight(ptr, count)
return (ptr + count) % customTapeMax
end
local UserInputService = game:GetService('UserInputService')
function brainfog:Execute(env)
local add, sub, left, right;
if (self.stdBFTapeCells) then
add, sub, left, right = brainfog._stdBFAdd, brainfog._stdBFSub, brainfog._stdBFLeft, brainfog._stdBFRight
else
add, sub, left, right = brainfog._nccBFAdd, brainfog._nccBFSub, brainfog._nccBFLeft, brainfog._nccBFRight
end
local pointer = 1
local stackedOutput, stringMode = false, false
local compiledString = ''
local index = 1
while (index <= #self.instructions) do
local instructionInfo = self.instructions[index]
local instructionCode, repetitions, position = instructionInfo[1], instructionInfo[2], instructionInfo[3]
if (instructionCode == instructionCodes['+']) then
self.tape[pointer] = add(self.tape[pointer], repetitions)
elseif (instructionCode == instructionCodes['-']) then
self.tape[pointer] = sub(self.tape[pointer], repetitions)
elseif (instructionCode == instructionCodes['<']) then
pointer = left(pointer, repetitions)
print('left', repetitions)
elseif (instructionCode == instructionCodes['>']) then
pointer = right(pointer, repetitions)
print('right', repetitions)
elseif (instructionCode == instructionCodes['[']) then
if (self.tape[pointer] == 0) then
index = self.loops[position]
end
elseif (instructionCode == instructionCodes[']']) then
if (self.tape[pointer] ~= 0) then
index = self.loops[position]
end
elseif (instructionCode == instructionCodes['.']) then
local cell = utf8.char(self.tape[pointer])
if (stackedOutput) then
if (stringMode) then
compiledString ..= cell
else
table.insert(self.stackOutputTape, cell)
end
else
print(cell)
end
elseif (instructionCode == instructionCodes['_']) then
if (compiledString ~= '') then
table.insert(self.stackOutputTape, compiledString)
end
stringMode = not stringMode
elseif (instructionCode == instructionCodes[',']) then
local input = UserInputService.InputBegan:Wait()
local fixedInput = input.KeyCode == Enum.KeyCode.Unknown and (input.UserInputType.Name) or (input.KeyCode.Name)
table.insert(self.stackOutputTape, fixedInput)
elseif (instructionCode == instructionCodes['=']) then
stackedOutput = not stackedOutput
elseif (instructionCode == instructionCodes['/']) then
table.clear(self.stackOutputTape)
elseif (instructionCode == instructionCodes['?']) then
print(table.unpack(self.stackOutputTape))
elseif (instructionCode == instructionCodes['$']) then
print(self.tape[pointer])
elseif (instructionCode == instructionCodes['@']) then
print(pointer)
elseif (instructionCode == instructionCodes['|']) then
task.wait(.1) -- this is fine
elseif (instructionCode == instructionCodes['#']) then
local value = self.stackOutputTape[#self.stackOutputTape]
if (value) then
table.insert(self.stackIndexTape, value)
end
elseif (instructionCode == instructionCodes['*']) then
table.remove(self.stackIndexTape, #self.stackIndexTape)
elseif (instructionCode == instructionCodes['%']) then
local value = self.stackOutputTape[#self.stackOutputTape]
if (value) then
table.insert(self.argTape, value)
end
elseif (instructionCode == instructionCodes['~']) then
table.remove(self.argTape, #self.argTape)
elseif (instructionCode == instructionCodes['^']) then
local init = (env or getfenv(2))
print(init)
for _, v in (self.stackIndexTape) do
init = init[v]
end
print(self.stackIndexTape)
init(table.unpack(self.argTape))
end
index += 1
end
end
return brainfog
example:
local bf = require(script.Parent.brainfog).New(true)
local env = {}
env.A = function(x)
print('sheesh', utf8.codepoint(x, 1, 1))
end
bf:Tokenization('>+++++[<+++++++++++++> -]< =.=# /[-] =+++++.=% ^'):Execute(env)
brainfog.lua (7.4 KB)