1 |
torben |
2671 |
|
2 |
|
|
This file documents the TStExpression and TStExpressionEdit components.
|
3 |
|
|
|
4 |
|
|
|
5 |
|
|
TStExpression
|
6 |
|
|
=============
|
7 |
|
|
|
8 |
|
|
TStExpression is a non-visual component that provides expression evaluation
|
9 |
|
|
at several different levels. At the lowest level, simple mathematical
|
10 |
|
|
expressions can be evaluated and the resulting value obtained. On a higher
|
11 |
|
|
level, you can define alpha-numeric constants that can then be used within
|
12 |
|
|
expressions; You can add user-defined functions (and even methods of a class)
|
13 |
|
|
so that the names of these routines can be used in expressions; You can
|
14 |
|
|
define variables that relate directly to variables in your program and even
|
15 |
|
|
use them in expressions.
|
16 |
|
|
|
17 |
|
|
Note: TStExpression replaces AnalyzeExpr that SysTools version 2.00 provided,
|
18 |
|
|
but a version of that routine is still provided for backward compatibility.
|
19 |
|
|
|
20 |
|
|
The TStExpression expression parser implements the following grammar, similar
|
21 |
|
|
to a subset of Pascal:
|
22 |
|
|
|
23 |
|
|
expression: term | expression+term | expression-term
|
24 |
|
|
term: factor | term*factor | term/factor
|
25 |
|
|
factor: base | base^factor
|
26 |
|
|
base: unsigned_num | (expression) | sign factor | func_call
|
27 |
|
|
unsigned_num: digit_seq | digit_seq.digit_seq | digit_seq scale_fac |
|
28 |
|
|
digit_seq.digit_seq scale_fac
|
29 |
|
|
sign: + | -
|
30 |
|
|
func_call: identifier | identifier(params)
|
31 |
|
|
params: expression | params,expression
|
32 |
|
|
scale_fac: E digit_seq | E sign digit_seq
|
33 |
|
|
digit_seq: digit | digit_seq digit
|
34 |
|
|
identifier: starts with A..Z,_ continues with A..Z,_,0..9
|
35 |
|
|
digit: 0..9
|
36 |
|
|
|
37 |
|
|
Case is not significant when matching characters.
|
38 |
|
|
|
39 |
|
|
The grammar follows normal rules of arithmetic precedence, with ^ highest, *
|
40 |
|
|
and / in the middle, and + and - lowest. Thus, 1+2*3^4 means 1+(2*(3^4)).
|
41 |
|
|
Parentheses can be used to force non-default precedence.
|
42 |
|
|
|
43 |
|
|
Note that the power operator x^y is right-associative. This means that
|
44 |
|
|
2^0.5^2 is equivalent to 2^(0.5^2). All other arithmetic operators are left
|
45 |
|
|
associative: 1-2-3 is equivalent to (1-2)-3.
|
46 |
|
|
|
47 |
|
|
The following functions are supported in 16-bit and 32-bit applications:
|
48 |
|
|
|
49 |
|
|
abs, arctan, cos, exp, frac, int(trunc), ln, pi, round, sin, sqr,
|
50 |
|
|
sqrt
|
51 |
|
|
|
52 |
|
|
If the VCL Math unit is available and you define the "UseMathUnit" define in
|
53 |
|
|
STDEFINE.INC, the following are also available:
|
54 |
|
|
|
55 |
|
|
arccos, arcsin, arctan2, tan, cotan, hypot, cosh, sinh, tanh,
|
56 |
|
|
arccosh, arcsinh, arctanh, lnxp1, log10, log2, logn, ceil, floor
|
57 |
|
|
|
58 |
|
|
The calling conventions for all functions match those of the VCL runtime
|
59 |
|
|
library or Math unit. The acceptable parameter ranges and output values also
|
60 |
|
|
match thoses of the VCL runtime library or MATH unit.
|
61 |
|
|
|
62 |
|
|
When the input expression contains an error, TStExpression raises an
|
63 |
|
|
exception of type EStExprError. Its ErrorCode property provides more detail
|
64 |
|
|
about the error. Its ErrorColumn property gives the string index of the start
|
65 |
|
|
of the token where the error was detected.
|
66 |
|
|
|
67 |
|
|
TStExpression is very flexible. You can add support for your own functions
|
68 |
|
|
easily. For example, to add support for the Sin() function, first write a
|
69 |
|
|
function to provide the proper number and type of parameters (the "far" can
|
70 |
|
|
be omitted with 32-bit compilers):
|
71 |
|
|
|
72 |
|
|
function _Sin(Value : TStFloat) : TStFloat; far;
|
73 |
|
|
begin
|
74 |
|
|
Result := Sin(Value);
|
75 |
|
|
end;
|
76 |
|
|
|
77 |
|
|
and then add it to the TStExpression component:
|
78 |
|
|
|
79 |
|
|
MyStExpression.AddFunction1Param('sin', _Sin);
|
80 |
|
|
|
81 |
|
|
Or, if you wanted to use a method of the form (or any other class) that you
|
82 |
|
|
were working in, you could do the same thing this way:
|
83 |
|
|
|
84 |
|
|
function MyForm._Sin(Value : TStFloat) : TStFloat;
|
85 |
|
|
begin
|
86 |
|
|
Result := Sin(Value);
|
87 |
|
|
end;
|
88 |
|
|
|
89 |
|
|
and then add it to the TStExpression component:
|
90 |
|
|
|
91 |
|
|
MyStExpression.AddMethod1Param('sin', _Sin);
|
92 |
|
|
|
93 |
|
|
TStExpression supports user-defined functions with 0 to 3 parameters. The
|
94 |
|
|
parameters and function result must be the TStFloat type (defined in the
|
95 |
|
|
STBASE unit). In the example above, that's why we didn't just add
|
96 |
|
|
the Sin() function directly, in the call to AddFunction1Param -- The
|
97 |
|
|
TStExpression component must know the data types of parameters and return
|
98 |
|
|
values. If the function you are adding has no parameters, use the
|
99 |
|
|
AddFunction0Parm() method. AddFunction2Param for functions with two
|
100 |
|
|
parameters, etc.
|
101 |
|
|
|
102 |
|
|
The following function and method types define all possible user-defined
|
103 |
|
|
function and method types accepted by the TStExpression component:
|
104 |
|
|
|
105 |
|
|
{user-defined functions with up to 3 parameters}
|
106 |
|
|
TStFunction0Param =
|
107 |
|
|
function : TStFloat;
|
108 |
|
|
TStFunction1Param =
|
109 |
|
|
function(Value1 : TStFloat) : TStFloat;
|
110 |
|
|
TStFunction2Param =
|
111 |
|
|
function(Value1, Value2 : TStFloat) : TStFloat;
|
112 |
|
|
TStFunction3Param =
|
113 |
|
|
function(Value1, Value2, Value3 : TStFloat) : TStFloat;
|
114 |
|
|
|
115 |
|
|
{user-defined methods with up to 3 parameters}
|
116 |
|
|
TStMethod0Param =
|
117 |
|
|
function : TStFloat
|
118 |
|
|
of object;
|
119 |
|
|
TStMethod1Param =
|
120 |
|
|
function(Value1 : TStFloat) : TStFloat
|
121 |
|
|
of object;
|
122 |
|
|
TStMethod2Param =
|
123 |
|
|
function(Value1, Value2 : TStFloat) : TStFloat
|
124 |
|
|
of object;
|
125 |
|
|
TStMethod3Param =
|
126 |
|
|
function(Value1, Value2, Value3 : TStFloat) : TStFloat
|
127 |
|
|
of object;
|
128 |
|
|
|
129 |
|
|
Add predefined constant values by using the AddConstant method:
|
130 |
|
|
|
131 |
|
|
AddConstant('X', 50)
|
132 |
|
|
|
133 |
|
|
Then, in any expression that uses the identifier "X", the value 50 will be
|
134 |
|
|
used when the expression is evaluated.
|
135 |
|
|
|
136 |
|
|
Add references to variables in your program by using the AddVariable method:
|
137 |
|
|
|
138 |
|
|
var
|
139 |
|
|
MyVar : TStFloat;
|
140 |
|
|
|
141 |
|
|
AddVariable('MyVar', @MyVar);
|
142 |
|
|
|
143 |
|
|
Whenever an expression is evaluated that contains the "MyVar" identifier,
|
144 |
|
|
the actual value of the variable (in your program) is retrieved and used
|
145 |
|
|
to compute the expression result. Changes to variable's value in your
|
146 |
|
|
program will be reflected when the expression is next evaluated.
|
147 |
|
|
|
148 |
|
|
Two things to note: First, the variable must be a TStFloat type and second,
|
149 |
|
|
the variable must remain in "scope". In general, this means that the variable
|
150 |
|
|
must either be defined globally or as a class variable. You normally would not
|
151 |
|
|
use AddVariable for variables defined local to a procedure or function (a
|
152 |
|
|
stack variable).
|
153 |
|
|
|
154 |
|
|
TStExpression offers a way to dynamically determine the value of an variable
|
155 |
|
|
or function that is being used in an expression -- the OnGetIdentValue event.
|
156 |
|
|
This event is fired if the expression parser is unable to locate the identifier
|
157 |
|
|
in its internal list of identifier names. In response to the event, you should
|
158 |
|
|
assign a value to the Value parameter that corresponds to the identifier name
|
159 |
|
|
passed to the event as the Identifier parameter. If no event handler is
|
160 |
|
|
assigned to this even and the expression parser is unable to locate a match for
|
161 |
|
|
an identifier used in an expression, an exception is raised.
|
162 |
|
|
|
163 |
|
|
|
164 |
|
|
Reference Section
|
165 |
|
|
-----------------
|
166 |
|
|
|
167 |
|
|
methods
|
168 |
|
|
-------
|
169 |
|
|
|
170 |
|
|
function AnalyzeExpression : TStFloat;
|
171 |
|
|
-> AnalyzeExpression causes the expression contained in the Expression property
|
172 |
|
|
to be evaluated and returns the resulting value as the function result.
|
173 |
|
|
|
174 |
|
|
|
175 |
|
|
procedure AddConstant(const Name : string; Value : TStFloat);
|
176 |
|
|
-> AddConstant adds named constant values for use within expressions.
|
177 |
|
|
|
178 |
|
|
Example: AddConstant('X', 50)
|
179 |
|
|
|
180 |
|
|
|
181 |
|
|
procedure AddFunction0Param(const Name : string; FunctionAddr : TStFunction0Param);
|
182 |
|
|
procedure AddFunction1Param(const Name : string; FunctionAddr : TStFunction1Param);
|
183 |
|
|
procedure AddFunction2Param(const Name : string; FunctionAddr : TStFunction2Param);
|
184 |
|
|
procedure AddFunction3Param(const Name : string; FunctionAddr : TStFunction3Param);
|
185 |
|
|
-> AddFunctionXParam adds support for user-defined functions within expressions.
|
186 |
|
|
|
187 |
|
|
The four variations allow defining functions with no parameters, or, with one,
|
188 |
|
|
two, or three parameters. Name is the identifier that is entered into the
|
189 |
|
|
expression. The name does not need to be the same as the actual function name.
|
190 |
|
|
|
191 |
|
|
Parameter and function results must be defined as TStFloat.
|
192 |
|
|
|
193 |
|
|
|
194 |
|
|
procedure AddInternalFunctions;
|
195 |
|
|
-> AddInternalFunctions adds support for all of the predefined internal
|
196 |
|
|
functions.
|
197 |
|
|
|
198 |
|
|
Since AddInternalFunctions is called by default, calling this routine without
|
199 |
|
|
first calling ClearIdentifiers will result in duplicate identifier exceptions.
|
200 |
|
|
|
201 |
|
|
|
202 |
|
|
procedure AddMethod0Param(const Name : string; MethodAddr : TStMethod0Param);
|
203 |
|
|
procedure AddMethod1Param(const Name : string; MethodAddr : TStMethod1Param);
|
204 |
|
|
procedure AddMethod2Param(const Name : string; MethodAddr : TStMethod2Param);
|
205 |
|
|
procedure AddMethod3Param(const Name : string; MethodAddr : TStMethod3Param);
|
206 |
|
|
-> AddMethodXParam adds support for user-defined methods within expressions.
|
207 |
|
|
|
208 |
|
|
The four variations allow defining methods with no parameters, or, with one,
|
209 |
|
|
two, or three parameters. Name is the identifier that is entered into the
|
210 |
|
|
expression. The name does not need to be the same as the actual method name.
|
211 |
|
|
|
212 |
|
|
Parameter and function results must be defined as TStFloat.
|
213 |
|
|
|
214 |
|
|
|
215 |
|
|
procedure AddVariable(const Name : string; VariableAddr : PStFloat);
|
216 |
|
|
-> Adds Name as a reference to a variable in your program.
|
217 |
|
|
|
218 |
|
|
Name is the identifier used in expressions.
|
219 |
|
|
|
220 |
|
|
Example:
|
221 |
|
|
|
222 |
|
|
var
|
223 |
|
|
X : TStFloat;
|
224 |
|
|
...
|
225 |
|
|
AddVariable('X', @X)
|
226 |
|
|
|
227 |
|
|
|
228 |
|
|
procedure ClearIdentifiers;
|
229 |
|
|
-> ClearIdentifiers removes all function, method, constant, and variable identifiers.
|
230 |
|
|
|
231 |
|
|
|
232 |
|
|
procedure GetIdentList(S : TStrings);
|
233 |
|
|
-> GetIdentList fills S with a list of identifiers current recognized.
|
234 |
|
|
|
235 |
|
|
|
236 |
|
|
procedure RemoveIdentifier(const Name : string);
|
237 |
|
|
-> RemoveIdentifier removes support for the identifier Name.
|
238 |
|
|
|
239 |
|
|
If Name is not found, no action is taken.
|
240 |
|
|
|
241 |
|
|
|
242 |
|
|
properties
|
243 |
|
|
----------
|
244 |
|
|
property AsFloat : TStFloat (run-time read-only)
|
245 |
|
|
-> AsFloat evaluates the expression and returns the value as a TStFloat
|
246 |
|
|
value;
|
247 |
|
|
|
248 |
|
|
property AsInteger : Integer (run-time read-only)
|
249 |
|
|
-> AsInteger evaluates the expression and returns the value as a whole number
|
250 |
|
|
using the Round() function to convert the TStFloat value.
|
251 |
|
|
|
252 |
|
|
property AsString : string (run-time read-only)
|
253 |
|
|
-> AsString evaluates the expression and returns the value as a string using
|
254 |
|
|
the FloatToStr() function to format the TStFloat value.
|
255 |
|
|
|
256 |
|
|
property LastError : Integer (run-time read-only)
|
257 |
|
|
-> LastError returns the error code (zero if no error).
|
258 |
|
|
|
259 |
|
|
property ErrorPosition : Integer (run-time read-only)
|
260 |
|
|
-> ErrorPosition returns the position of the error within the expression.
|
261 |
|
|
|
262 |
|
|
ErrorPosition is valid only if LastError is non-zero.
|
263 |
|
|
|
264 |
|
|
property Expression : string (run-time)
|
265 |
|
|
-> Expression defines the expression that should be evaluated.
|
266 |
|
|
|
267 |
|
|
property AllowEqual : Boolean
|
268 |
|
|
default: True
|
269 |
|
|
-> AllowEqual determines if the use of the "=" symbol in the expression will
|
270 |
|
|
add constant declarations.
|
271 |
|
|
|
272 |
|
|
If true, expressions like X = 5 will cause the identifer "X" to be added and
|
273 |
|
|
associated with the value 5. This expression will also return a value of 5
|
274 |
|
|
when analyzed. If false, a bad character exception is raised.
|
275 |
|
|
|
276 |
|
|
|
277 |
|
|
events
|
278 |
|
|
------
|
279 |
|
|
property OnAddIdentifier : TNotifyEvent
|
280 |
|
|
-> OnAddIdentifier defines an event that is fired when a new identifier
|
281 |
|
|
is added.
|
282 |
|
|
|
283 |
|
|
This event is fired for additions of function, method, constant, and variable
|
284 |
|
|
identifiers.
|
285 |
|
|
|
286 |
|
|
property OnGetIdentValue : TGetIdentValueEvent
|
287 |
|
|
TGetIdentValueEvent =
|
288 |
|
|
procedure(Sender : TObject; const Identifier : string; var Value : TStFloat)
|
289 |
|
|
of object;
|
290 |
|
|
-> OnGetIdentValue defines an event handler that is fired to obtain the value
|
291 |
|
|
for an identifier that was not found in the internal list of known identifiers.
|
292 |
|
|
|
293 |
|
|
|
294 |
|
|
TStExpressionEdit
|
295 |
|
|
=================
|
296 |
|
|
The TStExpressionEdit component is a simple descendant of a TEdit component
|
297 |
|
|
that adds one new method, two properties, and two new events. In all other
|
298 |
|
|
respects, this control is the same as the standard VCL TEdit control.
|
299 |
|
|
|
300 |
|
|
The TStExpressionEdit uses an instance of the TStExpression component to do
|
301 |
|
|
most of the work. Any expression that is valid for the TStExpression
|
302 |
|
|
component can be entered into the component or assigned to the Text property.
|
303 |
|
|
The expression is evaluated when the component loses the focus (with AutoEval
|
304 |
|
|
true) or when the Evaluate method is called. Also, if AutoEval is true and
|
305 |
|
|
the control loses the focus, the resulting value is displayed in the control.
|
306 |
|
|
|
307 |
|
|
|
308 |
|
|
New properties and methods:
|
309 |
|
|
|
310 |
|
|
function Evaluate : TStFloat;
|
311 |
|
|
|
312 |
|
|
-> Evaluate evaluates the contents of the Text property as an expression
|
313 |
|
|
using the contained TStExpression component and returns the result of the
|
314 |
|
|
expression as the function result.
|
315 |
|
|
|
316 |
|
|
If an error occurs an exception is raised unless an event handler for the
|
317 |
|
|
OnError event is assigned. In which case, the event is fired instead.
|
318 |
|
|
|
319 |
|
|
Note: The AnalyzeExpr function (which is documented in the printed
|
320 |
|
|
manual and on-line help) is obsolete and is provided for backward
|
321 |
|
|
compatibility only.
|
322 |
|
|
|
323 |
|
|
|
324 |
|
|
property AutoEval : Boolean
|
325 |
|
|
|
326 |
|
|
-> AutoEval determines if the entered expression is automatically evaluated
|
327 |
|
|
when the control loses the focus.
|
328 |
|
|
|
329 |
|
|
If AutoEval is true, the Evaluate method is called automatically and the
|
330 |
|
|
Text of the edit control is set to the result of evaluating the expression.
|
331 |
|
|
If False, no additional action is taken.
|
332 |
|
|
|
333 |
|
|
|
334 |
|
|
property Expr : TStExpression (run-time)
|
335 |
|
|
|
336 |
|
|
-> Expr provides access to the contained TStExpression component and all of
|
337 |
|
|
its properties, methods, and events.
|
338 |
|
|
|
339 |
|
|
|
340 |
|
|
property OnAddIdentifier : TNotifyEvent
|
341 |
|
|
|
342 |
|
|
-> OnAddIdentifier defines an event that is fired when an identifier is
|
343 |
|
|
added to the internal TStExpression component.
|
344 |
|
|
|
345 |
|
|
This event is fired to notify you that a constant or function identifier has
|
346 |
|
|
been added to the contained TStExpression component.
|
347 |
|
|
|
348 |
|
|
|
349 |
|
|
property OnError : TStExprErrorEvent
|
350 |
|
|
|
351 |
|
|
TStExprErrorEvent =
|
352 |
|
|
procedure(Sender : TObject; ErrorNumber : LongInt; const ErrorStr : string)
|
353 |
|
|
of object;
|
354 |
|
|
|
355 |
|
|
-> OnError defines an event that is fired when an evaluation error occurs.
|