asami
asami

Reputation: 11

Input and output of signed single-digit decimal numbers

I'm having a problem with this code.

 .model small
.stack 100h

.data
    Msg1 DB 'Enter first number: $'
    Msg2 DB 10, 13, 'Enter second number: $'
    Msg3 DB 10, 13, 'Entered numbers are: $'
    PositiveMsg DB ' is positive$'
    NegativeMsg DB ' is negative$'
    InputBuffer DB 6 DUP('$')

.code
main proc
    mov ax, @data
    mov ds, ax

    ; Display message asking for the first number
    mov ah, 09h
    lea dx, Msg1
    int 21h

    ; Read the first number from the user
    mov ah, 01h
    int 21h
    sub al, '0'          ; Convert ASCII character to its corresponding numeric value
    mov bh, al           ; Move the numeric value of the first number to BH

    ; Determine if the first number is positive or negative
    cmp al, 0
    jge FirstPositive
    mov dx, OFFSET NegativeMsg  ; Display negativity message for the first number
    int 21h
    neg bh               ; Negate the value to make it positive
    jmp CheckSecondNumber
FirstPositive:
    mov dx, OFFSET PositiveMsg  ; Display positivity message for the first number
    int 21h

CheckSecondNumber:
    ; Display message asking for the second number
    mov ah, 09h
    lea dx, Msg2
    int 21h

    ; Read the second number from the user
    mov ah, 01h
    int 21h
    sub al, '0'          ; Convert ASCII character to its corresponding numeric value
    mov dh, al           ; Move the numeric value of the second number to DH

    ; Determine if the second number is positive or negative
    cmp al, 0
    jge SecondPositive
    mov dx, OFFSET NegativeMsg  ; Display negativity message for the second number
    int 21h
    neg dh               ; Negate the value to make it positive
    jmp DisplayNumbers
SecondPositive:
    mov dx, OFFSET PositiveMsg  ; Display positivity message for the second number
    int 21h

DisplayNumbers:
    ; Display message indicating the entered numbers
    mov ah, 09h
    lea dx, Msg3
    int 21h

    ; Display the first entered number
    mov dl, bh           ; Move the numeric value of the first number to DL
    add dl, '0'          ; Convert numeric value to its corresponding ASCII character
    mov ah, 02h
    int 21h

    ; Display the positivity/negativity message for the first number
    mov dx, OFFSET PositiveMsg
    int 21h

    ; Display a comma between the numbers
    mov dl, ','         
    int 21h

    ; Display the second entered number
    mov dl, dh           ; Move the numeric value of the second number to DL
    add dl, '0'          ; Convert numeric value to its corresponding ASCII character
    mov ah, 02h
    int 21h

    ; Display the positivity/negativity message for the second number
    mov dx, OFFSET PositiveMsg
    int 21h

    ; Exit program
    mov ah, 4Ch
    int 21h
main endp

end main

This is the Msg3 which is wrong output. It should shows the input numbers and determine whether its positive or negative:
screenshot

I already try different codes for that but the output for Msg3 is still wrong.

Upvotes: 0

Views: 89

Answers (1)

Sep Roland
Sep Roland

Reputation: 39516

The messed-up output is mainly due to not specifying the required function number AH=09h before invoking DOS to print a message, and to using DH for holding the second number while at the same time you use DX for another purpose. Remember that the 16-bit DX is composed of the two 8-bit parts DH and DL.

Input of a signed single-digit decimal number

The DOS.GetCharacter function 01h first waits for the user to press a keyboard key, then it writes the corresponding character on the screen, and finally it returns to your program with the key's ASCII code in the AL register. For some special keys the function will return AL=0, that way signaling that your program should invoke the function again so as to obtain the key's scancode.

If you want the user to be able to input a signed single-digit decimal number, so in the range [-9,9], you will have to take a two-step approach. If the first time that you use the function you already receive a digit [0,9] then you can just bypass the second step. If on the other hand the first character that you received happened to be a minus character then you must invoke the function a second time expecting a digit [0,9], and this time you must also negate the number.
Next simplified example validates the user input:

ReDo1:
  mov  ah, 01h       ; DOS.GetCharacter
  int  21h           ; -> AL
  sub  al, '0'
  cmp  al, 10
  jb   GotIt         ; Is positive [0,9]
  cmp  al, '-' - '0'
  jne  ReDo1         ; An invalid character detected
ReDo2:
  mov  ah, 01h       ; DOS.GetCharacter
  int  21h           ; -> AL
  sub  al, '0'
  cmp  al, 10
  jae  ReDo2         ; Not a decimal digit
  neg  al
GotIt:

You don't want to repeat yourself too much (DRY), so you should put the above in a subroutine.

  mov  dx, OFFSET Msg1 ; Read the first number from the user
  call Input           ; -> AL (AH)
  mov  bl, al
  mov  dx, OFFSET Msg2 ; Read the second number from the user
  call Input           ; -> AL (AH)
  mov  bh, al

  ...

; IN (dx) OUT (al) MOD (ah)
Input:
  mov  ah, 09h       ; DOS.PrintString
  int  21h
ReDo1:
  mov  ah, 01h       ; DOS.GetCharacter
  int  21h           ; -> AL
  sub  al, '0'
  cmp  al, 10
  jb   GotIt         ; Is positive [0,9]
  cmp  al, '-' - '0'
  jne  ReDo1         ; An invalid character detected
ReDo2:
  mov  ah, 01h       ; DOS.GetCharacter
  int  21h           ; -> AL
  sub  al, '0'
  cmp  al, 10
  jae  ReDo2         ; Not a decimal digit
  neg  al
GotIt:
  ret

Output of a signed single-digit decimal number

It is not sufficient to just add '0' and have DOS display the one character. A test for negative is in order and if required the output of a minus character:

  test bl, bl
  jns  IsPositive
  mov  dl, '-'
  mov  ah, 02h        ; DOS.PrintChar
  int  21h
  neg  bl
IsPositive:
  lea  dx, [bx + '0'] ; BH and DH are un-important here
  mov  ah, 02h        ; DOS.PrintChar
  int  21h

Displaying the final summarizing message can benefit from using a subroutine too. I did include the necessary logic to differentiate between your PositiveMsg and NegativeMsg messages, something that you forgot to do:

  mov  dx, OFFSET Msg3   ; BL contains first number
  call Output            ; -> (AX BL DX)
  mov  bl, bh            ; Load second number in BL
  mov  dx, OFFSET Msg4   ; Make this a ', $'
  call Output            ; -> (AX BL DX)

  ...

; IN (bl,dx) OUT () MOD (ax,bl,dx)
Output:
  mov  ah, 09h       ; DOS.PrintString
  int  21h
  test bl, bl
  pushf              ; (1) Need the test result later on
  jns  IsPositive1
  mov  dl, '-'
  mov  ah, 02h       ; DOS.PrintChar
  int  21h
  neg  bl
IsPositive1:
  lea  dx, [bx + '0'] ; BH and DH are not important here
  mov  ah, 02h        ; DOS.PrintChar
  int  21h
  mov  dx, OFFSET PositiveMsg
  popf                ; (1) Original BL no more available
  jns  IsPositive2
  mov  dx, OFFSET NegativeMsg
IsPositive2:
  mov  ah, 09h
  int  21h
  ret

If ever you need to go further than a single-digit input/output, then next Q/A's go much deeper into the subject: Inputting multi-radix multi-digit signed numbers with DOS and Displaying numbers with DOS.

Upvotes: 1

Related Questions