I'm trying to do program to basic operations in math. So, I want that the program calculate for example 3*2+4 etc. I already did something, but it needs upgrade. The problem is with division (/). Everything I write it's always the same result- 0. I don't know why. It is also important that the program take into account the brackets.
The point is, that we can input as many brackets, *, /, +, - as we want, and the program do this calculation by priority. We always do * and / first and then + and -. But If we use brackets () we calculate numbers between brackets first.
Example:
We can calculate simple expression:
2*3
3+2
3-2+5
8/4
3*4+1-3

or more complicated:
5+(2-3)+(4-2*5+(1+3))/2

Thanks

``````program basic_;
{\$APPTYPE CONSOLE}

uses
SysUtils,
Math;

type SetCharacters=set of char;

var characters: SetCharacters;
input: string;
o: real;
i: integer;

function brackets(s: string):string;
begin

end;

function basic(input: string): real;
var i,j,k: integer;
r1,r2:real;
r: real;   //result
poz, neg: string;
a,b,c: real;

begin
r1:=0;
r2:=0;
i:=0;
c:=0;

while i<length(input) do
begin
i:=i+1;
if (input[i]='(') or (input[i]=')')then
begin
brackets(input);
end;

if (input[i]='*') or (input[i]='/') then
begin
if input[i]='*' then
if input[i+1]='(' then
begin
brackets(input);
end
else
begin
a:=StrToInt(copy(input,pos('*',input)-1,1));
b:=StrToInt(copy(input,pos('*',input)+1,1));
c:=a*b;
end;
end
else                                              //it's not working
if input[i]='/' then
begin
a:=StrToInt(copy(input,pos('/',input)-1,1));
b:=StrToInt(copy(input,pos('/',input)+1,1));
c:=a/b;
end;

if (input[i]='+') or (input[i]='-') then
begin
if input[i]='+' then
if input[i+1]='(' then
begin
brackets(input);
end
else
begin
poz:=copy(input,i+1,1);               //save all positive numbers
j:=1;
while j<= length(poz) do              //sum all numbers in array
begin
r1:=r1+StrToInt(poz[j]);
j:=j+1;
end;
end

else

if input[i]='-' then
if input[i+1]='(' then
begin
brackets(input);
end
else
begin
neg:=copy(input,i+1,1);                 //i save negative numbers
k:=1;
while k<=length(neg) do              //i sum all numbers in array
begin
r2:=r2+StrToInt(neg[k]);
k:=k+1;
end;
end;
end;
end;
r:=c+r1-r2;
writeln('Result: ',r:2:2);
end;

begin
characters:=['e','p','+','-','*','/','!','^','(',')','1','2','3','4','5','6','7','8','9','0'];
write('Input: ');
i:=1;
if input[i] in characters then
begin
o:=basic(input);
end
else
begin
writeln('Error.');
end
end.``````

## All 8 Replies

I suspect the problem is what's called 'integer division' (you can read up on it). Basically, the situation is that when dividing an integer by an integer, the result is always an integer. So 4/8 = 0 (since this is the closest integer smaller than the answer) while 4.0/8.0 = 0.5, since these are doubles, so the answer is a double. Try casting your integers a and b in `c:=a/b;` to doubles. Again, you can look up casting. Haven't done Pascal/Delphi since high school.

Hope that helps :)

Wow, they still teach pascal?

Anyway, looks like you are trying to build an expression evaluator. In that case you should think about using recursion! Also you need an operator precedence handler.

``````3*4+2

3[_]
3[*] _
3[*]4
(3[*]4)+_
(3[*]4)+2``````

Essentially you build an expression tree. Each node has the operator with a left and right child. The child can be an operator or a constant, etc.

``````3   4
\  /
*       2
\    /
+``````

First pass buids the tree.
Second pass recursively parses it!
Start with the + but sees the *operator on the left so recurses in.
* operator constant 3 on left constant 4 on right resolves it recurses back then sets the * to the result of the 3*4 So tree now looks like

``````12       2
\    /
+``````

swinefish I tried with double but it is still not working. I figure out, that if I want to do / program skip part for calculate division and go to the end of the program.

wildgoose thats very good idea. I like it! But the only bad thing is, that I dont like recursion very much.

In your initial design work parenthesis into it! Think of '(' as an operator and the ')' as a down one level and then it becomes whitespace. Parenthesis are essentially markers for positioning expressions in a tree.

Here's a link to a starting place. One of the best ways to learn is to look at others code and pick it apart as to what you like, don't like, etc.

that link is great wildgoose, but the code is written in C language. I need pascal.

Hi

Regarding your code, you must switch these two lines

``````begin
if input[i]='*' then``````

or the program will skip to the +/- "if"

But I agree with wildgoose, recursion is the way to go.
Visit http://www.arstdesign.com/articles/expression_evaluation.html
for an algorithm

HTH

First compile this unit with your pascal compiler

``````Unit Lengyel;

INTERFACE

{a verem adatszerkezethez készült típusok}

Type
PVeremelem=^TVeremelem;
TVeremelem=Record
Ertek: Byte;
Ertek2: Real;
Next: PVeremelem;
End;

Verem=Record
First: PVeremelem;
Last: PVeremelem;
End;

{Hia konstansok}

Const
Er_DivBy0 = 1;
Er_Zarjel = 2;
er_Illegal= 3;
Var
hiba: byte;

Function GetResult(s: String): Real;
{ Ez a függvény lengyelformát kap          }
{ paraméterként és az eredményt adja vissza}

Function MakePoland(s: String): String;
{ Kifejezésből lengyelforma }

Function isOK(s: String): Boolean;
{ Egyszerű ellenőrző rutin }

IMPLEMENTATION

Function isOK(s: String): Boolean;
Var
i,zj: Integer;
Ok: Boolean;
Begin
ok:=true;
zj:=0;
For i:=1 to Length(s) do
Begin
if s[i]='(' then Inc(zj);
if s[i]=')' then Dec(zj);
if not (s[i] in ['0'..'9','+','-','*','(',')','/',' ','.']) then Begin;ok:=false;hiba:=er_illegal;End;
End;
if zj<>0 then Begin;ok:=false;Hiba:=Er_zarjel;End;
if (pos('-+',s)<>0)  or (pos('---',s)<>0) or
(pos('+--',s)<>0) or (pos('-*',s)<>0) or
(pos('+*',s)<>0)  or (pos('**',s)<>0) or
(pos('++',s)<>0)  or (pos('()',s)<>0) or
(pos('(*',s)<>0)  or (pos('+)',s)<>0) or
(pos('*)',s)<>0)  or (pos('-)',s)<>0) or
(pos(')(',s)<>0)  or (pos('(+',s)<>0) then
Begin
ok:=false;
Hiba:=Er_illegal;
End;
isok:=ok;
End;

Procedure InitVerem(var v: Verem);
Begin
v.first:=nil;
v.last:=nil;
End;

Function SeeFirst(var v: verem): byte;
Begin
SeeFirst:=v.first^.ertek;
End;

Function GetFirst(var v: verem): Byte;
Var
L: PVeremelem;
Begin
GetFirst:=v.first^.ertek;
if v.first=v.last then exit;
l:=v.first;
v.first:=l^.next;
Dispose(l);
End;

Function SeeFirst2(var v: verem): Real;
Begin
SeeFirst2:=v.first^.ertek2;
End;
Function GetFirst2(var v: verem): Real;
Var
L: PVeremelem;
Begin
GetFirst2:=v.first^.ertek2;
if v.first=v.last then exit;
l:=v.first;
v.first:=l^.next;
Dispose(l);
End;

Procedure NewToVerem(var v: verem;value: Byte);
Var
P: PVeremElem;
Begin
New(P);
p^.next:=nil;
P^.ertek:=value;
if v.first=nil then
Begin
p^.next:=nil;
v.first:=P;
v.Last:=P;
End
Else
Begin
P^.next:=v.first;
v.first:=P;
End;
End;

Procedure NewToVerem2(var v: verem;value: Real);
Var
P: PVeremElem;
Begin
New(P);
P^.ertek2:=value;
if v.first=nil then
Begin
p^.next:=nil;
v.first:=P;
v.Last:=P;
End
Else
Begin
P^.next:=v.first;
v.first:=P;
End;
End;

Const
opss: String='(+-*/)';

{ Ez a függvény visszaadja a
paraméterként kapott
műveleti jel prioritását }
Function prior(s: char): Byte;
Begin
prior:=0;
if s='(' then prior:=1;
if ((s='-') or (s='+')) then prior:=2;
if ((s='*') or (s='/')) then prior:=3;
if s=')' then prior:=4;
End;

{ Készítsünk lengyelformát }
Function makePoland(s: String): String;
Var
ss: String;  {Ide készül a lengyelforma }
i: Integer;
V: Verem;
j: Integer;
Begin
InitVerem(v);
NewToVerem(v,0);
ss:='';
j:=1; {****************************************************}
for i:=1 to Length(s) do
Begin
if s[i] in ['0'..'9','.'] then ss:=ss+s[i];
{ Ha számot találunk, azt egyszerűen átírjuk }

if (s[i] in ['(',')','+','-','*','/']) then
Begin
if (ss[Length(ss)]<>' ') and (ss<>'') then ss:=ss+' ';
if s[i]<>')' then
Begin
{ Ha  műveleti jelet találunk, a nálánál
nagyobb prioritással rendelkezőket
kivesszük a veremből és átírjuk a
lengyelformába...}
While (prior(opss[SeeFirst(v)])>=prior(s[i])) and (s[i]<>'(') do
Begin
ss:=ss+opss[GetFirst(v)]+' ';
End;
{...majd az aktuális műveleti jelet
lerakjuk a verembe }
NewToVerem(v,pos(s[i],opss));
End
Else
Begin
{ Ha bezáró zárójelet találunk,
a nyitózárójelig minden műveleti
jelet átírunk a lengyelformába }
While opss[v.first^.ertek]<>'(' do
Begin
if Opss[SeeFirst(v)]<>'(' then ss:=ss+opss[GetFirst(v)]+' ';
End;
{ A nyitózárójelet nem írjuk át,
de kivesszük a veremből }
GetFirst(v);
End;
End;
End;
{ Kivesszük a veremből a maradék műveleti jeleket }
if (ss[Length(ss)]<>' ') and (ss<>'') then ss:=ss+' ';
while v.first<>v.last do ss:=ss+opss[GetFirst(v)]+' ';
makepoland:=ss;
End;

{ Itt születik az eredmény }
Function GetResult(s: String): Real;
Var
v: Verem;
i: Integer;
sx: String;
code: Integer;
h: Real;
o1,o2: Real;
Begin
InitVerem(v);
sx:='';
For i:=1 to Length(s) do
Begin
if s[i] in ['0'..'9','.'] then sx:=sx+s[i];
{ A számokat kigyűjtjük egy
átemeti változóba (sx) }
if ((s[i]=' ') and (sx<>'')) then
Begin
{ Ha egy szám véget ér,
lerakjuk a verembe }
Val(sx,h,code);
NewToVerem2(v,h);
sx:='';
End;
if s[i] in ['+','-','*','/'] then
Begin
{ Ha műveleti jelet találunk,
az operandusokat kivesszük
a veremből...}
o2:=GetFirst2(v);
o1:=GetFirst2(v);
Case s[i] of
'+': o1:=o1+o2;
'*': o1:=o1*o2;
'-': o1:=o1-o2;
'/': Begin
if o2=0 then Hiba:=er_divby0 else o1:=o1/o2;
End;
{...Elvégezzük a műveletet...}
End;
NewToVerem2(v,o1);
{...az eredményt lerakjuk a verembe}
End;
End;
{ A kiértékelés végén kivesszük a veremből
az eredményt }
GetResult:=GetFirst2(v);
End;

End.``````

And then you can write my code to try the unit lengyel

``````Program basic_operation;
Uses Crt,lengyel;      {listen the units}
var s:String;
Begin
ClrScr;
Write('Give me the expression: ');
ClrScr;
Write('Give me the expression: ');
Write(s,'=',GetResult(MakePoland(s)):0:0);
End.``````

The unit lengyel was written by another hungarian guy,so the comments are hungarian.I do not want to rewrite his comments...

I integrated the unit 'lengyel' for you now you can use this program,just copy and paste :)

``````Program Basic_expression_evaluator;
Uses Crt;
Const
Er_DivBy0 = 1;
Er_Zarjel = 2;
er_Illegal= 3;
Type
PVeremelem=^TVeremelem;
TVeremelem=Record
Ertek: Byte;
Ertek2: Real;
Next: PVeremelem;
End;
Verem=Record
First: PVeremelem;
Last: PVeremelem;
End;

var   hiba: byte;
s:String;
Function isOK(s: String): Boolean;
Var
i,zj: Integer;
Ok: Boolean;
Begin
ok:=true;
zj:=0;
For i:=1 to Length(s) do
Begin
if s[i]='(' then Inc(zj);
if s[i]=')' then Dec(zj);
if not (s[i] in ['0'..'9','+','-','*','(',')','/',' ','.']) then Begin;ok:=false;hiba:=er_illegal;End;
End;
if zj<>0 then Begin;ok:=false;Hiba:=Er_zarjel;End;
if (pos('-+',s)<>0)  or (pos('---',s)<>0) or
(pos('+--',s)<>0) or (pos('-*',s)<>0) or
(pos('+*',s)<>0)  or (pos('**',s)<>0) or
(pos('++',s)<>0)  or (pos('()',s)<>0) or
(pos('(*',s)<>0)  or (pos('+)',s)<>0) or
(pos('*)',s)<>0)  or (pos('-)',s)<>0) or
(pos(')(',s)<>0)  or (pos('(+',s)<>0) then
Begin
ok:=false;
Hiba:=Er_illegal;
End;
isok:=ok;
End;

Procedure InitVerem(var v: Verem);
Begin
v.first:=nil;
v.last:=nil;
End;

Function SeeFirst(var v: verem): byte;
Begin
SeeFirst:=v.first^.ertek;
End;

Function GetFirst(var v: verem): Byte;
Var
L: PVeremelem;
Begin
GetFirst:=v.first^.ertek;
if v.first=v.last then exit;
l:=v.first;
v.first:=l^.next;
Dispose(l);
End;

Function SeeFirst2(var v: verem): Real;
Begin
SeeFirst2:=v.first^.ertek2;
End;
Function GetFirst2(var v: verem): Real;
Var
L: PVeremelem;
Begin
GetFirst2:=v.first^.ertek2;
if v.first=v.last then exit;
l:=v.first;
v.first:=l^.next;
Dispose(l);
End;

Procedure NewToVerem(var v: verem;value: Byte);
Var
P: PVeremElem;
Begin
New(P);
p^.next:=nil;
P^.ertek:=value;
if v.first=nil then
Begin
p^.next:=nil;
v.first:=P;
v.Last:=P;
End
Else
Begin
P^.next:=v.first;
v.first:=P;
End;
End;

Procedure NewToVerem2(var v: verem;value: Real);
Var
P: PVeremElem;
Begin
New(P);
P^.ertek2:=value;
if v.first=nil then
Begin
p^.next:=nil;
v.first:=P;
v.Last:=P;
End
Else
Begin
P^.next:=v.first;
v.first:=P;
End;
End;

Const
opss: String='(+-*/)';

{ Ez a függvény visszaadja a
paraméterként kapott
műveleti jel prioritását }
Function prior(s: char): Byte;
Begin
prior:=0;
if s='(' then prior:=1;
if ((s='-') or (s='+')) then prior:=2;
if ((s='*') or (s='/')) then prior:=3;
if s=')' then prior:=4;
End;

{ Készítsünk lengyelformát }
Function makePoland(s: String): String;
Var
ss: String;  {Ide készül a lengyelforma }
i: Integer;
V: Verem;
j: Integer;
Begin
InitVerem(v);
NewToVerem(v,0);
ss:='';
j:=1;
for i:=1 to Length(s) do
Begin
if s[i] in ['0'..'9','.'] then ss:=ss+s[i];
{ Ha számot találunk, azt egyszerűen átírjuk }

if (s[i] in ['(',')','+','-','*','/']) then
Begin
if (ss[Length(ss)]<>' ') and (ss<>'') then ss:=ss+' ';
if s[i]<>')' then
Begin
{ Ha  műveleti jelet találunk, a nálánál
nagyobb prioritással rendelkezőket
kivesszük a veremből és átírjuk a
lengyelformába...}
While (prior(opss[SeeFirst(v)])>=prior(s[i])) and (s[i]<>'(') do
Begin
ss:=ss+opss[GetFirst(v)]+' ';
End;
{...majd az aktuális műveleti jelet
lerakjuk a verembe }
NewToVerem(v,pos(s[i],opss));
End
Else
Begin
{ Ha bezáró zárójelet találunk,
a nyitózárójelig minden műveleti
jelet átírunk a lengyelformába }
While opss[v.first^.ertek]<>'(' do
Begin
if Opss[SeeFirst(v)]<>'(' then ss:=ss+opss[GetFirst(v)]+' ';
End;
{ A nyitózárójelet nem írjuk át,
de kivesszük a veremből }
GetFirst(v);
End;
End;
End;
{ Kivesszük a veremből a maradék műveleti jeleket }
if (ss[Length(ss)]<>' ') and (ss<>'') then ss:=ss+' ';
while v.first<>v.last do ss:=ss+opss[GetFirst(v)]+' ';
makepoland:=ss;
End;

{ Itt születik az eredmény }
Function GetResult(s: String): Real;
Var
v: Verem;
i: Integer;
sx: String;
code: Integer;
h: Real;
o1,o2: Real;
Begin
InitVerem(v);
sx:='';
For i:=1 to Length(s) do
Begin
if s[i] in ['0'..'9','.'] then sx:=sx+s[i];
{ A számokat kigyűjtjük egy
átemeti változóba (sx) }
if ((s[i]=' ') and (sx<>'')) then
Begin
{ Ha egy szám véget ér,
lerakjuk a verembe }
Val(sx,h,code);
NewToVerem2(v,h);
sx:='';
End;
if s[i] in ['+','-','*','/'] then
Begin
{ Ha műveleti jelet találunk,
az operandusokat kivesszük
a veremből...}
o2:=GetFirst2(v);
o1:=GetFirst2(v);
Case s[i] of
'+': o1:=o1+o2;
'*': o1:=o1*o2;
'-': o1:=o1-o2;
'/': Begin
if o2=0 then Hiba:=er_divby0 else o1:=o1/o2;
End;
{...Elvégezzük a műveletet...}
End;
NewToVerem2(v,o1);
{...az eredményt lerakjuk a verembe}
End;
End;
{ A kiértékelés végén kivesszük a veremből
az eredményt }
GetResult:=GetFirst2(v);
End;
{here begins the main program}
Begin
ClrScr;
Write('Give me the expression: ');