Mips 代码出现错误
Mips code with bug on the occurrences
我找到了解决我的练习的方法,但我的代码有一个错误...有些短语效果很好,有些则不行...我用 2 个例子解释得更好:
- aaaaabc ---> 字母 '' 出现次数最多,是现在时间。
- 世界,您好! ---> 字母 'l' 出现次数最多,出现了 3 次。
这是我的代码,可能是我对'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
我找到了解决我的练习的方法,但我的代码有一个错误...有些短语效果很好,有些则不行...我用 2 个例子解释得更好:
- aaaaabc ---> 字母 '' 出现次数最多,是现在时间。
- 世界,您好! ---> 字母 'l' 出现次数最多,出现了 3 次。
这是我的代码,可能是我对'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