Reputation: 25
.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
I am trying to check for palindrome. So, the idea is to revese the string and check at each index that the character in the reverse string is the same as the original one. I am trying to check if org_str equals rev_str but it exists every single time as $t7 and $t4 even if they are equal. rev_str is the reversed string of org_str.
Upvotes: 0
Views: 671
Reputation: 26646
Anyone writing assembly language should be able to single step and watch/verify their code execute.
Single step and verify that each instruction does what you expect. Most instructions have a main effect: change the value of a register, or change the value of memory. And all instructions tell the processor what instruction to run next. So, we need to verify the main effect and the control flow (what instruction comes next). (syscall
s can change multiple memory locations and offer a return result as well.)
When you're debugging fresh code that's never been tested, use the smallest possible input to make debugging simple.
For example, test the input 'A' (0x41). (Technically, the smallest input is the empty string, and, it would be a good idea to test that as well.)
As you evolve your program, use breakpoints to skip over code that you already know is working, then single step the new code from there.
In your program's case you should have noticed that the first byte of the copy is wrong, before it even stores to memory, and, you can see this by single stepping with around 35 instructions.
You have a classic off by one error, which is caused by the newline character that the read string syscall appends to the user-entered text. Checking memory of org_str
after the read string syscall, you should have seen this. This newline character causes an off by one error in two places in the code — at the copy loop and at the pal check loop. You can either make your loops count-based instead or smash the newline character with null byte to shorten the input of that character.
You make a count of the number of characters, then copy the characters going backward, but falsely rely on the null byte preceding the org_str to stop the copy loop.
We only null terminate strings, one should not expect a string to be null begun as well as null terminated — unless that null beginner is explicitly provided for (not so in your case). In general when working with strings (passed as parameters, created by other code), we cannot rely on being able to easily provide a null beginner, so it would be better programming practice instead to end the copy loop when the count (the decrementing one) reaches zero. (easy to be off by one here so do test with the empty string as well (i.e. should be structured as a while loop, not a repeat until.))
Stop initializing registers to zero and then setting some other value. You're doing the equivalent of
int s0 = 0; // <--- this initialization is pointless
s0 = t0 - 1; // since s0 is immediately repurposed with a new value here
Btw, you never use s0
, so even setting it to t0-1
goes unused, but that might change when you fix the code's off-by-one errors.
Upvotes: 5