unit Unit5;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, contnrs, Math, Dialogs;
type
PInt = ^Integer;
{ RPNCreator }
RPNCreator = class
private
operatori: TStack;
operandi: TStack;
value: String;
function IsOperator(c: Char): Boolean;
function Precedence(n1, n2: Char): Integer;
procedure ReduceOperator;
function InfixToPostfix: Double;
public
constructor Create(v: String);
function Calculate: Double;
end;
implementation
{ RPNCreator }
constructor RPNCreator.Create(v: String);
begin
operatori := TStack.Create;
operandi := Tstack.Create;
value := v; //la stringa che contiene la funzione da calcolare
end;
function RPNCreator.Calculate: Double;
begin
Result := InfixToPostfix;
end;
function RPNCreator.IsOperator(c: Char): Boolean;
begin
case c of
'+', '-', '*', '/', '^': Result := True;
else
Result := False;
end;
end;
function RPNCreator.Precedence(n1, n2: Char): Integer;
var
a, b: Integer;
begin
case n1 of
'(': a := 4;
'^': a := 3;
'*', '/': a := 2;
'+', '-': a := 1;
else
a := 0;
end;
case n2 of
'(': b := 4;
'^': b := 3;
'*', '/': b := 2;
'+', '-': b := 1;
else
b := 0;
end;
Result := a - b;
end;
procedure RPNCreator.ReduceOperator;
var
opCurr: Char;
a, b: Double;
ris: PDouble;
begin
opCurr := Char(operatori.Pop^);
case opCurr of
'*':
begin
a := Double(operandi.Pop^);
b := Double(operandi.Pop^);
New(ris);
ris^ := a * b;
operandi.Push(ris);
end;
'/':
begin
a := Double(operandi.Pop^);
b := Double(operandi.Pop^);
New(ris);
ris^ := a / b;
operandi.Push(ris);
end;
'+':
begin
a := Double(operandi.Pop^);
b := Double(operandi.Pop^);
New(ris);
ris^ := a + b;
operandi.Push(ris);
end;
'-':
begin
a := Double(operandi.Pop^);
b := Double(operandi.Pop^);
New(ris);
ris^ := a - b;
operandi.Push(ris);
end;
'^':
begin
a := Double(operandi.Pop^);
b := Double(operandi.Pop^);
New(ris);
ris^ := Power(a, b);
operandi.Push(ris);
end;
end;
end;
function RPNCreator.InfixToPostfix: Double;
var
i, aux: Integer;
c, s: Char;
n: PInt;
begin
i := 1;
value := Trim(value);
while i < Length(value) do
begin
if value[i] = ')' then
begin
while Char(operatori.Peek^) <> '(' do
begin
ReduceOperator;
end;
operatori.Pop;
end;
if value[i] = '(' then
operatori.Push(@value[i])
else
if IsOperator(value[i]) then
begin
if Precedence(Char(operatori.Peek^), value[i]) < 0 then
operatori.Push(@value[i])
else
begin
ReduceOperator;
operatori.Push(@value[i]);
end;
end
else //è un numero, vediamo se è a più cifre
begin
New(n);
n^ := 0;
while TryStrToInt(value[i], aux) do
begin
n^ := n^ * 10;
n^ := n^ + aux;
Inc(i);
end;
operandi.Push(n);
end;
Inc(i);
end;
while operatori.Count > 0 do
ReduceOperator;
Result := Double(operandi.Peek^);
end;
end.