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
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?
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
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
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 ?
Ahh yes 32 bit
Using Kips Library and MASM
INCLUDE Irvine32.inc
.data
num1 DWORD ?
num2 DWORD ?
operator BYTE ?
.code
And so on
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.
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
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.
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
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.
sorry - i updated my previous post and it should now answer your question :P
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
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
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
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...
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 ???
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
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)
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)
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???
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
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.
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 ....
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
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:
lodswmov ax, [esi]
add esi, 2
lodsdmov eax, [esi]
add esi, 4
See \masm32\help\opcodes.chm for more info.
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?
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...
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
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
:U
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.
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
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
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?
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
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.
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?
i would probably try to write it as a parser loop
but, that may not be the best way to do it :P