GNU/Linux xterm bash 84 views

📌 Demostración: Contar frecuencia de caracteres en una cadena en ARM64 Assembly

💻 Lenguajes de Interfaz en TECNM Campus ITT
👨‍💻 Autor: Alejandro Suarez Sandoval
📅 Fecha: 2025/04/08

🎯 Descripción

Este programa cuenta la frecuencia de cada carácter de una cadena dada.
La implementación se realiza en:

Assembly ARM64 para RaspbianOS en Raspberry Pi

🔧 Compilación en Raspberry Pi (ARM64)

as frecuencia_caracter.s -o frecuencia_caracter.o  
ld frecuencia_caracter.o -o frecuencia_caracter

▶️ Ejecución

./frecuencia_caracter

👀 Código fuente

🔗 Código fuente en Gist: Programa 18 Contador de Frecuencia de Caracteres Código Assembly ARM64 para RaspbianOS

/*
 ______  ____               ____  __ __      
/\  _  \/\  _`\   /'\_/`\  /'___\/\ \\ \     
\ \ \L\ \ \ \L\ \/\      \/\ \__/\ \ \\ \    
 \ \  __ \ \ ,  /\ \ \__\ \ \  _``\ \ \\ \_  
  \ \ \/\ \ \ \\ \\ \ \_/\ \ \ \L\ \ \__ ,__\
   \ \_\ \_\ \_\ \_\ \_\\ \_\ \____/\/_/\_\_/
    \/_/\/_/\/_/\/ /\/_/ \/_/\/___/    \/_/  
                                             
♡ ∩_∩ 
(„• ֊ •„)♡
| ̄U U ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄| 
| • Lenguajes de Interfaz en TECNM Campus ITT                            |   
| • Autor: Alejandro Suarez Sandoval                                     | 
| • Fecha: 2025/04/08                                                    | 
| • Descripción: Programa que cuenta la frecuencia de caracteres en      | 
|   una cadena en Rust y Assembly ARM64 para RaspbianOS.                 | 
| • Demostración:                                                        |
|   https://asciinema.org/a/713375                                       |
| • Compilación (Raspberry Pi ARM64):                                    |  
|     as frecuencia_caracter.s -o frecuencia_caracter.o                  |  
|     ld frecuencia_caracter.o -o frecuencia_caracter                    |  
| • Ejecución: ./frecuencia_caracter                                     |  
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄                                        

⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂ ⠂⠄⠄⠂☆
═════════•°• Demostración Código en lenguaje Rust •°•═══════

use std::collections::HashMap;

fn main() {
    let input_text = "A mi me gusta mucho jugar overwatch y escuchar a the boyz.\n";
    
    println!("Analizando frecuencia de caracteres en el texto:");
    println!("{}", input_text);
    
    let mut char_counts = HashMap::new();
    
    for c in input_text.chars() {
        if c.is_ascii() {
            *char_counts.entry(c).or_insert(0) += 1;
        }
    }
    
    println!("\nResultados (mostrando caracteres con frecuencia > 0):");
    
    let mut sorted_chars: Vec<_> = char_counts.keys().collect();
    sorted_chars.sort();
    
    for &c in sorted_chars {
        let count = char_counts.get(&c).unwrap();
        println!("Carácter '{}': {}", c, count);
    }
}

════════════════════•°• ☆ •°•══════════════════════════════
/*

/* ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂ ⠂⠄⠄⠂☆
═════════════•°• Código en ARM64 Assembly •°•═════════════ */

.global _start      // Punto de entrada global

.data
// Texto para analizar
input_text:
    .ascii "A mi me gusta mucho jugar overwatch y escuchar a the boyz.\n"
text_length = . - input_text

// Mensajes
msg_intro:
    .ascii "Analizando frecuencia de caracteres en el texto:\n"
msg_intro_len = . - msg_intro

msg_results:
    .ascii "\nResultados (mostrando caracteres con frecuencia > 0):\n"
msg_results_len = . - msg_results

msg_char:
    .ascii "Carácter '"
msg_char_len = . - msg_char

msg_freq:
    .ascii "': "
msg_freq_len = . - msg_freq

newline:
    .ascii "\n"
newline_len = . - newline

// Arreglo para contar la frecuencia (128 posiciones para cubrir ASCII)
.align 4            // Asegurar alineamiento adecuado
char_counts:
    .skip 128 * 4   // 4 bytes por contador (word)

// Búfer para convertir números a texto
buffer:
    .skip 20

.text
_start:
    // Mostrar mensaje de introducción
    mov x0, #1
    adr x1, msg_intro
    mov x2, #msg_intro_len
    mov x8, #64
    svc #0
    
    // Mostrar el texto a analizar
    mov x0, #1
    adr x1, input_text
    mov x2, #text_length
    mov x8, #64
    svc #0
    
    // Inicializar el array de conteo a cero
    adr x19, char_counts   // Dirección del array de contadores
    mov x20, #0           // Índice para inicialización
    
init_counts:
    cmp x20, #128
    b.ge count_chars
    
    // Poner a cero cada contador
    str wzr, [x19, x20, lsl #2]  // char_counts[i] = 0
    add x20, x20, #1
    b init_counts
    
count_chars:
    adr x19, input_text   // Dirección del texto
    mov x20, #0          // Índice para recorrer el texto
    adr x21, char_counts  // Dirección del array de contadores
    
count_loop:
    // Comprobar si hemos llegado al final del texto
    cmp x20, #text_length
    b.ge show_results
    
    // Cargar el carácter actual
    ldrb w22, [x19, x20]  // w22 = carácter actual
    
    // Si es ASCII válido (< 128), incrementar su contador
    cmp w22, #128
    b.ge next_char
    
    // Incrementar el contador para este carácter
    lsl x23, x22, #2      // x23 = índice * 4 (tamaño de word)
    ldr w24, [x21, x23]   // w24 = valor actual del contador
    add w24, w24, #1      // w24 = w24 + 1
    str w24, [x21, x23]   // Guardar valor incrementado
    
next_char:
    add x20, x20, #1      // Incrementar índice
    b count_loop
    
show_results:
    // Mostrar mensaje de resultados
    mov x0, #1
    adr x1, msg_results
    mov x2, #msg_results_len
    mov x8, #64
    svc #0
    
    // Recorrer el array de contadores para mostrar resultados
    mov x20, #32         // Empezar por espacio (ASCII 32)
    mov x25, #127        // Terminar en DEL (ASCII 127)
    
show_loop:
    // Verificar si hemos llegado al final
    cmp x20, x25
    b.gt exit_program
    
    // Obtener la frecuencia para este carácter
    lsl x23, x20, #2     // x23 = índice * 4
    ldr w24, [x21, x23]  // w24 = frecuencia
    
    // Si la frecuencia es 0, pasar al siguiente carácter
    cbz w24, next_result
    
    // Mostrar: "Carácter 'X': "
    mov x0, #1
    adr x1, msg_char
    mov x2, #msg_char_len
    mov x8, #64
    svc #0
    
    // Reservar espacio en la pila y alinear
    sub sp, sp, #16
    
    // Guardar el carácter en la pila
    strb w20, [sp]
    
    // Mostrar el carácter
    mov x0, #1
    mov x1, sp           // Dirección del carácter en la pila
    mov x2, #1           // Longitud: 1 carácter
    mov x8, #64
    svc #0
    
    // Restaurar pila
    add sp, sp, #16
    
    // Mostrar ": "
    mov x0, #1
    adr x1, msg_freq
    mov x2, #msg_freq_len
    mov x8, #64
    svc #0
    
    // Mostrar la frecuencia
    mov x25, x24         // Copiar frecuencia para convertir
    bl num_to_ascii
    
    // Mostrar nueva línea
    mov x0, #1
    adr x1, newline
    mov x2, #newline_len
    mov x8, #64
    svc #0
    
    // Restaurar límite superior para el bucle
    mov x25, #127

next_result:
    add x20, x20, #1     // Incrementar al siguiente carácter
    b show_loop
    
exit_program:
    // Salir del programa
    mov x0, #0
    mov x8, #93
    svc #0

// Subrutina para convertir número a ASCII y mostrarlo
num_to_ascii:
    // Preparar para convertir el número a texto
    mov x24, x25           // Copiar número a x24
    adr x26, buffer        // x26 = puntero al búfer
    add x26, x26, #19      // Empezar desde el final del búfer
    mov x27, #10           // x27 = base 10 para división
    
    // Caso especial si el número es 0
    cbnz x24, convert_loop
    mov w28, '0'           // Carácter ASCII '0'
    strb w28, [x26]
    sub x26, x26, #1
    b end_convert

convert_loop:
    // Comprobar si el número es 0
    cbz x24, end_convert
    
    // Obtener el último dígito (número % 10)
    udiv x28, x24, x27     // x28 = x24 / 10
    msub x29, x28, x27, x24 // x29 = x24 - (x28 * 10) = x24 % 10
    
    // Convertir dígito a ASCII y guardarlo
    add w29, w29, #'0'     // Convertir a carácter ASCII
    strb w29, [x26]        // Guardar en búfer
    sub x26, x26, #1       // Mover puntero
    
    // Actualizar número para siguiente iteración
    mov x24, x28           // Número = número / 10
    b convert_loop

end_convert:
    // Calcular longitud de la cadena resultante
    add x26, x26, #1       // Ajustar puntero al primer dígito
    adr x25, buffer
    add x25, x25, #20
    sub x2, x25, x26       // x2 = longitud de la cadena
    
    // Imprimir número
    mov x0, #1             // File descriptor: 1 para stdout
    mov x1, x26            // Dirección del búfer
    mov x8, #64            // Syscall número 64: write
    svc #0                 // Llamada al sistema
    
    ret