Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ; kalkulator.asm
- ; x86-64 Linux / NASM / Box64
- ; Decimal fixed point: 8 decimal places
- ; No libc
- section .data
- prompt db "> "
- plen equ $-prompt
- newline db 10
- scale dq 100000000
- ten dq 10
- section .bss
- buf resb 128
- outbuf resb 128
- intbuf resb 32
- acc resq 1
- operand resq 1
- op resb 1
- section .text
- global _start
- _start:
- mov qword [acc], 0
- mov byte [op], 0
- ; ================================================
- ; Main loop
- ; ================================================
- main_loop:
- ; Prompt
- mov eax, 1
- mov edi, 1
- mov rsi, prompt
- mov edx, plen
- syscall
- ; Read line
- xor eax, eax
- xor edi, edi
- mov rsi, buf
- mov edx, 128
- syscall
- test rax, rax
- jle exit
- mov r14, rax
- ; Skip leading spaces
- xor r8, r8
- skip_spaces:
- cmp r8, r14
- jge main_loop
- mov al, [buf+r8]
- cmp al, ' '
- jne first_char
- inc r8
- jmp skip_spaces
- first_char:
- cmp al, 'q'
- je exit
- ; Operator?
- cmp al, '+'
- je operator_found
- cmp al, '-'
- je operator_found
- cmp al, '*'
- je operator_found
- cmp al, '/'
- je operator_found
- ; Otherwise parse number
- lea rsi, [buf+r8]
- mov rdx, r14
- sub rdx, r8
- call parse_number
- mov [operand], rax
- cmp byte [op], 0
- jne calculate
- ; No pending operation: set accumulator
- mov [acc], rax
- jmp show_result
- operator_found:
- mov [op], al
- inc r8
- ; Skip spaces after operator
- operator_spaces:
- cmp r8, r14
- jge main_loop
- mov al, [buf+r8]
- cmp al, ' '
- jne inline_number
- cmp al, 10
- je main_loop
- inc r8
- jmp operator_spaces
- inline_number:
- cmp al, 10
- je main_loop
- cmp al, 13
- je main_loop
- ; Operator and number on same line
- lea rsi, [buf+r8]
- mov rdx, r14
- sub rdx, r8
- call parse_number
- mov [operand], rax
- jmp calculate
- ; ================================================
- ; Parse decimal fixed-point number
- ; Input: RSI = pointer, RDX = length
- ; Output: RAX = signed fixed-point value
- ; ================================================
- parse_number:
- mov r9, rdx
- xor rbx, rbx ; integer part
- xor r12, r12 ; fractional part
- xor r13, r13 ; fractional digits
- xor r8, r8 ; decimal point flag
- xor r15, r15 ; sign
- xor rcx, rcx ; index
- ; Optional sign
- mov al, [rsi]
- cmp al, '-'
- jne check_plus
- mov r15, 1
- inc rcx
- jmp parse_loop
- check_plus:
- cmp al, '+'
- jne parse_loop
- inc rcx
- parse_loop:
- cmp rcx, r9
- jge parse_done
- movzx rax, byte [rsi+rcx]
- inc rcx
- cmp al, 10
- je parse_done
- cmp al, 13
- je parse_done
- cmp al, ' '
- je parse_done
- cmp al, '.'
- je decimal_point
- sub al, '0'
- cmp al, 9
- ja parse_done
- movzx rdx, al
- test r8, r8
- jnz fractional_digit
- imul rbx, rbx, 10
- add rbx, rdx
- jmp parse_loop
- fractional_digit:
- cmp r13, 8
- jge parse_loop
- imul r12, r12, 10
- add r12, rdx
- inc r13
- jmp parse_loop
- decimal_point:
- mov r8, 1
- jmp parse_loop
- parse_done:
- ; Pad fraction to 8 digits
- cmp r13, 8
- jge make_number
- imul r12, r12, 10
- inc r13
- jmp parse_done
- make_number:
- mov rax, rbx
- imul rax, 100000000
- add rax, r12
- test r15, r15
- jz parse_return
- neg rax
- parse_return:
- ret
- ; ================================================
- ; Arithmetic
- ; ================================================
- calculate:
- mov rax, [acc]
- mov rbx, [operand]
- mov cl, [op]
- cmp cl, '+'
- je addition
- cmp cl, '-'
- je subtraction
- cmp cl, '*'
- je multiplication
- cmp cl, '/'
- je division
- jmp clear_operation
- addition:
- add rax, rbx
- jmp save_result
- subtraction:
- sub rax, rbx
- jmp save_result
- multiplication:
- ; (acc * operand) / scale
- imul rbx
- idiv qword [scale]
- jmp save_result
- division:
- ; (acc * scale) / operand
- test rbx, rbx
- jz clear_operation
- imul qword [scale]
- idiv rbx
- jmp save_result
- save_result:
- mov [acc], rax
- clear_operation:
- mov byte [op], 0
- show_result:
- call print_acc
- jmp main_loop
- ; ================================================
- ; Print accumulator
- ; ================================================
- print_acc:
- mov rax, [acc]
- xor r15, r15
- test rax, rax
- jns print_positive
- neg rax
- mov r15, 1
- print_positive:
- ; Separate integer and fractional parts
- xor rdx, rdx
- div qword [scale]
- mov r12, rax
- mov r13, rdx
- lea rdi, [outbuf]
- ; Sign
- test r15, r15
- jz convert_integer
- mov byte [rdi], '-'
- inc rdi
- convert_integer:
- ; Convert integer part backwards
- lea r8, [intbuf+31]
- mov rax, r12
- test rax, rax
- jnz integer_loop
- dec r8
- mov byte [r8], '0'
- jmp copy_integer
- integer_loop:
- xor rdx, rdx
- div qword [ten]
- add dl, '0'
- dec r8
- mov [r8], dl
- test rax, rax
- jnz integer_loop
- copy_integer:
- mov rsi, r8
- lea r9, [intbuf+32]
- copy_loop:
- cmp rsi, r9
- jge integer_done
- mov al, [rsi]
- mov [rdi], al
- inc rsi
- inc rdi
- jmp copy_loop
- integer_done:
- ; Fraction zero?
- test r13, r13
- jz output_result
- mov byte [rdi], '.'
- inc rdi
- ; Generate exactly 8 decimal digits
- mov r10, r13
- mov r11, 10000000
- fraction_loop:
- mov rax, r10
- xor rdx, rdx
- div r11
- add al, '0'
- mov [rdi], al
- inc rdi
- mov r10, rdx
- mov rax, r11
- xor rdx, rdx
- div qword [ten]
- mov r11, rax
- test r11, r11
- jnz fraction_loop
- ; Remove trailing zeros
- trim_fraction:
- cmp byte [rdi-1], '0'
- jne trim_done
- dec rdi
- jmp trim_fraction
- trim_done:
- cmp byte [rdi-1], '.'
- jne output_result
- dec rdi
- output_result:
- mov byte [rdi], 10
- inc rdi
- mov rsi, outbuf
- mov rdx, rdi
- sub rdx, rsi
- mov eax, 1
- mov edi, 1
- syscall
- ret
- ; ================================================
- ; Exit
- ; ================================================
- exit:
- mov eax, 60
- xor edi, edi
- syscall
Advertisement
Add Comment
Please, Sign In to add comment