global exit_code
exit_code = main()
exit(exit_code)

function main
	local secret_number
	local guess
	global 32 input_line
	local p_line
	p_line = &input_line
	secret_number = getrand(100)
	puts(.str_intro)
	
	:guess_loop
		puts(.str_guess)
		syscall(0, 0, p_line, 30)
		guess = stoi(p_line)
		if guess < secret_number goto too_low
		if guess > secret_number goto too_high
		puts(.str_got_it)
		return 0
		:too_low
			puts(.str_too_low)
			goto guess_loop
		:too_high
			puts(.str_too_high)
			goto guess_loop

:str_intro
	string I'm thinking of a number.
	byte 10
	byte 0

:str_guess
	string Guess what it is:
	byte 32
	byte 0

:str_got_it
	string You got it!
	byte 10
	byte 0

:str_too_low
	string Too low!
	byte 10
	byte 0

:str_too_high
	string Too high!
	byte 10
	byte 0

; get a "random" number from 0 to x using the system clock
function getrand
	argument x
	global 16 getrand_time
	local ptime
	local n
	
	ptime = &getrand_time
	syscall(228, 0, ptime) ; clock_gettime(CLOCK_REALTIME, ptime)
	ptime += 8 ; nanoseconds at offset 8 in struct timespec
	n = *4ptime
	n %= x
	return n

; 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 strlen
	argument s
	local p
	p = s
	:strlen_loop
		if *1p == 0 goto strlen_loop_end
		p += 1
		goto strlen_loop
	:strlen_loop_end
	return p - s

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

function fputn
	argument fd
	argument n
	local s
	s = itos(n)
	fputs(fd, s)
	return

function exit
	argument status_code
	syscall(0x3c, status_code)

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
