See my code, can calculate + - * /.
type
EExpression = class(Exception);
TOperatorPriority = (opError, opLower, opSame, opHigher);
const
Operators = '+-*/()#';
OpPriority: array[1..7, 1..7] of TOperatorPriority = (
(opHigher, opHigher, opLower, opLower, opLower, opHigher, opHigher),
(opHigher, opHigher, opLower, opLower, opLower, opHigher, opHigher),
(opHigher, opHigher, opHigher, opHigher, opLower, opHigher, opHigher),
(opHigher, opHigher, opHigher, opHigher, opLower, opHigher, opHigher),
(opLower, opLower, opLower, opLower, opLower, opSame, opError ),
(opHigher, opHigher, opHigher, opHigher, opError, opHigher, opHigher),
(opLower, opLower, opLower, opLower, opLower, opError, opSame )
);
{ Math expression calculation }
{ Compare priority of between Op1 and Op2
Result
opLower: Op1's priority is lower than Op2's
opSame: Op1's priority is same as Op2's
opHigher: Op1's priority is higher than Op2's }
function ComparePriority(Op1, Op2: Char): TOperatorPriority;
var
I1, I2: Integer;
begin
Result := opError;
I1 := Pos(Op1, Operators);
I2 := Pos(Op2, Operators);
if (I1 > 0) and (I2 > 0) then
Result := OpPriority[I1, I2];
end;
function IsOperator(C: Char): Boolean;
begin
Result := Pos(C, Operators) > 0;
end;
procedure GetElement(var P: PChar;
var Optr: Char;
var Opnd: string);
function GetOperand(var P: PChar): string;
var
P0: PChar;
begin
P0 := P;
while (P^ <> #0) and not IsOperator(P^)do
Inc(P);
SetString(Result, P0, P - P0);
end;
function GetOperator(var P: PChar): Char;
begin
Result := P^;
Inc(P);
end;
begin
Optr := #0;
Opnd := '';
if IsOperator(P^) then
Optr := GetOperator(P) else
Opnd := GetOperand(P);
end;
function Operate(A, B:do
uble;
Optr: Char):do
uble;
begin
case Optr of
'+': Result := A + B;
'-': Result := A - B;
'*': Result := A * B;
'/': Result := A / B;
else
raise EExpression.CreateFmt('Invalid operate: %s', [Optr]);
end;
end;
function CalcExpr(const Expr: string): string;
var
OptrStack, OpndStack: TStack;
S, Opnd: string;
Optr,do
Optr: Char;
P: PChar;
OpndA, OpndB: ^Double;
begin
// '#' used as the terminator of expression
S := Expr + '#';
OptrStack := TStack.Create;
OpndStack := TStack.Create;
try
{ To decide whether expression has been calculated completely, we add a
'#' before calculation. When OptrStack left only one item '#', and the
last terminator '#' is reached, the calculation is over. }
OptrStack.Push(Pointer(Byte('#')));
P := PChar(S);
GetElement(P, Optr, Opnd);
while (Optr <> '#') or (Char(OptrStack.Peek) <> '#')do
begin
if Optr = #0 then
begin
GetMem(OpndA, SizeOf(Double));
OpndA^ := StrToFloat(Opnd);
OpndStack.Push(OpndA);
GetElement(P, Optr, Opnd);
end else
case ComparePriority(Char(OptrStack.Peek), Optr) of
opError:
raise EExpression.Create('Invalid expression');
opLower: // Priority is lower, so push Optr into OptrStack as the current
begin
// Operator
OptrStack.Push(Pointer(Byte(Optr)));
GetElement(P, Optr, Opnd);
end;
opSame: // Priority is same, this case only occurs parentheses '(', ')',
begin
// so simply Pop the '(' and discard it
OptrStack.Pop;
GetElement(P, Optr, Opnd);
end;
OpHigher: // Priority is higher, so pop and calculate (operandA operator
begin
// operandB), and push the result into OpndStack as an operand
do
Optr := Char(OptrStack.Pop);
OpndB := OpndStack.Pop;
OpndA := OpndStack.Pop;
OpndA^ := Operate(OpndA^, OpndB^,do
Optr);
OpndStack.Push(OpndA);
// OperandA is the result of Operate, can't free its memory
FreeMem(OpndB);
// OperandB is not used, free its memory
end;
end;
end;
{ OptrStack left the only operator '#', and OpndStack must only left one
item too, that's the expression result }
if OpndStack.Count <> 1 then
raise EExpression.Create('Invalid expression');
OpndA := OpndStack.Pop;
Result := FloatToStr(OpndA^);
FreeMem(OpndA);
finally
OptrStack.Free;
OpndStack.Free;
end;
end;