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 :)
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.