0

I am faced with a task of allowing the user to define the expressions using the compiled classes with RTTI enabled. Let me put it in a simple way.

TAnimal = class(TPersistent)
private
  fWeight : Double;
  fHeight : Double;
  fName : string;
published
  property Weight : Double read fWeight write fWeight;
  property Height : Double read fHeight write fHeight;
  property Name : string read fName write fName;
end;

And i have a routine which will evaluate the animal with the supplied expression

function EvaluateAnimal(const animal : TAnimal; expression : string) : Double;
begin
  //Result :=  Turn expression to evaluation and give the result
end;

The user expression is (TAnimal.Weight * TAnimal.Height)/(TAnimal.Weight + TAnimal.Height)

Now, I can get the TAnimal using the RTTI Context and get the value of the animal's Height and Weight. However, how can i evaluate the expression what the user has supplied??

Is there any mechanism which i can use to prepare the user expression when my application starts and at runtime, just send the instance of animal to retrieve the value. The user is free to change the expression at anytime and the application has to evaluate the expression.

I am using Delphi XE3.

Rahul W
  • 833
  • 11
  • 26
  • I'd use JclExprEval for this. What's more, the properties are instance properties and not class properties. – David Heffernan May 20 '13 at 13:26
  • For mathematical parsers, see [`mathematical expression parser in Delphi?`](http://stackoverflow.com/q/1326258/576719). Depending on how complex the expression is, a scripting language could be used, see [`Scripting library for Delphi`](http://stackoverflow.com/q/226135/576719). – LU RD May 20 '13 at 13:30
  • @LURD but, does using scripting library introduce any performance bottlenecks?? like if the expression is parsed all the time. – Rahul W May 20 '13 at 13:43
  • @DavidHeffernan if i have to write a expression evaluator, what should be the starting point?? I m keen on developing the framework to solve my problem. – Rahul W May 20 '13 at 13:45
  • @RahulW Well, I'm suggesting that you don't do that. Just use `JclExprEval`. Has all you need. XE3 has live bindings with an expression evaluator, but I've personally never used it. I expect that it works. – David Heffernan May 20 '13 at 13:48
  • 2
    I guess the inner workings of scripting languages all differs a bit. Many of them allows to pre-compile at runtime and run multiple times. I suggest to look at [`DWScript`](https://code.google.com/p/dwscript/wiki/FAQ). – LU RD May 20 '13 at 13:49

1 Answers1

2

You can use Live Bindings to evaluate expressions. Here's a trivial example:

program BindingsDemo;
{$APPTYPE CONSOLE}

uses
  System.Rtti,
  System.Bindings.Expression,
  System.Bindings.EvalProtocol,
  System.Bindings.Helper;

type
  TFoo = class
    Val1: Integer;
    Val2: Integer;
    Result: TValue;
  end;

procedure Main;
var
  Foo: TFoo;
  scope: IScope;
  expr: TBindingExpression;
begin
  Foo := TFoo.Create;
  Foo.Val1 := 42;
  Foo.Val2 := 666;
  scope := TBindings.CreateAssociationScope([Associate(Foo, 'Foo')]);
  expr := TBindings.CreateUnmanagedBinding(
    [Scope],
    'Foo.Val1 + Foo.Val2',
    [Scope],
    'Foo.Result',
    nil
  );
  expr.Evaluate;
  Assert(Foo.Result.AsInteger=708);
  Writeln(Foo.Result.ToString);
end;

begin
  Main;
  Readln;
end.

Note, I've intentionally omitted the code to free objects and so this code leaks. I chose to do that so we could concentrate on the expression evaluation aspect.

Vivian Mills
  • 2,552
  • 14
  • 19
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • The line expr.Evaluate, does it try to parse the expression again or will it be compiled to some arbitrary code stack and evaluated? The reason being, the expressions needs to be evaluated for many objects of the same kind with near realtime processing. Anyways, i will follow on the same lines which you have suggested and check the performance. – Rahul W May 20 '13 at 14:30
  • The expression is compiled in the call to `CreateUnmanagedBinding`. It's not compiled to executable code, just to an intermediate representation of the expression which is then evaluated. – David Heffernan May 20 '13 at 14:39