Swapping every two characters in a string and fixing exception error

Viewed 74

I'm getting an exception error and I'm not sure why. I need some help with the fix for the exception and how to swap chars in the user inputted string?

The input and output should look something like this:

Input : Apples

Output : pAlpse

.text
main:

#Prompt user for string
la $a0, promptStr
li $v0, 4
syscall

#Get String
li $v0,8 
    la $a0, buffer 
    li $a1, 20
syscall

move $t0, $a0

#Initialize pointer to start of string (specify register)
la $t0, buffer 

#Get a char from the string (register)
loop:   lb $t1, ($t0)

I'm getting Instruction references undefined here and I have no idea why because I've used it in similar problems to branch out of a loop when at the end of a string.

Here's the error message

Instruction references undefined symbol at 0x00400058
[0x00400058] 0x11200000  beq $9, $0, 0 [strEnd-0x00400058]; 48: beqz $t1, strEnd 
#IF at end of the string branch to endStr
beqz $t0, strEnd 

#Add 1 to the string pointer
add $t0, 1#Fixed

#get the next char in the string
lb $t2, ($t0)

I don't know if this code is right. I just need help understanding how to swap chars and what the code will look like.

#Swap the 2 chars by writing them back to the original string
sb $t2, ($t0)
sb $t1, ($t0)

#Add 1 to the string pointer
add $t0, 1 #Fixed

#Jump back to loopStart
j loop

#Display modified string
endStr: la $a0,ans
li $v0, 4
syscall

move $a0,$t2
li $v0, 4
syscall

#Blankline
la $a0, end
li $v0, 4
syscall

#Exit porgram
    li $v0, 10
syscall

.data
buffer: .space 20
promptStr: .asciiz "Input a string : "
blankLine   : .asciiz "\n"
1 Answers

The issue with your error beqz $t0, strEnd is a typo: the label you meant is endStr. The error itself tells you this, highlighting [strEnd-0x00400058] as undefined. Additionally, spim warns me on load:

The following symbols are undefined:
end
ans

After fixing the missing labels, the logic is not quite correct, although it looks like you're on the right track. The idea is to step over the string in character pairs, swapping elements and exiting when hitting a null character (and, optionally, a newline depending on how you want to handle that--stripping/chomping it is probably best).

For starters and a rather minor point, there is a dead instruction near the top of your program:

move $t0, $a0  # $t0 will be overwritten by the next la

#Initialize pointer to start of string (specify register)
la $t0, buffer

Stepping into the loop and the main logic, the code beqz $t0, strEnd uses the address of the string which will never be 0 as the branch condition rather than the byte at that address, $t1. This gives an infinite loop.

Next, there is a problem with $t0, the pointer that walks the string. The logic

sb $t2, ($t0)
sb $t1, ($t0)

doesn't work because $t0 was already incremented so the code loses track of the previous byte address after

#Add 1 to the string pointer
add $t0, 1#Fixed

A solution is to store $t0 in a temporary register before any add $0, 1 operations. Something like:

move $t3 $t0    # save the address of buf for swap

# ... later on, after incrementing `$t0` ...

sb $t2, ($t3)
sb $t1, ($t0)

You could also use an indexing strategy here by adding/subtracting offsets or using an index to walk the string.

Lastly, I'm not sure what move $a0,$t2 should do towards the end of the program when you're printing.

Here's one possible solution that addresses these issues and generally cleans up the logic:

.text
main:
    # prompt user for string
    la $a0 prompt
    li $v0 4
    syscall

    # get string
    la $a0 buffer 
    li $a1 20
    li $v0 8
    syscall

    move $s0 $a0    # incrementable pointer to buf

loop:
    # t1 = *(buf++) and exit if '\0' or '\n'
    move $t0 $s0    # save the address of buf for swap
    lb $t1 ($t0)    # t1 = *buf
    beqz $t1 end    # break if '\0'
    beq $t1 10 end  # break if '\n'
    add $s0 1       # buf++

    # t2 = *buf and exit if '\0' or '\n'
    lb $t2 ($s0)    # t2 = *buf
    beqz $t2 end    # break if '\0'
    beq $t2 10 end  # break if '\n'

    # swap the chars
    sb $t2 ($t0)    # *prev_buf = curr_buff_char
    sb $t1 ($s0)    # *buf = prev_buff_char

    # increment pointer and continue to the next pair
    add $s0 1       # buf++
    j loop

end: 
    # display modified string
    la $a0 buffer
    li $v0 4
    syscall
    
    # exit program
    li $v0 10
    syscall

.data
buffer: .space 20
prompt: .asciiz "Input a string : "

Sample runs:

$ spim -f swap_alternating_chars.s
Input a string : Apple
pAlpe
$ spim -f swap_alternating_chars.s
Input a string : Apples
pAlpse
Related