lang-bootstrap/05/util.b

444 lines
6.5 KiB
Brainfuck
Raw Normal View History

2022-01-07 23:32:27 -05:00
function file_error
argument name
fputs(2, .str_file_error)
fputs(2, name)
fputc(2, 10)
exit(1)
:str_file_error
string Error opening file:
byte 32
byte 0
function malloc
argument size
local total_size
local memory
total_size = size + 8
memory = syscall(9, 0, total_size, 3, 0x22, -1, 0)
if memory ] 0xffffffffffff0000 goto malloc_failed
*8memory = total_size
return memory + 8
:malloc_failed
fputs(2, .str_out_of_memory)
exit(1)
:str_out_of_memory
string Out of memory.
byte 10
byte 0
function free
argument memory
local psize
local size
psize = memory - 8
size = *8psize
syscall(11, psize, size)
return
; returns a pointer to a null-terminated string containing the number given
function itos
global 32 itos_string
argument x
local c
local p
p = &itos_string
p += 30
:itos_loop
c = x % 10
c += '0
*1p = c
x /= 10
if x == 0 goto itos_loop_end
p -= 1
goto itos_loop
:itos_loop_end
return p
; returns the number at the start of the given string
function stoi
argument s
local p
local n
local c
n = 0
p = s
:stoi_loop
c = *1p
if c < '0 goto stoi_loop_end
if c > '9 goto stoi_loop_end
n *= 10
n += c - '0
p += 1
goto stoi_loop
:stoi_loop_end
return n
function memchr
argument mem
argument c
local p
p = mem
:memchr_loop
2022-01-08 12:15:17 -05:00
if *1p == c goto memchr_loop_end
2022-01-07 23:32:27 -05:00
p += 1
goto memchr_loop
:memchr_loop_end
return p
2022-01-08 14:37:39 -05:00
; copy from *p_src to *p_dest until terminator is reached, setting both to point to their respective terminators
function memccpy_advance
argument p_dest
argument p_src
argument terminator
local src
local dest
local c
src = *8p_src
dest = *8p_dest
:memccpy_advance_loop
c = *1src
*1dest = c
if c == terminator goto memccpy_advance_loop_end
src += 1
dest += 1
goto memccpy_advance_loop
:memccpy_advance_loop_end
*8p_src = src
*8p_dest = dest
return
2022-01-07 23:32:27 -05:00
function strlen
argument s
local p
p = s
:strlen_loop
2022-01-08 12:15:17 -05:00
if *1p == 0 goto strlen_loop_end
2022-01-07 23:32:27 -05:00
p += 1
goto strlen_loop
:strlen_loop_end
return p - s
2022-01-08 14:37:39 -05:00
; like C strcpy, but returns a pointer to the terminating null character in dest
2022-01-07 23:32:27 -05:00
function strcpy
argument dest
argument src
local p
local q
local c
p = dest
q = src
:strcpy_loop
c = *1q
*1p = c
if c == 0 goto strcpy_loop_end
p += 1
q += 1
goto strcpy_loop
:strcpy_loop_end
return p
2022-01-08 14:37:39 -05:00
function str_equals
argument a
argument b
local c
local d
:str_equals_loop
c = *1a
d = *1b
if c != d goto return_0
if c == 0 goto return_1
a += 1
b += 1
goto str_equals_loop
2022-01-07 23:32:27 -05:00
function str_startswith
argument s
argument prefix
local p
local q
local c1
local c2
p = s
q = prefix
:str_startswith_loop
c1 = *1p
c2 = *1q
if c2 == 0 goto return_1
if c1 != c2 goto return_0
p += 1
q += 1
goto str_startswith_loop
function fputs
argument fd
argument s
local length
length = strlen(s)
syscall(1, fd, s, length)
return
function puts
argument s
fputs(1, s)
return
2022-01-08 14:37:39 -05:00
function print_separator
fputs(1, .str_separator)
return
:str_separator
byte 10
string ------------------------------------------------
byte 10
byte 0
2022-01-07 23:32:27 -05:00
function fputn
argument fd
argument n
local s
s = itos(n)
fputs(fd, s)
return
2022-01-08 18:13:48 -05:00
function putn
argument n
fputn(1, n)
return
2022-01-07 23:32:27 -05:00
function fputc
argument fd
argument c
2022-01-08 12:15:17 -05:00
syscall(1, fd, &c, 1)
2022-01-07 23:32:27 -05:00
return
function putc
argument c
fputc(1, c)
return
; returns 0 at end of file
function fgetc
argument fd
local c
c = 0
2022-01-08 12:15:17 -05:00
syscall(0, fd, &c, 1)
2022-01-07 23:32:27 -05:00
return c
; read a line from fd as a null-terminated string
; returns 0 at end of file, 1 otherwise
function fgets
argument fd
argument buf
argument size
local p
local end
local c
p = buf
end = buf + size
:fgets_loop
c = fgetc(fd)
if c == 0 goto fgets_eof
if c == 10 goto fgets_eol
*1p = c
p += 1
if p == end goto fgets_eob
goto fgets_loop
:fgets_eol ; end of line
*1p = 0
return 1
:fgets_eof ; end of file
*1p = 0
return 0
:fgets_eob ; end of buffer
p -= 1
*1p = 0
return 1
; open the given file for reading
function open_r
argument filename
local fd
fd = syscall(2, filename, 0)
if fd < 0 goto open_r_error
return fd
:open_r_error
file_error(filename)
return -1
; open the given file for writing with the given mode
function open_w
argument filename
argument mode
local fd
fd = syscall(2, filename, 0x241, mode)
if fd < 0 goto open_w_error
return fd
:open_w_error
file_error(filename)
return -1
function close
argument fd
syscall(3, fd)
return
function isupper
argument c
if c < 'A goto return_0
if c <= 'Z goto return_1
goto return_0
2022-01-08 12:15:17 -05:00
function islower
argument c
if c < 'a goto return_0
if c <= 'z goto return_1
goto return_0
function isdigit
argument c
if c < '0 goto return_0
if c <= '9 goto return_1
goto return_0
function isalpha
argument c
if c < 'A goto return_0
if c <= 'Z goto return_1
if c < 'a goto return_0
if c <= 'z goto return_1
goto return_0
; characters which can start identifiers in C
function isalpha_or_underscore
argument c
if c < 'A goto return_0
if c <= 'Z goto return_1
if c == '_ goto return_1
if c < 'a goto return_0
if c <= 'z goto return_1
goto return_0
; characters which can appear in identifiers in C
function isalnum_or_underscore
argument c
if c < '0 goto return_0
if c <= '9 goto return_1
if c < 'A goto return_0
if c <= 'Z goto return_1
if c == '_ goto return_1
if c < 'a goto return_0
if c <= 'z goto return_1
goto return_0
2022-01-07 23:32:27 -05:00
function exit
argument status_code
syscall(0x3c, status_code)
:return_0
return 0
:return_1
return 1
function syscall
; I've done some testing, and this should be okay even if
; rbp-56 goes beyond the end of the stack.
; mov rax, [rbp-16]
byte 0x48
byte 0x8b
byte 0x85
byte 0xf0
byte 0xff
byte 0xff
byte 0xff
; mov rdi, rax
byte 0x48
byte 0x89
byte 0xc7
; mov rax, [rbp-24]
byte 0x48
byte 0x8b
byte 0x85
byte 0xe8
byte 0xff
byte 0xff
byte 0xff
; mov rsi, rax
byte 0x48
byte 0x89
byte 0xc6
; mov rax, [rbp-32]
byte 0x48
byte 0x8b
byte 0x85
byte 0xe0
byte 0xff
byte 0xff
byte 0xff
; mov rdx, rax
byte 0x48
byte 0x89
byte 0xc2
; mov rax, [rbp-40]
byte 0x48
byte 0x8b
byte 0x85
byte 0xd8
byte 0xff
byte 0xff
byte 0xff
; mov r10, rax
byte 0x49
byte 0x89
byte 0xc2
; mov rax, [rbp-48]
byte 0x48
byte 0x8b
byte 0x85
byte 0xd0
byte 0xff
byte 0xff
byte 0xff
; mov r8, rax
byte 0x49
byte 0x89
byte 0xc0
; mov rax, [rbp-56]
byte 0x48
byte 0x8b
byte 0x85
byte 0xc8
byte 0xff
byte 0xff
byte 0xff
; mov r9, rax
byte 0x49
byte 0x89
byte 0xc1
; mov rax, [rbp-8]
byte 0x48
byte 0x8b
byte 0x85
byte 0xf8
byte 0xff
byte 0xff
byte 0xff
; syscall
byte 0x0f
byte 0x05
return