GNU/Linux xterm-256color bash 137 views

/*
Autor: Victor Manuel Madrid Lugo
Fecha: 08/04/2025
Descripción: Calcula la secuencia Fibonacci hasta un límite ingresado por el usuario
Demostración: [https://asciinema.org/a/wsOJ9BAXA8rFC7QANIxGeLykN]
*/

/*
# Programa Fibonacci en Python
def fibonacci():
    n = int(input("Ingrese el número de términos Fibonacci a generar: "))
    
    if n <= 0:
        print("Error: Debe ingresar un número positivo.")
        return
    
    a, b = 0, 1
    print(a, end=' ')
    
    if n == 1:
        print()
        return
    
    print(b, end=' ')
    
    for _ in range(2, n):
        c = a + b
        print(c, end=' ')
        a, b = b, c
    
    print()  # Nueva línea al final

fibonacci()
*/


.section .data
    msg_prompt: .asciz "Ingrese el número de términos Fibonacci: "
    msg_error:  .asciz "Error: Entrada inválida (debe ser ≥1)\n"
    msg_space:  .asciz " "
    msg_newline: .asciz "\n"
    buffer:     .skip 32        // Buffer ampliado para entrada

.section .text
.global _start

_start:
    // Solicitar entrada
    mov x0, #1
    ldr x1, =msg_prompt
    mov x2, #42         // Longitud exacta del mensaje
    mov x8, #64         // syscall write
    svc #0

    // Leer entrada
    mov x0, #0
    ldr x1, =buffer
    mov x2, #32         // Tamaño del buffer
    mov x8, #63         // syscall read
    svc #0

    // Convertir a entero
    ldr x0, =buffer
    bl atoi
    mov x19, x0         // Guardar n términos en x19

    // Validar entrada (n ≥ 1)
    cmp x19, #1
    b.ge init_fib
    mov x0, #1
    ldr x1, =msg_error
    mov x2, #33         // Longitud del mensaje error
    mov x8, #64
    svc #0
    b exit

init_fib:
    // Inicializar Fibonacci
    mov x20, #0         // F(0) = 0
    mov x21, #1         // F(1) = 1
    mov x22, #1         // Contador

    // Imprimir F(0)
    mov x0, x20
    bl print_num
    bl print_space

    // Si solo quiere 1 término
    cmp x19, #1
    b.eq finish

    // Imprimir F(1)
    mov x0, x21
    bl print_num
    bl print_space

fib_loop:
    // Calcular siguiente término
    add x23, x20, x21   // F(n) = F(n-1) + F(n-2)

    // Imprimir término actual
    mov x0, x23
    bl print_num
    bl print_space

    // Actualizar valores
    mov x20, x21
    mov x21, x23

    // Incrementar contador
    add x22, x22, #1
    cmp x22, x19
    b.lt fib_loop

finish:
    bl print_newline

exit:
    // Salir correctamente
    mov x0, #0
    mov x8, #93
    svc #0

// ========== FUNCIONES AUXILIARES (CORREGIDAS) ==========

// atoi: Convierte string a entero (maneja errores)
atoi:
    mov x1, #0          // Resultado
    mov x3, #10         // Base 10
    mov x4, #0          // Signo (0=positivo)

    // Primer carácter
    ldrb w2, [x0], #1
    cmp w2, #'-'
    b.ne check_digit
    mov x4, #1          // Es negativo
    ldrb w2, [x0], #1   // Siguiente carácter

check_digit:
    // Verificar si es dígito
    cmp w2, #'0'
    b.lt atoi_error
    cmp w2, #'9'
    b.gt atoi_error

atoi_loop:
    // Convertir y acumular
    sub w2, w2, #'0'
    mul x1, x1, x3
    add x1, x1, x2

    // Siguiente carácter
    ldrb w2, [x0], #1
    cmp w2, #10         // Salto de línea
    b.eq atoi_done
    cmp w2, #0          // Null terminator
    b.eq atoi_done
    
    // Verificar dígito
    cmp w2, #'0'
    b.lt atoi_error
    cmp w2, #'9'
    b.gt atoi_error
    b atoi_loop

atoi_done:
    // Aplicar signo
    cbz x4, atoi_ok
    neg x1, x1

atoi_ok:
    mov x0, x1
    ret

atoi_error:
    mov x0, #-1         // Valor de error
    ret

// print_num: Imprime número en x0 (Versión corregida)
print_num:
    stp x29, x30, [sp, #-32]!  // Ajuste de alineación a 16 bytes
    mov x29, sp

    // Buffer local (19 dígitos para 64 bits + signo + null)
    sub sp, sp, #20
    mov x1, sp

    // Manejo especial para 0
    cbz x0, print_zero

    // Manejar negativos
    cmp x0, #0
    b.gt positive
    neg x0, x0
    mov w2, #'-'
    strb w2, [x1], #1

positive:
    mov x2, #10
    mov x3, #0          // Contador dígitos

digit_loop:
    udiv x4, x0, x2     // Dividir por 10
    msub x5, x4, x2, x0 // Obtener residuo
    add x5, x5, #'0'    // ASCII
    strb w5, [x1, x3]   // Almacenar
    add x3, x3, #1
    mov x0, x4
    cbnz x0, digit_loop

    // Invertir dígitos
    mov x4, #0          // Inicio
    sub x5, x3, #1      // Fin

reverse:
    cmp x4, x5
    b.ge print
    ldrb w6, [x1, x4]
    ldrb w7, [x1, x5]
    strb w7, [x1, x4]
    strb w6, [x1, x5]
    add x4, x4, #1
    sub x5, x5, #1
    b reverse

print_zero:
    mov w2, #'0'
    strb w2, [x1]
    mov x3, #1

print:
    // Imprimir
    mov x0, #1          // stdout
    sub x1, x1, x3      // Ajustar puntero
    add x3, x3, #1      // Incluir posible signo
    mov x2, x3          // Longitud
    mov x8, #64         // write
    svc #0

    // Restaurar stack
    add sp, sp, #20
    ldp x29, x30, [sp], #32
    ret

print_space:
    stp x29, x30, [sp, #-16]!
    mov x0, #1
    ldr x1, =msg_space
    mov x2, #1
    mov x8, #64
    svc #0
    ldp x29, x30, [sp], #16
    ret

print_newline:
    stp x29, x30, [sp, #-16]!
    mov x0, #1
    ldr x1, =msg_newline
    mov x2, #1
    mov x8, #64
    svc #0
    ldp x29, x30, [sp], #16
    ret