; 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