How to recieve integer input from user

Started by xwiz, March 21, 2012, 05:29:39 PM

Previous topic - Next topic

xwiz

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!

MichaelW

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.

eschew obfuscation

dedndave

is this what you mean ?

(i already had the routines written for another program   :P )

xwiz

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.

xwiz

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?

dedndave

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

dedndave

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

xwiz

Okay, thanks, I changed the Link563 in your assembly code to link16 and it now works fine :)

I'm using DosBox to run my codes :)

xwiz

Also, do you have any idea of how I can change the settings of the qeditor masm32 compiler or can these not be changed?

dedndave

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

xwiz

Yeah, I get it now. Besides, since I have to use an emulator to run my code (I'm now using msdos 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.

dedndave

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

xwiz

Cool, thanks :8). I guess you're more correct. The link 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?

dedndave

yes, an error - never noticed that one - lol

xwiz

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