Reverse string in MIPS - string

I am trying to write a program that gets a user string input and reverse that string in MIPS.
However, I must be doing something horribly wrong as it doesn't just display the user input in reverse but, it also reverses the prompt to the user. It seems that the user input is not identified with a null(zero?) character in the end.
.data
prompt: .asciiz "Please enter your name. You're only permitted 20 characters. \n"
userInput: .space 20 #user is permitted to enter 20 characters
.globl main
.text
main:
# user prompt
li $v0, 4
la $a0, prompt
syscall
# getting the name of the user
li $v0, 8
la $a0, userInput
li $a1, 20
syscall
add $t0, $a0, $0 # loading t0 with address of array
strLength:
lbu $t2, 0($t0)
beq $t2, $zero, Exit # if reach the end of array, Exit
addiu $t0, $t0, 1 # add 1 to count the length
j strLength
Exit:
add $t1, $t0, $0 # t1 = string length
li $t2, 0 # counter i = 0
li $v0, 11
reverseString:
slt $t3, $t2, $t1 # if i < stringlength
beq $t3, $0, Exit2 # if t3 reaches he end of the array
addi $t0, $t0, -1 # decrement the array
lbu $a0, 0($t0) # load the array from the end
syscall
j reverseString
Exit2:
li $v0, 10
syscall

Problem number 1:
add $t1, $t0, $0 #t1 = string length
What you're assigning to $t1 here isn't the length of the string; it's the address of the first byte past the end of the string.
Problem number 2 is that you never increment $t2 (or decrement $t1) within the reverseString loop.
I suggest that you make use of the debugging features in SPIM/MARS (like the ability to set breakpoints and single-step through the code), as that would've made finding these problems yourself fairly simple.

Related

Mips error printing length of string

This seems like it should work but clearly doesn't. When I try to count the length of the string it returns some crazy long number. When I one step the program it works fine but prints out the wrong number. Can somebody point me back on track so that I can work on the next function? I just need to figure out what is throwing off the count
############################################
# Program Name: strings.s
# Programmer: David Bierbrauer
# Date: 9/07/2017
############################################
# Functional Description:
#
#
############################################
# Cross References:
#
#
############################################
.data # Data declaration section
stringa: .asciiz "Enter the first string: "
stringb: .asciiz "\nEnter the second string: "
.text
main: # Start of code section
#li $v0, 4 #get first string input
la $a0, stringa
jal read
jal length
jal print
#get second string input
la $a0, stringb
jal read
jal length
jal print
j end
length:
li $t0, -1 #loop count 0
j lengthloop
lengthloop: #exit address $s1
lb $t1, 0($a0) #load next char into $t1
beqz $t1, endlength
addi $a0, $a0, 1 #increment string pointer
addi $t0, $t0, 1 #increment count
j lengthloop
endlength:
jr $ra
equality:
lb $t2, 0($a0)
lb $t3, 0($a1)
bne $t2,$t3 notequal
append:
print:
li $v0, 1
la
syscall
jr $ra
read:
li $v0, 4
syscall #print prompt
li $v0,9
li $a0,80
syscall
move $a0,$v0
li $v0,8
li $a1,80
syscall
jr $ra
end:
li $v0, 10
syscall
The code you've posted doesn't even assemble, because there's a stray la in the print routine.
Aside from that, your length routine returns the length in $t0, while your print routine assumes that the value is in $a0. That's why you get the wrong output.
Your print looks odd. spim yells at me - bad syntax of la pseudoinstruction. I guess, you mean
print:
li $v0, 1
la $a0, 0($t0)
syscall
jr $ra

Finding out number of vowels in given string in MIPS

I have to write a program to count the number of vowels in a string in MIPS. My current code is giving me a memory out of bounds error in QtSPim.
I'm at the beginner level in MIPS, so any help would be appreciated.
Code so far:
.data
str: .space 20
my_chars: .space 20
vow1: .byte 'a'
vow2: .byte 'e'
vow3: .byte 'i'
vow4: .byte 'o'
vow5: .byte 'u'
.text
main:
li $s0,0 #initilaze loop var1
li $t0,20 #initialize loop var2
li $s1,0 #initialize counter
la $t1, my_chars # base address of array
li $a1,20 #max input to be read
li $a0,8
syscall
loop:
beq $s0, $t0, exit
la $t2, str #string into t2
lb $v0, 0($t2) #access first index
lb $t9, vow1
beq $v0, $t9, then #comparing to a
then:
addi $s1, $s1, 1
lb $t8, vow2
beq $v0, $t8, then1 #comparing to e
then1:
addi $s1, $s1, 1
lb $t7, vow3
beq $v0, $t7, then2 #comparing to i
then2:
addi $s1, $s1, 1
lb $t6, vow4
beq $v0, $t6, then3 #comparing to o
then3:
addi $s1, $s1, 1
lb $t5, vow5
beq $v0, $t5, then4 #comparing to u
then4:
addi $s1, $s1, 1
addi $t1, $t1,1 #increment base address
addi $s0, $s0,1 #increment loop variable
j L1
syscall
Because your posted code had missing labels, etc. I couldn't run it to look for the runtime error.
From visual inspection, the read from user input code had a few issues. li $a0,8 should be li $v0,8 [the syscall number to read a string]. $a0 should contain the address of the buffer to read into. In your code, this was 8 and [probably] not a valid address. So, you'd probably want something like la $a0,my_chars or la $a0,str. One of them should be the input buffer and the other seems unnecessary.
As I was trying to add labels [based on educated guesswork], I realized that your program could/would be much simpler if the vowels were in an array, so I refactored the code.
I also changed the loop termination to look for EOS (0x00) instead of decrementing a count, which may have been another potential source of an out-of-bounds issue. This also reduces the number of registers needed (i.e. reduces complexity)
I added the missing boilerplate/syscalls [please pardon the gratuitous style cleanup]:
.data
vowel: .asciiz "aeiou"
msg_prompt: .asciiz "Enter string: "
msg_out: .asciiz "Number of vowels is: "
msg_nl: .asciiz "\n"
str: .space 80
.text
.globl main
main:
# print user prompt
li $v0,4
la $a0,msg_prompt
syscall
# get string to scan
li $v0,8
la $a0,str
li $a1,80
syscall
li $s2,0 # initialize vowel count
la $s0,str # point to string
# registers:
# s0 -- pointer to string character
# s1 -- pointer to vowel character
# s2 -- count of vowels
#
# t0 -- current string character
# t1 -- current vowel character
string_loop:
lb $t0,0($s0) # get string char
addiu $s0,$s0,1 # point to next string char
beqz $t0,string_done # at end of string? if yes, fly
la $s1,vowel # point to vowels
vowel_loop:
lb $t1,0($s1) # get the vowel we wish to test for
beqz $t1,string_loop # any more vowels? if not, fly
addiu $s1,$s1,1 # point to next vowel
bne $t0,$t1,vowel_loop # is string char a vowel? -- if no, loop
addi $s2,$s2,1 # yes, increment vowel count
j string_loop # do next string char
string_done:
# print count message
li $v0,4
la $a0,msg_out
syscall
# print vowel count
li $v0,1
move $a0,$s2
syscall
# print a newline
li $v0,4
la $a0,msg_nl
syscall
# exit program
li $v0,10
syscall

Changing Characters in a String in MIPS (Caesar Shift)

Hey guys i want to write a simple Caesar Shift in MIPS. My program takes in the string to be encrypted/decrypted. Then the program asks for the key (the number of letters to shift) and then asks to encode or decode.
---EDIT ---
Sorry i forgot to clarify my question. The output of my program is "estuvwL" for a shift of 1 on the string "abcde". Obviously, this is not correct. Any thoughts on where i am going wrong?
Here is my code:
.data # Data declaration section
prompt: .asciiz "Enter a message: " #prompt to enter message
key_prompt: .asciiz "Enter a key for this message: " # enter number to shift letters
enc_dec: .asciiz "(e)ncrypt or (d)ecrypt? " # encrypt or decrypt prompt
encode_bytes: .byte 1 #bytes for encoding
key: .word 0 # the variable for encoding key
String: .space 255 # the string to be encrypted/decrypted
encode: .space 1 #the character (e) or (d) to ask encrypt or decrypt
e: .ascii "e"
d: .ascii "d"
.text
main: # Start of code section
__Start:
li $v0, 4 #print string
la $a0, prompt # print the first prompt
syscall
li $v0, 8 # read in string to be encrpyted
la $a0, String # stores string in variable
li $a1, 255 # the string allocates room for up to 255 chars
syscall
li $v0, 4 #print string
la $a0, key_prompt
syscall
li $v0, 5 #code to read in int
syscall # reading in the integer
move $t5, $a0 #moving key to $t5
li $v0, 4 #print string
la $a0, enc_dec #print the encode string
syscall
li $v0, 12 #read character code
#la $a0, encode #load address of encode to register $a0
#li $a1, 2 #limit input to 1 char
syscall
li $s7, 101
li $s6, 100
beq $v0, $s7, __encrypt_Loop
beq $v0, $s6, __decrypt_Loop
__encrypt_Loop:
la $t0, String #holding address of String
__encode_Loop:
lb $t2, ($t0) #loading the byte to be manipulated into $t2
beqz $t2, __print_String # if string is equal to zero, jump to print new string
__continue:
add $t2, $t2, $t5 #adding the key to the string (manipulating chars)
li $t3, 'z' #loading the value of z, for checking purposes
bgt $t3, $t2, __encrypt_Check #if the char is "bigger" than z jump to fix
sb $t2, ($t0) #store the value
addi $t0, 1 #incrementing to next char
j __encode_Loop
__encrypt_Check:
li $s4, 25
sub $t2, $t2, $s4
sb $t2, ($t0) #store char in string
addi $t0, 1 #incrementing to next char
j __continue
__decrypt_Loop:
la $t0, String #holding address of String
# la $t5, key #loading the key into $t5
__decode_Loop:
lb $t2, ($t0) #making $t2 the address of the string
beqz $t2, __print_String # if string is equal to zero, jump to print new string
___continue:
sub $t2, $t2, $t5 #subtracting the key to the string (manipulating chars)
li $t3, 'a' #loading the value of z, for checking purposes
blt $t3, $t2, __decode_Check #if the char is "smaller" than a jump to fix
sb $t2, ($t0) #store the value
addi $t0, 1 #incfementing to next char
j __decode_Loop
__decode_Check:
li $s4, 25
add $t2, $t2, $s4
sb $t2, ($t0) #store char in string
addi $t0, 1 #incrementing to next char
j __continue
__print_String:
li $v0, 4
#move $a0, $t0
la $a0, String
syscall
__end_program:
li $v0, 10
syscall
A few problems here:
First is the line move $t5, $a0 #moving key to $t5 which should read move $t5, $v0 as the syscall returns the key in $v0 not $a0.
Secondly, I'm not sure what the purpose of the "check" functions is, so I commented out the branch to them and everything worked as I expected.
At any rate, the check for them is clearly wrong. You wrote:
blt $t3, $t2, __decode_Check #if the char is "smaller" than a jump to fix
But the arguments are reversed from the comment. It should read
blt $t2, $t3, __decode_Check #if the char is "smaller" than a jump to fix
Likewise for the __encrypt_Check function.

MIPS randomized word scrambler

I am trying to write code that uses the MARS (my MIPS simulator) pseudorandom number generator to pick a random char in the string, take it out of memory and into a register, and replace that char in memory with an asterisk, '*'.
So far, it only scrambles part of the word, and it's driving me insane. I can't find what in this code isn't working. I don't even need a direct answer, just hints/tips would be SO helpful.
Here is the code:
#this loop extracts a char at random from a string in memory, stores it in a register, and replaces the char in the string with an asterisk '*'
.data
.align 2
string0: .ascii "Tyler\n"
.align 2
endString: .asciiz "Loop completed!\n"
.align 2
scrambleString: .asciiz
.text
#counter
li $t0, 5
#pointer to string0
la $s0, string0
loop2:
#is counter = 0? go to loop3 if so
beq $t0, $0, loop3
#seed & prepare randomized number generator
li $v0, 30
syscall
li $v0, 40 #sets seed
syscall
#generates random number in $a0, with the coUnter $t0 being the upper bound
addi $a1, $t0, 1
li $v0, 42
syscall
#add STRING POINTER by random number in $a0, store this new address in $t1
#addi $a0, $a0, 1
add $t1, $s0, $a0
#srlv $t1, $s0, $a0
#isolates that bytesized char, puts it into $t2
lbu $t2, ($t1)
#beq $t2, 0x5c, loop2
#replaces char in original string with "*"
li $t3, 0x2a
sb $t3, ($t1)
beq $t1, $t3, loop2
#decrement counter
addi $t0, $t0, -1
#loop return
j loop2
loop3:
la $a0, string0
li $v0, 4
syscall
li $v0, 10
syscall
You are resetting the random number seed on every iteration of
your loop (loop2:).
Syscalls 40 and 42 each take 2 parameters which should be in $a0 and
$a1. See here.
The temporary registers $t0,...,$t9 get altered by each
syscall. You should be using the callee saved registers
$s0,...$s8 instead.

Pig Latin in MIPS Assembly

In my MIPs Assembly Programming class I've been tasked with writing a program that converts a string into simplified pig latin.
Simplified pig latin assumes all words in the string are at least 2 characters long, and every word has its first letter shifted to the end followed by "ay". Also, assume there are no punctuation marks of any kind.
So, "stackoverflow is great" becomes "tackoverfloway siay reatgay".
I've taken a stab at this program and I'm nearly completed. It works fine, except that for some reason I have a line break in the middle of the last word every time.
For example:
tackoverflowsay siay reat
gay
Instead of:
tackoverflowsay siay reatgay
I've tried decuding what would be causing this line break in the last exit portion of my program but I don't see it. Do I have a pre-mature null terminated string? If I do, I don't see it.
Here is my code:
####################################################
# Text Segment
####################################################
.text
.globl main
main:
la $t0, char
la $t1, buffer
lb $t3, space
la $a0, prompt
li $v0, 4
syscall
la $a0, buffer
li $a1, 200
li $v0, 8
syscall
lb $t2, ($t1) # Load first char
addi $t1, $t1, 1
loop:
lb $t4, ($t1) # Load next character into $t4
addi $t1, $t1, 1
beqz $t4, exit # Reached end of string, exit?
beq $t3, $t4, loop2 # If $t4 = " " char, second loop
move $a0, $t4 # else, lets keep printing chars
li $v0, 11
syscall
j loop
loop2:
move $a0, $t2
li $v0, 11
syscall
la $a0, aystr
li $v0, 4
syscall
lb $t2, ($t1)
addi $t1, $t1, 1
j loop
exit:
move $a0, $t2
li $v0, 11
syscall
la $a0, aystr
li $v0, 4
syscall
li $v0, 10
syscall # Cya...
####################################################
# Data Segment
####################################################
.data
prompt: .asciiz "Enter Phrase: "
result: .asciiz "Pig Latin: "
space: .ascii " "
aystr: .asciiz "ay "
char: .byte 1
buffer: .byte 200
You almost certainly have a string of the form:
stackoverflow is great\n
where \n is a newline character. This would translate into:
tackoverflowsay siahy reat\ngay
if you simplistically detected the end of the word as either space or null-terminator.
I'm not going to give you the code (since this is homework) but the easiest solution, in my opinion, would be to have another loop processing the entire string, replacing all "\n" characters with spaces.
This would be done before your latinization loops.

Resources