Convert String of ASCII digits to int in MIPS/Assembler

49,449

Solution 1

Mask the first four bits by anding the string with 0x0F as shown below

andi $t0,$t0,0x0F # where $t0 contains the ascii digit .

now $t0 has the int of it.

Solution 2

Assumes that $s1 points to the beginning of a NULL-terminated string (i.e. to the most significant digit), $t0 contains 10, and $s2 contains 0:

lp:         
  lbu $t1, ($s1)       #load unsigned char from array into t1
  beq $t1, $0, FIN     #NULL terminator found
  blt $t1, 48, error   #check if char is not a digit (ascii<'0')
  bgt $t1, 57, error   #check if char is not a digit (ascii>'9')
  addi $t1, $t1, -48   #converts t1's ascii value to dec value
  mul $s2, $s2, $t0    #sum *= 10
  add $s2, $s2, $t1    #sum += array[s1]-'0'
  addi $s1, $s1, 1     #increment array address
  j lp                 #jump to start of loop

This has one mul less per iteration, and there's no need of knowing the length of the string before entering the loop.

Share:
49,449
user1730099
Author by

user1730099

Updated on July 12, 2022

Comments

  • user1730099
    user1730099 almost 2 years

    Im writing some MIPS code to take a string of ASCII digits and convert the string into an integer. The string is entered by the user and can be at most 10 digits in length. My code works fine and uses the obvious method of performing looped addition after multiplying the Least Significant number in the string by a power of ten determined by the index of the array, starting from the last digit entered (10^0) to the first digit entered (10^n, n=number of digits in the array).

    I was wondering if there was an alternate method that would be quicker or shorter to write. In particular, I wanted to know if using a logical bit shift might make this process shorter. Any ideas for optimizing or improving this code would be greatly appreciated!

    Also, as a side note, I would like to call the gets and readInt subroutines using jal, but because gets and readInt both call subroutines, using jal in the main method to call gets or readInt causes problems. Any ideas how to get around this? Thanks again Cheers

    PS: sorry for the formatting of the comments in this code, copy and pasting from MARS simulator into the stack overflow text box caused the alignment to be off :/

    #IO
    #Prompts user to input 10 ascii digits into an array
    #Converts the string of digits into a single int
    #Also handles any number of digits between 1 and 10 
    #Returns 0 if non-digit chars are entered into the string
    
    .data           #declaration of vars follows
    array: .space 11    #reserves space for a 10 elem array
    char: .space 2
    prompt: .asciiz "Please enter 10 numbers, then press ENTER:  \n"
    null: .asciiz ""
    space: .ascii " "
    newline: .asciiz "\n"
    .text           #instructions follow
    
    main:
    la $a0, prompt      #load prompt message into $a0 for syscall
    li $v0, 4               #load syscall to print string
    syscall         #print prompt message
    j readInt               #call readInt function to get user input string         
    
    gets:           #read multiple chars from keyboard buffer until ENTER key,
                                #add NULL char and store into buffer pointed to by *array
                                #passed to the subroutine
    la $s1, array       #set base address of array to s1
    loop:           #start of read loop
    jal getc        #jump to getc subroutine
    lb $t0, char        #load the char from char buffer into t0, stripping null
    sb $t0, 0($s1)      #store the char into the nth elem of array
    lb $t1, newline     #load newline char into t1
    beq $t0, $t1, done  #end of string?  jump to done
    addi $s1, $s1, 1    #increments base address of array
    j loop          #jump to start of read loop
    
    getc:           #read char from keyboard buffer and return ascii value
    li $v0, 8       #call code for read string
    la $a0, char        #load address of char for read
    li $a1, 2       #length of string is 1byte char and 1byte for null
    syscall         #store the char byte from input buffer into char
    jr $ra          #jump-register to calling function
    
    readInt:        #read string of ascii digits, store into a local variable and  
                        #convert into integer, return that int unless string contains 
                        #non-integers 
    j gets          #let s1 be top address of array, let s0 be the digitcounter
    done:           #let s2 be the sum total
    addi $s1, $s1, -1   #reposition array pointer to last char before newline char
    la $s0, array       #set base address of array to s0 for use as counter
    addi $s0, $s0, -1   #reposition base array to read leftmost char in string
    add $s2, $zero, $zero   #initialize sum to 0
    li $t0, 10      #set t0 to be 10, used for decimal conversion
    li $t3, 1
    lb $t1, 0($s1)      #load char from array into t1
    blt $t1, 48, error  #check if char is not a digit (ascii<'0')
    bgt $t1, 57, error  #check if char is not a digit (ascii>'9')
    addi $t1, $t1, -48  #converts t1's ascii value to dec value
    add $s2, $s2, $t1   #add dec value of t1 to sumtotal
    addi $s1, $s1, -1   #decrement array address
    lp:         #loop for all digits preceeding the LSB
    mul $t3, $t3, $t0   #multiply power by 10
    beq $s1, $s0, FIN   #exit if beginning of string is reached
    lb $t1, ($s1)       #load char from array into t1
    blt $t1, 48, error  #check if char is not a digit (ascii<'0')
    bgt $t1, 57, error  #check if char is not a digit (ascii>'9')
    addi $t1, $t1, -48  #converts t1's ascii value to dec value
    mul $t1, $t1, $t3   #t1*10^(counter)
    add $s2, $s2, $t1   #sumtotal=sumtotal+t1
    addi $s1, $s1, -1   #decrement array address
    j lp            #jump to start of loop
    
    error:          #if non digit chars are entered, readInt returns 0
    add $s2, $zero, $zero
    j FIN
    
    FIN:
    li $v0, 1
    add $a0, $s2, $zero
    syscall 
    li $v0, 10      #ends program
    syscall