MIPS prompt for a string and exchange the case of each character - mips

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

Related

Why is my MIPS assignment not printing what it should>

I'm sure I've done the math correct for both factoring and amicability, but it doesn't print past the range and I don't know why. Is my math incorrect? Or am I not actually printing the amicability out?
#all the string variables
.data
startrange: .asciiz "Input the start of the range: " #where the range begins
endrange: .asciiz "What is the end of the range: " #where the range ends
pairs: .asciiz "The pairs of amicable numbers are: " #results of amicable #s in range
quit: .asciiz "Unable to check non-positive values\nExiting..." #circumstance for a < 0 or b < 0
swap: .asciiz "End of range < start of range -- swapping values" #if the end of range is less than the start of range, swap the values
range: .asciiz "\nRange of numbers: " #what the range is (startrange -> endrange)
line: .asciiz "-" #dash for range
output1: .asciiz " are amicable numbers" #results if amicable
output2: .asciiz " are not amicable numbers." #results if not amicable
a: .word 0 #input of startrange
be: .word 0 #input of endrange
.text
main:
la $a0, startrange #load address startrange into $a0
li $v0, 4 #gets ready to print string
syscall #prints out startrange
la $s0, a #loads address of startrange input, a, into $s0
li $v0, 5 #gets ready to read string
syscall #reads startrange input, a
addi $s0, $v0, 0
jal negativeInput #calls for negativeInput fxn to check for negative inputs in a or be
la $a0, endrange #load address endrange into $a1
li $v0, 4 #gets ready to print string
syscall #prints out endrange
la $s1, be #loads address of endrange, be, input into $s1
li $v0, 5 #gets ready to read string
syscall #reads endrange input, be
addi $s1, $v0, 0
#if(a < 0 || b < 0) then exit
jal negativeInput #calls for negativeInput fxn to check for negative inputs in a or be
#if(b < a) swap values
jal swapping #jumps to swapping fxn
#print out range of numbers between a and b
jal printRange #jumps to printrange method
jal isFactor #calls for isFactor fxn to check is inputs have factors
jal isAmicable #calls for isAmicable fxn to check is inputs are amicable
negativeInput:
slt $t1, $s0, $zero #if $s0 (a or be) < 0 put in $t1
bne $t1, $zero, negativeTrue #if above is true (a !> 0) jumps to negativeTrue fxn
jr $ra #return to main
negativeTrue:
la $a0, quit #load string quit into $a0
li $v0, 4 #specifies the print string service
syscall #prints out
j exit
swapping:
slt $t1, $s1, $s0 #if $s1 (be) is < $s0 (a) put in $t1
bne $t1, $zero, swapTrue #if above is true (a > b) jumps to swaptrue fxn
jr $ra #returns to main
swapTrue:
la $a0, swap #load string swap into $a0
li $v0, 4 #gets ready to print
syscall #prints out
move $t2, $s0 #moves input a into $t2
move $s0, $s1 #moves input be into $s0
move $s1, $t2 #moves input a into $s1
#addi $t4, $s0, 0 #gets ready to start loop at beginning (a)
printRange:
la $a0, range #loads range statement into $a0
li $v0, 4 #gets ready to print
syscall #prints out
li $v0, 1 #ready to print int
move $a0, $s0 #moving input a into $a0
syscall #printing it out
la $a0, line #moves line statement (-) into $a0
li $v0, 4 #ready to print string
syscall #prints out
li $v0, 1 #ready to print int
move $a0, $s1 #moves input be into $a0
syscall #prints out
exit:
li $v0, 10
syscall
isFactor:
addi $t6, $s0, 0 #i = a to start loop
addi $t4, $zero, 0 #sum_a = 0
blt $t6, $s0, isFactorLoop #while i < a jump to isFactorLoop fxn
isFactor2:
addi $t6, $s1, 0 #i = be to start loop
addi $t4, $zero, 0 #sum_be = 0
blt $t6, $s1, isFactorLoop2 #while i < b jump to isFactorLoop2 fxn
isFactorLoop:
div $s0, $t6 #a/i
mfhi $t5 #a/i == $t5
beq $t5, 0, isFactorLoopTrue #if a/i == 0 jump to isFactorLoopTrue fxn
isFactorLoop2:
div $s1, $t6 #be/i
mfhi $t5 #be/i == $t5
beq $t5, 0, isFactorLoopTrue2 #if be/i == 0 jump to isFactorLoopTrue fxn
isFactorLoopTrue:
add $t4, $t6, $t4 #sum_a += i
move $s3, $t4 #moves sum_a into saved register
j isFactorLoop #repeats loop
isFactorLoopTrue2:
add $t4, $t6, $4 #sum_be += i
move $s4, $t4 #moves sum_be into saved register
j isFactorLoop2 #repeats loop
isAmicable:
addi $t7, $s0, 0 #a/startrange
addi $t8, $s1, 0 #be/endrange
addi $t6, $zero, 0 #i=0
blt $t6, $t8, isAmicableLoop #if i < be jump
beq $t6, $t8, isAmicableLoop #if i == be jump
isAmicableLoop:
addi $t9, $s1, 0 #j = be
bgt $t9, $t7, isAmicableIf #if j > a jump
beq $t9, $t7, isAmicableIf #if j == a jump
isAmicableIf:
#if sum_a == be && sum_be == a they're amicable
beq $s3, $s1, printIsAmicable #if sum_a == be jump
beq $s4, $s0, printIsAmicable #if sum_b == a jump
bne $s3, $s1, printIsNotAmicable #if sum_a != be jump
bne $s4, $s0, printIsNotAmicable #if sum_be != a jump
printIsAmicable:
la $a0, output1 #load address startrange into $a0
li $v0, 4 #gets ready to print string
syscall
printIsNotAmicable:
la $a0, output2 #load address startrange into $a0
li $v0, 4 #gets ready to print string
syscall
I'm sure I did a system call to at least print out the string but thats not working. Even jumped back to main and didn't work. All it prints out to is the range, and doesn't say whether the numbers within that range are amicable.
The problem lies in this function:
printRange:
la $a0, range #loads range statement into $a0
li $v0, 4 #gets ready to print
syscall #prints out
li $v0, 1 #ready to print int
move $a0, $s0 #moving input a into $a0
syscall #printing it out
la $a0, line #moves line statement (-) into $a0
li $v0, 4 #ready to print string
syscall #prints out
li $v0, 1 #ready to print int
move $a0, $s1 #moves input be into $a0
syscall #prints out
exit:
li $v0, 10
syscall
It's important to remember that a label does not alter execution flow simply by existing. The program is printing the range and then "falling through" to your exit routine. This is because labels are merely a hardware abstraction, a convenience so that you don't have to adjust your "line numbers" (read: memory offsets) of your jal, b, and j statements every time you change your code. The assembler converts your source code, which specifies a label, to either a jump to the memory address where the instruction directly beneath that label is stored, or the distance between the current program counter value and that instruction (measured in bytes), as appropriate. The labels no longer exist in your assembled executable program.
Not only that, your isFactorLoop appears to have no way to exit and thus would loop forever.

A MIPS palindrome

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

MIPS - Printing a certain number of characters from a string

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

Count number of lowercase letters

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
...

MIPS: removing non alpha-numeric characters from a string

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