8 Commits
Author SHA1 Message Date
PleegWat 3968179026 Optimize digit parse loops 2026-09-04 23:07:21 +02:00
PleegWat f18199c5d0 Only allow 0o prefix for octal, not just 0 2026-09-03 16:45:04 +02:00
PleegWat b4af75a18e Handle negative in radix-specific preludes 2026-09-03 14:31:54 +02:00
PleegWat 836b977fc9 Implement negative number parsing 2026-09-03 13:42:11 +02:00
PleegWat 2c6e025dff Refactor tests to use data structs
Rather than a pointer to the end of the parseable string, we now store
the number of bytes we expect to be parsed. Current code allows for 11
bytes of string data which should suffice for most usecases.
2026-09-03 11:34:01 +02:00
PleegWat 9ff0a3192c Fix binary parsing and more tests 2026-09-02 21:33:58 +02:00
PleegWat fd5469aafc Add some cases, fix an octal bug 2026-09-02 21:28:29 +02:00
PleegWat e8cf5ae35f Initial version of atoi
Functions to convert strings to integers in various bases
2026-09-02 21:22:04 +02:00
3 changed files with 244 additions and 0 deletions
+1
View File
@@ -1,2 +1,3 @@
pub include bit
pub include imath
pub include strint
+188
View File
@@ -0,0 +1,188 @@
; Internal register assignments:
; r1 - Partially parsed output integer
; r2 - Parsing position
; r3 - Character being parsed
; r4 - Set to -1 if the input is negative
; 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
; r4 - Negative marker
; Note: Unless the input is "0", tail-calls into a base-specific specialization.
pub atoi:
mov r2, r1
mov r1, 0
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
atoi_positive:
load_16 r3, [r2] ; 2-byte prefix "0b", "0o", "0x", etc.
or r3, r3, 0x20 ; 2nd char to lower case
add r2, r2, 2
cmp r3, 0x3062 ; "0b"
je atoi_bin_loop
cmp r3, 0x306F ; "0o"
je atoi_oct_loop
cmp r3, 0x3078 ; "0x"
je atoi_hex_loop
sub r2, r2, 2 ; no matching prefix, move pointer back
jmp atoi_dec_loop
; Epilogue
atoi_done:
add r1, r1, r4 ; If r4 is -1, negate r1. Else it's 0 and no effect.
xor r1, r1, r4
mov flags, 0 ; No error
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
; r4 - Negative marker
pub atoi_dec:
mov r2, r1
mov r1, 0
mov r4, 0
load_8 r3, [r2]
cmp r3, 0x2D ; '-'
jne atoi_dec_positive
sub r4, zr, 1 ; Set r4 to -1
add r2, r2, 1
atoi_dec_loop:
load_8 r3, [r2]
atoi_dec_positive:
sub r3, r3, 0x30 ; '0'
cmp r3, 9
ja atoi_done
add r2, r2, 1
lsl flags, r1, 2 ; Use flags to help multiply by 10
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
; r4 - Negative marker
pub atoi_bin:
mov r2, r1
mov r1, 0
mov r4, 0
load_8 r3, [r2]
cmp r3, 0x2D ; '-'
jne atoi_bin_positive
sub r4, zr, 1 ; Set r4 to -1
add r2, r2, 1
atoi_bin_positive:
load_16 r3, [r2] ; check for prefix
or r3, r3, 0x20 ; 2nd char to lower case
cmp r3, 0x3062 ; "0b"
jne atoi_bin_loop
add r2, r2, 2
atoi_bin_loop:
load_8 r3, [r2]
sub r3, r3, 0x30 ; '0'
cmp r3, 1
ja atoi_done
add r2, r2, 1
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
; r4 - Negative marker
pub atoi_oct:
mov r2, r1
mov r1, 0
mov r4, 0
load_8 r3, [r2]
cmp r3, 0x2D ; '-'
jne atoi_oct_positive
sub r4, zr, 1 ; Set r4 to -1
add r2, r2, 1
atoi_oct_positive:
load_16 r3, [r2] ; check for prefix
or r3, r3, 0x20 ; 2nd char to lower case
cmp r3, 0x306F ; "0o"
jne atoi_oct_loop
add r2, r2, 2
atoi_oct_loop:
load_8 r3, [r2]
sub r3, r3, 0x30 ; '0'
cmp r3, 7
ja atoi_done
add r2, r2, 1
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
; r4 - Negative marker
pub atoi_hex:
mov r2, r1
mov r1, 0
mov r4, 0
load_8 r3, [r2]
cmp r3, 0x2D ; '-'
jne atoi_hex_positive
sub r4, zr, 1 ; Set r4 to -1
add r2, r2, 1
atoi_hex_positive:
load_16 r3, [r2] ; check for prefix
or r3, r3, 0x20 ; 2nd char to lower case
cmp r3, 0x3078 ; "0x"
jne atoi_hex_loop
add r2, r2, 2
atoi_hex_loop:
load_8 r3, [r2]
sub r3, r3, 0x30 ; '0'
cmp r3, 10
jb atoi_hex_add
sub r3, r3, 0x11 ; 'A' - '0'
and r3, r3, 0xdf ; to lower case
cmp r3, 5 ; 0-5: 6 letters
ja atoi_done
add r3, r3, 10 ; Adjust for digits below
atoi_hex_add:
add r2, r2, 1
lsl r1, r1, 4
add r1, r1, r3
jmp atoi_hex_loop
+55
View File
@@ -0,0 +1,55 @@
; test harness for strint.atoi
; Registers:
; r8 - test address
; r9 - expected result
; r10 - actual length
; r11 - expected length
mov r8, tests
next_test:
; Set up arguments and run test
add r1, r8, 5 ; Start of test string
mov r13, atoi_test_ret
jmp stdlib.strint.atoi
atoi_test_ret:
; Load reference data
load_32 r9, [r8] ; Expected result
sub r10, r2, r8
sub r10, r10, 5 ; Actual string length
add r11, r8, 4 ; Address of expected length
load_8 r11, [r11] ; Expected length
; Verify results
cmp r1, r9
incorrect_result: jne incorrect_result
cmp r10, r11
incorrect_length: jne incorrect_length
; Next test
add r8, r8, 0x10
cmp r8, end_of_tests
jl next_test
; Done
success: jmp success
include stdlib
@0x1000
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 0x4B4 U8 5 "0x4B4g\0"
@0x1080 U32 0o23 U8 4 "0o239\0"
@0x1090 U32 0b1011 U8 6 "0b1011\0"
@0x10a0 U32 0b10001 U8 7 "0b100012\0"
@0x10b0 U32 0xFFFFFFEB U8 3 "-21\0" ; Yuk
@0x10c0
end_of_tests: