在MIPS中复制新字符串

时间:2014-11-26 05:44:56

标签: arrays string assembly stack mips

所以这个程序采用一串“脏”的公式“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

0 个答案:

没有答案