Mips 代码出现错误

Mips code with bug on the occurrences

我找到了解决我的练习的方法,但我的代码有一个错误...有些短语效果很好,有些则不行...我用 2 个例子解释得更好:

这是我的代码,可能是我对'a'字母的控制有问题

.data
m1: .asciiz "Inserisci una stringa: "
m2: .asciiz "\nLa lettera '"
m3: .asciiz "' è quella con più occorrenze, cioè è presente "
m4: .asciiz " volte."
     .align 2
myArray: .space 104  #Array di contatori

.text
.globl main

main:
#Stampo messaggio
li $v0, 4
la $a0, m1
syscall

#Alloco spazio per la stringa in ingresso
addi $sp, $sp, -256

#Salvo sp
move $s0, $sp

#Leggo una stringa fino all'invio
move $a0, $sp
li $a1, 255
li $v0, 8
syscall

#Passo parametri alla funzione
move $a0, $s0

#vado alla funzione
jal analizza_stringa

#Passo i parametri alla funzione
move $a0, $v0 #codice lettera
move $a1, $v1 #occorrenze

#vado alla funzione
jal stampa_risultato


end_program:

#Termino il programma
li $v0, 10
syscall


analizza_stringa:

#Faccio una copia di $a0 che servira per il loop
#piu interno mentre quello presente in a0
#serve per il loop piu esterno e dato che hanno due incrementi diversi
#ne uso due
move $t7, $s0

while_string:

# preleva un carattere (byte) dal messaggio
lb $t0, ($a0)

# N.B. la stringa (.asciiz) termina con "0"
beq $t0, $zero, check_best 

#Se trova "invio" esce dal ciclo
beq $t0, 10, check_best

#Ricavo l'indice dell'array
subi $t3, $t0, 97

#Moltiplico per 4 perche ogni cella di memoria ha 4 byte
mul $t4, $t3, 4

#Sposto $s0(=a0 inizialmente) in un registro di appoggio altrimenti
#mi altera le iterazioni per il primo loop
move $t6, $t7

    while_occorrenza:
         #quando finisce la stringa esci dal ciclo
         beq $t1, 10, continue

         #prelevo dallo stack un dato
         lb $t1,($t6) 

         #Controllo l'occorrenza
         bne $t1, $t0, continue2 

         #Conto occorrenza
         addi $t5, $t5, 1

         continue2: 
         #Incrementare il puntatore alla stringa
         addi $t6, $t6, 1

         #Ripeto
         j while_occorrenza

    continue:
    #Metto il dato nella posizone calcolata
    sw $t5, myArray($t4)

    #Azzero t5
    li $t5, 0

    #Azzero t3
    li $t3, 0

    #Azzero t1
    li $t1, 0   

    # punta al carattere successivo
    addi $a0, $a0, 1

    # ripeti il ciclo
    j while_string

check_best:

#inizializzo t0
li $t0, 0

#Carico il primo valore
lw $t1, myArray($t0)

#Incremento il puntatore all'array
addi $t0, $t0, 4

while_check_best:
    #Quando t0 ha visitato tutto l'array, esce
    beq $t0, 104, exit_check

    #contatore per ottenere la lettera
    addi $t5, $t5, 1

    #Carico in t4 il numero in t0
    lw $t4, myArray($t0)    

    #Effettuo il controllo sui caratteri  ---> ex bgt
    bge $t4, $t1, scambia #se t1>t4 non fai nulla


    #Ripeto il giro
    j continue_check

    scambia:
        #Controllo adesso, se la lettera letta
        #ha un numero di occorrenze maggiore di 
        #quella che ho gia salvato in t2 (cioe letta prima)
        blt $t4, $t2, continue_check  

        #Contiene il carattere letto nel ciclo
        #che è piu grande di quello letto fuori
        #dal ciclo
        move $t2, $t4

        #calcolo lettera
        add $t3, $t5, 97

    continue_check:
    #Incremento il puntatore dell'array
    addi $t0, $t0, 4

    #Ripeto
    j while_check_best

exit_check:
    #Passo per convenzione al chiamante il codice della lettera
    move $v0, $t3

    #ed il numero delle occorrenze
    move $v1, $t2 

    #ritorno al chiamante
    jr $ra


stampa_risultato:
#Salvo il codice ascii della lettera 
#ottenuta
move $t0, $a0

#Stampo il primo messaggio
li $v0, 4
la $a0, m2
syscall

#Stampo la lettera tramite codice ascii
li $v0, 11
move $a0, $t0
syscall

#Stampo il secondo messaggio
li $v0, 4
la $a0, m3
syscall

#Stampo numero di occorrenze
li $v0, 1
move $a0, $a1 #recupero il dato passato alla funzione in a1
syscall

#Stampo ultimo messaggio
li $v0, 4
la $a0, m4
syscall

#ritorno al chiamante
jr $ra

其他的解释,可以看我下面这个post。非常感谢。

编辑: 也许问题真的在 'a' 字母上,如果它是问题的话,因为如果我尝试 'a' 我没有结果(描述中的第一点),所有其他字母是(第二点)在描述中)

因为您只发布了少量代码(即仅扫描出现次数最多的 table 频率),所以很难推测您的 true/full 意图。

由于您的程序中有很多 发布,因此从头开始重新编码频率扫描部分更容易。这是一个工作程序,我相信 满足您的要求:

    .data

    .align  4
freq:   .space  1024                # frequency table
ibuf:   .space  800                 # input buffer

msg_prompt: .asciiz "Enter phrase: "
msg_hi1:    .asciiz "The letter '"
msg_hi2:    .asciiz "' has the largest number of occurrences, is present "
msg_hi3:    .asciiz " times.\n"

    .text
    .globl  main
main:
    # prompt user
    li      $v0,4
    la      $a0,msg_prompt
    syscall

    # get input string
    li      $v0,8
    la      $a0,ibuf
    li      $a1,800
    syscall

    # exit program if empty line given
    lbu     $v0,0($a0)
    li      $v1,0x0A
    beq     $v0,$v1,main_exit

    jal     freqcalc                # calculate frequency table
    jal     freqbest                # get best entry
    j       main                    # get another

main_exit:
    li      $v0,10
    syscall

# freqcalc -- calculate frequency
#
# registers:
#   t0 -- current input char value
#   t1 -- miscelaneous
#   t5 -- frequency table current pointer
#   t6 -- current buffer pointer
#   t7 -- frequency table base pointer
freqcalc:
    la      $t7,freq                # get base address of frequency table

    # reset all entries
    li      $t6,256                 # number of entries
    move    $t5,$t7                 # point to table start
freqcalc_zero:
    sw      $zero,0($t5)            # reset entry
    addiu   $t5,$t5,4               # point to next entry
    subi    $t6,$t6,1               # decrement remaining count
    bgtz    $t6,freqcalc_zero

    la      $t6,ibuf                # point to input buffer

freqcalc_loop:
    lbu     $t0,0($t6)              # get current char
    addiu   $t6,$t6,1               # point to next buffer char
    beqz    $t0,freqcalc_done       # at end? if yes, fly

    subu    $t1,$t0,0x61            # subtract 'a'
    bltz    $t1,freqcalc_loop       # reject if too low
    li      $t2,26
    bge     $t1,$t2,freqcalc_loop   # reject if beyond 'z'

    sll     $t5,$t0,2               # get word offset
    add     $t5,$t7,$t5             # point to frequency table entry

    lw      $t0,0($t5)              # get entry value
    addi    $t0,$t0,1               # increment
    sw      $t0,0($t5)              # update entry value

    j       freqcalc_loop

freqcalc_done:
    jr      $ra

# freqbest -- find largest occurrence
#
# RETURNS:
#   t3 -- best letter offset
#   t4 -- best letter frequency
#
# registers:
#   t0 -- current frequency count value
#   t5 -- current letter offset
#   t6 -- number of remaining entries
#   t7 -- frequency table pointer
freqbest:
    la      $t7,freq                # get base address of frequency table
    li      $t6,256                 # number of frequency entries
    li      $t5,0                   # starting letter offset

    li      $t3,0                   # prime the best letter offset
    lw      $t4,0($t7)              # prime the best frequency count

freqbest_loop:
    lw      $t0,0($t7)              # get current frequency count
    ble     $t0,$t4,freqbest_next   # got a higher number? if no, fly

    move    $t4,$t0                 # remember better frequency count
    move    $t3,$t5                 # remember better letter

freqbest_next:
    addiu   $t7,$t7,4               # point to next frequency count
    addi    $t5,$t5,1               # advance letter offset
    subiu   $t6,$t6,1               # bump down count
    bgtz    $t6,freqbest_loop       # at end? if no, loop

freqbest_done:
    beqz    $t3,freqbest_exit       # bug out if no applicable chars matched

    li      $v0,4
    la      $a0,msg_hi1
    syscall

    # print letter with highest frequency
    li      $v0,11
    move    $a0,$t3
    syscall

    li      $v0,4
    la      $a0,msg_hi2
    syscall

    # print frequency count
    li      $v0,1
    move    $a0,$t4
    syscall

    li      $v0,4
    la      $a0,msg_hi3
    syscall

freqbest_exit:
    jr      $ra