Solution
program.asm
.data
fnf: .ascii “The file was not found: ”
###important: UPDATE THIS PATH TO WHERE YOU SAVED THE TEXT FILE
#asciiz directive creates null-terminated string
file: .asciiz “C:/Users/Rami/Documents/2017/mp1/input.txt”
pstring:.asciiz ” printable characters.\nFile Contents: \n”
buffer: .space 1024
cstring:.asciiz “\nFile Contents after capitalization: \n”
.text
#QUICK REFERENCE OF REGISTER MAPPINGS
#$s0 – save the file descriptor of the file containing text
#$s1 – save the address of the buffer text was loaded (base address)
#$s2 – iterator (i) to buffer character array
#$s3 – count number of printable characters
#$t0 – where we will temporarily keep the address of CURRENT character, i.e. $s1 + $s2
#$t1 – where we will temporarity load the current character, i.e. character at address in $t0
#These lines opens and reads the file containing text to be modified
main:
li $v0, 13 # Set $v0 to 13 for syscall to open file
la $a0, file # Load file to read, $a0 set to address of string
# containing filename
li $a1, 0 # Set read-only flag
li $a2, 0 # Set mode
syscall # the file descriptor will be returned in $v0
blt $v0, 0, err # Go to handler if failed to open file
# blt is a pseudo-instruction
# but you can use those in this assignment
add $s0, $v0, $zero # Save file descriptor in $v0 to new register $s0
# because $v0 will be used in other system calls
# These files read text from the file we just loaded
read:
li $v0, 14 # Set $v0 to 14 for system call to read file
add $a0, $s0, $zero # Load file descriptor to $a0, we previously saved in $s0
la $a1, buffer # Set $a1 to address of input buffer where
# text will be loaded to
li $a2, 1024 # Set $a2 to number of characters to read
syscall # $v0 will contain number of characters (bytes) read
# $v0 set to -1 if error
add $s1,$a1,$zero # save address of buffer to $s1
#set last byte to null so we know when to stop loop later
add $t4, $s1, $v0 #recall, $v0 has the number of characters, so
#this will give us the address of the byte
#just after the last character
sb $zero, 0($t4) #ASCII code for NULL is ‘0’
#initialize some registers
init:
li $s2, 0 # $s2 will be message character iterator i
# initialize i=0
li $s3, 0 # $s3 will count the number of printable characters
#loop to count PRINTABLE characters
loop:
add $t0, $s1, $s2 # $t0 <= BA + i, address of current character
# BA: address start of buffer, in $s1
lb $t1, 0($t0) # load char in buffer[i] to $t1
beq $t1, $zero, print # null, reached end of buffer
#let’s check for printable characters
#see ASCII table; let’s not count any ASCII code less than 33 (exclamation point)
#or greater 126 (~)
#note that you can use the pseudo-instruction blt and bge as well
#even though they are not native MIPS instructions, qtSPIM will handle them
slti $t2,$t1,33 #$t2 is 1 if $t1<33; 0 if >=33
#i.e. if $t2 is 1, not printable character
bne $t2,$zero,next #move to next character if $t2 is 1
slti $t3,$t1,127 #note: will only come here if $t1>=33 ($t2 is 0)
#$t3 is 1 if $t1<127; 0 if $t1>=127
#therefore, this is a printable character if
#$t2 is 0 AND $t3 is 1
beq $t3,$zero,next #move to next character if $t3 is 0 ($t1>=127)
addi $s3,$s3,1 #note: will only come here if ASCII code is
#between 33 and 126 (what we consider as printable characters)
next: #move to next character/iteration
addi $s2, $s2, 1 #i++
j loop #continue iterating through each character
# Print data to console
print:
li $v0, 1 # System call to print integer
add $a0, $s3, $zero # Load to $a0 integer to print
syscall
#print pstring
li $v0, 4 # System call to print string
la $a0, pstring # Load to $a0 string to print
syscall
#print actual file contents
li $v0, 4 # System call to print string
add $a0, $s1, $zero # copy BA of buffer to $a0
syscall
# Close File
close:
li $v0, 16 # Set $v0 to 16 for system call to close file
add $a0, $s0, $zero # Load File Descriptor
syscall
#correct case
jalcorrect_case # call the procedure to correct the case
#print cstring
li $v0, 4 # System call to print string
la $a0, cstring # Load to $a0 string to print
syscall
#print corrected file contents
li $v0, 4 # System call to print string
add $a0, $s1, $zero # copy BA of buffer to $a0
syscall
j done # Goto done
#Error
err:
li $v0, 4 # System call to print string
la $a0, fnf # Load Error String
syscall
# Done
done:
li $v0, 10 # Exit Syscall
syscall
# Procedure that corrects the case of the characters in the text buffer
# On entry:
# $s1 = pointer to null-terminated text buffer
correct_case:
add $t0,$s1,$zero # we will use t0 to point to the current char in the buffer
li $t3,1 # we will use t3 as the flag for capitalizing characters, first char is uppercase
cloop: # go through each character and correct capitalization
lb $t1, 0($t0) # load char in buffer[i] to $t1
beq $t1, $zero, return # null, reached end of buffer
li $t2, 10 # newline char
beq $t1, $t2, setcap # if is’t a newline, set capitalization
li $t2, 33 # exclamation
beq $t1, $t2, setcap # if is’t an exclamation, set capitalization
li $t2, 46 # period
beq $t1, $t2, setcap # if is’t a period, set capitalization
li $t2, 63 # question mark
bne $t1, $t2, upcase # if it’s not a question mark, it was not a special character, try with upper case
setcap: # in any other case:
li $t3,1 # next char must be capitalized
bnexti # skip following comparisons and go to next char
upcase:
slti $t2,$t1,91 # if it’s less than 91 it could be an upper case (Z=90)
beq $t2,$zero,lowcase # if it was >= 90, it could be lowercase, go to next tests
slti $t2,$t1,65 # if it’s less than 65 it’s not an upper case (A=65)
bne $t2,$zero,nexti # if it’s less than 65, go to next char
bne $t3,$zero,clrcap # if it needs to be uppercase, it already is, clear flag
xori $t1,$t1,32 # if it needs to be lowercase, change from upper to lowercase
sb $t1,0($t0) # save changed letter in buffer
bnexti # go to next character
lowcase:
slti $t2,$t1,123 # if it’s less than 123 it could be a lower case (z=122)
beq $t2,$zero,nexti # if it was >= 123, is not a letter, go to next char
slti $t2,$t1,97 # if it’s less than 97 it’s not a lower case (a=97)
bne $t2,$zero,nexti # if it’s less than 97, go to next char
beq $t3,$zero,nexti # if it needs to be lowercase, it already is, go to next char
xori $t1,$t1,32 # if it needs to be uppercase, change from lowercase to uppercase
sb $t1,0($t0) # save changed letter in buffer
clrcap:
li $t3,0 # next char must not be capitalized
nexti: #move to next character/iteration
addi $t0, $t0, 1 #i++
j cloop #continue iterating through each character
return: