簡體   English   中英

MIPS中的遞歸-Pascal三角形

[英]Recursivity in MIPS - Pascal triangle

我正在做一個Pascal Triangle來練習MIPS,但是當我必須執行遞歸函數時,我的代碼就會中斷。 我不知道要做代碼中標記的return語句:

首先,我將顯示我正在翻譯的C代碼,最后,您可能會看到沖突的return語句(已標記)

// C Language

#include <stdio.h>

int trianguloPascal(int i, int k);

int main(void) {
    int num, i, j, k;

    printf("Introduce el número de filas: ");
    scanf("%i", &num);

    for (i = 0; i < num; i++) {
        for (j = num; j > i; j--) {
            printf("   ");
        }
        for (k = 0; k <= i; k++) {
            printf("%6d", trianguloPascal(i, k));
        }
        printf("\n");
    }

    return 0;
}

int trianguloPascal(int i, int k) {
    if ((i == 0) || (k == 0) || (i == k)) {
        return 1;
    } else {
///////////////////////////////////
// THIS IS THE CONFLCTING RETURN //
///////////////////////////////////
        return (trianguloPascal(i-1, k-1) + trianguloPascal(i-1, k));
    }
}

現在,我將顯示MIPS代碼,最后,您在嘗試執行此沖突的return語句時會看到沖突(已標記)

// MIPS Languaje
    .data
var_i:              .word 0
var_j:              .word 0
var_k:              .word 0
var_num:            .space 4
msg_pedirNumeroFilas:       .asciiz "Introduce el número de filas: "
msg_espacioCorto:           .asciiz "   "
msg_espacioLargo:           .asciiz "      "
msg_saltoDeLinea:           .asciiz "\n"

    .text
# Función principal del programa
MAIN:   
    # Mostrar el mensaje de pedir un número de filas                
    la $a0, msg_pedirNumeroFilas        # Cargamos la cadena de texto que vamos a mostrar
    li $v0, 4               # Cargar en $v0 la llamada al sistema para 'Mostrar String'
    syscall                 # Ejecutar la llamada al sistema
    # Recoger el número de filas que desea el usuario               
    li $v0, 5               # Cargar en $v0 la llamada al sistema para 'Recoger Int'
    syscall                 # Ejecutar la llamada al sistema
    # Guardar en memoria el número de filas obtenido    
    sw $v0, var_num             # Guardar en 'num' el número recogido anteriormente

    # Cargamos de memoria las variables, almacenándolas en variables salvadas
    lw $s0, var_i               # Guardamos en $s0 la variable var_i
    lw $s1, var_j               # Guardamos en $s1 la variable var_j
    lw $s2, var_k               # Guardamos en $s2 la variable var_k
    lw $s3, var_num             # Guardamos en $s2 la variable var_num
    # Guardamos en pila los valores de i, j, k, num
    addi $sp, $sp, -16
    sw $s0, 0($sp)          
    sw $s1, 4($sp)
    sw $s2, 8($sp)
    sw $s3, 12($sp)

    # for (i = 0; i < num; i++)
    li $s0, 0                   # i = 0 para cada inicio del bucle FOR_I
    FOR_I:
    bge $s0, $s3, END_FOR_I             # (i >= num) ? GOTO END_FOR_I : CONTINUE

        # for (j = num; j > i; j--) {
        move $s1, $s3               # j = num para cada inicio del bucle FOR_J
        FOR_J:
        ble $s1, $s0, END_FOR_J         # (j <= i) ? GOTO END_FOR_J : CONTINUE
            # Imprimir los espacios 
            la $a0, msg_espacioCorto    # Cargamos la cadena de texto que vamos a mostrar
            li $v0, 4           # Cargar en $v0 la llamada al sistema para 'Mostrar String'
            syscall             # Ejecutar la llamada al sistema
        addi $s1, $s1, -1           # j -= 1
        j FOR_J                 # Volvemos al bucle FOR_J
        END_FOR_J: 

        # for (k = 0; k <= i; k++) {
        li $s2, 0               # k = 0 para cada inicio del bucle FOR_K
        FOR_K:
        bgt $s2, $s0, END_FOR_K         # (k > i) ? GOTO END_FOR_K : CONTINUE
            # Imprimir los espacios 
            la $a0, msg_espacioLargo    # Cargamos la cadena de texto que vamos a mostrar
            li $v0, 4           # Cargar en $v0 la llamada al sistema para 'Mostrar String'
            syscall             # Ejecutar la llamada al sistema
            # Llamada a la función recursiva
            move $a0, $s0           # Pasar como primer agumento i
            move $a1, $s2           # Pasar como segundo agumento k
            jal TRIANGULO_PASCAL        # Llamada a triangulo_pascal(i, k)
            # Imprimir resultado devuelto
            move $a0, $v0           # Cargamos la cadena de texto que vamos a mostrar
            li $v0, 1           # Cargar en $v0 la llamada al sistema para 'Mostrar Int'
            syscall             # Ejecutar la llamada al sistema

        addi $s2, $s2, 1            # k += 1
        j FOR_K                 # Volvemos al bucle FOR_K
        END_FOR_K: 

    # Imprimir un salto de línea            
    la $a0, msg_saltoDeLinea        # Cargamos la cadena de texto que vamos a mostrar
    li $v0, 4               # Cargar en $v0 la llamada al sistema para 'Mostrar String'
    syscall                 # Ejecutar la llamada al sistema

    addi $s0, $s0, 1            # i += 1
    j FOR_I                 # Volvemos al bucle FOR_I
    END_FOR_I:

    # Cargamos de pila los valores de i, j, k, num
    lw $s0, 0($sp)          
    lw $s1, 4($sp)
    lw $s2, 8($sp)
    lw $s3, 12($sp)
    addi $sp, $sp, 16

    EXIT:                   # Salir del programa
        li $v0, 10          # Cargar en $v0 la llamada al sistema para 'Salir'
        syscall             # Ejecutar la llamada al sistema
    END_EXIT:
END_MAIN:

# Función que obtiene los dígitos del triángulo de Pascal
TRIANGULO_PASCAL:           
    IF:                     # ((i == 0) || (k == 0) || (i == k)) ? GOTO ELSE : CONTINUE
    beq $a0, 0, MULTIPLE_CONDITION_OK   # (i == 0) ? GOTO MULTIPLE_CONDITION_OK : CONTINUE      
    beq $a1, 0, MULTIPLE_CONDITION_OK   # (k == 0) ? GOTO MULTIPLE_CONDITION_OK : CONTINUE          
    bne $a0, $a1, ELSE          # (i != k) ? GOTO ELSE : CONTINUE   
    MULTIPLE_CONDITION_OK:
        li $v0, 1           # return 1
    jr $ra
    ELSE:
############################################
##### HERE I TRY DO RECURSIVE FUNCTION #####
############################################
    move $t0, $a0
    move $t1, $a1

    addi $a0, $t0, -1           # i-1
    addi $a1, $t1, 0            # k
    j TRIANGULO_PASCAL
    move $t5, $v0
    addi $a0, $t0, -1           # i-1
    addi $a1, $t1, -1           # k-1
    j TRIANGULO_PASCAL
    move $t6, $v0

    add $t7, $t5, $t6
    move $t7, $v0               # return $t7
    jr $ra                  # Volvemos a la línea después de la llamada
    END_IF_ELSE:
END_TRIANGULO_PASCAL:

知道我該如何解決嗎? 我已經搜索信息很長時間了,但無法解決。

謝謝。

PD:兩種代碼均為MCVE,因此將復制粘貼運行。



編輯1:

正如@Jester所建議的那樣,我已更改了C遞歸返回語句,例如:

  int trianguloPascal(int i, int k) { if ((i == 0) || (k == 0) || (i == k)) { return 1; } else { /////////////////////////////////// // THIS IS THE CONFLCTING RETURN // /////////////////////////////////// int tmp = 0; tmp = trianguloPascal(i-1, k-1); tmp += trianguloPascal(i-1, k); return (tmp); } } 

並且更新的TrianglePascalFunction MIPS代碼為:

 TRIANGULO_PASCAL: IF: # ((i == 0) || (k == 0) || (i == k)) ? GOTO ELSE : CONTINUE beq $a0, 0, MULTIPLE_CONDITION_OK # (i == 0) ? GOTO MULTIPLE_CONDITION_OK : CONTINUE beq $a1, 0, MULTIPLE_CONDITION_OK # (k == 0) ? GOTO MULTIPLE_CONDITION_OK : CONTINUE bne $a0, $a1, ELSE # (i != k) ? GOTO ELSE : CONTINUE MULTIPLE_CONDITION_OK: li $v0, 1 # return 1 jr $ra ELSE: li $t8, 0 # int tmp = 0 move $t0, $a0 # $t0 = i move $t1, $a1 # $t1 = k addi $a0, $t0, -1 # i-1 addi $a1, $t1, -1 # k-1 j TRIANGULO_PASCAL add $t8, $t8, $v0 addi $a0, $t0, -1 # i-1 addi $a1, $t1, 0 # k j TRIANGULO_PASCAL add $t8, $t8, $v0 move $v0, $t8 # return $t8 jr $ra # Volvemos a la línea después de la llamada END_IF_ELSE: END_TRIANGULO_PASCAL: 

通過此代碼獲得的結果是:

  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 

因此,我在ELSE語句中出現錯誤,該錯誤始終返回1。為什么會這樣? 任何想法?

最終,我實現了MIPS代碼能夠正常工作。 我將展示如何做到這一點:

    .data
var_i:              .word 0
var_j:              .word 0
var_k:              .word 0
var_num:            .space 4
msg_pedirNumeroFilas:       .asciiz "Input number of rows: "
msg_espacioCorto:           .asciiz "   "
msg_espacioLargo:           .asciiz "      "
msg_saltoDeLinea:           .asciiz "\n"

    .text
# Función principal del programa
MAIN:   
    # Show message "InputNumRows"               
    la $a0, msg_pedirNumeroFilas        
    li $v0, 4               
    syscall                 
    # Get number of rows                
    li $v0, 5               
    syscall                 
    # Save in memory this number of rows    
    sw $v0, var_num             

    # Store in saved var our program variables
    lw $s0, var_i               # Save in $s0 var_i
    lw $s1, var_j               # Save in $s1 var_j
    lw $s2, var_k               # Save in $s2 var_k
    lw $s3, var_num             # Save in $s2 var_num
    # Save in stack i, j, k, num
    addi $sp, $sp, -16
    sw $s0, 0($sp)          
    sw $s1, 4($sp)
    sw $s2, 8($sp)
    sw $s3, 12($sp)

    # for (i = 0; i < num; i++)
    li $s0, 0                   # i = 0 
    FOR_I:
    bge $s0, $s3, END_FOR_I             # (i >= num) ? GOTO END_FOR_I : CONTINUE

        # for (j = num; j > i; j--) {
        move $s1, $s3               # j = num 
        FOR_J:
        ble $s1, $s0, END_FOR_J         # (j <= i) ? GOTO END_FOR_J : CONTINUE
            # Print spaces  
            la $a0, msg_espacioCorto    
            li $v0, 4           
            syscall             
        addi $s1, $s1, -1           # j -= 1
        j FOR_J                 # GOTO FOR_J
        END_FOR_J: 

        # for (k = 0; k <= i; k++) {
        li $s2, 0               # k = 0 
        FOR_K:
        bgt $s2, $s0, END_FOR_K         # (k > i) ? GOTO END_FOR_K : CONTINUE
            # Print spaces
            la $a0, msg_espacioLargo    
            li $v0, 4           
            syscall             
            # Llamada a la función recursiva
            move $a0, $s0           # Pass as first argument i
            move $a1, $s2           # Pass as second argument k
            jal TRIANGULO_PASCAL        # Call to triangulo_pascal(i, k)
            # Print returned result
            move $a0, $v0           
            li $v0, 1           
            syscall             

        addi $s2, $s2, 1            # k += 1
        j FOR_K                 # GOTO FOR_K
        END_FOR_K: 

    # Print \n          
    la $a0, msg_saltoDeLinea        
    li $v0, 4               
    syscall                 

    addi $s0, $s0, 1            # i += 1
    j FOR_I                 # GOTO FOR_I
    END_FOR_I:

    # Load from stack i, j, k, num
    lw $s0, 0($sp)          
    lw $s1, 4($sp)
    lw $s2, 8($sp)
    lw $s3, 12($sp)
    addi $sp, $sp, 16

    EXIT:                   # Exit program
        li $v0, 10          
        syscall             
    END_EXIT:
END_MAIN:

# Pascal triangle function
TRIANGULO_PASCAL:   
    # Save in stack
    addi $sp, $sp, -20 
    sw   $ra, 0($sp)                # Save StackPointer 
    sw   $s0, 4($sp)                # Save i
    sw   $s1, 8($sp)                # Save j
    sw   $s2, 12($sp)               # Save returned value of trianguloPascal(i-1, k-1)
    sw   $s3, 16($sp)               # ave returned value of trianguloPascal(i-1, k)

    move $s0, $a0                   # $s0 = i actual ((i-1), ((i-1)-1), ...)
    move $s1, $a1                   # $s1 = k actual ((k-1), ((k-1)-1), k, ...)

    IF:                         # ((i == 0) || (k == 0) || (i == k)) ? GOTO ELSE : CONTINUE
    beq $s0, 0, RETURN_1                # (i == 0) ? GOTO RETURN_1 : CONTINUE       
    beq $s1, 0, RETURN_1                # (k == 0) ? GOTO RETURN_1 : CONTINUE           
    bne $s0, $s1, ELSE              # (i != k) ? GOTO ELSE : CONTINUE   

        RETURN_1:
            li $v0, 1           # return (1)
            j END_TRIANGULO_PASCAL      # GOTO END_TRIANGULO_PASCAL
        END_RETURN_1:

    ELSE:
    addi $a0, $s0, -1               # i-1
    addi $a1, $s1, -1               # k-1
    jal TRIANGULO_PASCAL                # Call to trianguloPascal(i-1, k-1)
    add $s2, $zero, $v0                     # $s2 = trianguloPascal(i-1, k-1)

    addi $a0, $s0, -1               # i-1
    addi $a1, $s1, 0                # k
    jal TRIANGULO_PASCAL                # Call to trianguloPascal(i-1, k)
    add $s3, $zero, $v0                 # $s3 = trianguloPascal(i-1, k)

    add $v0, $s2, $s3                       # return (trianguloPascal(i-1, k-1) + trianguloPascal(i-1, k))
    END_IF_ELSE:

END_TRIANGULO_PASCAL:
    # Load from stack
    lw   $ra, 0($sp)     
    lw   $s0, 4($sp)
    lw   $s1, 8($sp)
    lw   $s2, 12($sp)
    lw   $s3, 16($sp)
    addi $sp, $sp, 20     
    jr $ra                      # Return to $ra

我希望它對與我有同樣問題的其他人有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM