使用 mips 程序集检查回文
Check palindrome using mips assembly
.data
org_str: .space 256
rev_str: .space 256
str: .asciiz "Enter the Line: "
pal: .asciiz "palindrome"
not_pali: .asciiz "Not palindrome"
.text
.globl main
main:
li $v0, 4
la $a0, str
syscall
# Taking String from the user
li $v0, 8
la $a0, org_str
li $a1, 256
syscall
# Initilize $t0 and $t2
li $t0, 0
li $t1, 0
loop_len:
add $t1, $a0, $t0
lb $t2, 0($t1) # Load the data in the byte in $t2
beqz $t2, len_exit # Loop till $t2 reaches zero
addiu $t0, $t0, 1 # increment of the counter
j loop_len
len_exit:
#Return $t0 to the last Charater
subi $t0, $t0, 1
li $s0, 0 # Initialize variable
addi $s0, $t0, 0 # Save the length of the String
# Load the original string in $t2
la $t2, org_str
# Intialize i and j
li $t1, 0 # i
li $t3, 0 # j
reverse_loop:
add $t3, $t2, $t0 # $t2 is the base address
lb $t4, 0($t3) # load a byte
beqz $t4, exit # go to the exit if null was found
sb $t4, rev_str($t1) # Overwrite the byte
addi $t0, $t0, -1 # decrement of j by 1 (j--)
addi $t1, $t1, 1 # increment of i by one (i++)
j reverse_loop # Loop until we reach the length of the String
exit:
li $t0, 0
li $t4, 0
li $t7, 0
CheckChar_loop:
lb $t4, org_str($t0)
lb $t7, rev_str($t0)
beq $t4, $zero, exit_1 # go to the exit if null was found
bne $t4, $t7, not_pal # if $t7 and $t4 not equal
addi $t0, $t0, 1 # increment of i by 1 (i++)
j CheckChar_loop
exit_1:
#li $v0, 1
#addi $a0, $t0, 0
#syscall
li $v0, 4
la $a0, pal
syscall
#Exit the program
li $v0, 10
syscall
not_pal:
#li $v0, 1
#addi $a0, $t0, 0
#syscall
li $v0, 4
la $a0, not_pali
syscall
#Exit the program
li $v0, 10
syscall
.end main
我正在尝试检查 回文。因此,想法是反转字符串并在每个索引处检查反转字符串中的字符是否与原始字符串相同。
我正在尝试检查 org_str 是否等于 rev_str 但它每次都以 $t7 和 $t4 的形式存在,即使它们相等。
rev_str 是 org_str.
的反转字符串
基本调试技巧
任何编写汇编语言的人都应该能够单步执行 watch/verify 他们的代码。
单步验证每条指令是否符合您的预期。大多数指令有一个主要作用:改变寄存器的值,或改变内存的值。并且所有指令都告诉处理器下一条 运行 的指令。因此,我们需要验证主要效果和控制流程(接下来是什么指令)。 (syscall
s 可以更改多个内存位置并提供 return 结果。)
调试从未测试过的新代码时,使用尽可能小的输入使调试变得简单。
例如,测试输入'A' (0x41)。 (从技术上讲,最小的输入是空字符串,最好也测试一下。)
随着您开发程序,使用断点跳过您已知有效的代码,然后从那里单步执行新代码。
在您的程序中,您应该注意到副本的第一个字节是错误的,甚至在它存储到内存之前,您可以通过单步执行大约 35 条指令来看到这一点。
你有一个经典的错误,这是由读取字符串系统调用附加到用户输入文本的换行符引起的。在读取字符串系统调用后检查 org_str
的内存,您应该已经看到了。这个换行符在代码中的两个地方引起了一个错误——在复制循环和 pal 检查循环。您可以改为基于循环计数,或者用空字节粉碎换行符以缩短该字符的输入。
您计算字符数,然后向后复制字符,但错误地依赖 org_str 之前的空字节来停止复制循环。
我们只以空终止字符串,不应期望字符串以空开头和以空结尾 — 除非明确规定了空开头(在您的情况下不是这样)。通常,在处理字符串(作为参数传递,由其他代码创建)时,我们不能依赖于能够轻松提供一个空初学者,因此更好的编程实践是在计数(递减的一个)时结束复制循环) 达到零。 (这里很容易出错,所以也用空字符串进行测试(即应该构造为 while 循环,而不是重复直到。))
停止将寄存器初始化为零然后设置其他值。您所做的相当于
int s0 = 0; // <--- this initialization is pointless
s0 = t0 - 1; // since s0 is immediately repurposed with a new value here
顺便说一句,您从不使用 s0
,因此即使将其设置为 t0-1
也不会被使用,但是当您修复代码的差一错误时,这可能会改变。
.data
org_str: .space 256
rev_str: .space 256
str: .asciiz "Enter the Line: "
pal: .asciiz "palindrome"
not_pali: .asciiz "Not palindrome"
.text
.globl main
main:
li $v0, 4
la $a0, str
syscall
# Taking String from the user
li $v0, 8
la $a0, org_str
li $a1, 256
syscall
# Initilize $t0 and $t2
li $t0, 0
li $t1, 0
loop_len:
add $t1, $a0, $t0
lb $t2, 0($t1) # Load the data in the byte in $t2
beqz $t2, len_exit # Loop till $t2 reaches zero
addiu $t0, $t0, 1 # increment of the counter
j loop_len
len_exit:
#Return $t0 to the last Charater
subi $t0, $t0, 1
li $s0, 0 # Initialize variable
addi $s0, $t0, 0 # Save the length of the String
# Load the original string in $t2
la $t2, org_str
# Intialize i and j
li $t1, 0 # i
li $t3, 0 # j
reverse_loop:
add $t3, $t2, $t0 # $t2 is the base address
lb $t4, 0($t3) # load a byte
beqz $t4, exit # go to the exit if null was found
sb $t4, rev_str($t1) # Overwrite the byte
addi $t0, $t0, -1 # decrement of j by 1 (j--)
addi $t1, $t1, 1 # increment of i by one (i++)
j reverse_loop # Loop until we reach the length of the String
exit:
li $t0, 0
li $t4, 0
li $t7, 0
CheckChar_loop:
lb $t4, org_str($t0)
lb $t7, rev_str($t0)
beq $t4, $zero, exit_1 # go to the exit if null was found
bne $t4, $t7, not_pal # if $t7 and $t4 not equal
addi $t0, $t0, 1 # increment of i by 1 (i++)
j CheckChar_loop
exit_1:
#li $v0, 1
#addi $a0, $t0, 0
#syscall
li $v0, 4
la $a0, pal
syscall
#Exit the program
li $v0, 10
syscall
not_pal:
#li $v0, 1
#addi $a0, $t0, 0
#syscall
li $v0, 4
la $a0, not_pali
syscall
#Exit the program
li $v0, 10
syscall
.end main
我正在尝试检查 回文。因此,想法是反转字符串并在每个索引处检查反转字符串中的字符是否与原始字符串相同。 我正在尝试检查 org_str 是否等于 rev_str 但它每次都以 $t7 和 $t4 的形式存在,即使它们相等。 rev_str 是 org_str.
的反转字符串基本调试技巧
任何编写汇编语言的人都应该能够单步执行 watch/verify 他们的代码。
单步验证每条指令是否符合您的预期。大多数指令有一个主要作用:改变寄存器的值,或改变内存的值。并且所有指令都告诉处理器下一条 运行 的指令。因此,我们需要验证主要效果和控制流程(接下来是什么指令)。 (syscall
s 可以更改多个内存位置并提供 return 结果。)
调试从未测试过的新代码时,使用尽可能小的输入使调试变得简单。
例如,测试输入'A' (0x41)。 (从技术上讲,最小的输入是空字符串,最好也测试一下。)
随着您开发程序,使用断点跳过您已知有效的代码,然后从那里单步执行新代码。
在您的程序中,您应该注意到副本的第一个字节是错误的,甚至在它存储到内存之前,您可以通过单步执行大约 35 条指令来看到这一点。
你有一个经典的错误,这是由读取字符串系统调用附加到用户输入文本的换行符引起的。在读取字符串系统调用后检查
org_str
的内存,您应该已经看到了。这个换行符在代码中的两个地方引起了一个错误——在复制循环和 pal 检查循环。您可以改为基于循环计数,或者用空字节粉碎换行符以缩短该字符的输入。您计算字符数,然后向后复制字符,但错误地依赖 org_str 之前的空字节来停止复制循环。
我们只以空终止字符串,不应期望字符串以空开头和以空结尾 — 除非明确规定了空开头(在您的情况下不是这样)。通常,在处理字符串(作为参数传递,由其他代码创建)时,我们不能依赖于能够轻松提供一个空初学者,因此更好的编程实践是在计数(递减的一个)时结束复制循环) 达到零。 (这里很容易出错,所以也用空字符串进行测试(即应该构造为 while 循环,而不是重复直到。))停止将寄存器初始化为零然后设置其他值。您所做的相当于
int s0 = 0; // <--- this initialization is pointless
s0 = t0 - 1; // since s0 is immediately repurposed with a new value here
顺便说一句,您从不使用 s0
,因此即使将其设置为 t0-1
也不会被使用,但是当您修复代码的差一错误时,这可能会改变。