/*
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