Hola estoy teniendo problemas la la hora de realizar este programa, se supone que el programa debe de contar los caracteres que escribes y después imprimirlos diciendo cuantas veces aparece tal carácter, por ejemplo
cadena: Anita lava la tina
A = 1
a = 5
n = 2
i = 2
t = 2
y así sucesivamente
alguien que sepa que me falla? o que me pueda ayudar con esto, seria de mucha ayuda...
Esto es lo que tengo:
___________________________
data segment
; add your data here!
cadena db 258 dup(0) ; para definir bits
resultados db 00h
letra db 00h
numero db 00h
ends
stack segment
dw 258 dup(0)
ends
code segment
start:
; set segment registers:
mov ax, data
mov ds, ax
mov es, ax
mov cadena[00], 0ffh
lea dx, cadena
mov ah, 0ah
int 21h
mov si, 02h
dec ah
inicio: mov al, cadena[si]
mov dl, ax
inc resultados[dl]
inc si
cmp al, 0dh
jz imprimir
jmp inicio
imprimir: mov ah, 09h
mov dx, resultados
int 21h
mov bx, si
mov letra[0], bl
lea dx, letra
int 21h
mov al, resultados[si]
mov ah, 00h
mov bl, 64h
div bl
add al, 30h
mov numero[0], al
div bl
add ah, 30h
mov numero[2], ah
add al, 30h
mov numero[1], al
lea dx, numero
mov ah, 09h
int 21h
div bl
add ah, 30h
mov numero[2], ah
add al,
ciclo: cmp si, 080h
jz fin
cmp si, 0dh
jz siguiente
mov al, resultado[si]
cmp al, 00h
jz siguiente
mov ah, 09h
lea dx, l3
siguiente: inc si
jmp ciclo
fin: lea dx, pkey
mov ah, 9
int 21h
mov ah, 01h
int 21h
mov ax, 4c00h ; exit to operating system.
int 21h
ends
end start ; set entry point and stop the assembler.
Hola @mythik_751 (https://underc0de.org/foro/index.php?action=profile;u=111702)
Observando un poco su código, se puede ver que le faltan operandos a algunas instrucciones y otras vienen siendo inválidas porque el ensamblador no tendrá manera de saber el tamaño con los que va a interactuar. Aquí le escribí un pequeño programa que hace lo que está buscando: contar los caracteres, pero tiene algunas rutinas para facilitar la lectura. Espero le ayude.
bits 16
; El tamaño de la pila (valor arbitrario)
%define STACK_SIZE 0x256
; Para poder salir de la entrada
%define KEY_END 0xd
; Misceláneas
%define TRUE 1
%define FALSE 0
segment code
..start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov sp, stacktop
push prompt
call writeString
add sp, 2
; offset
mov si, characters
.L1:
mov al, 0x01
int 0x21
movzx bx, al ; Necesitamos a bx o di para usar el desplazamiento
inc byte [si+bx]
cmp al, KEY_END
jne .L1
xor bx, bx
mov cx, characters_size
.L2:
movzx dx, byte [si+bx] ; Las veces que fue escrito
test dl, dl
jz .L5 ; No hace falta imprimirlo si nunca fue escrito
push bx
call isPrint
add sp, 2
test al, al
jz .L3
; Es imprimible, por lo que e imprime normalmente
push bx
call writeChar
add sp, 2
jmp .L4
.L3:
; No es imprimible, por lo que para mostrarse en pantalla
; se hace lo siguiente:
push '\\' ; Por convención, no es necesario
call writeChar
add sp, 2
push bx ; Se imprime su número ASCII, es vez del carácter
call writeDec
add sp, 2
.L4:
push equal_str
call writeString
add sp, 2
push dx
call writeDec
add sp, 2
push nueva_linea
call writeString
add sp, 2
.L5:
inc bx
loop .L2
mov ax, 0x4c00
int 0x21
isPrint:
push bp
mov bp, sp
mov al, [bp+4]
cmp al, 0o40
jb .L2
cmp al, 0o176
ja .L2
mov al, TRUE ; Es imprimible
jmp .L3
.L2:
xor al, al ; No es imprimible
.L3:
pop bp
ret
writeString:
push bp
mov bp, sp
push ax
push dx
mov ah, 0x09
mov dx, [bp+4]
int 0x21
pop dx
pop ax
pop bp
ret
writeChar:
push bp
mov bp, sp
pusha
mov ah, 0x02
mov dl, [bp+4]
int 0x21
popa
pop bp
ret
writeDec:
push bp
mov bp, sp
; Reservamos 3 palabras (1 bytes sin usar)
; ya que por lógica solo se puede pasar en
; el argumento 1 del procedimiento writeDec
; 5 cifras, pero es para que quede par.
sub sp, 6
pusha
mov ax, [bp+4] ; número a imprimir
xor si, si
lea di, [bp-6]
mov bx, 10
.L1:
xor dx, dx
div bx
or dl, 0x30 ; Lo convertimos a un carácter imprimible
mov [di], dl
inc si
inc di
test ax, ax
jnz .L1
mov cx, si
dec di
.L2:
movzx dx, byte [di]
push dx
call writeChar
add sp, 2
dec di
loop .L2
popa
mov sp, bp
pop bp
ret
segment data
characters: times 255 db 0 ; Sólo el número de caracteres ASCII
characters_size EQU $-characters
prompt: db "Escriba su cadena: $"
equal_str: db " = $"
nueva_linea: db 0xd,0xa,'$'
segment stack stack
resb STACK_SIZE
stacktop:
Espero no sea molestia, pero tuve que usar NASM porque en este momento no puedo usar TASM/MASM, pero no es tan complicado hacer la equivalencia y comprender cada cosa.
~ DtxdF
rayos carnal, no se que paso pero se borro la continuidad del chat, que me habías contestado, pero lo intente y no hubo resultado ahorita ya acomode mi código de tal manera que me lo ejecuta pero sigo teniendo problema a la hora que imprima el resultado de los caracteres mira así es como lo tengo
______________
data segment
; add your data here!
l1 db "Escribe algo en pantalla: $"
l2 db "El resultado de caracteres leidos es: $"
cadena db 258 dup(0) ; defino el maximo de bits
contador db 130 dup(0)
letra db 00h
numero db 00h
salto db 0ah, 0dh, 24h
pkey db "fin ..$"
ends
stack segment
dw 128 dup(0)
ends
code segment
start:
; set segment registers:
mov ax, data
mov ds, ax
mov es, ax
lea dx, l1
mov ah, 09h ; Aqui se lee el letrero 1
int 21h
lea dx, salto
mov ah, 09h ; Ponemos un salto de linea
int 21h
mov cadena[0], 0FFh ; Especificamos el total de caracteres
lea dx, cadena ; que queremos leer
mov ah, 0ah
int 21h
lea dx, salto
mov ah, 09h ; Ponemos un salto de linea
int 21h
mov si, 02h
dec ah
inicio: mov al, cadena[si]
mov di, dx
inc contador[di]
inc si
cmp al, 0dh
jz imprimir
jmp inicio
imprimir: lea dx, l2
mov ah, 09h ; Leemos el letrero 2
int 21h
lea dx, salto
mov ah, 09h ; Ponemos un salto de linea
int 21h
lea dx, contador[si]
mov ah, 09h
int 21h
ciclo: cmp si, 080h
jz fin
cmp si, 0dh
jz siguiente
mov al, contador[si]
cmp al, 00h
jz siguiente
mov ah, 09h
lea dx, l1
int 21h
mov bx, si
mov letra[0], bl
lea dx, letra
int 21h
mov al, contador[si]
mov ah, 00h
mov bl, 64h
div bl
add al, 30h
mov numero[0], al
mov al, ah
mov ah, 00h
mov bl, 0ah
div bl
add ah, 30h
mov numero[2], ah
add al, 30h
mov numero[1], al
lea dx, numero
mov ah, 09h
int 21h
siguiente: inc si
jmp ciclo
fin: lea dx, pkey
mov ah, 09h
int 21h
mov ah, 01h
int 21h
mov ax, 4c00h ; exit to operating system.
int 21h
ends
end start ; set entry point and stop the assembler.
@mythik_751
Fue un problema del foro, pero ya está todo bien. Si necesita el mensaje, se lo puedo parafrasear según lo que recuerde, no obstante, no creo que sea necesario para este caso, ya que lo que le estaba contestando era una aclaratoria sobre el uso del operador OFFSET en masm para una instrucción del snippet que había dejado en su anterior comentario (el que fue borrado).
Ahora, nos direccionamos a su código y vemos algunas incongruencias. Según tengo entendido, desea que el programa reciba una cadena como entrada y que se muestre como la salida la cantidad total de caracteres ingresados (con sus respectivas repeticiones numéricas). Volviendo al ejemplo que dejó en el primer comentario, si el usuario escribiera
Anita lava la tina debería obtener entonces:
(https://imgur.com/DkLiBCX.png)
Aclarando que este es el programa ensamblado con NASM que le dejé, aquí la explicación abstracta: El programa lo que hace es declarar e inicializar un arreglo en bytes puestos a 0, podemos llamarle a éste el contador de todos los caracteres ASCII, siendo 255 en este caso. Entonces lo que se necesitaría ahora son dos cosas: el desplazamiento del contador y un índice; éste último es sencillo: el índice es el mismo carácter ASCII pero en decimal (octal, hexadecimal, etc., lo importante es que sea un número no más grande que el tamaño del arreglo
characters). Ahora usaremos el desplazamiento más el índice para poder saber dónde se deberá sumar 1 en el arreglo, indicando que se ha escrito ese carácter.
characters: times 255 db 0 ; El contador de caracteres
Ahora basándome en la explicación, el carácter ASCII, o sea el índice, lo escribirá el mismo usuario con la función
0x01 de la interrupción
0x21:
.L1:
mov al, 0x01
int 0x21
movzx bx, al
inc byte [si+bx]
cmp al, KEY_END
jne .L1
Este es un extracto del programa. El registro
al vendría siendo el índice, pero necesitamos a
bx para poder indexarlo con el desplazamiento que se encuentra en el registro
si, aunque en realidad solo necesitamos ajustar la parte baja, y la alta la ajustamos con ceros con la instrucción
movzx. Una vez hemos hecho toda esta operación, incrementamos según el resultado de
[si+bx] aclarándole a NASM que sólo necesitamos un byte. Luego se comprueba que no se ha tecleado el carácter para salir, si fue así, se sale y continúa imprimiendo el resultado.
Nota:
Si no mal recuerdo, emu8086 no emula la instrucción movzx, que, según tengo entendido fue agregada en el 80386[1][2]Ya para ultimar la pequeña explicación del programa, lo único que sigue es recorrer todo el arreglo de caracteres. por lo que seguiremos usando el desplazamiento y a la misma vez el índice, que protagonizará dos actuaciones: la primera ser el carácter ASCII que vamos a imprimir, y la segunda, ser el desplazamiento del arreglo, que a su vez nos dirá cuantas veces se ha repetido ese carácter. Por obvias razones si el número de repeticiones es cero, no se imprime (aunque esto dependerá de lo que se desea hacer, en este caso, se deja tal cual). Además para agregar un extra, se verifica si el carácter es o no imprimible; si lo es, se imprime normalmente, si no, se imprime el carácter ASCII en decimal pero como prefijo una barra diagonal invertida.
Además, el programa no guarda la cadena porque no es necesario, así se le deja en libertad al usuario de teclear en demasía una cadena de caracteres.
Si desea, también puede estudiar este programa en C que hace más o menos lo mismo:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define CHARACTERS_SIZE 256
char characters[CHARACTERS_SIZE];
int main(void) {
int c;
while ((c = getchar()) != '\n' && c != EOF)
if (c < CHARACTERS_SIZE)
characters[c] += 1;
for (int i = 0; i < CHARACTERS_SIZE; i++)
if (characters[i] != 0)
if (isprint(i))
printf("%c = %d\n", i, characters[i]);
else
printf("\\%d = %d\n", i, characters[i]);
return EXIT_SUCCESS;
}
Sobre las incongruencias que le digo, es que no veo que trate usted de imprimir en su programa el carácter que se escribió y entre otras cosas que pienso deberían pasar, como también escribir el carácter de igualdad (
=) y el número de repeticiones, que según creo, lo quería hacer en este bucle:
ciclo: cmp si, 080h
jz fin
cmp si, 0dh
jz siguiente
mov al, contador[si]
cmp al, 00h
jz siguiente
mov ah, 09h
lea dx, l1
int 21h
mov bx, si
mov letra[0], bl
lea dx, letra
int 21h
mov al, contador[si]
mov ah, 00h
mov bl, 64h
div bl
add al, 30h
mov numero[0], al
mov al, ah
mov ah, 00h
mov bl, 0ah
div bl
add ah, 30h
mov numero[2], ah
add al, 30h
mov numero[1], al
lea dx, numero
mov ah, 09h
int 21h
siguiente: inc si
jmp ciclo
Además, tenga cuidado con esto:
mov numero[0], al
mov al, ah
mov ah, 00h
mov bl, 0ah
div bl
add ah, 30h
mov numero[2], ah
add al, 30h
mov numero[1], al
Sabiendo que después de
numero le sigue
salto, se sobreescribirán los datos y si desea después usarla para imprimir la nueva línea, habrá incongruencias.
Además también veo en ese mismo bucle que imprime nuevamente la cadena que se encuentra en
l1 por lo que me deja aún más con dudas, que serían gratas que las aclarara, aunque es lo de menos, lo importante es que entienda los pequeños ejemplos y trate de recrearlo según lo que haya entendido, algo así como aprender un nuevo concepto y tratar de explicarlo parafraseandolo.
Espero le haya sido útil.
Referencias:
La instrucción movzx según tengo entendido fue agregada en el 80386:
1,- http://www.posix.nl/linuxassembly/nasmdochtml/nasmdoca.html
2.- https://www.nasm.us/doc/nasmdocb.html
~ DtxdF