Search code examples
assemblymipsmars-simulator

MIPS : parsing and modifying a string


I have to write a program in MIPS where I have to open a file whose name is entered by the user and parse it,using the MARS simulator . However, since the syscall 8 (which reads a string from user input) follows the semantics of the C function fgets, I have to remove the line feed \n character from the string before I can try and open the file.

I am able to parse the string (here I print the ASCII code of every character for debugging purpose ) . However when I try to change the line feed character into a NULL character with the line

sb $zero 0($t1)

Mars encounters an exception during execution :

"Runtime exception at 0x00400050: address out of range 0x00000000"

If I comment out this line , the program runs fine and prints every ascii code of the string.

.data

prompt : .asciiz "enter filename:\n"
lf : .asciiz "\n"
space : .asciiz " "

.text 

la $a0 prompt      # asking user for filename
jal print_string
jal read_string

la $t0 ($a0)   #copying the string address 
lb $t1 0($t0)  #loading the first  byte

parsing_string : #loop
beq $t1 0 remove_line_feed  # reaching the NULL character '\0'

move $a0  $t1   #printing the ascii code
li $v0 1 
syscall

la $a0 space  #printing a space
li $v0 4
syscall  

add $t0 $t0 1   # loading  
lbu $t1 ($t0)   # the next byte

j parsing_string

remove_line_feed :
sb $zero 0($t1)   # runtime exception if i uncomment  this line 
j end

end : 


li $v0 10     # syscall 10 : end program 
syscall



read_string :   #read a string in $a0

li $a1 100  # $a1 = maximum number of characters to read        
li $v0 8    # syscall 8  : fgets()
syscall 
jr $ra


print_string  :  #print string in $a0
li $v0 4      # syscall 4 : print string
syscall
jr $ra

I don't understand what I'm doing wrong here, at this point of the program the register $t1 should contain the address where the line feed character is written . However I may have misunderstood how the instructions save byte and load byte actually work.

Any help or suggestions are greatly appreciated :)


Solution

  • In the asm code

    sb $zero 0($t1)   # runtime exception if i uncomment  this line 
    

    you use $t1 as the adress of the byte you want to clear.

    But it is not. You used

    la $t0 ($a0)   #copying the string address 
    

    and all your accesses use $t0.

    At the end of your parsing_string function, you read the char at address $t0 and put it in $t1:

    lbu $t1 ($t0)   # the next byte
    

    then you go back to parsing_string, test if t1 is 0

    beq $t1 0 remove_line_feed  # reaching the NULL character '\0'
    

    go to remove_line_feed

    remove_line_feed :
    sb $zero 0($t1)   # runtime exception if i uncomment  this line 
    j end
    

    Where you try to write zero at address 0+$t1 (that you just tested as being equal to zero).

    And the simulator properly tells you that you try to write at address 0 and generates an error.

    If you change your code to

    remove_line_feed :
    sb $zero 0($t0)   # runtime exception if i uncomment  this line 
    j end
    

    this will remove the runtime error.

    But, it will not make your code correct. What you want to do is to clear the '\n' which is just before the \0 and you code should be

    remove_line_feed :
    sb $zero -1($t0)    
    j end
    

    Alternatively, you can change the comparison and instead of searching the final \0 of the string, search a 10 (ascii line feed) and replace the same char with 0.