
This file documents the TStExpression and TStExpressionEdit components.


TStExpression
=============

TStExpression is a non-visual component that provides expression evaluation
at several different levels. At the lowest level, simple mathematical
expressions can be evaluated and the resulting value obtained. On a higher
level, you can define alpha-numeric constants that can then be used within
expressions; You can add user-defined functions (and even methods of a class)
so that the names of these routines can be used in expressions; You can
define variables that relate directly to variables in your program and even
use them in expressions.

Note: TStExpression replaces AnalyzeExpr that SysTools version 2.00 provided,
but a version of that routine is still provided for backward compatibility.

The TStExpression expression parser implements the following grammar, similar
to a subset of Pascal:

   expression:    term | expression+term | expression-term
   term:          factor | term*factor | term/factor
   factor:        base | base^factor
   base:          unsigned_num | (expression) | sign factor | func_call
   unsigned_num:  digit_seq | digit_seq.digit_seq | digit_seq scale_fac |
                  digit_seq.digit_seq scale_fac
   sign:          + | -
   func_call:     identifier | identifier(params)
   params:        expression | params,expression
   scale_fac:     E digit_seq | E sign digit_seq
   digit_seq:     digit | digit_seq digit
   identifier:    starts with A..Z,_ continues with A..Z,_,0..9
   digit:         0..9

Case is not significant when matching characters.

The grammar follows normal rules of arithmetic precedence, with ^ highest, *
and / in the middle, and + and - lowest.  Thus, 1+2*3^4 means 1+(2*(3^4)).
Parentheses can be used to force non-default precedence.

Note that the power operator x^y is right-associative. This means that
2^0.5^2 is equivalent to 2^(0.5^2). All other arithmetic operators are left
associative: 1-2-3 is equivalent to (1-2)-3.

The following functions are supported in 16-bit and 32-bit applications:

    abs, arctan, cos, exp, frac, int(trunc), ln, pi, round, sin, sqr,
    sqrt

If the VCL Math unit is available and you define the "UseMathUnit" define in
STDEFINE.INC, the following are also available:

    arccos, arcsin, arctan2, tan, cotan, hypot, cosh, sinh, tanh,
    arccosh, arcsinh, arctanh, lnxp1, log10, log2, logn, ceil, floor

The calling conventions for all functions match those of the VCL runtime
library or Math unit. The acceptable parameter ranges and output values also
match thoses of the VCL runtime library or MATH unit.

When the input expression contains an error, TStExpression raises an
exception of type EStExprError. Its ErrorCode property provides more detail
about the error. Its ErrorColumn property gives the string index of the start
of the token where the error was detected.

TStExpression is very flexible. You can add support for your own functions
easily. For example, to add support for the Sin() function, first write a
function to provide the proper number and type of parameters (the "far" can
be omitted with 32-bit compilers):

function _Sin(Value : TStFloat) : TStFloat; far;
begin
  Result := Sin(Value);
end;

and then add it to the TStExpression component:

   MyStExpression.AddFunction1Param('sin', _Sin);

Or, if you wanted to use a method of the form (or any other class) that you
were working in, you could do the same thing this way:

function MyForm._Sin(Value : TStFloat) : TStFloat;
begin
  Result := Sin(Value);
end;

and then add it to the TStExpression component:

  MyStExpression.AddMethod1Param('sin', _Sin);

TStExpression supports user-defined functions with 0 to 3 parameters. The
parameters and function result must be the TStFloat type (defined in the
STBASE unit). In the example above, that's why we didn't just add
the Sin() function directly, in the call to AddFunction1Param -- The
TStExpression component must know the data types of parameters and return
values. If the function you are adding has no parameters, use the
AddFunction0Parm() method. AddFunction2Param for functions with two
parameters, etc.

The following function and method types define all possible user-defined
function and method types accepted by the TStExpression component:

  {user-defined functions with up to 3 parameters}
  TStFunction0Param =
    function : TStFloat;
  TStFunction1Param =
    function(Value1 : TStFloat) : TStFloat;
  TStFunction2Param =
    function(Value1, Value2 : TStFloat) : TStFloat;
  TStFunction3Param =
    function(Value1, Value2, Value3 : TStFloat) : TStFloat;

  {user-defined methods with up to 3 parameters}
  TStMethod0Param =
    function : TStFloat
    of object;
  TStMethod1Param =
    function(Value1 : TStFloat) : TStFloat
    of object;
  TStMethod2Param =
    function(Value1, Value2 : TStFloat) : TStFloat
    of object;
  TStMethod3Param =
    function(Value1, Value2, Value3 : TStFloat) : TStFloat
    of object;

Add predefined constant values by using the AddConstant method:

  AddConstant('X', 50)

Then, in any expression that uses the identifier "X", the value 50 will be
used when the expression is evaluated.

Add references to variables in your program by using the AddVariable method:

  var
    MyVar : TStFloat;

  AddVariable('MyVar', @MyVar);

Whenever an expression is evaluated that contains the "MyVar" identifier,
the actual value of the variable (in your program) is retrieved and used
to compute the expression result. Changes to variable's value in your
program will be reflected when the expression is next evaluated.

Two things to note: First, the variable must be a TStFloat type and second,
the variable must remain in "scope". In general, this means that the variable
must either be defined globally or as a class variable. You normally would not
use AddVariable for variables defined local to a procedure or function (a
stack variable).

TStExpression offers a way to dynamically determine the value of an variable
or function that is being used in an expression -- the OnGetIdentValue event.
This event is fired if the expression parser is unable to locate the identifier
in its internal list of identifier names. In response to the event, you should
assign a value to the Value parameter that corresponds to the identifier name
passed to the event as the Identifier parameter. If no event handler is
assigned to this even and the expression parser is unable to locate a match for
an identifier used in an expression, an exception is raised.


Reference Section
-----------------

methods
-------

function AnalyzeExpression : TStFloat;
-> AnalyzeExpression causes the expression contained in the Expression property
   to be evaluated and returns the resulting value as the function result.


procedure AddConstant(const Name : string; Value : TStFloat);
-> AddConstant adds named constant values for use within expressions.

Example: AddConstant('X', 50)


procedure AddFunction0Param(const Name : string; FunctionAddr : TStFunction0Param);
procedure AddFunction1Param(const Name : string; FunctionAddr : TStFunction1Param);
procedure AddFunction2Param(const Name : string; FunctionAddr : TStFunction2Param);
procedure AddFunction3Param(const Name : string; FunctionAddr : TStFunction3Param);
-> AddFunctionXParam adds support for user-defined functions within expressions.

The four variations allow defining functions with no parameters, or, with one,
two, or three parameters. Name is the identifier that is entered into the
expression. The name does not need to be the same as the actual function name.

Parameter and function results must be defined as TStFloat.


procedure AddInternalFunctions;
-> AddInternalFunctions adds support for all of the predefined internal
   functions.

Since AddInternalFunctions is called by default, calling this routine without
first calling ClearIdentifiers will result in duplicate identifier exceptions.


procedure AddMethod0Param(const Name : string; MethodAddr : TStMethod0Param);
procedure AddMethod1Param(const Name : string; MethodAddr : TStMethod1Param);
procedure AddMethod2Param(const Name : string; MethodAddr : TStMethod2Param);
procedure AddMethod3Param(const Name : string; MethodAddr : TStMethod3Param);
-> AddMethodXParam adds support for user-defined methods within expressions.

The four variations allow defining methods with no parameters, or, with one,
two, or three parameters. Name is the identifier that is entered into the
expression. The name does not need to be the same as the actual method name.

Parameter and function results must be defined as TStFloat.


procedure AddVariable(const Name : string; VariableAddr : PStFloat);
-> Adds Name as a reference to a variable in your program.

Name is the identifier used in expressions.

Example:

  var
    X : TStFloat;
  ...
  AddVariable('X', @X)


procedure ClearIdentifiers;
-> ClearIdentifiers removes all function, method, constant, and variable identifiers.


procedure GetIdentList(S : TStrings);
-> GetIdentList fills S with a list of identifiers current recognized.


procedure RemoveIdentifier(const Name : string);
-> RemoveIdentifier removes support for the identifier Name.

If Name is not found, no action is taken.


properties
----------
property AsFloat : TStFloat (run-time read-only)
-> AsFloat evaluates the expression and returns the value as a TStFloat
   value;

property AsInteger : Integer (run-time read-only)
-> AsInteger evaluates the expression and returns the value as a whole number
   using the Round() function to convert the TStFloat value.

property AsString : string (run-time read-only)
-> AsString evaluates the expression and returns the value as a string using
   the FloatToStr() function to format the TStFloat value.

property LastError : Integer (run-time read-only)
-> LastError returns the error code (zero if no error).

property ErrorPosition : Integer (run-time read-only)
-> ErrorPosition returns the position of the error within the expression.

ErrorPosition is valid only if LastError is non-zero.

property Expression : string (run-time)
-> Expression defines the expression that should be evaluated.

property AllowEqual : Boolean
default: True
-> AllowEqual determines if the use of the "=" symbol in the expression will
   add constant declarations.

If true, expressions like X = 5 will cause the identifer "X" to be added and
associated with the value 5. This expression will also return a value of 5
when analyzed. If false, a bad character exception is raised.


events
------
property OnAddIdentifier : TNotifyEvent
-> OnAddIdentifier defines an event that is fired when a new identifier
   is added.

This event is fired for additions of function, method, constant, and variable
identifiers.

property OnGetIdentValue : TGetIdentValueEvent
TGetIdentValueEvent =
  procedure(Sender : TObject; const Identifier : string; var Value : TStFloat)
  of object;
-> OnGetIdentValue defines an event handler that is fired to obtain the value
for an identifier that was not found in the internal list of known identifiers.


TStExpressionEdit
=================
The TStExpressionEdit component is a simple descendant of a TEdit component
that adds one new method, two properties, and two new events.  In all other
respects, this control is the same as the standard VCL TEdit control.

The TStExpressionEdit uses an instance of the TStExpression component to do
most of the work. Any expression that is valid for the TStExpression
component can be entered into the component or assigned to the Text property.
The expression is evaluated when the component loses the focus (with AutoEval
true) or when the Evaluate method is called. Also, if AutoEval is true and
the control loses the focus, the resulting value is displayed in the control.


New properties and methods:

function Evaluate : TStFloat;

-> Evaluate evaluates the contents of the Text property as an expression
using the contained TStExpression component and returns the result of the
expression as the function result.

If an error occurs an exception is raised unless an event handler for the
OnError event is assigned. In which case, the event is fired instead.

Note: The AnalyzeExpr function (which is documented in the printed
manual and on-line help) is obsolete and is provided for backward
compatibility only.


property AutoEval : Boolean

-> AutoEval determines if the entered expression is automatically evaluated
   when the control loses the focus.

If AutoEval is true, the Evaluate method is called automatically and the
Text of the edit control is set to the result of evaluating the expression.
If False, no additional action is taken.


property Expr : TStExpression (run-time)

-> Expr provides access to the contained TStExpression component and all of
   its properties, methods, and events.


property OnAddIdentifier : TNotifyEvent

-> OnAddIdentifier defines an event that is fired when an identifier is
   added to the internal TStExpression component.

This event is fired to notify you that a constant or function identifier has
been added to the contained TStExpression component.


property OnError : TStExprErrorEvent

  TStExprErrorEvent =
    procedure(Sender : TObject; ErrorNumber : LongInt; const ErrorStr : string)
    of object;

-> OnError defines an event that is fired when an evaluation error occurs.
