home *** CD-ROM | disk | FTP | other *** search
- {
- From: WARREN PORTER
- Subj: eval
- Program to evaluate expressions using a stack. }
-
- const
- Maxstack = 100;
-
- type
-
- stack = record
- top : 0..Maxstack;
- Item : array[1..Maxstack] of char
- end;
-
- RealStack = record
- top: 0..Maxstack;
- Item : array[1..Maxstack] of real
- end;
-
- xptype = record
- oper : char;
- opnd : real
- end;
-
- Function Empty(var A:stack):boolean;
-
- Begin
- Empty:= A.top = 0;
- End;
-
- Function Pop(var A:stack):char;
-
- Begin
- if A.Top < 1 then
- begin
- writeln('Attempt to pop an empty stack');
- halt(1)
- end;
- Pop:= A.item[A.top];
- A.top:= A.top - 1
- End;
-
- Procedure Push(var A:stack; Nchar:char);
-
- Begin
- if A.Top = Maxstack then
- begin
- writeln('Stack already full');
- halt(1)
- end;
- A.top:= A.top + 1;
- A.item[A.top]:=Nchar
- End;
-
- {The following functions are for the real stack only.}
-
- Function REmpty(var D:RealStack):boolean;
-
- Begin
- REmpty:= D.top = 0;
- End;
-
- Function RPop(var D:RealStack):real;
-
- Begin
- if D.Top < 1 then
- begin
- writeln('Attempt to pop an empty RealStack');
- halt(1)
- end;
- RPop:= D.item[D.top];
- D.top:= D.top - 1
- End;
-
- Procedure RPush(var D:RealStack; Nreal:real);
-
- Begin
- if D.Top = MaxStack then
- begin
- writeln('Stack already full');
- halt(1)
- end;
- D.top:= D.top + 1;
- D.item[D.top]:=Nreal
- End;
-
- Function pri(op1, op2:char):boolean;
-
- var
- tpri: boolean;
- Begin
- if op2 = ')' then
- tpri:= true else
- if (op1 = '$') and (op2 <> '$') and (op2 <> '(') then
- tpri:= true else
- if (op1 in ['*','/']) and (op2 in ['+','-']) then
- tpri:= true
- else
- tpri:= false;
- pri:= tpri{;
- write('Eval op 1= ',op1, ' op2 = ',op2);
- if tpri= false then
- writeln(' false')
- else
- writeln(' true')}
- End;
-
- Function ConvReal(a:real;NumDec:integer):real;
-
- var
- i, tenpower: integer;
-
- Begin
- tenpower:= 1;
- for i:= 1 to NumDec do
- tenpower:= tenpower * 10;
- ConvReal:= a / tenpower
- End;
-
- Function ROper(opnd1, opnd2: real; oper: char):real;
- Var temp: real;
-
- Begin
- Case oper of
- '+': temp:= opnd1 + opnd2;
- '-': temp:= opnd1 - opnd2;
- '*': temp:= opnd1 * opnd2;
- '/': temp:= opnd1 / opnd2;
- '$': temp:= exp(ln(opnd1) * opnd2)
- End {Case} ;
- {Writeln(opnd1:6:3,' ',oper,' ',opnd2:6:3 ,' = ',temp:6:3);}
- ROper := temp
- End; {R oper}
-
- {Main procedure starts here}
-
- var
- A: stack;
- Inbuff:string[Maxstack];
- len, i, j, NumDecPnt, lenexp: integer;
- temp, opnd1, opnd2, result : real;
- valid, expdigit, expdec, isneg, openok: boolean;
- operators, digits : set of char;
- HoldTop : char;
- B: array[1..Maxstack] of xptype;
- C: array[1..Maxstack] of xptype;
- D: RealStack;
-
- Begin
- digits:= ['0'..'9'];
- operators:= ['$','*','/','+','-','(',')'];
- Writeln('Enter expression to evaluate or RETURN to stop');
- Writeln('A space should follow a minus sign unless it is used to');
- Writeln('negate the following number. Real numbers with multi-');
- Writeln('digits and decimal point (if needed) may be entered.');
- Writeln;
- Readln(Inbuff);
- len:=length(Inbuff);
-
- repeat
- i:= 1;
- A.top:= 0;
- valid:= true;
- repeat
- if Inbuff[i] in ['(','[','{'] then
- push(A,Inbuff[i])
- else
- if Inbuff[i] in [')',']','}'] then
- if empty(A) then
- valid:= false
- else
- if (ord(Inbuff[i]) - ord(Pop(A))) > 2 then
- valid:= false;
- i:= i + 1
- until (i > len) or (not valid);
- if not empty(A) then
- valid:= false;
- if not valid then
- Writeln('The expression is invalid')
- else
- Begin
- {Change all groupings to parenthesis}
- for i:= 1 to len do Begin
- if Inbuff[i] in ['[','{'] then
- Inbuff[i]:= '(' else
- if Inbuff[i] in [']','}'] then
- Inbuff[i]:= ')';
- B[i].oper:= ' ';
- B[i].opnd:= 0;
- C[i].oper:= ' ';
- C[i].opnd:= 0 End;
-
- { The B array will be the reformatted input string.
- The C array will be the postfix expression. }
-
- i:= 1; j:= 1; expdigit:= false; expdec:= false; isneg:= false;
- while i <= len do
- Begin
- if (Inbuff[i] = '-') and (Inbuff[i + 1] in digits) then
- Begin
- isneg:= true;
- i:= i + 1
- End;
- if (Inbuff[i] = '.' ) then Begin
- i:= i + 1;
- expdec:= true End;
- if Inbuff[i] in digits then
- Begin
- if expdec then
- NumDecPnt:= NumDecPnt + 1;
- if expdigit then
- temp:= temp * 10 + ord(inbuff[i]) - ord('0')
- else Begin
- temp:= ord(inbuff[i]) - ord('0');
- expdigit:= true End
- End
- else
- if expdigit = true then Begin
- if isneg then
- temp:= temp * -1;
- B[j].opnd:= ConvReal(temp,NumDecPnt);
- j:= j + 1;
- expdigit := false;
- expdec := false;
- NumDecPnt:= 0;
- isneg:= false End;
-
- If Inbuff[i] in operators then Begin
- B[j].oper:= Inbuff[i];
- j:= j + 1 End;
-
- if not (Inbuff[i] in digits) and
- not (Inbuff[i] in operators) and
- not (Inbuff[i] = ' ') then Begin
- Writeln('Found invalid operator: ',Inbuff[i]);
- valid:= false End;
-
- i:= i + 1;
-
- End; {While loop to parse string.}
-
- if expdigit = true then Begin
- if isneg then
- temp:= temp * -1;
- B[j].opnd:= ConvReal(temp,NumDecPnt);
- j:= j + 1;
- expdigit := false;
- expdec := false;
- NumDecPnt:= 0;
- isneg:= false End;
-
- End; {First if valid loop. Next one won't run if invalid operator}
-
- if valid then
- Begin
- lenexp:= j - 1; {Length of converted expression}
- writeln;
- for i:= 1 to lenexp do
- Begin
- if B[i].oper = ' ' then
- write(B[i].opnd:2:3)
- else
- write(B[i].oper);
- write(' ')
- End;
-
- {Ready to create postfix expression in array C }
-
- A.top:= 0;
- j:= 0;
-
- for i:= 1 to lenexp do
- Begin
- {writeln('i = ',i);}
- if B[i].oper = ' ' then Begin
- j:= j + 1;
- C[j].opnd:= B[i].opnd End
- else
- Begin
- openok := true;
- while (not empty(A) and openok and
- pri(A.item[A.top],B[i].oper)) do
- Begin
- HoldTop:= pop(A);
- if HoldTop = '(' then
- openok:= false
- else
- Begin
- j:= j + 1;
- C[j].oper:=HoldTop
- End
- End;
- if B[i].oper <> ')' then
- push(A,B[i].oper);
- End; {Else}
- End; {For loop}
-
- while not empty(A) do
- Begin
- HoldTop:= pop(A);
- if HoldTop <> '(' then
- Begin
- j:= j + 1;
- C[j].oper:=HoldTop
- End
- End;
-
- lenexp:= j; {Since parenthesis are not included in postfix.}
-
- for i:= 1 to lenexp do
- Begin
- if C[i].oper = ' ' then
- write(C[i].opnd:2:3)
- else
- write(C[i].oper);
- write(' ')
- End;
-
- {The following evaluates the expression in the real stack}
-
- D.top:=0;
- for i:= 1 to lenexp do
- Begin
- if C[i].oper = ' ' then
- Rpush(D,C[i].opnd)
- else
- Begin
- opnd2:= Rpop(D);
- opnd1:= Rpop(D);
- result:= ROper(opnd1,opnd2,C[i].oper);
- Rpush(D,result)
- End {else}
- End; {for loop}
- result:= Rpop(D);
- if Rempty(D) then
- writeln(' = ',result:2:3)
- else
- writeln(' Could not evaluate',chr(7))
- End;
-
- Readln(Inbuff);
- len:= length(Inbuff)
- until len = 0
- End.
-