## TFatExpression 1.01

a component by Gasper Kozak, July 2001
This component is completely free for any (ab)use. I do not promise any support or new updates. The component probably includes bugs. If you find any, please let me know.
check for a new version on Delphi pages.

new from 1.0
* bug-fix: factorial operation (!)
* bug-fix: operation processing order was messed-up (8-2-2 was 8, now it's 4)
* added scientific notation support (1.23E-2 = 1.23 * 10^(-2))

this is an expression-calculation component. Simply by passing an string-expression to it, you can evaluate its value. It uses a very simple parser and a syntax-tree approach.
FEATURES
operations: + - * / ^ !
parenthesis: ( )
functions:
In the TFatExpression component, there is a Functions: TStringList property, which holds a list of user-defined functions. These can be entered at design-time, or assigned at run-time (see demo). Functions without parameters can also serve as constants (see bellow for function Pi).
the function format is as follows:

    function = function_name [ "(" argument_name [";" argument_name ... ] ")" ] "=" expression

valid function_name (and also argument_name) consists of:

     first character      = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_
     every next character = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$#@&0123456789

here are a few examples of valid functions:
no parameter: Pi=3.14
one parameter: f(t) = 4*t*t + 2*t + 1
one parameter: sqr(x)=x*x
one parameter: sqrt(x)=x^(1/2)
see how functions can include each other
one parameter: circle_area(radius)=Pi*sqr(radius)
two parameters: add(x;y)=x + y
note: in function definition and also in expression, multiple parameters must be separated with a ";" character.
When calculating, you would use some of these functions like this:
FatExpression1.Text := 'sqr(2) + sqrt(16) + add(4; 4)';
in this case, function FatExpression1.Value should return 16
Another type of function-implementing is available. If the component, while evaluating the expression, comes along an unknown function, it generates an OnEvaluate event. It passes the function name, argument count and argument list to the event, expecting the programer to provide it's result value. This can be used for variables, arrays and constants that are application-dependant.
Here is some code showing how you could make the "add(x;y)=x+x" function the other way, by not adding it to the Functions property.
The event handler first checks the Eval argument, and if is the right function (add), it returns a result of "first argument plus second argument" to the Value. Argument list is zero-based, meaning the first argument is Args[0], second is Args[1], ... and the last is Args[ArgCount - 1]. ArgCount tells you how many arguments are in the Args array.

    procedure TForm1.FatExpression1Evaluate(Sender: TObject; Eval: String;
      Args: array of Double; ArgCount: Integer; var Value: Double);
    begin
      if UpperCase(Eval) = 'ADD' then
        Value := Args[0] + Args[1];
    end;

This code is equal to writing "add(x;y)=x+y" function in the Functions property, although it is probably faster, since it is compiled and optimized by Delphi. There is also one big advantage using this approach. it has a dynamic number of arguments.
Imagine this:
you add this function to the FatExpression1.Functions property: "add(a;b;c;d;e;f;g;h)=a+b+c+d+e+f+g+h".
In expression, you can pass less or more arguments (than there are specified in the function-definition) to the function-call, for example:
FatExpression1.Text := 'add(1;2;3)'; // returns 6
FatExpression1.Text := 'add(1;1;1;1;1;1;1;1;1;1;1;1;1)'; // returns 8, because the function definition only includes 8 parameters
If you pass less arguments, than the parser expects, the missing parameter are treated as zeros.
As you can see in demo, I handle the ADD function through OnEvaluate event. This way, I can take care of any number of arguments passed to the function-call:

      var I: Integer;

      if UpperCase(Eval) = 'ADD' then
        for I := 0 to ArgCount - 1 do
          Value := Value + Args[I];

This code will add any number of arguments and return the value. So now, a call to
FatExpression1.Text := 'add(1;1;1;1;1;1;1;1;1;1;1;1;1)';
returns 13.
Function-calls in expression can also be nested within each other:
add(add(1; 1); add(1; 1))
add(add(add(add(1); 1); 1); 1))
add(add(add(add(4))))
All these functions return 4.

properties

- EvaluateOrder: TEvaluateOrder = (eoInternalFirst, eoEventFirst)
  Sets the order of evaluating functions. eoInternalFirst means the Functions property is checked first. If the function is found, it is evaluated and no event is triggered. If the function is not found, the event is triggered.
- Functions: TStringList
  A list of functions in specified format.
- Text: String
  The mathematical expression in string. This cannot be an equation.
- Value: Double
  Returns the value of "Text", using Functions property and OnEvaluate event for evaluating unknown functions.

events

- OnEvaluate(Sender: TObject; Eval: String; Args: array of Double; ArgCount: Integer; var Value: Double; var Done: Boolean)
  Eval is the name of the evaluated function. Args is the array of values, presenting the called function's arguments. ArgCount is number of elements in Args. Args is zero-based array. The Value argument is the result value that should be filled. If you handle the function and return the result, you should set Done to TRUE.

so... this is the basic info. For more, you should see demo, dig into the source or email me (in this order).

eof