所以这个程序采用一串“脏”的公式“12.0 +(34 - 45)* A67 / z89 并打印“清洁”公式“120+(34-45)* 67/89 cleanFormula方法只接受数字0-9,算术运算符+ - * /和括号作为有效字符。其余的迭代完毕。
我对这个程序的问题是:我的迭代循环正常工作,我的副本将所有字符复制到我的堆栈,我的清理循环遍历无效字符,将所有有效字符存储在$ t2中,然后跳转到printFormula用于非数字的有效字符。
但是printFormula没有打印我修改过的字符串。相反,它打印原始字符串。谁能帮我这个?我觉得这是在printFormula的堆栈上放置值的问题,因为printFormula有指令sw $ a0,8($ sp)
#结合test12和test13。
# From test12:
# Changes $s register usage in main to make sure cleanFormula is not relying
# on getting values from main by way of the $s registers..
# From test13:
# printFormula appends " -- from printFormula" to each line. This is to
# confirm that printFormula is being called.
.data
mainFormulas:
.word mainFormula2
.word mainFormula1
.word mainFormula3
.word mainFormula4
mainNumFormulas:
.word 4
mainFormula1:
.asciiz "1742163829863897628673002651087650871620387650876540817263087612035897601287650128973501982650986508716408172658765987506501297568751078965"
mainFormula2:
.asciiz "((((((slkdj*+-+++------))))))((((****///soifh//***lskdhgoiuy****---+++))))"
mainFormula3:
.asciiz "1"
mainFormula4:
.asciiz "a"
mainNewline:
.asciiz "\n"
.data
mainOrigStr:
.asciiz "In main, original formula: "
.text
main:
# Function prologue -- even main has one
addiu $sp, $sp, -24 # allocate stack space -- default of 24 here
sw $fp, 0($sp) # save frame pointer of caller
sw $ra, 4($sp) # save return address
addiu $fp, $sp, 20 # setup frame pointer of main
# for ( i = 0; i < mainNumFormulas; i++ )
# print the original string
# cleanFormula
# print the original string
addi $s5, $zero, 0 # $s5 = i = 0
la $t0, mainNumFormulas
lw $s6, 0($t0) # $s6 = number of strings
la $s7, mainFormulas # $s7 = addr mainFormulas[0]
mainLoopBegin:
slt $t0, $s5, $s6 # $t0 = i < mainNumFormulas
beq $t0, $zero, mainLoopEnd
lw $s1, 0($s7) # $s1 = addr of start of current string
# print the original formula
la $a0, mainOrigStr
addi $v0, $zero, 4
syscall
addi $a0, $s1, 0
addi $v0, $zero, 4
syscall
la $a0, mainNewline
addi $v0, $zero, 4
syscall
addi $a0, $s1, 0 # $a0 = addr of string start
jal cleanFormula
# print the original formula
la $a0, mainOrigStr
addi $v0, $zero, 4
syscall
lw $a0, 0($s7) # $a0 = addr of start of current string
addi $v0, $zero, 4
syscall
la $a0, mainNewline
addi $v0, $zero, 4
syscall
syscall # print blank line
addi $s5, $s5, 1 # i++
addi $s7, $s7, 4 # $s7 = addr of next string
j mainLoopBegin
mainLoopEnd:
mainDone:
# Epilogue for main -- restore stack & frame pointers and return
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore frame pointer of caller
addiu $sp, $sp, 24 # restore stack pointer of caller
jr $ra # return to caller
printFormula:
.data
printFormulaNewline:
.asciiz " -- from printFormula\n"
.text
# Function prologue
addiu $sp, $sp, -24 # allocate stack space -- default of 24 here
sw $fp, 0($sp) # save frame pointer of caller
sw $ra, 4($sp) # save return address
sw $a0, 8($sp) # save $a0 = addr of first char to print
sw $a1, 12($sp) # save $a1 = how many chars to print
addiu $fp, $sp, 20 # setup frame pointer of printFormula
# for (i = $a0; i < $a0 + $a1; i++)
# print byte
addi $t0, $a0, 0 # i = $t0 = start of characters to print
add $t1, $a0, $a1 # $t1 = addr of last character to print
printFormulaLoopBegin:
slt $t2, $t0, $t1 # $t2 = i < $a0 + $a1
beq $t2, $zero, printFormulaLoopEnd
# print the character
lb $a0, 0($t0)
addi $v0, $zero, 11
syscall
addi $t0, $t0, 1 # i++
j printFormulaLoopBegin
printFormulaLoopEnd:
la $a0, printFormulaNewline
addi $v0, $zero, 4
syscall
# Epilogue for printFormula -- restore stack & frame pointers & return
lw $a1, 12($sp) # restore $a1
lw $a0, 8($sp) # restore $a0
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore frame pointer of caller
addiu $sp, $sp, 24 # restore stack pointer of caller
jr $ra # return to caller
#Your code goes below this line
#cleanFormula
#Takes a string formula and "cleans" it
#To do this: the formula is copied into a new string
#New string only copies digits 0 - 9, parentheses, and
#mathematic operators + - * /
#cleanFormula calls printFormula to print the "clean" formula
cleanFormula:
# Prologue: set up stack and frame pointers for printFormula
addiu $sp, $sp, -24 # allocate stack space -- default of 24
sw $fp, 0($sp) # save frame pointer of caller
sw $ra, 4($sp) # save return address
addi $fp, $sp, 20 # setup frame pointer for cleanFormula
# We need to make additional space to hold each character of the the
# string. To do this, we iterate through the string to get the
# string length then we add this to our stack
# We do this in loopStringIterationBegin
# $a0 is the address of the string
# initialize $t1 to count = 0
addi $t1, $zero, 0 # $t1 = count = 0
cleanFormulaLoopStringIterationBegin:
# Base case
lb $t0, 0($a0) # $t0 = address of string
beq $t0, $zero, cleanFormulaLoopStringIterationEnd
# while ( char != null)
#count++
# Where string is null, count = length
# add 1 to $a0 to continue iterating over string
addi $t1, $t1, 1 # $t1 = count++
addi $a0, $a0, 1 # $a0++
j cleanFormulaLoopStringIterationBegin
cleanFormulaLoopStringIterationEnd:
# $t1 is the length of our string
# Allocate our stack space by 1 byte per character
# in order to fit our string on the stack
# In order to keep the stack word aligned, we have to
# add some number to $t1 to make it divisible by 4
# To do this: divide $t1 by 4 and subtract
# the value of the HI register (remainder) by 4
# our value 4 - HI is the necessary amount of bytes
# to add to keep our stack aligned
# However HI itself can not be used with arithmetic
# instruction, so we move the value of HI to another
# register for operating
addi $t0, $zero, 4 # $t0 = 4 for our division
div $t1, $t0 # $t1/$t0 LO is quotient HI is remainder
mfhi $t2 # Moves mfhi to $t2 for our loop
sub $t2, $t0, $t2 # $t2 = 4 - HI
add $t3, $t1, $t2 # $t3 = $t1 + $t2
# $t1 now has all bytes to reference each char in the
# string and additional bytes to keep the stack
# aligned
# allocate our new stack space
subu $sp, $sp, $t3 # $sp = -24 - (string.length() + 4 - HI)
# cleanFormulaCopyLoopBegin
# Copy the characters of the string onto our stack
# while ( char != null )
# character[i] onto stack
# i++
# put a null character at the end
addi $t2, $sp, 0 # $t2 references original sp
sub $a0, $a0, $t1 # restores $a0
cleanFormulaCopyLoopBegin:
lb $t0, 0($a0) # $t0 = address of string
beq $t0, $zero, cleanFormulaCopyLoopEnd
sb $t0, 0($t2) # $t2 = string[i]
addi $t2, $t2, 1 # $t2++
addi $a0, $a0, 1 # $a0++
j cleanFormulaCopyLoopBegin
cleanFormulaCopyLoopEnd:
#put a null character at the end for our cleaning loop next
sb $zero, 0($t2)
#set $a0 to the address of our stack
# cleanFormulaCleanLoopBegin
# Iterate the string by interating
# the characters copied to the stack
# Then comparing characters for valid characters
# 0 - 9, parentheses, or opetarors * / - +
# only copy valid characters, otherwise skip
# To do this: compare ascii values
# Ascii equivalences: 0 - 9 (48-57), ( ) (40, 41),
# * (42), + (43), - (45), / (47)
# $a1 will be the length of the string
# Initialize $a1 at 0
addi $a0, $sp, 0 # $a0 = address of $sp
addi $a1, $zero, 0 # $a1 = 0
addi $t2, $sp, 0 # reset $t2 to start of stack
cleanFormulaCleanLoopBegin:
# for(int i = 0; i < string.length(); i++)
# if validCharacter
# newString += thatCharacter
#Base Case
lb $t0, 0($t2) # get character
beq $t0, $zero, cleanFormulaCleanLoopEnd
# When $t0 == nul character on the end of our string
# Compare character
# Our range of valid ascii characters is 40 - 57 excluding
# 44 and 46. We need 2 slti and 4 branch conditions to
# reflect this
slti $t4, $t0, 58 # $t4 = char <= largest ascii digit
beq $t4, $zero, cleanFormulaCleanLoopIncrement
# This says if !$t0 < 58) -> $t0 >= 58 -> $t0 > 57
# our highest valid ascii char (9) then skip the character
slti $t4, $t0 40 #$t4 = $t0 < smallest ascii digit
bne $t4, $zero, cleanFormulaCleanLoopIncrement
# This says if $t0 < 40, our lowest valid ascii char ('(')
# then skip the character
# 44 and 46 are also invalid ascii characters for our clean formula
addi $t4, $zero, 44 #$t4 = 44
beq $t0, $t4, cleanFormulaCleanLoopIncrement
addi $t4, $zero, 46 #$t4 = 46
beq $t0, $t4, cleanFormulaCleanLoopIncrement
# Only valid ascii characters are left now
# Concatenate to a new string
# increment $a1 to number of characters to print
# Save $a1 before increment for reference
addi $a2, $a1, 0
addi $a1, $a1, 1 # $a1++
sb $t0, 0($t2) # stores character in $t2
# printFormula is called each time an arithmetic operator
# or parenthesis is found, so we separate digits from these
# chars. Digits will jump to increment while these other
# or parenthesis is found, so we separate digits from these
# chars. Digits will jump to increment while these other
# chars will call printFormula
# Compare valid characters for digits (ascii 48-57)
# We already know the min value of a character here is 57 (9)
# and the range of digits is 48-57,
# so if char >= 48, it is a digit
slti $t4, $t0, 48 #$t4 = $t0 < smallest digit (0)
beq $t4, $zero, cleanFormulaCleanLoopIncrement
# If !($t0 < 48) -> $t0 >= 48 and $t0 is a digit
# Now we only have (, ), *, +, -, / possible characters
# jal to printFormula for the above characters
# No further comparisons are necessary
jal printFormula
# restore $t2 after jump
# $t2 is stack pointer + $a2
# ($a1 before increment)
add $t2, $sp, $a2
cleanFormulaCleanLoopIncrement:
# increment $t1 to next member of stack
addi $t2, $t2, 1 # $t2++
j cleanFormulaCleanLoopBegin
cleanFormulaCleanLoopEnd:
# Concatenated and printed new string formula
# Calls printFormula one last time
jal printFormula
cleanFormulaDone:
# Epilogue for cleanFormula: restore stack & frame pointers and return
# Remove the extra bytes used by the string
add $sp, $sp, $t3 # Removes all extra bytes used by string
# Now, clean up the rest of the stack
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore frame pointer for caller
addiu $sp, $sp, 24 # restore stack pointer for caller
jr $ra # return to caller