Mips 中的回文检查器

Palindrome Checker in Mips

我正在参加一个计算机组织 class,该组织通过 MIPS 汇编教授计算机的低级功能。作业中的一个问题是回文检查器。这是:

Write a MIPS function (called “palindrome”) that returns 1 if the input string is a palindrome and returns 0 otherwise. The address of the string will be passed in $a0 and the value should be returned in $v0. Here a string is a palindrome if it reads the same in forward or backward direction (including white spaces, punctuation marks, and so on, but is case insensitive (i.e., „A‟ and „a‟ are considered to be the same)). Note the string is ended with „[=13=]‟ (C/C++ convention). You need to test your program using “test_palindrome.s”

我写了一个简单的c++程序来解决这个问题,包括一个基本的tolower函数。然后我手动将它翻译成 mips。我已经达到 运行,但是用我的 c++ 程序和 mips 程序检查回文测试字符串,我没有得到相同的结果。

为了测试mips函数,我使用了教授提供的程序。它说 none 其中是回文。这是 MIPS 代码,有一个注释部分显示了我的原始 c++ 代码。

# Program to test if a palindrome function works properly or not
# Written by Xiuwen Liu for CDA 3100 - Homework #3, problem #2
# Register usage
# $s7 - save $ra
# $s2 - current address of the string to be tested
# $s3 - the next of the last string to be tested 
# $a0 - for function parameter / syscall parameter
# $v0 - syscall number / function return value

    .text
    .globl main
main:
    addu     $s7, $ra, $zero,   # Save the ra
    la  $s2,  test_str          # Load the starting address of the array
    la  $s3, is_pali_msg,       # the next of last address
pali_test_loop: 
    lw  $a0, 0($s2)             # $a0 is the address of the string
    li      $v0, 4              # system call to print a string
    syscall                     # print string
    li      $v0, 4              # print a new line
    la      $a0, newline
    li      $v0, 4 
    syscall
    lw  $a0, 0($s2)             # $a0 is the address of the string
    jal palindrome              # call palindrome
    beq $v0, $zero, pali_no     #if $v0 is 0, it is not a palindrome
    li      $v0, 4              #it is a palindrome
    la      $a0, is_pali_msg
    syscall
    j   pali_test_end
pali_no:                        #it is not a palindrome
    li      $v0, 4 
    la      $a0, not_pali_msg    
    syscall
pali_test_end:
    li      $v0, 4 
    la      $a0, newline
    syscall
    addiu   $s2, $s2, 4
    lw  $a0, 0($s2)
    beq $a0, $s3, pali_done
    j   pali_test_loop    

pali_done:
    li  $v0, 10
    syscall
    addu    $ra, $zero, $s7     #restore $ra since the function calles
                                #another function
    jr      $ra
    add $zero, $zero, $zero
    add $zero, $zero, $zero
########## End of main function #########    

所以这是我的代码:

# My working c++ code
# int arrayLen ( char s[]) {
#    int counter = 0;
#    while(s[counter] != '[=11=]'){
#        if (s[counter] > 64 && s[counter] < 91)
#            s[counter] = s[counter] + 32;
#        counter++;
#    }
#    return counter;
# }
#
# int palindrom(char s[]){
#    int i;
#    int l = arrayLen(s);
#    for(i=0;i<=l/2;i++)
#        if(s[i]!=s[l-i-1]) return 0;
#    return 1;
# }    

palindrome:
    addu    $s4, $ra, $zero     # save $ra
    jal arrayLen                # get string length and set to lowercase
    move    $t0, $zero          # i = 0
    move    $t1, $v1            # l = arrayLen(s)
    srl $t2, $t1, 1             # divide l by 2

palinFor:
    bgt $t0, $t2, palinForExit  # end for loop when i > l/2

    sub $t3, $t1, $t0           # l - i 
    addi    $t3, $t3, -1        # l - i - 1    

    add $t4, $a0, $t0           # s[i]
    add $t5, $a0, $t3           # s[l-i-1]
    addi    $t0, $t0, 1         # i++
    lbu $t4, ($t4)              # load s[i]
    lbu $t5, ($t5)              # load s[l-i-1]
    sne $t6, $t4, $t5           # if not equal, set $t6 to 1
    beq $t6, 1, palinForExit    # leave loop if not equal    

    j   palinFor                # loop again

palinForExit:
    sne     $v0, $t6, $zero     # set return value: 0 for not palindrome, 1 for palindrome
    addu    $ra, $zero, $s4     # restore $ra
    jr  $ra                     # return to function caller


arrayLen:
    li  $t0, 0                  # counter = 0
    sll $t1, $t0, 2             # counter * 4
    add $t1, $t1, $a0           # address of s[counter] in $t1
    lbu     $t2, ($t1)          # load s[counter]
while:
    beq $t2, 0, whileEnd        # skip to end of while loop if s[counter] == [=11=]
    blt     $t2, 64, breakIf    # skip if not uppercase range
    bgt $t2, 91, breakIf        # skip if not uppercase range
    addi    $t2, $t2, 32        # add 32 to make character lowercase
    sw  $t2, ($t1)              # save change to memory
breakIf:
    addi    $t0, $t0, 1         # counter++
whileEnd:
    move    $v1, $t0            # return value of arrayLen is counter
    jr  $ra                     # return to function caller   

这是我的代码停止的地方,下面是测试代码的 .data 部分:

    .data
#The following examples were copied from 
#   http://en.wikipedia.org/wiki/Palindrome
pali1:  
    .asciiz "Socorram me subi no on ibus em Marrocos" #Brazilian Portuguese
pali2:  
    .asciiz "Ein Neger mit Gazelle zagtim Regen nie" #German
pali3:  
    .asciiz "stressed  desserts"
pali4:
    .asciiz "palindromes"
pali5:  
    .asciiz "tattarrattat"
is_pali_msg: 
    .asciiz "    The string is a palindrome."
not_pali_msg: 
    .asciiz "    The string is not a palindrome."
newline:    
    .asciiz "\n"    
test_str:
    .word  pali1, pali2, pali3, pali4, pali5, is_pali_msg

学这些东西我的脑袋疼。不胜感激,谢谢 :D

试试这个:

.text

strlen:
    # ------------
    # arguments:
    # a0 = string
    # ------------

    li      $v0,    0                           #set return value to 0
strlen_loop:
    lb      $t0,    0($a0)                      #load byte from beginning of the string
    beq     $t0,    [=10=],     strlen_exit         #when character value is 0 we have 
                                                #reached the end of the string
    addi    $a0,    $a0,    1                   #shift pointer to string one space right
    addi    $v0,    $v0,    1                   #increment return value by one
    j       strlen_loop

strlen_exit:
    # ------------
    # returns:
    # INTEGER (string length)
    # ------------
    jr      $ra                                 #return

palindrom:
    # ------------
    # arguments:
    # a0 = string
    # ------------

    sub     $sp,    $sp,    8                   #allocate memory on stack
    sw      $ra     0($sp)                      #save return address
    sw      $a0     4($sp)                      #save argumrnt value

    jal     strlen                              #call strlen
    move    $t0,    $v0                         #save result

    lw      $a0     4($sp)                      #load argument
    move    $t1,    $a0                         #save its value to t1

    li      $t2,    1                           #set counter to 1
    li      $v0,    1                           #prepare return value
    div     $t3,    $t0,    2                   #calculate string length / 2
    addi    $t3,    $t3,    1                   #add one more in case of even number
palindrom_loop:
    bge     $t2,    $t3     palindrom_exit      #when counter reaches half of the string length - exit
    lb      $t4,    0($a0)                      #get character from beginning

    sub     $t5,    $t0,    $t2                 #subtract counter from the string length
    add     $t6,    $t5,    $t1                 #add index from the end of the string to start address
    lb      $t7,    0($t6)                      #get corresponding character from the end of the string

    beq     $t4,    $t7,    palindrom_continue  #check to determine are the characters exact match
    li      $v0,    0                           #if not return 0, immediately
    j       palindrom_exit

palindrom_continue:
    addi    $a0,    $a0,    1                   #shift pointer to string one space right
    addi    $t2,    $t2,    1                   #increment counter by one
    j       palindrom_loop

palindrom_exit:
    # ------------
    # returns:
    # TRUE (1) or FALSE (0)
    # ------------
    lw      $ra     0($sp)                      #load return address
    addi    $sp,    $sp,    8                   #free stack
    jr      $ra                                 #return

main:
    #entry point
    la      $a0,    str                         #load string
    jal     palindrom                           #call palindrom

    move    $a0,    $v0                         #set a0 to palindrom return value
    li      $v0,    1                           #set 1 to v0 - as this is system call for print int
    syscall                                     #make the call

    li      $v0,    10                          #set 10 to v0 - as this is system call for exit program
    syscall                                     #make the call

.data
    str: .asciiz "thiispalindrome_emordnilapsiiht"

方法是从字符串的开头获取字符,从字符串的末尾获取对应的字符。如果完全匹配,则继续执行直到计数器达到字符串长度的一半。如果发现任何一对字符不同,立即停止执行并且 return FALSE.

还有一点,我还没有实现大写字母与小写字母没有区别的部分。但这并不难。你可以自己添加。这个想法是测试每个加载的字符,如果它的 ascii 在 A (65) 和 Z (90) 之间。如果是这样,您将向 ascii 值添加 32,您将得到小写字母。