From 3bf7ba988ea14137fff4e893f85cae43ffe634ea Mon Sep 17 00:00:00 2001 From: PleegWat Date: Wed, 2 Sep 2026 21:11:45 +0200 Subject: [PATCH] Initial version of atoi Functions to convert strings to integers in various bases --- stdlib.asm | 1 + strint.asm | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ strint_test.asm | 86 ++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+) create mode 100644 strint.asm create mode 100644 strint_test.asm diff --git a/stdlib.asm b/stdlib.asm index 1b352f1..0135382 100644 --- a/stdlib.asm +++ b/stdlib.asm @@ -1,2 +1,3 @@ pub include bit pub include imath +pub include strint \ No newline at end of file diff --git a/strint.asm b/strint.asm new file mode 100644 index 0000000..b8c45ff --- /dev/null +++ b/strint.asm @@ -0,0 +1,145 @@ +; Convert string to integer +; Arguments: +; r1 - Pointer to string +; Result: +; r1 - Parsed integer +; r2 - Pointer to first rejected input byte +; Clobbers: +; flags +; r3 - last character read +pub fn_atoi: +load_8 r3, [r1] +cmp r3, 0x30 ; '0' +jne fn_atoi_dec ; No prefix, parse decimal +add r1, r1, 1 +load_8 r3, [r1] ; From "boxBOX", or an octal digit +cmp r3, 0x30 ; '0' +jl atoi_badprefix +cmp r3, 0x37 ; '7' +jle fn_atoi_oct +add r1, r1, 1 ; Not octal; 2-byte prefix +and r3, r3, 0x5f ; to uppercase +cmp r3, 0x42 ; 'B' +je fn_atoi_bin +cmp r3, 0x4F ; 'O' +je fn_atoi_oct +cmp r3, 0x58 ; 'X' +je fn_atoi_hex + +; not a valid prefix, but we did see a zero +atoi_badprefix: +mov r2, r1 +mov r1, 0 +; Only exists because conditional register jumps are not allowed +atoi_done: +jmp r13 + +; Convert decimal string to integer +; Arguments: +; r1 - Pointer to string +; Result: +; r1 - Parsed integer +; r2 - Pointer to first rejected input byte +; Clobbers: +; flags +; r3 - last character read +pub fn_atoi_dec: +mov r2, r1 +mov r1, 0 +atoi_dec_loop: +load_8 r3, [r2] +cmp r3, 0x30 ; '0' +jl atoi_done +cmp r3, 0x39 ; '9' +jg atoi_done +add r2, r2, 1 +sub r3, r3, 0x30 ; '0' +lsl flags, r1, 2 +add r1, r1, flags +lsl r1, r1, 1 +add r1, r1, r3 +jmp atoi_dec_loop + +; Convert binary string to integer +; Arguments: +; r1 - Pointer to string +; Result: +; r1 - Parsed integer +; r2 - Pointer to first rejected input byte +; Clobbers: +; flags +; r3 - last character read +pub fn_atoi_bin: +mov r2, r1 +mov r1, 0 +atoi_bin_loop: +load_8 r3, [r2] +cmp r3, 0x30 ; '0' +jl atoi_done +cmp r3, 0x39 ; '1' +jg atoi_done +add r2, r2, 1 +sub r3, r3, 0x30 ; '0' +lsl r1, r1, 1 +add r1, r1, r3 +jmp atoi_bin_loop + +; Convert octal string to integer +; Arguments: +; r1 - Pointer to string +; Result: +; r1 - Parsed integer +; r2 - Pointer to first rejected input byte +; Clobbers: +; flags +; r3 - last character read +pub fn_atoi_oct: +mov r2, r1 +mov r1, 0 +atoi_oct_loop: +load_8 r3, [r2] +cmp r3, 0x30 ; '0' +jl atoi_done +cmp r3, 0x39 ; '7' +jg atoi_done +add r2, r2, 1 +sub r3, r3, 0x30 ; '0' +lsl r1, r1, 3 +add r1, r1, r3 +jmp atoi_oct_loop + +; Convert hexadecimal string to integer +; Arguments: +; r1 - Pointer to string +; Result: +; r1 - Parsed integer +; r2 - Pointer to first rejected input byte +; Clobbers: +; flags +; r3 - last character read +pub fn_atoi_hex: +mov r2, r1 +mov r1, 0 +atoi_hex_loop: +load_8 r3, [r2] +cmp r3, 0x30 ; '0' +jl atoi_done +cmp r3, 0x39 ; '9' +jg atoi_hex_letter +add r2, r2, 1 +sub r3, r3, 0x30 ; '0' +lsl r1, r1, 4 +add r1, r1, r3 +jmp atoi_hex_loop + +atoi_hex_letter: +and r3, r3, 0x5f ; to uppercase +cmp r3, 0x41 ; 'A' +jl atoi_done +cmp r3, 0x46 ; 'F' +jg atoi_done +add r2, r2, 1 +sub r3, r3, 0x37 ; 'A' - 10 +lsl r1, r1, 4 +add r1, r1, r3 +jmp atoi_hex_loop \ No newline at end of file diff --git a/strint_test.asm b/strint_test.asm new file mode 100644 index 0000000..d6bc854 --- /dev/null +++ b/strint_test.asm @@ -0,0 +1,86 @@ +mov r1, 1 +mov r2, test1 +mov r3, test1_end +mov r13, test1_pass +jmp atoi_test +test1_pass: + +mov r1, 2 +mov r2, test2 +mov r3, test2_end +mov r13, test2_pass +jmp atoi_test +test2_pass: + +mov r1, 3 +mov r2, test3 +mov r3, test3_end +mov r13, test3_pass +jmp atoi_test +test3_pass: + +mov r1, 4 +mov r2, test4 +mov r3, test4_end +mov r13, test4_pass +jmp atoi_test +test4_pass: + +mov r1, 5 +mov r2, test5 +mov r3, test5_end +mov r13, test5_pass +jmp atoi_test +test5_pass: + +success: +jmp success + +; test strint.fn_atoi +; Arguments: +; r1 - test number +; r2 - test data label +; r3 - test end-of-string label +; Result: +; void. Hangs in failure: on failure. +; Clobbers: +; r8 - test number +; r9 - Expected result in r1 +; r10 - Expected result in r2 +; Notes: +; Depends on fn_atoi not clobbering r8-r10. +atoi_test: +mov r8, r1 +load_32 r9, [r2] +add r1, r2, 4 +mov r10, r3 +push r13 +mov r13, atoi_test_ret +jmp stdlib.strint.fn_atoi +atoi_test_ret: +pop r13 +cmp r1, r9 +jne failure +cmp r2, r10 +jne failure +jmp r13 + +failure: +jmp failure + +test1: U32 0 "0" +test1_end: "\0" + +test2: U32 1 "1" +test2_end: "\0" + +test3: U32 2 "2" +test3_end: "\0" + +test4: U32 42 "42" +test4_end: "\0" + +test5: U32 67 "67" +test5_end: "lol" + +include stdlib