首页 > 解决方案 > MIPS:解析和修改字符串

问题描述

我必须在 MIPS 中编写一个程序,我必须使用 MARS 模拟器打开一个用户输入名称的文件并解析它。但是,由于系统调用 8(从用户输入中读取字符串)遵循 C 函数 fgets 的语义,因此我必须先从字符串中删除换行符 \n 才能尝试打开文件。

我能够解析字符串(这里我打印每个字符的 ASCII 码以进行调试)。但是,当我尝试将换行符更改为 NULL 字符时

sb $zero 0($t1)

Mars 在执行过程中遇到异常:

“0x00400050 处的运行时异常:地址超出范围 0x00000000”

如果我注释掉这一行,程序运行良好并打印字符串的每个 ascii 代码。

.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

我不明白我在这里做错了什么,在程序的这一点上,寄存器 $t1 应该包含写入换行符的地址。但是我可能误解了指令如何保存字节和加载字节实际工作。

非常感谢任何帮助或建议:)

标签: assemblymipsmars-simulator

解决方案


在 asm 代码中

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

$t1用作要清除的字节的地址。

但事实并非如此。你用过

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

并且您的所有访问都使用$t0.

parsing_string函数结束时,您读取地址处的字符$t0并将其放入$t1

lbu $t1 ($t0)   # the next byte

然后你回到parsing_string,测试t1是否为0

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

remove_line_feed

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

您尝试在地址处写入零的位置0+$t1(您刚刚测试为等于零)。

模拟器会正确地告诉您您尝试在地址 0 处写入并生成错误。

如果您将代码更改为

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

这将消除运行时错误。

但是,它不会使您的代码正确。您要做的是清除 '\n'之前\0代码,您的代码应该是

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

或者,您可以更改比较,而不是搜索\0字符串的结尾,而是搜索 10(ascii 换行符)并将相同的字符替换为 0。


推荐阅读