GNU/Linux xterm-256color bash 145 views

/*
Autor: Victor Manuel Madrid Lugo
Fecha: 08/04/2025
Descripción: Cuenta las letras de una cadena ingresada por el usuario
Demostración: [https://asciinema.org/a/ZOMYXiv7JpWTt8WumQ3Zrq4Dl]
*/

/*
Equivalente en C:

#include <stdio.h>
#include <ctype.h>

int main() {
    char buffer[256];
    int contador = 0;
    
    printf("Ingrese una cadena de texto: ");
    fgets(buffer, sizeof(buffer), stdin);
    
    // Contar letras
    for (int i = 0; buffer[i] != '\0'; i++) {
        if ((buffer[i] >= 'A' && buffer[i] <= 'Z') || 
            (buffer[i] >= 'a' && buffer[i] <= 'z')) {
            contador++;
        }
    }
    
    printf("La cadena tiene %d letras.\n", contador);
    return 0;
}
*/

.global _start

.data
prompt:         .asciz "Ingrese una cadena de texto: "
prompt_len = . - prompt

resultado:      .asciz "La cadena tiene "
resultado_len = . - resultado

letras:         .asciz " letras.\n"
letras_len = . - letras

buffer:         .space 256  // Buffer para almacenar la entrada del usuario

.text
_start:
    // Mostrar prompt
    mov x0, #1               // stdout
    ldr x1, =prompt          // mensaje
    mov x2, prompt_len       // longitud
    mov x8, #64              // syscall write
    svc #0
    
    // Leer entrada del usuario
    mov x0, #0               // stdin
    ldr x1, =buffer          // buffer
    mov x2, #256             // tamaño máximo
    mov x8, #63              // syscall read
    svc #0
    
    // x0 contiene bytes leídos (incluyendo salto de línea)
    mov x19, x0              // guardar cantidad de bytes leídos
    
    // Contar solo letras (a-z, A-Z)
    mov x20, #0              // contador de letras
    ldr x21, =buffer         // puntero al buffer
    
contar_loop:
    cmp x19, #0              // ¿Hemos llegado al final?
    beq mostrar_resultado    // Si es 0, terminar conteo
    
    // Cargar byte actual
    ldrb w22, [x21], #1      // cargar byte y avanzar puntero
    sub x19, x19, #1         // decrementar contador de bytes
    
    // Verificar si es una letra
    // Primero comprobar si es A-Z (ASCII 65-90)
    cmp w22, #'A'
    blt no_es_letra
    cmp w22, #'Z'
    ble es_letra
    
    // Comprobar si es a-z (ASCII 97-122)
    cmp w22, #'a'
    blt no_es_letra
    cmp w22, #'z'
    ble es_letra
    b no_es_letra
    
es_letra:
    add x20, x20, #1         // incrementar contador de letras
no_es_letra:
    b contar_loop
    
mostrar_resultado:
    // Mostrar mensaje inicial de resultado
    mov x0, #1               // stdout
    ldr x1, =resultado       // mensaje
    mov x2, resultado_len    // longitud
    mov x8, #64              // syscall write
    svc #0
    
    // Convertir contador a texto y mostrar
    mov x0, x20              // valor a imprimir
    bl print_int
    
    // Mostrar mensaje final
    mov x0, #1               // stdout
    ldr x1, =letras          // mensaje
    mov x2, letras_len       // longitud
    mov x8, #64              // syscall write
    svc #0
    
    // Salir del programa
    mov x0, #0               // código de salida
    mov x8, #93              // syscall exit
    svc #0
    
// Función para imprimir un entero
print_int:
    // Guardar registros
    sub sp, sp, #48
    str x19, [sp, #0]
    str x20, [sp, #8]
    str x21, [sp, #16]
    str x22, [sp, #24]
    str x30, [sp, #32]   // Link register
    
    mov x19, x0         // Guardar el valor a imprimir
    
    // Asignar buffer en la pila
    sub sp, sp, #32     // 32 bytes para el buffer
    mov x21, sp         // x21 = buffer
    
    // Manejar caso especial de 0
    cmp x19, #0
    bne convert_loop
    mov w22, #'0'
    strb w22, [x21]
    mov x20, #1         // Longitud = 1
    b print_digits
    
convert_loop:
    mov x20, #0         // x20 = contador de dígitos
    mov x22, x19        // x22 = valor a convertir
    
    // Obtener dígitos en orden inverso
loop:
    cmp x22, #0
    beq reverse_digits
    mov x0, x22
    mov x1, #10
    udiv x2, x0, x1     // x2 = x0 / 10
    msub x3, x2, x1, x0 // x3 = x0 - (x2 * 10) = x0 % 10
    
    add w3, w3, #'0'    // Convertir a ASCII
    strb w3, [x21, x20] // Guardar en buffer
    add x20, x20, #1    // Incrementar contador
    
    mov x22, x2         // Continuar con el cociente
    b loop
    
reverse_digits:
    // Invertir los dígitos (si hay más de 1)
    cmp x20, #1
    ble print_digits
    
    mov x0, #0          // índice inicio
    sub x1, x20, #1     // índice fin
    
reverse_loop:
    cmp x0, x1
    bge print_digits
    
    ldrb w2, [x21, x0]  // cargar byte de inicio
    ldrb w3, [x21, x1]  // cargar byte de fin
    
    strb w3, [x21, x0]  // intercambiar
    strb w2, [x21, x1]
    
    add x0, x0, #1
    sub x1, x1, #1
    b reverse_loop
    
print_digits:
    // Imprimir los dígitos
    mov x0, #1          // stdout
    mov x1, x21         // buffer
    mov x2, x20         // longitud
    mov x8, #64         // syscall write
    svc #0
    
    // Limpiar y restaurar
    add sp, sp, #32     // liberar buffer
    ldr x19, [sp, #0]
    ldr x20, [sp, #8]
    ldr x21, [sp, #16]
    ldr x22, [sp, #24]
    ldr x30, [sp, #32]  // Link register
    add sp, sp, #48
    ret