The MASM Forum Archive 2004 to 2012

Miscellaneous Forums => 16 bit DOS Programming => Topic started by: xwiz on March 21, 2012, 05:29:39 PM

Title: How to recieve integer input from user
Post by: xwiz on March 21, 2012, 05:29:39 PM
I am trying to write an assembly program to display even numbers starting from 0 to I where I is supplied by the user. I'm trying to use the following code:

.model small
.stack
code segment
assume cs:code
_start:
mov ah, 1h
int 21h
mov dl, al
mov ah, 2h
myloop:
    sub dl, 2
    mov ah, 2h
    int 21h
    cmp dl, 0
    jge myloop
mov ah, 4ch
int 21h
code ends
end _start


However, I'm facing several problems.

I can only get a single character input
I can't really convert the supplied input to integer (it seems to be an ascii character); subtracting 48 from input wouldn't work because the user can want to start from 100
I only want to display numbers as output not the whole ascii characters starting from input
Thanks!
Title: Re: How to recieve integer input from user
Post by: MichaelW on March 21, 2012, 06:48:04 PM
One easy way to get an input string from the user is the Buffered Input function:

http://www.ctyme.com/intr/rb-2563.htm

To do the conversion from an ASCII string to an integer value, a rough description in some fairly-crappy pseudo code:

value = 0
starting at first char of string:
for each char
    if char is digit
        digitvalue = char - 30h
        value = value * 10
        value = value + digitvalue
    else
        if at end of string
            done
        else
            invalid char in string
        endif   
    endif
end for


You may want to code the conversion to handle a leading sign, or to ignore leading zeros. And an easy way to handle invalid (non-digit) characters is to just stop the conversion at the first invalid character, and assume that you have reached the end of the string.

Title: Re: How to recieve integer input from user
Post by: dedndave on March 21, 2012, 07:12:36 PM
is this what you mean ?

(i already had the routines written for another program   :P )
Title: Re: How to recieve integer input from user
Post by: xwiz on March 21, 2012, 08:36:43 PM
Wow, thanks so much @dedndave! I guess the lines I really need are:

;display even numbers from 0 to <UserValue>

        mov     bx,dx
        xor     ax,ax

Evens0: call    UnsDec
        call    StrOut
        add     ax,2
        jc      Exit00

        cmp     ax,bx
        jbe     Evens0


However, jc and xor are new to me, can you explain to me properly what happens there?

Thanks.
Title: Re: How to recieve integer input from user
Post by: xwiz on March 21, 2012, 08:40:47 PM
Also when I try to compile this using masm32 qeditor, it gives me the following errors:

QuoteAssembling: C:\masm32\even.asm
C:\masm32\even.asm(5) : warning A4015: directive ignored with /coff switch
C:\masm32\even.asm(55) : error A2006: undefined symbol : DGROUP
C:\masm32\even.asm(57) : error A2006: undefined symbol : DGROUP
C:\masm32\even.asm(64) : error A2074: cannot access label through segment registers
C:\masm32\even.asm(185) : error A2074: cannot access label through segment registers

NOTE: I'm running win7 x64, and I've seen this error with other programs, so I guess it's not peculiar to this one.
Do you know why this is happening?
Title: Re: How to recieve integer input from user
Post by: dedndave on March 21, 2012, 08:41:11 PM
well - if they enter the value 65535, the thing will run endlessly   :P
so, to prevent that, i put in a JC instruction (jump if carry)
if adding 2 to the register causes it to rollover, or overflow, i exit the loop

XOR is used in many ways - in this case, it is a shortcut method of setting a register to 0
this recent thread has some related discussion...
http://www.masm32.com/board/index.php?topic=18543.0
Title: Re: How to recieve integer input from user
Post by: dedndave on March 21, 2012, 08:43:31 PM
1) you shouldn't be using the /COFF switch for 16-bit programs
2) you should use the 16-bit linker for 16-bit programs (link16.exe) instead of the 32-bit linker
3) i dunno how that program works for you, as 16-bit programs aren't supposed to run under 64-bit OS's   :bg

here is the batch file i use to assemble and link 16-bit programs (a16.bat)...
@echo off
if "x%1"=="x" goto a16usage
if exist %1.asm goto a16asm
:a16usage
echo Usage: a16 asmfile
echo "asmfile" = asmfile.asm
goto batchexit
:a16asm
if exist %1.obj del %1.obj
c:\masm32\bin\ml /c /Fl %1.asm >c:\masm32\bin\asmbl.txt
if errorlevel 1 goto showtxt
if exist %1.exe del %1.exe
c:\masm32\bin\Link563 /MAP %1.obj; >>c:\masm32\bin\asmbl.txt
:showtxt
if exist %1.obj del %1.obj
type c:\masm32\bin\asmbl.txt
:batchexit
dir %1.* /o-d
Title: Re: How to recieve integer input from user
Post by: xwiz on March 21, 2012, 09:21:41 PM
Okay, thanks, I changed the Link563 in your assembly code to link16 and it now works fine :)

I'm using DosBox (http://www.dosbox.com/) to run my codes :)
Title: Re: How to recieve integer input from user
Post by: xwiz on March 21, 2012, 09:23:33 PM
Also, do you have any idea of how I can change the settings of the qeditor masm32 compiler or can these not be changed?
Title: Re: How to recieve integer input from user
Post by: dedndave on March 21, 2012, 09:37:22 PM
well - you don't want to change the ones he has in there
you will want them for when you do 32-bit code

but, i think you can add one to the list
create the a16 batch file as i show above and place it in the bin folder
then, have a look at the INI files for QE - i suspect you just add a line for it

lnk563 and link16 are more-or-less the same thing
however, lnk563 is a self-extracting zip file - a little confusing the first time you run it
because it wants to overwrite itself
Title: Re: How to recieve integer input from user
Post by: xwiz on March 21, 2012, 09:47:39 PM
Yeah, I get it now. Besides, since I have to use an emulator to run my code (I'm now using msdos (http://homepage3.nifty.com/takeda-toshiya/msdos/index.html) instead, supports more output on screen), I don't mind using only 2 lines (thanks to your batch code) to execute my programs in cmd.

Also in your code there's a line like this:
div     bx                  ;divide DX:AX by 10
I hope I'm not sounding dumb/painful, but I really don't understand what's happening there. I will also like to have a link where I can learn what registers? like di means.

Thanks for your time.
Title: Re: How to recieve integer input from user
Post by: dedndave on March 21, 2012, 09:52:24 PM
well - that particular instruction does as the comment suggests
the BX register holds 10 throughout the loop, as i recall
so, it divides the 32-bit value in DX:AX by 10
the remainder will be in DX and the quotient will be in AX

http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/toc.html
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-1.html
Title: Re: How to recieve integer input from user
Post by: xwiz on March 21, 2012, 10:01:37 PM
Cool, thanks :8). I guess you're more correct. The link (http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-2.html#HEADING2-451) has a tiny error:
QuoteIf the operand is a 16 bit quantity, then the div instruction divides the 32 bit quantity in dx:ax by the operand leaving the quotient in ax and the remainder in . With 32 bit operands (on the 80386 and later) div divides the 64 bit value in edx:eax by the operand leaving the quotient in eax and the remainder in edx.
Obviously it's missing dx after in?
Title: Re: How to recieve integer input from user
Post by: dedndave on March 21, 2012, 10:08:41 PM
yes, an error - never noticed that one - lol
Title: Re: How to recieve integer input from user
Post by: xwiz on March 21, 2012, 10:41:43 PM
I'm beginning to have a bit of a hard time. I'm trying to add some comments based on what I understand to the code myself.

PrInp1: lodsb  ;get next character in dx and set in al
        xor     al,30h ;subtract 48 from this character
        cmp     al,9 ; with line below, checks if the character is above 9 after subtraction and jumps? does that if we have - 2 after subtraction what then?
        ja      PrInp2 ;

        cmp     dx,6553 ; Guess the choice of 6553 is random?
        ja      PrInp4

        shl     dx,1 ;I don't quite understand are you converting to byte by using 3 shl instructions (From what I read now that's equal to * 8) ? why not do it once if that's the case?
        mov     bx,dx
        shl     dx,1
        shl     dx,1
        add     dx,bx ; after multiplication by first 2 add multiplication by 4? 2 value?
        add     dx,ax ; can you help me with what ax will hold at this point?
        jc      PrInp4 ; if value is greater than the 8 byte limit jump???

        loop    PrInp1

        pop     ax                  ;discard string pointer
        pop     si                  ;restore registers
        pop     cx
        pop     bx
        pop     ax
        ret


Pls check my comments for my understanding of your code. Thanks
Title: Re: How to recieve integer input from user
Post by: dedndave on March 21, 2012, 11:04:04 PM
PrInp1: lodsb             ;same as MOV AL,[SI]/INC SI
        xor     al,30h    ;convert ASCII numeric character to binary
        cmp     al,9      ;if the result is greater than 9,
        ja      PrInp2    ;then it wasn't an ASCII numeric character

        cmp     dx,6553   ;16-bit registers hold 65535 max
        ja      PrInp4    ;if above 6553, multiplying by 10 would be overflow

;here, we multiply the saved (accumulated) value by 10, then add the new binary digit

        shl     dx,1      ;DX = 2 X val
        mov     bx,dx     ;BX = DX = 2 X val
        shl     dx,1      ;DX = 4 X val
        shl     dx,1      ;DX = 8 X val
        add     dx,bx     ;(8 X val) + (2 X val) = 10 X val
        add     dx,ax     ;add the new binary digit
        jc      PrInp4    ;if the result is greater than 65535, overflow

        loop    PrInp1    ;loop until done (same as DEC CX/JNZ PrInp1)
Title: Re: How to recieve integer input from user
Post by: Force on March 21, 2012, 11:10:09 PM
I think You tried to  input just even numbers from keyboard in your code

using "DIV" is better way for it

.model small
.stack
.data


.code
start:
mov ax,@data
mov ds,ax

lp1:
mov ah, 1h
int 21h
cmp al,0Dh
je exit
cmp al,30h
jb go

cmp al,39h
ja go

mov bl,al
xor ah,ah
mov dl,2
div dl
cmp ah,0
jne go

mov dl,bl
mov ah,02h
int 21h

go:


mov dl,08h
mov ah,02h
int 21h

mov dl,00h
mov ah,02h
int 21h

mov dl,08h
mov ah,02h
int 21h


jmp lp1

exit:
mov ah, 4ch
int 21h


end start 
Title: Re: How to recieve integer input from user
Post by: xwiz on March 22, 2012, 07:19:39 AM
Quote from: dedndave on March 21, 2012, 11:04:04 PM
PrInp1: lodsb             ;same as MOV AL,[SI]/INC SI
        xor     al,30h    ;convert ASCII numeric character to binary
        cmp     al,9      ;if the result is greater than 9,
        ja      PrInp2    ;then it wasn't an ASCII numeric character

        cmp     dx,6553   ;16-bit registers hold 65535 max
        ja      PrInp4    ;if above 6553, multiplying by 10 would be overflow

;here, we multiply the saved (accumulated) value by 10, then add the new binary digit

        shl     dx,1      ;DX = 2 X val
        mov     bx,dx     ;BX = DX = 2 X val
        shl     dx,1      ;DX = 4 X val
        shl     dx,1      ;DX = 8 X val
        add     dx,bx     ;(8 X val) + (2 X val) = 10 X val
        add     dx,ax     ;add the new binary digit
        jc      PrInp4    ;if the result is greater than 65535, overflow

        loop    PrInp1    ;loop until done (same as DEC CX/JNZ PrInp1)

:eek Thanks, that was really very helpful. :bg I wonder how long it will really take me to understand asm language.
Title: Re: How to recieve integer input from user
Post by: xwiz on March 22, 2012, 07:21:40 AM
Quote from: Force on March 21, 2012, 11:10:09 PM
I think You tried to  input just even numbers from keyboard in your code

using "DIV" is better way for it

.model small
.stack
.data


.code
start:
mov ax,@data
mov ds,ax

lp1:
mov ah, 1h
int 21h
cmp al,0Dh
je exit
cmp al,30h
jb go

cmp al,39h
ja go

mov bl,al
xor ah,ah
mov dl,2
div dl
cmp ah,0
jne go

mov dl,bl
mov ah,02h
int 21h

go:


mov dl,08h
mov ah,02h
int 21h

mov dl,00h
mov ah,02h
int 21h

mov dl,08h
mov ah,02h
int 21h


jmp lp1

exit:
mov ah, 4ch
int 21h


end start 

@Force, thanks, the problem is not just receiving the inputs, after receiving the input I want to list even numbers from the supplied input to 0 or vice versa. If you could comment your code also, it will be very helpful. Thanks