-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbfk.lua
More file actions
405 lines (385 loc) · 11.5 KB
/
bfk.lua
File metadata and controls
405 lines (385 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
local global_args = {...}
local programfile = fs.open(global_args[1], "r")
if not programfile then
print("Error opening file "..global_args[1])
return
end
local interpreter = "bfk.lua"
local program = programfile.readAll():gsub("[^(><+-.,%[%])]", "")
programfile.close()
local root = "/bfroot/"
if not fs.exists(root) then
fs.makeDir(root)
end
local memsize = 2^14
local memory = {}
for x=1,memsize do
memory[x] = 0
end
local PC = 0
local ptr = 2^14 / 2
local syscallsize = 4
local exeargs = {}
if #global_args>1 then
for x=2, #global_args do
exeargs[x-1] = global_args[x]
end
end
local function strtotable(input)
local t = {}
for x=1,#input do
t[x] = string.byte(input:sub(x, x))
end
t[#input + 1] = 0
return t
end
local function chartoint(str)
local res = 0
for x=1,#str do
res = res + str[x] * math.pow(256, (#str-x))
end
return res
end
local function inttochar(int, size)
local t = {}
local nsize = math.ceil(math.log(int)/math.log(255))
for x=1,size do
if size-x>=nsize then
t[x] = 0
else
t[x] = math.floor((int / (math.pow(256, size-x)) % 256 + 0.5))
end
end
return t
end
local function tabletostr(t)
return table.concat({string.char(table.unpack(t))}):sub(1,-2) --Remove \0
end
local fileslots = {}
local modemap = {
["rt"] = "r",
["wt"] = "w",
["at"] = "a",
["rb"] = "rb",
["wb"] = "wb",
["ab"] = "ab",
}
local syscalls = { --4 chars for each syscall
--I/O
["PRNT"] = function(args) --Print text
write(tabletostr(args))
end,
["READ"] = function(args) --read()
local input = read()
return strtotable(input)
end,
["SLEP"] = function(args) --Sleep
local ax = chartoint(args)
sleep(args[1]*0.05)
end,
["SCPX"] = function(args) --Get/set cursor X
local x, y = term.getCursorPos()
local ax = chartoint(args)
term.setCursorPos(ax+1, y)
end,
["SCPY"] = function(args) --Get/set cursor Y
local x, y = term.getCursorPos()
local ay = chartoint(args)
term.setCursorPos(x, ay+1)
end,
["GCPX"] = function(args) --Get/set cursor X
local x, y = term.getCursorPos()
return inttochar(x, 2)
end,
["GCPY"] = function(args) --Get/set cursor Y
local x, y = term.getCursorPos()
return inttochar(y, 2)
end,
["CLRS"] = function(args) --Clear screen
term.clear()
end,
["GETW"] = function(args) --Get width
return inttochar(select(1, term.getSize()), 2)
end,
["GETH"] = function(args) --Get height
return inttochar(select(2, term.getSize()), 2)
end,
["SCRL"] = function(args) --Scroll
term.scroll(chartoint(args))
end,
["CHAR"] = function(args) --Pull single char event
return {string.byte(select(2, os.pullEvent("char")))}
end,
--Filesystem, absolute paths
["OPEN"] = function(args) --Open
local sargs = tabletostr(args)
if (args[1] == 0x25) and (args[2] == 0x4F) then
term.write("9551\n")
return {0}
end
local mode = sargs:sub(1, 2)
local filepath = root .. sargs:sub(3, -1)
for x=1,255 do
if fileslots[x]==nil then --Fill open slot
local file, err = fs.open(filepath, assert(modemap[mode], ("Mode doesn't exist: " .. tostring(mode))))
if file==nil then
return {0} -- error
else
fileslots[x] = file
return {x}
end
end
end
error("No more file slots left")
end,
["CLOS"] = function(args) --Close
local fileslot = args[1]
if fileslots[fileslot]~=nil then
fileslots[fileslot].close()
fileslots[fileslot] = nil
end
end,
["REAB"] = function(args) --Read bytes
local fileslot = args[1]
local size = chartoint({args[2], args[3]})
if (fileslots[fileslot]~=nil) and (fileslots[fileslot].read) then
local readstr = fileslots[fileslot].read(size)
if readstr==nil then
return {0}
end
return strtotable(readstr)
end
end,
["WRTE"] = function(args) --Write bytes
local fileslot = args[1]
local buf = tabletostr(args):sub(2, -1)
if (fileslots[fileslot]~=nil) and (fileslots[fileslot].write) then
fileslots[fileslot].write(buf)
end
end,
["SIZE"] = function(args) --Get size of file
if fs.exists(root .. tabletostr(args)) then
return inttochar(fs.getSize(root .. tabletostr(args)), 2)
else
return {0}
end
end,
["LSSZ"] = function(args) --List files in directory
if fs.exists(root .. tabletostr(args)) then
return {#fs.list(root .. tabletostr(args))%256}
else
return {0}
end
end,
["GTLS"] = function(args) --Get file in index of directory
local sarg = tabletostr(args)
local fileindex = args[1] or 1
local dirpath = root .. sarg:sub(2, -1)
local file = fs.list(dirpath)[fileindex]
if file then
local output
if fs.isDir(dirpath .. file) then --Add a char for if it's a file or a directory
output = "D"
else
output = "F"
end
output = output .. file
return strtotable(output)
end
end,
["EXEC"] = function(args) --Execute file with interpreter
local ok, err = pcall(
function()
loadfile(interpreter)(root .. tabletostr(args), table.unpack(exeargs))
end
)
if not ok then
print(err)
end
end,
["MDIR"] = function(args) --Make directory
fs.makeDir(root .. tabletostr(args))
end,
["DELF"] = function(args) --Delete path
fs.delete(root .. tabletostr(args))
end,
["FCPY"] = function(args) --Make directory
local fstringsize = args[1]
local string = tabletostr(args):sub(2, -1)
local filea = string:sub(1, fstringsize)
local fileb = string:sub(fstringsize + 1, -1)
fs.copy(root .. filea, root .. fileb)
end,
["FMOV"] = function(args) --Move file
local fstringsize = args[1]
local string = tabletostr(args):sub(2, -1)
local filea = string:sub(1, fstringsize)
local fileb = string:sub(fstringsize + 1, -1)
fs.move(root .. filea, root .. fileb)
end,
["EDIR"] = function(args) --Get if directory exists
local file = root .. tabletostr(args)
if fs.exists(file) then
return {fs.isDir(file) and 1 or 0} --Return 1 or 0
else
return {0}
end
end,
["EFIL"] = function(args) --Get if file exists
local file = root .. tabletostr(args)
if fs.exists(file) then
return {(not fs.isDir(file)) and 1 or 0} --Return 1 or 0
else
return {0}
end
end,
["GARG"] = function(args) --Get arguments
local index = args[1]
return strtotable(exeargs[index] or "")
end,
["SARG"] = function(args) --Set arguments
local arg = tabletostr(args):sub(2, -1)
local index = args[1]
exeargs[index] = arg
end,
["SEEK"] = function(args) --Seek in a file, absolute cursor
local offset = chartoint(args)
if (fileslots[fileslot]~=nil) then
fileslots[fileslot].seek("set", offset)
end
end
}
local syscalltype = { --Maps if syscall should perform with a null char or a size (false = null, 0 = no params, >0 param char count)
["PRNT"] = false,
["READ"] = 0,
["SLEP"] = 2,
["SCPX"] = 2,
["SCPY"] = 2,
["CLRS"] = 0,
["GETW"] = 0,
["GETH"] = 0,
["SCRL"] = 2,
["CHAR"] = 0,
["GCPX"] = 0,
["GCPY"] = 0,
["OPEN"] = false,
["CLOS"] = 1,
["REAB"] = 3,
["SIZE"] = false,
["LSSZ"] = false,
["GTLS"] = false,
["EXEC"] = false,
["MDIR"] = false,
["DELF"] = false,
["WRTE"] = false,
["EDIR"] = false,
["EFIL"] = false,
["GARG"] = 1,
["SARG"] = false,
["FCPY"] = false,
["FMOV"] = false,
["SEEK"] = 2
}
local currentreturn = {}
local currentcall = {}
local calltype = -1
local syscallname = ""
local function dosyscall(syscallname)
local call = assert(syscalls[syscallname], "Syscall doesn't exist")
for x=1,syscallsize do
table.remove(currentcall, 1)
end
local res = call(currentcall)
if res then
currentreturn = res
end
calltype = -1
currentcall = {}
end
--[[
function env:
- p variable for "pointer"
- m variable for "memory"
- , calls "i", sets m[p]
- . calls "o", uses m[p]
--]]
local supported = "><+-.,"
local code = {}
local metacode = {}
local cptr = 0
local counter = 0
while cptr<#program do
cptr = cptr + 1
counter = counter + 1
local char = program:sub(cptr,cptr)
code[cptr] = string.byte(char)
local sptr = cptr
if code[cptr] == string.byte("[") then --[
metacode[counter] = "while m[p]~=0 do"
elseif code[cptr] == string.byte("]") then --]
metacode[counter] = "end"
elseif code[cptr] == string.byte(",") then
metacode[counter] = "i(m, p)"
elseif code[cptr] == string.byte(".") then
metacode[counter] = "o(m, p)"
else
code[cptr] = string.byte(char)
local sptr = cptr
while (program:sub(sptr,sptr)==char) do
sptr = sptr + 1
end
local dif = sptr-cptr
if (code[cptr]==string.byte("+")) then
metacode[counter] = "m[p]=(m[p]+" .. dif .. ")%256"
elseif (code[cptr]==string.byte("-")) then
metacode[counter] = "m[p]=(m[p]-" .. dif .. ")%256"
elseif (code[cptr]==string.byte(">")) then
metacode[counter] = "p=p+" .. dif
elseif (code[cptr]==string.byte("<")) then
metacode[counter] = "p=p-" .. dif
end
cptr = sptr-1
end
end
local globals = {
m = memory,
p = ptr,
o = function(memory, ptr) --MAKE A SYSCALL
-- Debug
-- for k,v in pairs(memory) do
-- if v~=0 then
-- print(k, string.char(v))
-- end
-- end
-- print(ptr, memory[ptr])
table.insert(currentcall, memory[ptr])
if (#currentcall>=syscallsize) then
if (calltype==-1) then
syscallname = ""
for x=1,syscallsize do
syscallname = syscallname .. string.char(currentcall[x])
end
calltype = syscalltype[syscallname]
if calltype==nil then
error("Syscall doesn't exist")
end
elseif (calltype==false) then --Null based syscall
if (memory[ptr]==0) then --Reached null char, do syscall
dosyscall(syscallname)
end
end
--Size based syscall
if (calltype~=false) and (#currentcall>=calltype+syscallsize) then
dosyscall(syscallname)
end
end
end,
i = function(memory, ptr) --GET RETURN OF SYSCALL
memory[ptr] = currentreturn[1] or 0
table.remove(currentreturn, 1) --Pop character from the return value
end
}
local concatmetacode = table.concat(metacode, "\n")
local code,err = loadstring(concatmetacode)
local brainload = setfenv(code, globals)
brainload() --Run compiled bf code