4

So I'm trying to convert a string to a number so I can add another number to it later. here is what I have to far in my .text for the conversion. num2Entered is what the user entered. Num1plusNum2 is the label that I will eventually add to. They are both declared in the .bss section. Any help would be appreciated!

    mov ax, [num2Entered + 0]
    sub ax, '0'
    mov bx, WORD 1000
    mul bx
    mov [Num1plusNum2], ax

    mov ax, [num2Entered + 1]
    sub ax, '0'
    mov bx, WORD 100
    mul bx
    add [Num1plusNum2], ax

    mov ax, [num2Entered + 2]
    sub ax, '0'
    mov bx, WORD 10
    mul bx
    add [Num1plusNum2], ax

    mov ax, [num2Entered + 3]
    sub ax, '0'
    add [Num1plusNum2], ax
Blake
  • 345
  • 1
  • 4
  • 14

3 Answers3

8

Each character is only a single byte, but you probably want to add it to a larger result. Might as well go for 32 bits... (can hobble your routine to 16 bits if you really want to)

mov edx, num3entered ; our string
atoi:
xor eax, eax ; zero a "result so far"
.top:
movzx ecx, byte [edx] ; get a character
inc edx ; ready for next one
cmp ecx, '0' ; valid?
jb .done
cmp ecx, '9'
ja .done
sub ecx, '0' ; "convert" character to number
imul eax, 10 ; multiply "result so far" by ten
add eax, ecx ; add in current digit
jmp .top ; until done
.done:
ret

That's off the top of my head and may have errors, but "something like that". It'll stop at the end of a zero-terminated string, or a linefeed-terminated string... or any invalid character (which you may not want). Modify to suit.

İsmet Alkan
  • 5,361
  • 3
  • 41
  • 64
Frank Kotler
  • 3,079
  • 2
  • 14
  • 9
4
or we can say:
"123"  -> starting from 1

1 + 0 * 10  = 1
2 + 1 * 10  = 12
3 + 12 * 10 = 123

This will match to atoi function as below:

atoi:

push    %ebx        # preserve working registers
push    %edx
push    %esi

mov $0, %eax        # initialize the accumulator
nxchr:
    mov $0, %ebx        # clear all the bits in EBX
    mov (%esi), %bl     # load next character in BL
    inc %esi            # and advance source index

    cmp $'0', %bl       # does character preceed '0'?
    jb  inval           # yes, it's not a numeral jb:jump below
    cmp $'9', %bl       # does character follow '9'?
    ja  inval           # yes, it's not a numeral ja:jump above

    sub $'0', %bl       # else convert numeral to int
    mull ten            # multiply accumulator by ten. %eax * 10
    add %ebx, %eax      # and then add the new integer
    jmp nxchr           # go back for another numeral

inval:
   pop  %esi            # recover saved registers
   pop  %edx
   pop  %ebx
   ret

Hope this will help.

user3380830
  • 101
  • 2
  • `imul $10, %eax` would let you use EDX for something else, and be more efficient. Also, `movzbl (%esi), %ebx` is how you do a zero-extending byte load. The range-check can be done more efficiently; sub and cmp are the same operation, just not writing the result. Since you already do `sub $'0', %bl` later, you could just do that instead of the first `cmp`, and adjust the 2nd to check for it being less than or equal integer `$9`, not ASCII `$'9'`. Or use one unsigned compare, as in [NASM Assembly convert input to integer?](https://stackoverflow.com/a/49548057) – Peter Cordes Nov 22 '22 at 15:58
2
"123"
 |||     val = 0
 |||______ val = val + ('3' - 48) * 10power0       [val now is 3]
 ||_______ val = 3   + ('2' - 48) * 10power1       [val now is 23] 
 |________ val = 23  + ('1' - 48) * 10power2       [val now is 123]

note: ascii of '1' means 49, '2' means 50 and so on
user3380830
  • 101
  • 2