Created
October 30, 2023 00:34
-
-
Save MCJack123/48999076fef81d0a7b9fcc7fd6acedf6 to your computer and use it in GitHub Desktop.
AOT Brainfuck compiler to bytecode for Lua 5.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
registers: 0 = data table, 1 = data pointer, 2 = function temp, 3 = current data (4 total) | |
expects `get(): number` and `put(n: number)` global functions | |
init code | |
GETGLOBAL R(0), K("setmetatable") | |
NEWTABLE R(1), 0, 0 | |
NEWTABLE R(2), 0, 1 | |
CLOSURE R(3), KP(0) | |
SETTABLE R(2), K("__index"), R(3) | |
CALL R(0), 3, 2 | |
LOADK R(1), K(0) | |
LOADK R(3), K(0) | |
>, increment data pointer | |
SETTABLE R(0), R(1), R(3) | |
ADD R(1), R(1), K(1) | |
GETTABLE R(3), R(0), R(1) | |
<, decrement data pointer | |
SETTABLE R(0), R(1), R(3) | |
SUB R(1), R(1), K(1) | |
GETTABLE R(3), R(0), R(1) | |
+, increment data | |
ADD R(3), R(3), K(1) | |
-, decrement data | |
SUB R(3), R(3), K(1) | |
., output byte | |
GETGLOBAL R(2), K("put") | |
CALL R(2), 2, 1 | |
,, input byte | |
GETGLOBAL R(3), K("get") | |
CALL R(3), 1, 2 | |
[, jump forward if zero | |
EQ 1, R(3), K(0) | |
JMP $displacement*3 | |
], jump backward if not zero | |
EQ 0, R(3), K(0) | |
JMP $displacement*-3 | |
]] | |
assert(_VERSION == "Lua 5.1") | |
local header = string.dump(function() end):sub(1, 12) | |
local ENDIAN = header:byte(7) == 0 and ">" or "<" | |
local INT = "i" .. header:byte(8) | |
local STRING = "s" .. header:byte(9) | |
local INSTRUCTION = "I" .. header:byte(10) | |
local NUMBER = (header:byte(12) == 0 and (header:byte(11) == 4 and "f" or "d") or ("i" .. header:byte(11))) | |
local HEADER = ENDIAN .. STRING .. INT .. INT .. "BBBB" | |
local FOOTER = (ENDIAN .. INT .. "B" .. NUMBER .. "B" .. NUMBER .. "B" .. STRING .. "B" .. STRING .. "B" .. STRING .. "B" .. STRING .. INT .. STRING .. INT .. INT .. "BBBB" .. INT .. INSTRUCTION:rep(2) .. INT .. "B" .. NUMBER .. INT:rep(7)):pack(6, 3, 0, 3, 1, 4, "put\0", 4, "get\0", 4, "setmetatable\0", 4, "__index\0", 1, "\0", 0, 0, 0, 0, 0, 1, 2, 0x00000001, 0x0100001E, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0) | |
local function encode(c) return (INT .. INSTRUCTION:rep(#c)):pack(#c, table.unpack(c)) end | |
local instructions = { | |
[">"] = { | |
0x0080C009, | |
0x00C0404C, | |
0x000040C6 | |
}, | |
["<"] = { | |
0x0080C009, | |
0x00C0404D, | |
0x000040C6 | |
}, | |
["+"] = { | |
0x01C040CC | |
}, | |
["-"] = { | |
0x01C040CD | |
}, | |
["."] = { | |
0x00008085, | |
0x0100409C | |
}, | |
[","] = { | |
0x0000C0C5, | |
0x008080DC | |
}, | |
["["] = { | |
0x01C00057, | |
0x00000016 | |
}, | |
["]"] = { | |
0x01C00017, | |
0x00000016 | |
} | |
} | |
local function bfcompile(src) | |
local insts, stack = { | |
0x00010005, | |
0x0000004A, | |
0x0000408A, | |
0x000000E4, | |
0x8280C089, | |
0x0180801C, | |
0x00000041, | |
0x000000C1 | |
}, {} | |
for c in src:gmatch "[<>%+%-%.,%[%]]" do | |
local i = instructions[c] | |
insts[#insts+1] = i[1] | |
insts[#insts+1] = i[2] | |
insts[#insts+1] = i[3] | |
if c == "[" then stack[#stack+1] = #insts | |
elseif c == "]" then | |
local p = stack[#stack] | |
local d = #insts - p | |
stack[#stack] = nil | |
insts[p] = 0x16 + (d + 0x1FFFF) * 0x4000 | |
insts[#insts] = 0x16 + (0x1FFFF - d) * 0x4000 | |
end | |
end | |
insts[#insts+1] = 0x0080001E -- RETURN 0, 1 | |
local chunk = header .. HEADER:pack(src .. "\0", 0, 0, 0, 0, 0, 4) .. encode(insts) .. FOOTER | |
--[[print(chunk:gsub(".", function(c) return ("%02X "):format(c:byte()) end)) | |
local file = fs.open("bfcompile.tmp", "wb") | |
file.write(chunk) | |
file.close()]] | |
return load(chunk, src, "b", _ENV) | |
end | |
function get() return select(2, os.pullEvent("char")):byte() end | |
function put(c) write(string.char(c)) end | |
assert(bfcompile(read()))() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment