El ensamblaje de DOS lee dos caracteres sucesivos y los convierte en número

StackOverflow https://stackoverflow.com/questions/1640994

  •  08-07-2019
  •  | 
  •  

Pregunta

Estoy escribiendo un programa simple que toma dos números entre 1 y 99, los agrega e imprime el resultado. Ya terminé con la parte de impresión, puedo imprimir hasta tres dígitos, 99 + 99 = 198, así que es suficiente para este programa. Tengo el programa trabajando para dos números de un dígito.

Ejemplo: 1 1 = 2, 4 4 = 8

Entonces los dígitos están separados por espacios. Ahora necesito lo siguiente; 11 1 = 12, 1 45 = 46

lo que obtuve hasta ahora, cuando leí por primera vez un número válido, lo guardo en la pila mientras verifico cuál es el siguiente carácter, si el siguiente es espacio, entonces este número es solo un dígito. Si tengo otro personaje, tengo que multiplicar el primero por 10 y luego agregar el último personaje.

22 se leería así: 2 2 * 10 = 20 + 2 = 22

Tenga en cuenta que el resto de mi programa necesita el resultado de esto para estar en el registro dl. Tengo una pequeña pregunta sobre registros y ensamblaje, ¿se puede hacer referencia a un número almacenado en dl con dx? Me pregunto porque los operadores mov y aritméticos parecen exigir que los registros (operandos) sean del mismo tamaño.

Mi código hasta ahora

ReadNumber: ;; Reads one number 1-99
push ax
push bx
push cx
Lokke:
;; reads from keyboard
mov ah,01h
int 21h
cmp al, " "
je Lokke
cmp al,"0"
jb PrintError
cmp al,"9"
ja PrintError
;; First character is a valid number
push ax
;;storing the first on the stack while checking the next character
mov ah,01h
int 21h
cmp al," " 
je OneNumber
;;This part runs if the next char is a valid digit.
mov cl, al ;cl next digit
pop ax ; getting back the first from the stack
sub ax,"0" THIS LINE IS ADDED THANKS!!!!
mov bl, 10 
mul bl 
add ax, cx
mov dx,ax
mov dh,0 ;success variable set to true
mov dl,al
sub dl,"0"
pop ax
pop bx
pop cx
ret
OneNumber: 
pop ax ;; Don't need it.
mov dh,0 ;success variable set too true
mov dl,al
sub dl,"0"
pop ax
pop bx
pop cx
ret

Esto no funciona correctamente, ni siquiera para números de un dígito, no puedo entender por qué :( ¡Se ve muy bien! Gracias por tu aporte :)

¿Fue útil?

Solución

Un error obvio (puede haber otros) es que está almacenando el valor ASCII del dígito, pero lo está multiplicando como si fuera un número entero.

En otras palabras, el valor del primer dígito, almacenado temporalmente en la pila, está entre 48 y 57 (decimal), respectivamente para "0". a través de " 9 " ;.

Estoy buscando otros problemas ...

Editar : Segunda pasada ...
Seguí adelante y proporcioné una versión evolutiva de tu fragmento , cambiando algunas cosas que encontré mal / faltantes, pero también preparando el terreno para manejar más de 2 dígitos. Los principales cambios son:

  • Se agregó prueba para el dígito 0-9 para el 2do (y subsiguientes) caracteres leídos de la entrada
  • Convertido sistemáticamente a valor entero desde ASCII, tan pronto como se afirme la validez de los dígitos. (al ser consistentes evitamos errores)
  • Usó la palabra en la parte superior de la pila para mantener el valor acumulativo (esta forma de hacerlo es un poco extraño ya que hace que se asegure de resaltar esto, siempre que pueda ramificarse / salir. Más sobre esto tarde
  • se aseguró de que la parte alta de los registros se eliminara por cero (esto puede haber estado causando algunos de los errores)
  • Ahora solo tenemos un punto de salida (para el caso normal, es decir, sin contar el " PrintError "

Nota: este código no ha sido probado, de hecho ni siquiera está compilado (no tiene MASM aquí / ahora ...)

    ;; ReadNumber
    ;;    Reads a number from the input and returns its value in dx register
    ;;    For now 0-99 values only
    ;;      dh contains 0 = success code
    ;;      dl contains the value
    ;;    (this API should change so that bigger # can be returned)
    ReadNumber: 
    push ax
    push bx
    push cx
    Lokke:
    ;; First digit is handled separately, as to to allow for preceding spaces
    mov ah,01h
    int 21h
    cmp al, " "
    je Lokke   ;; skip spaces till first digit
    cmp al,"0"
    jb PrintError
    cmp al,"9"
    ja PrintError
    ;; First character is a valid number

    mov dh, 0
    mov dl, al
    sub dl, "0"
    push dx     ;; *** Cumulative value kept on top of stack ***

    MoreDigits:
    mov ah,01h
    int 21h
    pop cx   ;; in case of premature exit want the stack as expected...
    cmp al," "
    je DoneWithDigits
    cmp al,"0"
    jb PrintError
    cmp al,"9"
    ja PrintError
    mov dh, 0       ;; good: character is a digit
    mov dl, al
    sub dl, "0"     ;; down from ASCII
    mov ax, cx
    mov bl, 10
    mul bl
    add ax, dx    ;; fixed syntax error...
    push ax       ;; *** keep cumulative value on top of stack
    jmp DoneWithDigits  ;; For now only 2 digit max  (remove this 
                        ;; jmp to try with more)
    ;; @@@ here to test for overflow / too many char input
    jmp MoreDigits

    ;; Almost done
    DoneWithDigits: 
    pop dx 
    mov dh,0 ;success variable set too true   
    pop ax
    pop bx
    pop cx
    ret

Y ahora, algunas consideraciones generales más

  • Notó que no utiliza ninguna variable en memoria (es decir, ubicaciones de memoria que definiría con la sintaxis de tipo "MyLabel dw?" para crear variables globales), o incluso variables locales (encontradas en el desplazamiento relativo del puntero del marco). Esto es quizás solo para facilitar la programación de ensamblaje, etc. y / o un requisito de su (?) Asignación. No se apresure a abordar tales variables, pero las encontrará útiles cuando lo haga.
  • Convención de llamada : Los métodos ReadNumber () parecen estar a cargo de salvaguardar los registros ax, bx y cx. (y restablecerlos antes de salir). Esta es una convención un poco extraña, por lo general, la persona que llama a un método empuja su propio contexto a la pila (y luego empuja cualquier parámetro a la función, si corresponde). De todos modos, verá estas convenciones en acción, junto con la forma en que se usa el registro de puntero de marco (BP), etc. Quizás compruebe esto artículo de wikipedia como una vista previa (por cierto, dependiendo del ensamblador que use en particular si se trata de un ensamblador de macros, puede ocuparse de gran parte de esta mecánica.) No se apresure a hacer todo esto, primero familiarícese con el ensamblaje básico.
  • el diseño del código es un poco extraño, con el ensamblaje generalmente nos gusta el diseño de 4 columnas con las etiquetas en la primera columna, agradable y visible, luego las Instrucciones, seguidas de los operandos, y por último los comentarios de línea.

Espero que esto ayude,
ahora, diviértete!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top