MIPS 中的递归 - 帕斯卡三角形

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 递归 return 语句更改为:

    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 语句中有问题,它总是 return 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

希望对和我有同样问题的人有用。