DOS assembly read two succeeding characters, and convert to number

[亡魂溺海] 提交于 2021-02-05 08:17:26

问题


I'm writing a simple program that takes in two numbers between 1-99, adds them and prints out the result. I'm done with the printing part, I can print up too three digits, 99+99=198 so it's enough for this program. I have the program working for two one digit numbers.

Example: 1 1 = 2 , 4 4 = 8

So the digits is separated by spaces. Now I need the following; 11 1 = 12, 1 45 = 46

what I got so far, when I first read a valid number i store it on the stack while I check what the next char is, if the next is space then this number is only one-digit. If I have another character I have to multiply the first by 10 and then add the latest character.

22 would be read like this: 2 2*10 = 20+2 = 22

Note that the rest of my program needs the result from this to be in register dl. Got one tiny question about registers and assembly, can a number stored in dl be referenced with dx? I'm wondering because mov and arithmetic operators seems to demand that the registers(operands) are of the same size.

My code so far

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

This does not work properly, not even for one-digit numbers, I can't understand why :( It looks just fine! Thanks for input :)


回答1:


One obvious mistake (there may be others), is that you you are storing the ASCII value of the digit, yet you are multiplying it as if it were an integer.

In other words, the value of the first digit, stored temporarily on the stack is between 48 and 57 (decimal), for respectively "0" through "9".

I'm checking for other issues...

Edit: Second pass...
I went ahead and provided an evolutionary version from your snippet, changing a few things which I found wrong/missing, but also laying the ground for handling more than 2 digits. The main changes are:

  • Added test for digit 0-9 for 2nd (and subsequent) characters read from input
  • Systematically converted to integer value from ASCII, as soon as digit validity is asserted. (by being consistent we avoid errors)
  • Used the word at top of stack to hold the cumulative value (this way of doing is a bit funky as it causes you to ensure to pop this out, whenever you may branch/exit. More on this late
  • ensured that the high part of the registers were zero-ed out (this may have been causing some of the bugs)
  • We now have only one exit point (for the normal case, i.e. not counting the "PrintError"

Note: this code is untested, indeed not even compiled (don't have MASM here/now...)

    ;; 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

And now, a few more general considerations

  • Noted that you do not use any in-memory variables (i.e. memory locations that you'd define with "MyLabel dw ?" type syntax, to create "global" variables), or even local variables (found at relative offset of the frame pointer). This is maybe just to ease into assembly programming etc. and/or a requirement of your (?) assignment. No rush to get into addressing such variables, but you'll find these handy when you do.
  • Calling convention: The ReadNumber() methods seems to be in charge of safeguarding the ax, bx and cx registers. (and to reestablish these before exiting). This is a bit of an odd convention, typically the caller to a method pushes his own context onto the stack (and then pushes any parameter to the function, if any). Anyway you'll see these conventions in action, along with the way the frame pointer register (BP) is used etc. Maybe check this wikipedia article as a preview (BTW, depending on the assembler you use in particular if this is a macro assembler, you can get much of this mechanics taken care of.) No rush to do all this, first get familiar with basics assembly.
  • the layout of the code is a bit strange, with assembly we typically like the 4 column layout with the labels in the first column, nice and visible, then the Instructions, followed by the operands, and last the line comments.

Hope this helps,
now, have fun!



来源:https://stackoverflow.com/questions/1640994/dos-assembly-read-two-succeeding-characters-and-convert-to-number

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!