426 lines
7.4 KiB
NASM
426 lines
7.4 KiB
NASM
%define SYS_read 0
|
|
%define SYS_write 1
|
|
%define SYS_poll 7
|
|
%define SYS_exit 60
|
|
|
|
%define FD_stdin 0
|
|
%define FD_stdout 1
|
|
|
|
%define POLLIN 1
|
|
|
|
section .text
|
|
global _start
|
|
_start:
|
|
prompt_weight:
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,weight_prompt_text
|
|
mov rdx,weight_prompt_length
|
|
syscall
|
|
|
|
call read_float
|
|
cmp rax,0
|
|
jne good_weight
|
|
|
|
call clear_stdin
|
|
jmp prompt_weight
|
|
|
|
good_weight:
|
|
; convert weight to kg
|
|
divss xmm0,[lb_kg_scale]
|
|
movq r15,xmm0 ; weight
|
|
|
|
prompt_height:
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,height_prompt_text
|
|
mov rdx,height_prompt_length
|
|
syscall
|
|
|
|
call read_float
|
|
cmp rax,0
|
|
jne good_height
|
|
|
|
call clear_stdin
|
|
jmp prompt_height
|
|
|
|
good_height:
|
|
; convert height to cm
|
|
mulss xmm0,[inch_cm_scale]
|
|
movq r14,xmm0 ; height
|
|
|
|
; print metric weight
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,weight_notice_pre_text
|
|
mov rdx,weight_notice_pre_length
|
|
syscall
|
|
|
|
movq xmm0,r15
|
|
mov rdi,3
|
|
call print_float
|
|
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,weight_notice_post_text
|
|
mov rdx,weight_notice_post_length
|
|
syscall
|
|
|
|
; print metric height
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,height_notice_pre_text
|
|
mov rdx,height_notice_pre_length
|
|
syscall
|
|
|
|
movq xmm0,r14
|
|
mov rdi,3
|
|
call print_float
|
|
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,height_notice_post_text
|
|
mov rdx,height_notice_post_length
|
|
syscall
|
|
|
|
cmp r14,0
|
|
je print_inf_bmi
|
|
|
|
; calculate bmi (kg/(m^2))
|
|
movq xmm1,r14 ; height
|
|
divss xmm1,[_100f] ; cm to m
|
|
mulss xmm1,xmm1
|
|
movq xmm0,r15 ; weight
|
|
divss xmm0,xmm1
|
|
movq r15,xmm0 ; bmi
|
|
|
|
; write bmi
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,bmi_notice_text
|
|
mov rdx,bmi_notice_length
|
|
syscall
|
|
|
|
movq xmm0,r15
|
|
mov rdi,3
|
|
call print_float
|
|
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,newline_char
|
|
mov rdx,1
|
|
syscall
|
|
|
|
call clear_stdin
|
|
|
|
exit:
|
|
xor rdi,rdi
|
|
mov rax,SYS_exit
|
|
syscall
|
|
|
|
print_inf_bmi:
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,bmi_notice_text
|
|
mov rdx,bmi_notice_length
|
|
syscall
|
|
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,inf_float_text
|
|
mov rdx,inf_float_length
|
|
syscall
|
|
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,newline_char
|
|
mov rdx,1
|
|
syscall
|
|
|
|
jmp exit
|
|
|
|
clear_stdin:
|
|
; 16 - read buff
|
|
; 4 - pollfd.fd
|
|
; 2 - pollfd.events
|
|
; 2 - pollfd.revents
|
|
sub rsp,24
|
|
mov DWORD [rsp+16],FD_stdin
|
|
mov WORD [rsp+20],POLLIN
|
|
clear_stdin_loop:
|
|
mov rax,SYS_poll
|
|
lea rdi,[rsp+16]
|
|
mov rsi,1
|
|
xor rdx,rdx
|
|
syscall
|
|
|
|
cmp rax,0
|
|
jle clear_stdin_end
|
|
|
|
mov rax,SYS_read
|
|
mov rdi,FD_stdin
|
|
mov rsi,rsp
|
|
mov rdx,16
|
|
syscall
|
|
|
|
jmp clear_stdin_loop
|
|
|
|
clear_stdin_end:
|
|
add rsp,24
|
|
ret
|
|
|
|
print_float: ; void print_float(float f, int percission)
|
|
movq rax,xmm0
|
|
cmp rax,0
|
|
je print_float_zero
|
|
|
|
sub rsp,24
|
|
movss xmm1,[_10f]
|
|
mov rcx,rdi
|
|
print_float_scale_loop:
|
|
mulss xmm0,xmm1
|
|
loop print_float_scale_loop
|
|
|
|
; put digits in memory
|
|
cvtss2si rax,xmm0
|
|
mov rcx,23
|
|
mov rbx,10
|
|
print_float_mem_loop:
|
|
xor rdx,rdx
|
|
div rbx
|
|
add rdx,'0'
|
|
mov [rsp+rcx],dl
|
|
dec rcx
|
|
|
|
cmp rax,0
|
|
jne print_float_mem_loop
|
|
|
|
push rcx
|
|
push rdi
|
|
|
|
add rcx,17
|
|
|
|
; number to write
|
|
mov rdx,rcx
|
|
sub rdx,40
|
|
imul rdx,-1
|
|
sub rdx,rdi
|
|
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
lea rsi,[rsp+rcx]
|
|
syscall
|
|
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,period_char
|
|
mov rdx,1
|
|
syscall
|
|
|
|
pop rdi
|
|
pop rcx
|
|
|
|
lea rsi,[rsp+24]
|
|
sub rsi,rdi
|
|
mov rdx,rdi
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
syscall
|
|
|
|
add rsp,24
|
|
ret
|
|
|
|
print_float_zero:
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,zero_float_text
|
|
mov rdx,zero_float_length
|
|
syscall
|
|
ret
|
|
|
|
; on error, return 0 in rax. otherwise, return 1 in rax
|
|
; and the result in xmm0
|
|
read_float: ; float read_float()
|
|
push r15 ; read count
|
|
push r14 ; whole part
|
|
|
|
sub rsp,21 ; read buffer
|
|
xor r15,r15
|
|
mov r14,-1
|
|
read_float_loop:
|
|
cmp r15,20
|
|
je read_float_size_error
|
|
|
|
mov rax,SYS_read
|
|
mov rdi,FD_stdin
|
|
lea rsi,[rsp+20]
|
|
mov rdx,1
|
|
syscall
|
|
|
|
mov dil,[rsp+20]
|
|
|
|
cmp r15,0
|
|
sete ah
|
|
|
|
cmp dil,'0'
|
|
sete al
|
|
and al,ah
|
|
jnz read_float_loop
|
|
|
|
cmp dil,' '
|
|
sete al
|
|
and al,ah
|
|
jnz read_float_loop
|
|
|
|
cmp dil,0xA ; \n
|
|
je read_float_convert
|
|
|
|
cmp dil,'.'
|
|
je read_float_start_decimal
|
|
|
|
call is_number ; dil is preserved
|
|
cmp rax,0
|
|
je read_float_num_error
|
|
|
|
sub dil,'0'
|
|
mov [rsp+r15],dil
|
|
inc r15
|
|
|
|
xor rax,rax
|
|
cmp r14,-1
|
|
setne al
|
|
add r14,rax
|
|
|
|
jmp read_float_loop
|
|
|
|
read_float_start_decimal:
|
|
cmp r14,-1
|
|
jne read_float_num_error
|
|
|
|
xor r14,r14
|
|
jmp read_float_loop
|
|
|
|
read_float_convert:
|
|
; zero r14 if it is -1
|
|
xor rax,rax
|
|
cmp r14,-1
|
|
cmove r14,rax
|
|
|
|
; invert scale
|
|
sub r14,r15
|
|
imul r14,-1
|
|
|
|
mov rax,0
|
|
movq xmm0,rax
|
|
|
|
movss xmm7,[_10f]
|
|
|
|
xor rcx,rcx
|
|
read_float_convert_whole_loop:
|
|
cmp rcx,r14
|
|
je read_float_convert_dec_prepare
|
|
|
|
mulss xmm0,xmm7
|
|
|
|
xor eax,eax
|
|
mov al,[rsp+rcx]
|
|
cvtsi2ss xmm1,eax
|
|
|
|
addss xmm0,xmm1
|
|
|
|
inc rcx
|
|
jmp read_float_convert_whole_loop
|
|
|
|
read_float_convert_dec_prepare:
|
|
mov rax,1 ; return value
|
|
movss xmm7,[_0.1f]
|
|
movss xmm6,[_10f]
|
|
read_float_convert_dec_loop:
|
|
cmp rcx,r15
|
|
je read_float_end
|
|
|
|
xor ebx,ebx
|
|
mov bl,[rsp+rcx]
|
|
cvtsi2ss xmm1,ebx
|
|
|
|
mulss xmm1,xmm7
|
|
addss xmm0,xmm1
|
|
divss xmm7,xmm6
|
|
|
|
inc rcx
|
|
jmp read_float_convert_dec_loop
|
|
|
|
read_float_end:
|
|
add rsp,21
|
|
pop r14
|
|
pop r15
|
|
ret
|
|
|
|
read_float_num_error:
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,num_error_text
|
|
mov rdx,num_error_length
|
|
syscall
|
|
|
|
mov rax,0
|
|
jmp read_float_end
|
|
|
|
read_float_size_error:
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,size_error_text
|
|
mov rdx,size_error_length
|
|
syscall
|
|
|
|
mov rax,0
|
|
jmp read_float_end
|
|
|
|
; dil is preserved across calls
|
|
is_number: ; bool is_number(char n)
|
|
cmp dil,'0'
|
|
jl is_number_fail
|
|
|
|
cmp dil,'9'
|
|
jg is_number_fail
|
|
|
|
mov rax,1
|
|
ret
|
|
|
|
is_number_fail:
|
|
xor rax,rax
|
|
ret
|
|
|
|
section .data
|
|
num_error_text: db "Invalid number!",0xA
|
|
num_error_length: equ $ - num_error_text
|
|
size_error_text: db "Number too long!",0xA
|
|
size_error_length: equ $ - size_error_text
|
|
period_char: db "."
|
|
newline_char: db 0xA
|
|
zero_float_text: db ".000"
|
|
zero_float_length: equ $ - zero_float_text
|
|
inf_float_text: db "Infinity"
|
|
inf_float_length: equ $ - inf_float_text
|
|
_10f: dd 10.0
|
|
_0.1f: dd 0.1
|
|
_100f: dd 100.0
|
|
|
|
inch_cm_scale: dd 2.54
|
|
lb_kg_scale: dd 2.20462
|
|
|
|
weight_prompt_text: db "Enter weight (pounds): "
|
|
weight_prompt_length: equ $ - weight_prompt_text
|
|
height_prompt_text: db "Enter height (inches): "
|
|
height_prompt_length: equ $ - height_prompt_text
|
|
height_notice_pre_text: db "Your metric height: "
|
|
height_notice_pre_length: equ $ - height_notice_pre_text
|
|
height_notice_post_text: db "cm",0xA
|
|
height_notice_post_length: equ $ - height_notice_post_text
|
|
weight_notice_pre_text: db "Your metric weight: "
|
|
weight_notice_pre_length: equ $ - weight_notice_pre_text
|
|
weight_notice_post_text: db "kg",0xA
|
|
weight_notice_post_length: equ $ - weight_notice_post_text
|
|
bmi_notice_text: db "Your BMI: "
|
|
bmi_notice_length: equ $ - bmi_notice_text
|