236 lines
5.1 KiB
ObjectPascal
236 lines
5.1 KiB
ObjectPascal
unit FormExpr;
|
|
{--------------------------------------------------------------
|
|
| TFormulaParser
|
|
| Multi formula support
|
|
| Extension by Xavier Mor-Mur
|
|
| xmormur@telepolis.com
|
|
| xmormur@teleline.es
|
|
|
|
|
|---------------------------------------------------------------}
|
|
interface
|
|
uses Dialogs, OObjects, SysUtils, Classes, ParseExpr, ParseClass;
|
|
type
|
|
|
|
TFormulaParser = class(TExpressionParser)
|
|
private
|
|
FormulaNames: TStringList;
|
|
tslTmp: TStringList;
|
|
bTrace: Boolean;
|
|
ExprResult: double;
|
|
protected
|
|
procedure FillExpressList; override;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
function Formula(FName, FExpr: string): Integer;
|
|
function Eval(FIndex: Integer): double; overload;
|
|
function Eval(FName: string): double; overload;
|
|
function Index(FName: string): Integer;
|
|
function Name(FIndex: Integer): string;
|
|
function Text(FName: string): string;
|
|
property Trace: Boolean read bTrace write bTrace;
|
|
end;
|
|
implementation
|
|
uses Math;
|
|
|
|
var
|
|
sExpr: string; // needed for display(...) function
|
|
|
|
{ TFormulaParser }
|
|
|
|
constructor TFormulaParser.Create;
|
|
begin
|
|
inherited;
|
|
FormulaNames := TStringList.Create;
|
|
tslTmp := TStringList.Create;
|
|
DefineVariable('#', @ExprResult);
|
|
end;
|
|
|
|
destructor TFormulaParser.Destroy;
|
|
begin
|
|
inherited;
|
|
FormulaNames.Free;
|
|
tslTmp.Free;
|
|
end;
|
|
|
|
//---> Added start
|
|
// set formula string
|
|
|
|
function TFormulaParser.Formula(FName, FExpr: string): Integer;
|
|
var
|
|
i, j: Integer;
|
|
expr: TStringList;
|
|
begin
|
|
tslTmp.Clear;
|
|
tslTmp.SetText(PChar(FExpr));
|
|
expr := TStringList.Create;
|
|
Result := -1;
|
|
i := FormulaNames.IndexOf(FName);
|
|
if i >= 0 then
|
|
FormulaNames.Delete(i);
|
|
if tslTmp.Count > 0 then
|
|
begin
|
|
for i := 0 to tslTmp.Count - 1 do
|
|
begin
|
|
if tslTmp.Strings[i] <> '' then
|
|
begin
|
|
j := AddExpression(tslTmp.Strings[i]);
|
|
if j < 0 then
|
|
break;
|
|
if (copy(Expression[j], 1, 5) = 'goto(') or
|
|
(copy(Expression[j], 1, 7) = 'ifgoto(') or
|
|
(copy(Expression[j], 1, 8) = 'display(') or
|
|
(copy(Expression[j], 1, 4) = 'stop') then
|
|
expr.Add(IntToStr(-(j + 1)))
|
|
else
|
|
expr.Add(IntToStr(j + 1));
|
|
end;
|
|
end;
|
|
if expr.Count > 0 then
|
|
Result := FormulaNames.AddObject(FName, TObject(expr));
|
|
end;
|
|
end;
|
|
|
|
// evaluate formula by name
|
|
|
|
function TFormulaParser.Eval(FName: string): double;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := 0;
|
|
i := FormulaNames.IndexOf(FName);
|
|
if i >= 0 then
|
|
Result := Eval(i);
|
|
end;
|
|
|
|
// evaluate formula by index
|
|
|
|
function TFormulaParser.Eval(FIndex: Integer): double;
|
|
var
|
|
i, j, k: Integer;
|
|
expr: TStringList;
|
|
begin
|
|
ExprResult := 0;
|
|
if (FIndex >= 0) and (FIndex < FormulaNames.Count) then
|
|
begin
|
|
expr := TStringList(FormulaNames.Objects[FIndex]);
|
|
i := 0;
|
|
while i < expr.Count do
|
|
begin
|
|
Val(expr.Strings[i], j, k);
|
|
sExpr := '(' + IntToStr(i + 1) + ') ' + Expression[abs(j) - 1] +
|
|
char($0D0A) + char($0D0A);
|
|
if j < 0 then
|
|
begin
|
|
k := trunc(AsFloat[abs(j) - 1]);
|
|
if k > 0 then
|
|
i := k - 1 // goto(...), ifgoto(...), stop
|
|
else
|
|
begin
|
|
i := i + 1; // display(...)
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
ExprResult := AsFloat[abs(j) - 1];
|
|
i := i + 1;
|
|
end;
|
|
if Trace then
|
|
ShowMessage(sExpr + FloatToStr(ExprResult));
|
|
end;
|
|
end;
|
|
Result := ExprResult;
|
|
end;
|
|
|
|
// get formula index from its name
|
|
|
|
function TFormulaParser.Index(FName: string): Integer;
|
|
begin
|
|
Result := FormulaNames.IndexOf(FName);
|
|
end;
|
|
|
|
// get formula name from its index
|
|
|
|
function TFormulaParser.Name(FIndex: Integer): string;
|
|
begin
|
|
if (FIndex >= 0) and (FIndex < FormulaNames.Count) then
|
|
Result := FormulaNames.Strings[FIndex]
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
// get formula string
|
|
|
|
function TFormulaParser.Text(FName: string): string;
|
|
var
|
|
i, j, k: Integer;
|
|
expr: TStringList;
|
|
begin
|
|
tslTmp.Clear;
|
|
i := FormulaNames.IndexOf(FName);
|
|
if i >= 0 then
|
|
begin
|
|
expr := TStringList(FormulaNames.Objects[i]);
|
|
for i := 0 to expr.Count - 1 do
|
|
begin
|
|
Val(expr.Strings[i], j, k);
|
|
tslTmp.Add(Expression[abs(j)-1]);
|
|
end;
|
|
end;
|
|
Result := tslTmp.Text;
|
|
end;
|
|
|
|
procedure _stop(Param: PExpressionRec);
|
|
begin
|
|
with Param^ do
|
|
begin
|
|
Res := 999999;
|
|
end;
|
|
end;
|
|
|
|
procedure _goto(Param: PExpressionRec);
|
|
begin
|
|
with Param^ do
|
|
begin
|
|
Res := trunc(Args[0]^);
|
|
end;
|
|
end;
|
|
|
|
procedure _ifgoto(Param: PExpressionRec);
|
|
begin
|
|
with Param^ do
|
|
begin
|
|
if Args[0]^ < 0 then
|
|
Res := Args[1]^
|
|
else if Args[0]^ = 0 then
|
|
Res := Args[2]^
|
|
else if Args[0]^ > 0 then
|
|
Res := Args[3]^;
|
|
end;
|
|
end;
|
|
|
|
procedure _display(Param: PExpressionRec);
|
|
begin
|
|
with Param^ do
|
|
begin
|
|
sExpr := sExpr + char($0D0A) + char($0D0A) + FloatToStr(Args[0]^);
|
|
ShowMessage(sExpr);
|
|
Res := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TFormulaParser.FillExpressList;
|
|
begin
|
|
inherited;
|
|
with WordsList do
|
|
begin
|
|
Add(TFunction.Create('stop', 'stop execution formula', _stop, 0));
|
|
Add(TFunction.Create('goto', 'goto line number', _goto, 1));
|
|
Add(TFunction.Create('ifgoto', 'conditional goto', _ifgoto, 4));
|
|
Add(TFunction.Create('display', 'display result', _display, 1));
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|