Contributor: WARREN PORTER 
{
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.
 

AltStyle によって変換されたページ (->オリジナル) /