I'm in the process of writing a program in MIPS that will determine whether or not a user entered string is a palindrome. It has three subroutines which are under construction.
Here is the main block of code, subroutines to follow with relevant info:
.data
Buffer: .asciiz " " # 80 bytes in Buffer
intro: .asciiz "Hello, please enter a string of up to 80 characters. I will then tell you if that string was a palindrome!"
.text
main:
li $v0, 4 # print_string call number
la $a0, intro # pointer to string in memory
syscall
li $v0, 8 #syscall code for reading string
la $a0, Buffer #save read string into buffer
li $a1, 80 #string is 80 bytes long
syscall
li $s0, 0 #i = 0
li $t0, 80 #max for i to reach
la $a0, Buffer
jal stripNonAlpha
li $v0, 4 # print_string call number
la $a0, Buffer # pointer to string in memory
syscall
li $s0, 0
jal findEnd
jal toUpperCase
li $v0, 4 # print_string call number
la $a0, Buffer # pointer to string in memory
syscall
Firstly, it's supposed to remove all non alpha-numeric characters from the string before hand, but when it encounters a character designated for removal, all characters after that are removed.
stripNonAlpha:
beq $s0, $t0, stripEnd #if i = 80 end
add $t4, $s0, $a0 #address of Buffer[i] in $t4
lb $s1, 0($t4) #load value of Buffer[i]
addi $s0, $s0, 1 #i = i + 1
slti $t1, $s1, 48 #if ascii code is less than 48
bne $t1, $zero, strip #remove ascii character
slti $t1, $s1, 58 #if ascii code is greater than 57
#and
slti $t2, $s1, 65 #if ascii code is less than 65
slt $t3, $t1, $t2
bne $t3, $zero, strip #remove ascii character
slti $t1, $s1, 91 #if ascii code is greater than 90
#and
slti $t2, $s1, 97 #if ascii code is less than 97
slt $t3, $t1, $t2
bne $t3, $zero, strip #remove ascii character
slti $t1, $s1, 123 #if ascii character is greater than 122
beq $t1, $zero, strip #remove ascii character
j stripNonAlpha #go to stripNonAlpha
strip:
#add $t5, $s0, $a0 #address of Buffer[i] in $t5
sb $0, 0($t4) #Buffer[i] = 0
#addi $s0, $s0, 1 #i = i + 1
j stripNonAlpha #go to stripNonAlpha
stripEnd:
la $a0, Buffer #save modified string into buffer
jr $ra #return
Secondly, it is supposed to convert all lowercase characters to uppercase.
toUpperCase:
beq $s0, $s2, upperEnd
add $t4, $s0, $a0
lb $s1, 0($t4)
addi $s1, $s1, 1
slti $t1, $s1, 97
#beq $t1, $zero, upper
slti $t2, $s1, 123
slt $t3, $t1, $t2
bne $t1, $zero, upper
j toUpperCase
upper:
add $t5, $s0, $a0
addi $t6, $t6, -32
sb $t6, 0($t5)
j toUpperCase
upperEnd:
la $a0, Buffer
jr $ra
The final subroutine, which checks if the string is a palindrome isn't anywhere near complete at the moment. I'm having trouble finding the end of the string because I'm not sure what PC-SPIM uses as the carriage return character.
Any help is appreciated, I have the feeling most of my problems result from something silly and stupid so feel free to point out anything, no matter how small.
Uh, this is a really old question, but the problem is that you're replacing the non-alphanumeric characters with a null character, which terminates the string at that point.
You can find out the value by doing something like this:
syscall to reading a string
mov first value to $2
check the value of $2 with PC-SPIM or a debugger
Related
I have a MIPS programs with procedure that get two input strings as arguments and just concatenate them into one. I want to compare them and put the larger string into the smaller and print the full string length.
Here is the code that i have write till now:
.data
first: .space 255 #255 bytes for first string
second: .space 255 #255 bytes for second stringfull: .space 512 #255 bytes for first string
.text
main:
la $a0,first
li $a1,255
li $v0,8
syscall
la $a0,second
li $a1,255
li $v0,8
syscall
move $s0,$ra
la $a0,first
la $a1,second
la $a2,full
jal strcpy
move $ra,$s0
add $a0,$a1,$zero
li $v0, 1
syscall
#display a new-line
li $a0,10
li $v0,11
syscall
#exit
jr $ra
strcpy:
li $t8 10 #store newline in $t8
slt $s2,$a1,$a0
beq $s2,$zero,sCopyFirst
if_pocetok:
add $a3,$a1,$a0
add $a0,$a1,$zero
add $a1,$a3,$zero
beq $zero,$zero,sCopyFirst
#loop through first string and copy to output string
sCopyFirst:
lb $t0 0($a0)
beq $t0 $zero sCopySecond #exit loop on null byte
beq $t0 $t8 sCopySecond #exit loop on new-line
sb $t0 0($a2)
addi $a0 $a0 1
addi $a2 $a2 1
b sCopyFirst
#loop through second string and copy to output string
sCopySecond:
lb $t0 0($a1)
beq $t0 $zero sDone #exit on null byte
beq $t0 $t8 sDone #exit on new-line
sb $t0 0($a2)
addi $a1 $a1 1
addi $a2 $a2 1
b sCopySecond
sDone:
add $a1,$zero,$zero
sb $zero,0($a2) #null terminate string
addi $t1,$zero,0
loop:
lbu $t2, 0($a2)
beq $t2, $zero, exit
addi $a2, $a2, 1
addi $a1, $a1, 1
jal loop
exit:
jr $ra
The current code that I have looks as such. It can successfully read if a string is a palindrome when punctuation is not entered.
.data
buffer: .space 80
input: .asciiz "Enter a string: "
output: .asciiz "Your string: "
paly: .asciiz "This is a palindrome "
notp: .asciiz "This is not a palindrome"
.text
main:
li $v0, 4 # system call code for print_str
la $a0, input # address of string to print
syscall # print the input
li $v0, 8 # code for syscall read_string
la $a0, buffer # tell syscall where the buffer is
li $a1, 80 # tell syscall how big the buffer is
syscall
la $a0, buffer # move buffer into a0
li $v0, 4 # print buffer
syscall
la $t1, buffer # begining of the string
la $t2, buffer # end of the string
li $t0, 0
loop:
lb $t3,($t2) # load the byte of the end of the string
beqz $t3,endl # if its equal to 0 then branch out of the loop
addu $t2, $t2,1 # if in loop the increment to next character
jal loop # repeat the loop
upper:
addi $t4,$t4,32
j lowered
lowered:
addi $t0,$t0,1
sb $t4, 0($a0)
addi $a0,$a0,1
j loop
endl:
subu $t2, $t2, 2 # subtracting 2 to move back from \0 and \n
check:
#lb $t4, 0($a0)
#beqz $t4, after
#beq $t4, 10, after
#slti $t2, $t4, 91
#li $t3, 1
#beq $t2, $t3, upper
bge $t1, $t2, palindrome # if both sides are equal then its a palindrome
# call palindrome
lb $t3, ($t1) # load the byte into register t3
lb $t4, ($t2) # load the end byte into register t4
bne $t3, $t4, notpaly # if the two register bytes are not equal its it not a palindrome
addu $t1, $t1, 1 # increment the beginning of the string to next char
subu $t2, $t2, 1 # decrement end of string to next char to compare
jal check # repeat the loop
palindrome:
la $a0, paly # calling paly from data
li $v0, 4 # call for reading string
syscall
jal exit # jump to end
notpaly:
la $a0,notp # calling notp from data
li $v0, 4 # call for reading string
syscall
jal exit # jump to end
after:
li $v0, 4
la $a0, output
syscall
la $a0, buffer
li $v0, 4
syscall
exit:
li $v0 ,10 # call to end program
syscall # call os
Now I know I need to implement code such as to make uppercase lowercase, and to remove punctuation.
With my already stored bits in check: I have some commented code, and this would be to to test if a character is uppercase, then jump to the function and lower it by adding 32. But it does not compile correctly and i am assuming this is because I am not storing the bits correctly.
#lb $t4, 0($a0)
#beqz $t4, after
#beq $t4, 10, after
#slti $t2, $t4, 91
#li $t3, 1
#beq $t2, $t3, upper
If given a number, I want to print out the first 'x' number of letters from the alphabet. I've setup a counter to determine the number of iterations the loop goes through, but I do not know how to extract the correct number of letters from the alphabet string.
Here's what I've done so far:
.data
alphabet:
.space 28
msg1: .ascii " Please enter an integer from 1-26:"
msg2: .ascii "abcdefghijklmnopqrstuvwxyz"
.text
.globl main
main:
li $v0, 5 # syscall for read_int
syscall
add $a0, $v0, $zero
li $t0, 0
li $t1, 26 # loop will start from zero and iterate to 26
loop:
la $t2, 0($a0)
beq $t0, $t2, end # once $t1 and $a0 are equal, loops stops
#li $t2, 1
#blt $t1, $t2, nomodify # do nothing if int less than 0
#li $t2, 26
#bgt $t0, $t2, nomodify # do nothing if int greater than 25
addi $t0, $t0, 1 # add 1 to $t1
j loop # jump back to top
end:
# Here is where I want to take 'x' number of iterations and convert it to
# the string of 'x' letters
li $v0, 10
syscall
Any help would be appreciated.
Having all the characters in a string is unnecessary for this task. Characters are integers, so you can just start at 'a' and count upwards:
# Assuming the loop count is in $t0
li $a0, 'a' # start at character 'a'
print_chars:
li $v0, 11
syscall # syscall 11 = print_character
addiu $a0, $a0, 1 # set $a0 to the next character
addiu $t0, $t0, -1
bne $t0, $zero, print_chars
So I have created this program to count the number of lowercase letters in a string. The problem I am having is that when I reach the end of the string and the nl character is reached, the line beq $t0, $t1, end is not being executed; it just continues indefinitely. I'm not sure what I'm doing incorrectly.
.data
msg1: .word 0:24
.text
.globl main
main:
addu $s0, $0, $ra
li $v0, 8
la $a0, msg1
la $a1, 100
syscall
loop:
lb $t0, 4($a0)
li $t1, 0x0a
beq $t0, $t1, end
continue:
li $t1, 'a'
blt $t0, $t1, count
li $t1, 'z'
bgt $t0, $t1, count
count:
addi $t4, $t4, 1
j loop
end:
li $v0, 1
addu $a0, $t2, $0
syscall
jr $ra
You compare 4($a0) with 0x0a on each iteration of the loop, but you never change $a0 in the loop, so you are not advancing through your string and never look at the \n at the end of the string.
There also are a few other bugs in your code.
Use this at the start of your loop:
loop:
lb $t0, 0($a0)
addiu $a0, $a0, 1
...
I am writing a MIPS program that prompts the user for a string and then parse the string exchanging the case of each character.
for example ->
Hey You becomes hEY yOU.
My question is, how do i make it do nothing if it encounters a space ? Any help would be great!
.data
string4:.space 82 # space for input string
strPrompt:.asciiz "Please enter a string: "
.text
.globl main
main:
la $a0, strPrompt # print prompt
li $v0, 4
syscall
la $a0, string4 # read string
li $a1, 80
li $v0, 8
syscall
la $a0, string4 # print string
li $v0, 4
syscall
la $t0, string4 # $t0 = &string4[0]
li $t1, 0
loop4:
lb $t1, 0($t0)
nop
nop
beqz $t1, done4 # if $t1 == NUL, we are done
bgt $t1, 90, else # if char > 90 its a lower case
nop
addi $t1, $t1, 0x20 # if < 90 its upper case add 32
sb $t1, 0($t0)
addi $t0, $t0, 1 # add 1 to pointer
j loop4 # jump back to loop
nop
else:
addi $t1, $t1, -0x20
sb $t1, 0($t0)
addi $t0, $t0, 1
j loop4
nop
done4:
Here's a branchless way of changing the case of a character in $t1 if it's in the range A..Z or a..z, and do nothing if it's outside that range:
# if (upper($t1) >= 'A' && upper($t1) <= 'Z') $t2 = 1; else $t2 = 0;
andi $t3,$t1,0xDF # clear bit 5, if $t1 was an alphabetic character $t3 will now be uppercase
li $t2,'A'-1
sltu $t2,$t2,$t3
sltiu $t3,$t3,'Z'+1
and $t2,$t2,$t3
sll $t2,$t2,5 # $t2 = 0x20, or 0
xor $t1,$t1,$t2 # either swap case or do nothing