The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: Ani_Skywalker on July 21, 2010, 05:56:44 PM

Title: primitive type check in MASM?
Post by: Ani_Skywalker on July 21, 2010, 05:56:44 PM
Hi everybody,

I am a beginner that started MASM coding after I speed-read "The Art of Assembly Language" and "Introduction to 80x86 assembly language". Speed-read means I scooped interesting topics, read some 500 pages and so on. My problem is that I understand much better when I get to code then when I read page after page.

So, I am trying to build a basic calculator available to perform the 4 basic operands (+,-,*,/). So far, It's been going over exceptions, but not without some questions popping up, so here it goes:

; assume all the necessary includes are done and so on.

.data?
var1 dd, 0
var2 dd, 0

.code

start:
       
    mov var1, sval(input("Enter the first number: "))
    mov var2, sval(input("Enter the second number: "))
    print chr$(13,10)
    print str$(var1)
    print chr$(' ')
    print str$(var2)
    print chr$(13,10,13,10)

    xor eax, eax
   
    add eax, var1
    add eax, var2
   
    print str$(eax)
    print chr$(13,10,13,10)

mov eax, input("Press 'Enter' to exit. ")

exit



Questions:

1. Is there a way to _easy_ provide some kind of primitive-type check like those in high level languages to see if the user-input truly is an integer? If not, how do we do it the hard way then? We parse the input char by char and check if it is a number between 0-9?

2. I tried to add var1 and var2 to each other, like this: mov var1, var2. It did not compile and I guessed a register was the way to go, now I wonder, why is that so? Why is it not possible to add the two variables without adding them to a register?

3. Any other suggestions to my code?

As soon as I learn how to do type-control I move on to add the other operands and then a way to choose between the operands.

Thank you for your time!

Title: Re: primitive type check in MASM?
Post by: ecube on July 21, 2010, 06:01:47 PM
yeah looping through each character in the string to make sure it's 0-9 is a good method.
Title: Re: primitive type check in MASM?
Post by: Ani_Skywalker on July 21, 2010, 06:07:28 PM
Quote from: E^cube on July 21, 2010, 06:01:47 PM
yeah looping through each character in the string to make sure it's 0-9 is a good method.

Is there no other way?

If not, would it be a bad approach to learn how to create functions or classes in MASM, create a type-checking function/class in MASM and then re-use that function every time I need to type-check?
Title: Re: primitive type check in MASM?
Post by: KeepingRealBusy on July 21, 2010, 06:08:22 PM
2. An assembler creates code to execute whatever the hardware has implemented, and the hardware has no memory to memory operations.

Dave.
Title: Re: primitive type check in MASM?
Post by: Ani_Skywalker on July 21, 2010, 06:09:33 PM
Quote from: KeepingRealBusy on July 21, 2010, 06:08:22 PM
2. An assembler creates code to execute whatever the hardware has implemented, and the hardware has no memory to memory operations.

Dave.

Thank you! That answered it.
Title: Re: primitive type check in MASM?
Post by: dedndave on July 21, 2010, 06:11:24 PM
well - there are MOVS and CMPS string operations   :P

as for the integer thing - i would probably parse until i see a decimal and make it be an integer
Title: Re: primitive type check in MASM?
Post by: KeepingRealBusy on July 21, 2010, 06:14:14 PM
You are not allowed to say "Thank you." in this forum, nobody else does, why should you be allowed? :wink
Title: Re: primitive type check in MASM?
Post by: KeepingRealBusy on July 21, 2010, 06:15:19 PM
Quote from: dedndave on July 21, 2010, 06:11:24 PM
well - there are MOVS and CMPS string operations   :P

as for the integer thing - i would probably parse until i see a decimal and make it be an integer

But these are hardware macros that use the esi edi registers to access memory.

Dave.
Title: Re: primitive type check in MASM?
Post by: dedndave on July 21, 2010, 06:20:24 PM
i am not sure they are microcoded that way
they are native as far back as 8088/8086
at any rate, MOVS is ok - if you are moving a large amount of data
or a very small amount of data if it is "register convenient" and speed isn't critical
otherwise, you can probably write a faster loop   :P
CMPS isn't fast at all on newer CPU's - perhaps that indicates that it is microcoded in RISC
Title: Re: primitive type check in MASM?
Post by: Ani_Skywalker on July 21, 2010, 06:25:23 PM
Quote from: KeepingRealBusy on July 21, 2010, 06:14:14 PM
You are not allowed to say "Thank you." in this forum, nobody else does, why should you be allowed? :wink

Sorry, but I saw a point in clearing out that I understood the explanation so nobody else tried to explain. It was not just a "Thank you" but also a notification that the questions answer had be found. But sorry, I wont repeat it.

About the MOVS and CMPS, I will google and read the tutorials on them. Always good to know.
Title: Re: primitive type check in MASM?
Post by: KeepingRealBusy on July 21, 2010, 06:32:57 PM
Please, please, please observe the "Smiles" before you take someone literally. That was meant to be a funny poke at those that say nothing when you have given them a factual  response. I accep and appreciate your Thank you.

Dave.
Title: Re: primitive type check in MASM?
Post by: jj2007 on July 21, 2010, 06:59:47 PM
Quote from: Ani_Skywalker on July 21, 2010, 06:25:23 PM
About the MOVS and CMPS, I will google and read the tutorials on them. Always good to know.

Try \masm32\help\opcodes.chm - better than Google in this case.
There are also some practical hints here (http://www.webalice.it/jj2006/Masm32_Tips_Tricks_and_Traps.htm).

Welcome to the Forum :thumbu
Title: Re: primitive type check in MASM?
Post by: clive on July 21, 2010, 09:04:11 PM
Quote from: Ani_Skywalker
Is there no other way?

If not, would it be a bad approach to learn how to create functions or classes in MASM, create a type-checking function/class in MASM and then re-use that function every time I need to type-check?

At the assembler (machine code) level you are working with the "bare metal" of the processor, and the processor is pretty stupid. The implementation of the processor has gotten a lot more complicated over the years, but if you look at the original CPU designs from the 1970-80's you will get an idea of the simple state machine, serial processing model.

You have to write subroutines to do even the most trivial task, or use subroutines written by someone else.

Most of the CompSci students coming here have to write routines to convert ASCII digits into binary numbers, convert binary into decimal, add things, compute powers, create RPN calculators, etc.

Title: Re: primitive type check in MASM?
Post by: hutch-- on July 22, 2010, 01:27:27 AM
The normal technique to filter characters is to perform the character input in an edit control and set up a subclass to filter characters. Processing the WM_CHAR message usually does the job fine.

If you are trying to pick it up from the console or command line you have no choice other than taking the string and checking it for non-allowed characters.
Title: Re: primitive type check in MASM?
Post by: Ani_Skywalker on July 22, 2010, 11:56:54 PM
Hi guys,

Thank you for all your suggestions. And trust me, I've been reading them all. I read the masm32-editors help-files and looked up the links that jj2007 provided. Also, I've been looking up the movs, movsb and cmps commands.

Still, I am unfortunate to tell you that I'm stuck right where I were yesterday. I can't seem to pick out a byte at a time to compare it's ascii value and see if it is in the range of the ascii code for the 0-9 numbers. There is where I'm stuck at the moment. And if you could get some help from there, I would really appreciate it.

I tried code like the code below, found in the MASM32 Editors help chms. Also tried several other approaches, always with compile errors:

cld               ; set direction flag forward
    mov esi, source   ; put address into the source index
    mov edi, dest     ; put address into the destination index
    mov ecx, ln       ; put the number of bytes to copy in ecx
  ; --------------------------------------------------
  ; repeat copying bytes from ESI to EDI until ecx = 0
  ; --------------------------------------------------
    rep movsb


If you look to the code above, the first problem with is that I don't get what source and destination should be, if this is to be adapted to my current code.
Title: Re: primitive type check in MASM?
Post by: hutch-- on July 23, 2010, 12:47:13 AM
Source and Destination are simple enough, When you COPY data from one register to another the SOURCE is the data to copy, the DESTINATION is where you copy the data to.


  mov eax, 1234


Copy the immediate number 1234 into the EAX register. Source is the number 1234, destination is the EAX register.

Intel assembler notation has the destination first followed by the source (in 2 operand instructions)


  add eax, ecx


Add the value in the ECX register to the value in the EAX register.
Title: Re: primitive type check in MASM?
Post by: KeepingRealBusy on July 23, 2010, 12:51:15 AM
Quote from: Ani_Skywalker on July 22, 2010, 11:56:54 PM
Hi guys,

Thank you for all your suggestions. And trust me, I've been reading them all. I read the masm32-editors help-files and looked up the links that jj2007 provided. Also, I've been looking up the movs, movsb and cmps commands.

Still, I am unfortunate to tell you that I'm stuck right where I were yesterday. I can't seem to pick out a byte at a time to compare it's ascii value and see if it is in the range of the ascii code for the 0-9 numbers. There is where I'm stuck at the moment. And if you could get some help from there, I would really appreciate it.

I tried code like the code below, found in the MASM32 Editors help chms. Also tried several other approaches, always with compile errors:

cld               ; set direction flag forward
    mov esi, source   ; put address into the source index
    mov edi, dest     ; put address into the destination index
    mov ecx, ln       ; put the number of bytes to copy in ecx
  ; --------------------------------------------------
  ; repeat copying bytes from ESI to EDI until ecx = 0
  ; --------------------------------------------------
    rep movsb


If you look to the code above, the first problem with is that I don't get what source and destination should be, if this is to be adapted to my current code.

Try:


   cld
   mov esi, source   ; put address into the source index
   mov edi, dest     ; put address into the destination index
  mov ecx, ln       ; put the number of bytes to copy in ecx
Again:
  lodsb
  stosb
  or al,al
  jz Exit
  dec ecx
  jnz Again
Exit:


Or to check for value ranges:


   cld
   mov esi, source   ; put address into the source index
   mov edi, dest     ; put address into the destination index
  mov ecx, ln       ; put the number of bytes to copy in ecx
Again:
  lodsb
  stosb
  cmp al,'0'
  jz Exit
  cmp al,'9'
  ja Exit
  dec ecx
  jnz Again
Exit:


Dave.


Title: Re: primitive type check in MASM?
Post by: hutch-- on July 23, 2010, 12:55:27 AM
You should avoid using LODS STOS without the REP prefix as they are very slow. Incremented pointers use less registers and are faster.
Title: Re: primitive type check in MASM?
Post by: dedndave on July 23, 2010, 01:09:42 AM
they are nice in areas when speed isn't critical, though
they are single byte instructions and they increment or decrement the index register for you    :bg
Title: Re: primitive type check in MASM?
Post by: hutch-- on July 23, 2010, 01:39:10 AM
Yes but its sloppy and slow 1980s technology, incremented pointters are simple enough to use, use less registers and are faster. the 8088 is dead !  :bg
Title: Re: primitive type check in MASM?
Post by: dedndave on July 23, 2010, 02:07:25 AM
 we finally found something to disagree on   :lol
i don't think it's sloppy
if i wanted to write a special command-line parser.....
how fast and how many times do you need to parse the command-line, anyways ?
LODSB / STOSB are perfect for that kind of loop
they keep the code small when speed is not an issue
Title: Re: primitive type check in MASM?
Post by: Ani_Skywalker on July 23, 2010, 11:34:36 AM
.486                                   
.model flat, stdcall                 
option casemap :none

include \masm32\include\windows.inc     
include \masm32\macros\macros.asm

include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib


.data?
var1 dd, 0
var2 dd, 0
container dd, 0

.code

start:
       
    mov var1, sval(input("Enter the first number: "))

   cld
   mov esi, var1   ; put address into the source index
   mov edi, container     ; put address into the destination index
   mov ecx, 1       ; put the number of bytes to copy in ecx
   Again:
   lodsb
   stosb
   cmp al,'0'
   jz Exit
   cmp al,'9'
   ja Exit
   dec ecx
   jnz Again
   Exit:

    mov var2, sval(input("Enter the second number: "))
    print chr$(13,10)
    print str$(var1)
    print chr$(' ')
    print str$(var2)
    print chr$(13,10,13,10)

    xor eax, eax

    add eax, var1
    add eax, var2

    print str$(eax)
    print chr$(13,10,13,10)

mov eax, input("Press 'Enter' to exit. ")

exit

end start


The above code does compile but I get an error during running, just after you entered the first number, meaning it starts to bug here:

cld
   mov esi, var1   ; put address into the source index
   mov edi, container     ; put address into the destination index
   mov ecx, 1       ; put the number of bytes to copy in ecx
   Again:
   lodsb
   stosb
   cmp al,'0'
   jz Exit
   cmp al,'9'
   ja Exit
   dec ecx
   jnz Again
   Exit:


The above code I got by you guys and it looks some those approaches I tried myself. Now, can you guys see why it goes wrong here?
Title: Re: primitive type check in MASM?
Post by: Ani_Skywalker on July 23, 2010, 11:39:52 AM
Quote from: hutch-- on July 23, 2010, 12:47:13 AM
Source and Destination are simple enough, When you COPY data from one register to another the SOURCE is the data to copy, the DESTINATION is where you copy the data to.

Thank you Hutch, however, that part I knew. What I did not understand is how to adapt my code to that.

For example, I don't have a DESTINATION since I do not want to copy the data. I just want to parse the SOURCE byte by byte and condition each byte to see if it is in the range of ascii 0-9. I like to do this to be able to identify numbers from all other characters. So, since I don't need it, but every informative source I looked through use this approach, I am confused  :(
Title: Re: primitive type check in MASM?
Post by: jj2007 on July 23, 2010, 12:39:47 PM
mov ecx, 1       ; put the number of bytes to copy in ecx
...
dec ecx

Your loop will run exactly once.
Title: Re: primitive type check in MASM?
Post by: Ani_Skywalker on July 23, 2010, 12:49:53 PM
Quote from: jj2007 on July 23, 2010, 12:39:47 PM
mov ecx, 1       ; put the number of bytes to copy in ecx
...
dec ecx

Your loop will run exactly once.

Yes indeed. But why does it crash after? And how do I get it to run as long as there is no bytes left to loop? :)
Title: Re: primitive type check in MASM?
Post by: hutch-- on July 23, 2010, 01:10:29 PM
Ani,

You basically check each byte against two values, the highest and the lowest in the ascii/ansi range you are after to filter only number characters. In the masm32 help file there is an ascii/ansi charcters chart and there you will find the range, if the byte value is lower than 48 or greater than 57 then its not a number.

To do this you read each byte and compare it against the upper and lower limits, you allow characters that are within the limits, you disallow characters that are not.

Construct a loop that reads the characters up to the terminator which should be ascii 0 and with the characters you evaluate, only accept those that are within those limits.
Title: Re: primitive type check in MASM?
Post by: Ani_Skywalker on July 23, 2010, 01:24:58 PM
Quote from: hutch-- on July 23, 2010, 01:10:29 PM
Construct a loop that reads the characters up to the terminator which should be ascii 0 and with the characters you evaluate, only accept those that are within those limits.

But it is here I fail :( The other part about checking for the byte to be within ascii 48-57 I've figured out. But at the moment, I'm stuck on how to separate a byte to read, do some comparison on it and then go back to read the next byte.

For example, look this again and I try to comment more on this, which part I understand and which I don't.


   mov esi, var1   ; put address into the source index
   mov edi, container     ; put address into the destination index
   mov ecx, 1       ; put the number of bytes to copy in ecx
   

Oki, here is where I'm stuck. How do I get this to loop more then once? When I used "ln" before, I got compile-error. I'm sure there should be some index-mover or something that points to the next byte.



Again:
   lodsb
   stosb
   cmp al,'0'
   jz Exit
   cmp al,'9'
   ja Exit
   dec ecx
   jnz Again
   Exit:


Above is still to come, but I understand "Again" is a loop, it looks very much like "Labels" that I've come across in some other languages (Java, C#, C++). At the moment, let's ignore this part. How do I solve my first problem, the first one?

I've read the tutorials, and I can tell they DO bring this up, problem is, I don't get it since I'm stupid  :(
Title: Re: primitive type check in MASM?
Post by: jj2007 on July 23, 2010, 01:48:07 PM
sval gives you already an integer value. You want to examine the string returned by input. Try this:

.data?
var1 dd ?
var2 dd ?
container dd ?
TheBuffer db 80 dup(?)

.code

start:
mov esi, input("Enter the first number: ")
cld
mov container, offset TheBuffer
mov edi, container ; put address into the destination index
push edi ; stosb changes edi, so we save a copy
mov ecx, 80 ; put the number of bytes to copy in ecx

Again:
lodsb
stosb
cmp al, 0 ; 0, not '0'
jz Exit
cmp al, '9'
ja Exit
cmp al, '0'
jb Exit
dec ecx
jnz Again

Exit:
mov byte ptr [edi-1], 0 ; delimit your input string
pop edi
mov var1, sval(edi) ; convert string to integer
print "Result="
print str$(var1), 13, 10
exit
Title: Re: primitive type check in MASM?
Post by: hutch-- on July 23, 2010, 02:24:04 PM
Here is a simple test piece that filters so you only have numbers in the destination. I was trying to avoid writing it for you as you should learn enough and write your own.


IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                      Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include\masm32rt.inc



    chfilter PROTO :DWORD,:DWORD



    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL buffer[64]:BYTE
    LOCAL ptxt  :DWORD

    mov ptxt, ptr$(buffer)

    fn chfilter,"1b2g3h4k4m5k7k8d9a0",ptxt

    print ptxt,13,10

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

chfilter proc src:DWORD,dst:DWORD

    push esi
    push edi

    mov esi, src
    mov edi, dst
    sub esi, 1

  lbl0:
    add esi, 1
    mov al, [esi]               ; read byte into register
    test al, al                 ; check if its zero
    jz quit
    cmp al, 48
    jl lbl0                     ; is it less than 48 ?
    cmp al, 57
    jg lbl0                     ; is it greater than 57 ?
    mov [edi], al               ; if within range, write it to destination buffer
    add edi, 1
    jmp lbl0

  quit:

    mov BYTE PTR [edi], 0

    pop edi
    pop esi

    ret

chfilter endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start