The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: krikara on November 22, 2010, 09:48:38 AM

Title: Simple Arithmetic Input 8086
Post by: krikara on November 22, 2010, 09:48:38 AM
Okay so I am working on a program that needs to be able to to read input such as
"5 + 100"
And then out put 105.
The program is supposed to be able to perform any basic arithmetic including mod.

Reading integers are pretty easy because all I had to do was
call ReadInt
mov num1,eax

However I am confused what to call to read the sign.
Basically, I want to know how to read the input for the operator.
Right now, I have the following

call ReadInt
mov num1,eax
call ReadChar
mov operator,al
call ReadInt
mov num2,eax


However, this does not read my input correctly. I used DWORD for num1 and num2 and BYTE for operator. It seems to only register
the ReadInt commands because it only allows me to push enter twice before ending the program and if I enter 5 then enter 6, EAX comes as 6 in dumpregs.

__________________________________________________________________
I have a basic idea on what do to with the operator after the program reads it(although I am not sure if this idea works).
I would do something like
cmp op, '+'
jmp addtion

cmp op, '-'
jmp subtraction

and so on.
Help soon would be much appreciated.
Thanks
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 22, 2010, 09:56:06 AM
So apparently the line
call ReadChar
was working, but I didn't have to push enter after that because it only reads one char.

I finally discovered it worked after calling WriteChar :S
So now I just have to figure out how to use that input and make it do the appropriate arithmetic.
I will try attempting my method.

___________________

edit: it seems my method does not work where I do
cmp op,'+'
jmp addition

cmp op,'-'
jmp subtraction ......

How do I fix the code such that it compares the operator to the + - * / % signs?
Title: Re: Simple Arithmetic Input 8086
Post by: jj2007 on November 22, 2010, 09:57:31 AM
Try to read a full line with Masm32 lib StdIn:
include \masm32\include\masm32rt.inc

.data?
buffer db 1000 dup(?)

.code
AppName db "Masm32:", 0

start: print "Type something, then press Enter", 13, 10
mov esi, offset buffer
invoke StdIn, esi, sizeof buffer
.Repeat
lodsb
movzx eax, al
.break .if !eax
print str$(eax), " "
.Until 0
print esi, 13, 10, "That was your input", 13, 10
exit

end start
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 22, 2010, 10:13:28 AM
So far this is my code.
ReadInt and ReadChar works appropriately. However, the line that doesnt function is cmp operator,'+'
How am I supposed to write the code such that it will successfully compare operator to each individual sign (+  -  *  /  %)


call ReadInt
mov num1,eax
call ReadChar
mov operator,al
call ReadInt
mov num2,eax

mov al,operator ;I added this just incase
cmp operator,'+'
jmp addition

addition:
mov eax,num1
add eax,num2
call WriteInt


The addition surely works fine, however if I input 5 - 6, the program still does the addition. And that should not happen. How am I supposed to compare the Char input to a sign?

I even tested
mov al,operator ;I added this just incase
cmp al,'+'
jmp addition


And the program still jumps to addition even when i input 5-6
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 10:38:28 AM
well - we cannot see the entire construct of the program, as posted
is this a 16-bit or 32-bit program ?
are you using Kip's library ?
are you using MASM ?
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 22, 2010, 10:40:48 AM
Ahh yes 32 bit
Using Kips Library and MASM

INCLUDE Irvine32.inc

.data
num1 DWORD ?
num2 DWORD ?
operator BYTE ?

.code

And so on
Title: Re: Simple Arithmetic Input 8086
Post by: hutch-- on November 22, 2010, 10:48:22 AM
krikara,


"5 + 100"


With a task of this type you are writing a simple parser and you need to be able to split it up into its components.


1. 5
2. +
3. 100


I am not familiar with Kip Irvine's libraries but at a coding level the way to do this is to write a 256 character table which you can fill with zeros, the number positions 1s and the arithmetic operators 2 just as an example.

Then you scan the string from beginning to end recognising only the numbers and operators.

Write each item to a memory buffer then perform the arithmetic operation based on the operator, "+" in this instance.

Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 10:49:09 AM
here in the forum, many of us are not all that familiar with Kip's libraries
the masm32 package that most of us use contains a set of libraries and macros
as Hutch mentioned in this (http://www.masm32.com/board/index.php?topic=15400.msg125962#msg125962) thread, mixing libraries may no work so well
at any rate, we could use a little more info on the functions you are using   :P
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 22, 2010, 10:54:13 AM
Okay.

So far, I only called 2 different functions
ReadInt and ReadChar

ReadInt basically reads a 32 bit signed integer from user input in command prompt and stores it into eax. So I basically push
5, then enter and it stores 5 into eax.
Then I do mov num1,eax so it stores my inputted number into num1

ReadChar basically reads any single character. So once you type a character, it will be stored into al
And then I do mov operator,al so operator gets the operator sign stored, which should be one of these
(+  -  *  /  %)

I'm not sure I understand to the full extent of what Hutch said , but I have the operator stored and can move it into the AL register anytime I want. The problem I have is figuring out how to match the input operator to the correct function.
So if I input + , it should go to the addition function, if I input *, it should go to the multiplication function.
I thought cmp operator,'+' would work, however, that is not producing correct results because the program keeps going to the
addition function regardless of any operator I input.
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 11:00:29 AM
cmp operator,'+'
jmp addition


jumps to "addition" no matter what the results are of the CMP instruction
the JMP instruction is unconditional - that means it branches to the label, regardless of the flags
JZ branches if the zero flag is true (cmp sets the flags the same as sub)

it might look something like this:

        mov     al,operator
        cmp     al,'+'
        jz      addition

        cmp     al,'-'
        jz      subtraction

        cmp     al,'*'
        jz      multiplication

        cmp     al,'x'
        jz      multiplication

        cmp     al,'X'
        jz      multiplication

        cmp     al,'/'
        jz      division

        print   chr$('Invalid Operator'),13,10
        jmp     try_again


notice that if it fails all the tests for valid operator characters, it "defaults" to an "invalid operator" message and allows the user to try inputting again

also notice that PRINT and CHR$ are not part of Kip's lib
you may want to find his eqivalent functions and replace them

also...
notice that i moved the value of the operator into AL
then CMP AL,xx
this generates shorter and faster code
not that speed is an issue in this case, it is just good practice
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 22, 2010, 11:14:55 AM
replacing jmp with jz seems to work so far with addition and subtraction. Let me finish the rest of the program and test  :cheekygreen:

Although I don't quite understand why it didn't work with jmp.

doesn't cmp check if operator = '+'
and if it is true, it jumps to addition?

Or does it just auto jmp to addition because it jumps regardless whether operator is + or not.
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 11:16:29 AM
sorry - i updated my previous post and it should now answer your question   :P
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 11:21:42 AM
here is a good reference....

http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/toc.html

and, specifically, the section on conditional branches

http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-5.html#HEADING5-226
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 22, 2010, 11:35:49 AM
Okay, that aside, I wanted to know if there is a possible way to input
"5 + 6" (1 input) and have the program sort out the numbers and operator respectively.

Currently, my program is written with
call ReadInt
call ReadChar
call ReadInt

And thus my input is "5" enter, "+" , "6" enter. I basically have 3 different inputs right now.

So my question is how do I input the string and have the all the elements sorted out appropriately.
If I entered "[x operator y]"
x should be stored into num1
operator should be stored into operator
y should be stored into num2
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 11:43:26 AM
you could input the entire line as text
then, search for the operator, using it as both an operator and a parameter seperator
so, the user enters something like "1234+5678"
you find the "+" - the stuff before it is one parameter - the stuff after it is another - ignore any spaces

i am not sure what the fastest way to find the seperator is, actually
and, in this case, it doesn't need to be all that fast
in the reference link i mentioned above, find the section on string instructions
you might use REP SCASB, in this case

another method might be a not-so-simple parser loop that loads characters and branches accordingly
this is probably the method i would use
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 22, 2010, 11:49:54 AM
That makes sense, but what happens in the case of

"-100 + -200"
or
"100 + -200"

How will the program know when the operator is actually an operator and not the sign of the number?
I think it has to be done manually where it reads a number, then an operator, and then a number, but I don't know how to
code that  :'(

Are there certain instructions that I should look up?
I have no idea where to start with this...
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 11:53:33 AM
yes - that is an advantage of using a parser loop   :P
there are a number of ways to write it
many will tell you that LODSB is not a fast instruction (some say never use it), but this might be a good place to use it
speed is not a real issue, here, and the instruction is small and simple and increments the index for you   :bg

start with the line input
let's find out what Kip's function does
does it limit and/or return the input string length ???
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 11:58:51 AM
here we are...
ReadString
Waits for/reads an ASCII string.
Input: EDX contains the offset to store the string
ECX contains max character count
Output: EAX contains number of chars input


the docs i have don't tell me if he terminates the string with a nul   :bg
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 22, 2010, 12:06:30 PM
From my understanding, Strings are in BYTE

so lodsb would be the appropriate instruction since it loads BYTE into AL. However
if my input is "5+-6"
it should load "5" into eax
load "+" into al
load "-6" into eax.

What instructions should I use to separate the string? And also, the string is in BYTE, but I want to store part of the
string in EAX. Does that mean is use lodsd? How would I go about doing that as well.

EDIT: To read a string, I would use  call ReadString

I believe call ReadString stores into the al register.
This is how ReadString looks

Call args:  EDX points to the input buffer
            ECX max number of non-null chars to read

Return arg: EAX = size of input string.

Example:

.data
MAX = 80                     ;max chars to read
stringIn BYTE MAX+1 DUP (?)  ;room for null

.code
      mov  edx,OFFSET stringIn
      mov  ecx,MAX            ;buffer size - 1
      call ReadString
(Taken from Irvine lib help)

Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 12:15:10 PM
well - whether you choose to use LODSB or not...
a loop can read each character, one by one (LODSB loads a single byte into AL, then increments ESI)
basically, you want to find the address in the buffer where each element begins and ends

let's start by putting the count in ECX
so, you load a byte - see if it is part of a number
the first character may be a +/- sign, or it may be a numeric digit
there may be up to 10 digits for a 32-bit number
after the first character, only numeric digits may be allowed
if a non-numeric character is found, you have found the end address of the first element
it may be a space, or it may be the operator character
if it is a space, ignore it
as each character is parsed, decrement the count in ECX
if ECX = 0, you are done
if not, return to the top of the loop and continue parsing

that is the basic idea of a parser loop
(ASCII numeric digits are 30h - 39h,  representing 0 - 9)
(space = 20h)
Title: Re: Simple Arithmetic Input 8086
Post by: jj2007 on November 22, 2010, 12:56:39 PM
Quote from: dedndave on November 22, 2010, 12:15:10 PM
a loop can read each character, one by one (LODSB loads a single byte into AL, then increments ESI)
basically, you want to find the address in the buffer where each element begins and ends

See reply #2 above for code that gets you the buffer. Ashan, did you install the Masm32 package???
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 22, 2010, 01:11:53 PM
QuoteAshan, did you install the Masm32 package???

wrong thread, Jochen   :bg

i have helped Krikara before - he tries hard to write his own code   :U
Title: Re: Simple Arithmetic Input 8086
Post by: jj2007 on November 22, 2010, 07:10:29 PM
Quote from: dedndave on November 22, 2010, 01:11:53 PM
QuoteAshan, did you install the Masm32 package???

wrong thread, Jochen   :bg

i have helped Krikara before - he tries hard to write his own code   :U


Apologies to Krikara. However, the code in reply #2 of this thread is indeed the best start for a parser. You need to read a full line, then use lodsb (=mov al, [esi] combined with inc esi) to split the line into its components.
Title: Re: Simple Arithmetic Input 8086
Post by: hutch-- on November 23, 2010, 12:33:38 AM
krikara,

You are going to have to specify how the text is entered that is evaluated by a parser. You can have negative or positive numbers but there must be some way of differentiating sign notation from the operator between the two numbers.

-100 * +650

If you allow both positive and negative sign notation then you must have some space or other means of distinguishing between "-100" "*" and "+650".

Ideally you would use a table based parser and that can be done with the masm32 library but I am not sure how you would do it with Kip's library unless it has a dedicated capacity to do this type of stuff. Essentially what you need is a tokeniser that will separate text based on the delimiting characters between the numbers.

What you cannot do wihout a far more complex parser is allow input text like this.

-100*+650.

There is a trick if you did not have to run sign notation, replace all of the operators with an extra space each side so that "+" becomes " + " etc ....
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 23, 2010, 07:22:24 AM
Hey I found a way to do it, but it doesn't use lobsb. Although maybe it could.... I'm not exactly sure.
What is the difference between mov al, string[esi] and lodsb?

Anyways, here is the pseudocode/logic for what I am going to do. I am pretty sure this logic works, however I didn't code it yet, so I haven't tested it.

QuoteFirst
Check the first character. It can either be a sign or a number. If it is a sign, then a number is immediately after.

Read number:
Keep reading the numbers until a sign is reached. Store that number into num1

This sign is an operator sign, so store it into operator

Next, check for a sign again. Store that number into num2.

Basically, the only problem is storing the numbers correctly. But I think I have that solved as well. Just multiply the total number by 10 everytime.
So say the number is 123.
The program reads 1 first. Program knows that there is another number next, so it does 1*10 +2 = 12. Then there is a 3 next. So program does 12*10 +3 = 123. And it stops because that is the end of the number.
So far things are looking good and the coding itself seems fairly simple.

Hopefully, I can get this done soon. Also, it would be good to know the difference between lodsb and mov al, string[esi]  :D
Title: Re: Simple Arithmetic Input 8086
Post by: jj2007 on November 23, 2010, 09:01:04 AM
Quote from: krikara on November 23, 2010, 07:22:24 AM
Also, it would be good to know the difference between lodsb and mov al, string[esi]  :D

lodsb combines two actions in one instruction:
mov al, [esi]
inc esi


It is not the best instruction for an ultrafast innermost loop, but for parsing it's just excellent.
Note there variants that you don't need here:
lodsw
mov ax, [esi]
add esi, 2

lodsd
mov eax, [esi]
add esi, 4


See \masm32\help\opcodes.chm for more info.
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 23, 2010, 10:16:53 AM
Alright, I got the program compiling correctly performing all the arithmetic perfectly. Now I am just going to have some IllegalArgumentErrors for bad input.

And then I will experiment with lodsb :D

Also, should I upload the program for any future people that want to view a basic arithmetic calculator?
Title: Re: Simple Arithmetic Input 8086
Post by: jj2007 on November 23, 2010, 10:30:26 AM
Quote from: krikara on November 23, 2010, 10:16:53 AM
Also, should I upload the program for any future people that want to view a basic arithmetic calculator?

Sharing code is always a good thing: Zip it and attach the archive, using "Additional Options" in the lower left of the Reply window.
But can you include all needed non-Masm32 libraries, legally speaking? Otherwise most people won't be able to use it...
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 23, 2010, 10:41:49 AM
to use or not use LODS instructions is one, mainly, of speed
how fast do you need to parse a single line of text ? - lol
at any rate, i think it is a good idea for beginners to familiarize themselves with the string instructions
and, LODSB is one of the simplest ways to do that - another would be STOSB/REP STOSB
you should also read up on the CLD and STD instructions, noting that in win32, the flag is usually cleared for you

as for parsing the line, i would take the approach that it is always a 3 element line
so, i would parse through to the end of the first element, then find the simple one-char operator (second element)
after that, whatever is left is the third element

as Hutch mentioned, this type of parser can be a little complicated because numeric signs and operators use the same chars
and that would be especially true if there were more elements on the line
but, take the 1-2-3 element approach and it won't be too bad
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 23, 2010, 11:05:40 AM
Hmm

I have been debugging for about half an hour now and can't seem to figure out why my program always calls my BadInput function even when there isn't bad input.
The program itself does all the arithmetic correctly, but I am trying to make it so the program catches bad input. For some reason however, it sees the good
input as bad input too and I just don't understand why.

I;'ll upload what I have in zip. If someone could help soon, that would be awesome.

The only time I call BadInput is in checkElement near the begining.
And all Badinput does is display an error msg.



EDIT UPDATE:

I commented out the call BadInput
and it still displays the error message no matter what.
What is going on?!?!

EDIT 2 :
WOW I fixed it. Just because I didn't put ret at the end of my Operations function, it went to the next function (BadInput). I didn't
even know that was possible. Im pretty sure in high level programming languages that functions dont jump to other
functions if you dont return. Sigh... I will upload the final in the next post
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on November 23, 2010, 11:43:44 AM
 :U
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on November 23, 2010, 12:11:02 PM
There was actually one thing I didn't manage to do.
And that was check for certain overflow errors.

Because I am using 32 bit signed integers, that means maximum 10 digits per int before the basic equation is overflowed.
However that also means that the sum, difference, product, quotient and remainder can't also exceed 10 digits.
I didn't know how to check for that though because adding two 10 digit numbers together will produce something like -1023111031 which
is also 10 digits. It is clearly overflow, but the program doesn't catch it automatically and I don't know how to write code to catch it either.

However, everything else seems perfect, so I will upload the final :D


EDIT: I used Kip Irvine's library
To see his functions that I used, download the file IrvineLibHelp from here:
http://kipirvine.com/asm/files/index.html
He provides an explanation as well as the actual code for each function.

Title: Re: Simple Arithmetic Input 8086
Post by: RuiLoureiro on November 23, 2010, 05:16:45 PM
Hi,
       Your prog is hard to follow it is not easy for me...
        upload your .exe file

Quote
didn't know how to check for that though because adding two 10 digit numbers
together will produce something like -1023111031 which ...
         When you convert a 10 digit number you can check for overflow
         When you add 2 numbers you can check for overflow ... etc

         add    eax, ebx
         jc     _overflow           ; goes here and exit                             
Title: Re: Simple Arithmetic Input 8086
Post by: RuiLoureiro on November 23, 2010, 06:46:27 PM
Quote
n1:             ;Starts putting the digits together into one number in Eax
add overflowcounter,1
sub al,30h
mov ebx,0
mov bl,al
mov eax,num1
imul eax,10
add eax,ebx
mov num1, eax

            we dont need to count digits ( overflowcounter )
           
sub     al, 30h
movzx   ebx, al
mov     eax, 10
mul     num1
jc      overflow            ; define where to put this label
add     eax,ebx
jc      overflow            ; define where to put this label

mov     num1, eax           ; this number has not signal

            at the end we need to test the sign bit (bit 31):
            if set than overflow (we are working with 31 bits)
            (after/before    mov   operator, al)
            Or use  js   instead
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on December 12, 2010, 01:20:51 AM
Hey so that calculator was once a finished a project, but now I have a new assignment to make it even better :S.

Part of the assignment is to have the calculator have heximal and binary signed integers as input too and outputing the number in the format the first number was entered in.

So if a heximal + binary = output in hexidecimal.

I don't think this should be too hard , just some extra lines of code, but there was something I was wondering about the ADD SUB IMUL and IDIV instructions.

I already know they are capable of doing decimal integer arithmetic, but my text book never clearly stated whether they are capable of doing math in binary and hexidecimal. If they are capable of doing so, that would make my life a tad bit easier. If not, I think I would have to convert everything to decimal and do the arithmetic, and then reconvert the numbers to whichever the first number format was inputted in.

Decimals end in integers like 1000. Hexidecimals end with an h like 09Fh. and Binary numbers end in b like 1010101b.

_______________________________________

Edit:
My post may be unclear, so let me restate my questions.

Can the ADD SUb, etc instructions perform arithmetic in hexidecimal and binary
such as Hexi + Hexi = Hexi and Binary + Binary = Binary

and if so
can I do a cross between them? For example , can I do Hexi + Binary? If that works, then what format will be outputted?
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on December 12, 2010, 03:04:56 AM
binary is essentially the native tongue of the processor
hexidecimal is merely a human-friendly way to express binary values

in truth, you may consider 32-bit unsigned math as base 4294967296   :P
(a 32-bit register might be thought of as a single "digit", with 4294967296 possible values)
but - it is a binary-based representation
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on December 12, 2010, 05:31:46 PM
Interesting enough, when I tried adding 011b (binary number) + 001h( hexidecimal) and called WriteInt (which outputs in decimal),
the answer is correct.

This is mind blowing, but now I am starting to understand what you meant earlier by like 4294967296    bases.

btw I use WriteInt (outputs decimal value for eax), WriteBin(outputs binary value), and WriteHex (outputs hex value) from KipIrvine's library.
Title: Re: Simple Arithmetic Input 8086
Post by: krikara on December 12, 2010, 06:02:12 PM
Okay this poses a new problem with my program.

Before, the way my program worked was I inputted a string such as 44+55=

and it would output +99

my .data had where the program would evalute the numbers and load them into num1 and num2 accordingly
num1 DWORD 0
num2 DWORD 0
operator BYTE ?

For example the original program scans 4 and puts it as num1. It scans the next 4, and adds it to num1*10. Then it scans operator.
but now the input also has to allow input such as 0A4h+010b=
and thus, I have to rework my whole algorithm.

I am trying to find the shortest way to do so, but I can only think up of one solution.
That is to store num1 and num2 in strings instead. And then store num1 and num2 strings into DWORDs, where it checks the last letter to see if it is decimal, binary, or hexa. I was just wondering if there is a faster solution/algorithm I can use that require less code that will complete this arithmetic?
Title: Re: Simple Arithmetic Input 8086
Post by: dedndave on December 12, 2010, 08:45:18 PM
i would probably try to write it as a parser loop
but, that may not be the best way to do it   :P