From 836b977fc908f8b6c43d72bf1041c26c3b11b78b Mon Sep 17 00:00:00 2001 From: PleegWat Date: Thu, 3 Sep 2026 13:42:11 +0200 Subject: [PATCH] Implement negative number parsing --- strint.asm | 72 ++++++++++++++++++++++++++++++++++--------------- strint_test.asm | 29 ++++++++++---------- 2 files changed, 65 insertions(+), 36 deletions(-) diff --git a/strint.asm b/strint.asm index 3830e2b..2f258e0 100644 --- a/strint.asm +++ b/strint.asm @@ -1,3 +1,9 @@ +; Internal convention: +; r1 - Partially parsed output integer +; r2 - Parsing position +; r3 - Character being parsed +; r4 - Flag set if negative + ; Convert string to integer ; Arguments: ; r1 - Pointer to string @@ -9,30 +15,37 @@ ; r3 - last character read ; Note: Unless the input is "0", tail-calls into a base-specific specialization. pub atoi: -load_8 r3, [r1] -cmp r3, 0x30 ; '0' -jne 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 atoi_oct -add r1, r1, 1 ; Not octal; 2-byte prefix -and r3, r3, 0x5f ; to uppercase -cmp r3, 0x42 ; 'B' -je atoi_bin -cmp r3, 0x4F ; 'O' -je atoi_oct -cmp r3, 0x58 ; 'X' -je 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 +mov r4, 0 +load_8 r3, [r2] +cmp r3, 0x2D ; '-' +jne atoi_positive +sub r4, zr, 1 ; Set r4 to -1 +add r2, r2, 1 +load_8 r3, [r2] +atoi_positive: +cmp r3, 0x30 ; '0' +jne atoi_dec_loop ; No prefix, parse decimal +add r2, r2, 1 +load_8 r3, [r2] ; From "boxBOX", or an octal digit +cmp r3, 0x30 ; '0' +jl atoi_done +cmp r3, 0x37 ; '7' +jle atoi_oct_loop ; Octal with just '0' prefix +add r2, r2, 1 ; 2-byte prefix +and r3, r3, 0x5F ; to uppercase +cmp r3, 0x42 ; 'B' +je atoi_bin_loop +cmp r3, 0x4F ; 'O' +je atoi_oct_loop +cmp r3, 0x58 ; 'X' +je atoi_hex_loop + +; FALLTHROUGH: not a valid prefix, but we did see a zero atoi_done: +add r1, r1, r4 +xor r1, r1, r4 jmp r13 ; Convert decimal string to integer @@ -73,6 +86,11 @@ jmp atoi_dec_loop pub atoi_bin: mov r2, r1 mov r1, 0 +load_16 r3, [r2] ; check for prefix +and r3, r3, 0xFF5F ; to uppercase +cmp r3, 0x3042 ; "0B" +jne atoi_bin_loop +add r2, r2, 2 atoi_bin_loop: load_8 r3, [r2] cmp r3, 0x30 ; '0' @@ -97,6 +115,11 @@ jmp atoi_bin_loop pub atoi_oct: mov r2, r1 mov r1, 0 +load_16 r3, [r2] ; check for prefix +and r3, r3, 0xFF5F ; to uppercase +cmp r3, 0x304F ; "0O" +jne atoi_oct_loop +add r2, r2, 2 atoi_oct_loop: load_8 r3, [r2] cmp r3, 0x30 ; '0' @@ -121,6 +144,11 @@ jmp atoi_oct_loop pub atoi_hex: mov r2, r1 mov r1, 0 +load_16 r3, [r2] ; check for prefix +and r3, r3, 0xFF5F ; to uppercase +cmp r3, 0x3058 ; "0X" +jne atoi_oct_loop +add r2, r2, 2 atoi_hex_loop: load_8 r3, [r2] cmp r3, 0x30 ; '0' @@ -134,7 +162,7 @@ add r1, r1, r3 jmp atoi_hex_loop atoi_hex_letter: -and r3, r3, 0x5f ; to uppercase +and r3, r3, 0x5F ; to uppercase cmp r3, 0x41 ; 'A' jl atoi_done cmp r3, 0x46 ; 'F' diff --git a/strint_test.asm b/strint_test.asm index ccc68b5..407443b 100644 --- a/strint_test.asm +++ b/strint_test.asm @@ -33,21 +33,22 @@ jl next_test ; Done success: jmp success - include stdlib - @0x1000 tests: -; addr result inlen instr -@0x1000 U32 0 U8 0 "\0" -@0x1010 U32 0 U8 1 "0\0" -@0x1020 U32 1 U8 1 "1\0" -@0x1030 U32 2 U8 1 "2\0" -@0x1040 U32 42 U8 2 "42\0" -@0x1050 U32 67 U8 2 "67lol\0" -@0x1060 U32 0x69a U8 5 "0x69a\0" -@0x1070 U32 0o23 U8 3 "0239\0" -@0x1080 U32 0b1011 U8 6 "0b1011\0" -@0x1090 U32 0b10001 U8 7 "0b100012\0" -end_of_tests: +; inlen is the number of input bytes the function is expected to consume +; addr result inlen instr +@0x1000 U32 0 U8 0 "\0" +@0x1010 U32 0 U8 1 "0\0" +@0x1020 U32 1 U8 1 "1\0" +@0x1030 U32 2 U8 1 "2\0" +@0x1040 U32 42 U8 2 "42\0" +@0x1050 U32 67 U8 2 "67lol\0" +@0x1060 U32 0x69a U8 5 "0x69a\0" +@0x1070 U32 0o23 U8 3 "0239\0" +@0x1080 U32 0b1011 U8 6 "0b1011\0" +@0x1090 U32 0b10001 U8 7 "0b100012\0" +@0x10a0 U32 0xFFFFFFEB U8 3 "-21\0" ; Yuk +@0x10b0 +end_of_tests: \ No newline at end of file