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;
             writeln(c); readln;
        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);
   readln;
end;

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

Recommended Answers

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.

http://www.codeproject.com/KB/recipes/sota_expression_evaluator.aspx

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

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: ');
     ReadLn(s);
     ClrScr;
     Write('Give me the expression: ');
     Write(s,'=',GetResult(MakePoland(s)):0:0);
     ReadLn;
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: ');
     ReadLn(s);
     ClrScr;
     Write('Give me the expression: ');
     Write(s,'=',GetResult(MakePoland(s)):0:0);
     ReadLn;
End.
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.