18
TExpressionType = (etInteger, etString, etBoolean, etLargeInt, etFloat, etDateTime,
19
etLeftBracket, etRightBracket, etComma, etUnknown);
24
PDateTime = ^TDateTime;
25
EParserException = class(Exception);
26
PExpressionRec = ^TExpressionRec;
27
PDynamicType = ^TDynamicType;
31
TExprFunc = procedure(Expr: PExpressionRec);
35
TDynamicType = class(TObject)
41
constructor Create(DestMem, DestPos: PPChar; Size: PInteger);
43
procedure AssureSpace(ASize: Integer);
44
procedure Resize(NewSize: Integer; Exact: Boolean);
46
procedure Append(Source: PChar; Length: Integer);
47
procedure AppendInteger(Source: Integer);
49
property Memory: PPChar read FMemory;
50
property MemoryPos: PPChar read FMemoryPos;
51
property Size: PInteger read FSize;
54
TExpressionRec = record
55
//used both as linked tree and linked list for maximum evaluation efficiency
62
Args: array[0..MaxArg-1] of PChar;
63
ArgsPos: array[0..MaxArg-1] of PChar;
64
ArgsSize: array[0..MaxArg-1] of Integer;
65
ArgsType: array[0..MaxArg-1] of TExpressionType;
66
ArgList: array[0..MaxArg-1] of PExpressionRec;
69
TExprCollection = class(TNoOwnerCollection)
72
procedure EraseExtraBrackets;
84
ResultType: TExpressionType;
92
TExprWord = class(TObject)
99
function GetIsOperator: Boolean; virtual;
100
function GetIsVariable: Boolean;
101
function GetNeedsCopy: Boolean;
102
function GetFixedLen: Integer; virtual;
103
function GetCanVary: Boolean; virtual;
104
function GetResultType: TExpressionType; virtual;
105
function GetMinFunctionArg: Integer; virtual;
106
function GetMaxFunctionArg: Integer; virtual;
107
function GetDescription: string; virtual;
108
function GetTypeSpec: string; virtual;
109
function GetShortName: string; virtual;
111
constructor Create(AName: string; AExprFunc: TExprFunc);
113
function LenAsPointer: PInteger; virtual;
114
function AsPointer: PChar; virtual;
115
function IsFunction: Boolean; virtual;
117
property ExprFunc: TExprFunc read FExprFunc;
118
property IsOperator: Boolean read GetIsOperator;
119
property CanVary: Boolean read GetCanVary;
120
property IsVariable: Boolean read GetIsVariable;
121
property NeedsCopy: Boolean read GetNeedsCopy;
122
property FixedLen: Integer read GetFixedLen;
123
property ResultType: TExpressionType read GetResultType;
124
property MinFunctionArg: Integer read GetMinFunctionArg;
125
property MaxFunctionArg: Integer read GetMaxFunctionArg;
126
property Name: string read FName;
127
property ShortName: string read GetShortName;
128
property Description: string read GetDescription;
129
property TypeSpec: string read GetTypeSpec;
132
TExpressShortList = class(TSortedCollection)
134
function KeyOf(Item: Pointer): Pointer; override;
135
function Compare(Key1, Key2: Pointer): Integer; override;
136
procedure FreeItem(Item: Pointer); override;
139
TExpressList = class(TSortedCollection)
141
FShortList: TExpressShortList;
144
destructor Destroy; override;
145
procedure Add(Item: Pointer); override;
146
function KeyOf(Item: Pointer): Pointer; override;
147
function Compare(Key1, Key2: Pointer): Integer; override;
148
function Search(Key: Pointer; var Index: Integer): Boolean; override;
149
procedure FreeItem(Item: Pointer); override;
152
TConstant = class(TExprWord)
154
FResultType: TExpressionType;
156
function GetResultType: TExpressionType; override;
158
constructor Create(AName: string; AVarType: TExpressionType; AExprFunc: TExprFunc);
161
TFloatConstant = class(TConstant)
165
// not overloaded to support older Delphi versions
166
constructor Create(AName: string; AValue: string);
167
constructor CreateAsDouble(AName: string; AValue: Double);
169
function AsPointer: PChar; override;
171
property Value: Double read FValue write FValue;
174
TUserConstant = class(TFloatConstant)
176
FDescription: string;
178
function GetDescription: string; override;
180
constructor CreateAsDouble(AName, Descr: string; AValue: Double);
183
TStringConstant = class(TConstant)
187
constructor Create(AValue: string);
189
function AsPointer: PChar; override;
192
TIntegerConstant = class(TConstant)
196
constructor Create(AValue: Integer);
198
function AsPointer: PChar; override;
201
TBooleanConstant = class(TConstant)
205
// not overloaded to support older Delphi versions
206
constructor Create(AName: string; AValue: Boolean);
208
function AsPointer: PChar; override;
210
property Value: Boolean read FValue write FValue;
213
TVariable = class(TExprWord)
215
FResultType: TExpressionType;
217
function GetCanVary: Boolean; override;
218
function GetResultType: TExpressionType; override;
220
constructor Create(AName: string; AVarType: TExpressionType; AExprFunc: TExprFunc);
223
TFloatVariable = class(TVariable)
227
constructor Create(AName: string; AValue: PDouble);
229
function AsPointer: PChar; override;
232
TStringVariable = class(TVariable)
237
function GetFixedLen: Integer; override;
239
constructor Create(AName: string; AValue: PPChar; AFixedLen: Integer);
241
function LenAsPointer: PInteger; override;
242
function AsPointer: PChar; override;
244
property FixedLen: Integer read FFixedLen;
247
TDateTimeVariable = class(TVariable)
249
FValue: PDateTimeRec;
251
constructor Create(AName: string; AValue: PDateTimeRec);
253
function AsPointer: PChar; override;
256
TIntegerVariable = class(TVariable)
260
constructor Create(AName: string; AValue: PInteger);
262
function AsPointer: PChar; override;
265
{$ifdef SUPPORT_INT64}
267
TLargeIntVariable = class(TVariable)
271
constructor Create(AName: string; AValue: PLargeInt);
273
function AsPointer: PChar; override;
278
TBooleanVariable = class(TVariable)
282
constructor Create(AName: string; AValue: PBoolean);
284
function AsPointer: PChar; override;
287
TLeftBracket = class(TExprWord)
288
function GetResultType: TExpressionType; override;
291
TRightBracket = class(TExprWord)
293
function GetResultType: TExpressionType; override;
296
TComma = class(TExprWord)
298
function GetResultType: TExpressionType; override;
301
TFunction = class(TExprWord)
303
FIsOperator: Boolean;
305
FMinFunctionArg: Integer;
306
FMaxFunctionArg: Integer;
307
FDescription: string;
310
FResultType: TExpressionType;
312
function GetDescription: string; override;
313
function GetIsOperator: Boolean; override;
314
function GetMinFunctionArg: Integer; override;
315
function GetMaxFunctionArg: Integer; override;
316
function GetResultType: TExpressionType; override;
317
function GetTypeSpec: string; override;
318
function GetShortName: string; override;
320
procedure InternalCreate(AName, ATypeSpec: string; AMinFuncArg: Integer; AResultType: TExpressionType;
321
AExprFunc: TExprFunc; AIsOperator: Boolean; AOperPrec: Integer);
323
constructor Create(AName, AShortName, ATypeSpec: string; AMinFuncArg: Integer; AResultType: TExpressionType; AExprFunc: TExprFunc; Descr: string);
324
constructor CreateOper(AName, ATypeSpec: string; AResultType: TExpressionType; AExprFunc: TExprFunc; AOperPrec: Integer);
326
function IsFunction: Boolean; override;
328
property OperPrec: Integer read FOperPrec;
329
property TypeSpec: string read FTypeSpec;
332
TVaryingFunction = class(TFunction)
333
// Functions that can vary for ex. random generators
334
// should be TVaryingFunction to be sure that they are
337
function GetCanVary: Boolean; override;
341
ListChar = ','; {the delimiter used with the 'in' operator: e.g.,
343
('c' in 'a,b') =False}
345
function ExprCharToExprType(ExprChar: Char): TExpressionType;
351
function ExprCharToExprType(ExprChar: Char): TExpressionType;
354
'B': Result := etBoolean;
355
'I': Result := etInteger;
356
'L': Result := etLargeInt;
357
'F': Result := etFloat;
358
'D': Result := etDateTime;
359
'S': Result := etString;
365
procedure _FloatVariable(Param: PExpressionRec);
368
PDouble(Res.MemoryPos^)^ := PDouble(Args[0])^;
371
procedure _BooleanVariable(Param: PExpressionRec);
374
PBoolean(Res.MemoryPos^)^ := PBoolean(Args[0])^;
377
procedure _StringConstant(Param: PExpressionRec);
380
Res.Append(Args[0], StrLen(Args[0]));
383
procedure _StringVariable(Param: PExpressionRec);
386
Res.Append(PPChar(Args[0])^, StrLen(PPChar(Args[0])^));
389
procedure _StringVariableFixedLen(Param: PExpressionRec);
392
Res.Append(PPChar(Args[0])^, PInteger(Args[1])^);
395
procedure _DateTimeVariable(Param: PExpressionRec);
398
PDateTimeRec(Res.MemoryPos^)^ := PDateTimeRec(Args[0])^;
401
procedure _IntegerVariable(Param: PExpressionRec);
404
PInteger(Res.MemoryPos^)^ := PInteger(Args[0])^;
408
procedure _SmallIntVariable(Param: PExpressionRec);
411
PSmallInt(Res.MemoryPos^)^ := PSmallInt(Args[0])^;
415
{$ifdef SUPPORT_INT64}
417
procedure _LargeIntVariable(Param: PExpressionRec);
420
PLargeInt(Res.MemoryPos^)^ := PLargeInt(Args[0])^;
427
constructor TExprWord.Create(AName: string; AExprFunc: TExprFunc);
430
FExprFunc := AExprFunc;
433
function TExprWord.GetCanVary: Boolean;
438
function TExprWord.GetDescription: string;
443
function TExprWord.GetShortName: string;
448
function TExprWord.GetIsOperator: Boolean;
453
function TExprWord.GetIsVariable: Boolean;
455
Result := (@FExprFunc = @_StringVariable) or
456
(@FExprFunc = @_StringConstant) or
457
(@FExprFunc = @_StringVariableFixedLen) or
458
(@FExprFunc = @_FloatVariable) or
459
(@FExprFunc = @_IntegerVariable) or
460
// (@FExprFunc = @_SmallIntVariable) or
461
{$ifdef SUPPORT_INT64}
462
(@FExprFunc = @_LargeIntVariable) or
464
(@FExprFunc = @_DateTimeVariable) or
465
(@FExprFunc = @_BooleanVariable);
468
function TExprWord.GetNeedsCopy: Boolean;
470
Result := (@FExprFunc <> @_StringConstant) and
471
// (@FExprFunc <> @_StringVariable) and
472
// (@FExprFunc <> @_StringVariableFixedLen) and
473
// string variable cannot be used as normal parameter
474
// because it is indirectly referenced and possibly
475
// not null-terminated (fixed len)
476
(@FExprFunc <> @_FloatVariable) and
477
(@FExprFunc <> @_IntegerVariable) and
478
// (@FExprFunc <> @_SmallIntVariable) and
479
{$ifdef SUPPORT_INT64}
480
(@FExprFunc <> @_LargeIntVariable) and
482
(@FExprFunc <> @_DateTimeVariable) and
483
(@FExprFunc <> @_BooleanVariable);
486
function TExprWord.GetFixedLen: Integer;
488
// -1 means variable, non-fixed length
492
function TExprWord.GetMinFunctionArg: Integer;
497
function TExprWord.GetMaxFunctionArg: Integer;
502
function TExprWord.GetResultType: TExpressionType;
507
function TExprWord.GetTypeSpec: string;
512
function TExprWord.AsPointer: PChar;
517
function TExprWord.LenAsPointer: PInteger;
522
function TExprWord.IsFunction: Boolean;
529
constructor TConstant.Create(AName: string; AVarType: TExpressionType; AExprFunc: TExprFunc);
531
inherited Create(AName, AExprFunc);
533
FResultType := AVarType;
536
function TConstant.GetResultType: TExpressionType;
538
Result := FResultType;
543
constructor TFloatConstant.Create(AName, AValue: string);
545
inherited Create(AName, etFloat, _FloatVariable);
547
if Length(AValue) > 0 then
548
FValue := StrToFloat(AValue)
553
constructor TFloatConstant.CreateAsDouble(AName: string; AValue: Double);
555
inherited Create(AName, etFloat, _FloatVariable);
560
function TFloatConstant.AsPointer: PChar;
562
Result := PChar(@FValue);
567
constructor TUserConstant.CreateAsDouble(AName, Descr: string; AValue: Double);
569
FDescription := Descr;
571
inherited CreateAsDouble(AName, AValue);
574
function TUserConstant.GetDescription: string;
576
Result := FDescription;
581
constructor TStringConstant.Create(AValue: string);
583
firstChar, lastChar: Char;
585
inherited Create(AValue, etString, _StringConstant);
587
firstChar := AValue[1];
588
lastChar := AValue[Length(AValue)];
589
if (firstChar = lastChar) and ((firstChar = '''') or (firstChar = '"')) then
590
FValue := Copy(AValue, 2, Length(AValue) - 2)
595
function TStringConstant.AsPointer: PChar;
597
Result := PChar(FValue);
602
constructor TBooleanConstant.Create(AName: string; AValue: Boolean);
604
inherited Create(AName, etBoolean, _BooleanVariable);
609
function TBooleanConstant.AsPointer: PChar;
611
Result := PChar(@FValue);
616
constructor TIntegerConstant.Create(AValue: Integer);
618
inherited Create(IntToStr(AValue), etInteger, _IntegerVariable);
623
function TIntegerConstant.AsPointer: PChar;
625
Result := PChar(@FValue);
630
constructor TVariable.Create(AName: string; AVarType: TExpressionType; AExprFunc: TExprFunc);
632
inherited Create(AName, AExprFunc);
634
FResultType := AVarType;
637
function TVariable.GetCanVary: Boolean;
642
function TVariable.GetResultType: TExpressionType;
644
Result := FResultType;
649
constructor TFloatVariable.Create(AName: string; AValue: PDouble);
651
inherited Create(AName, etFloat, _FloatVariable);
655
function TFloatVariable.AsPointer: PChar;
657
Result := PChar(FValue);
662
constructor TStringVariable.Create(AName: string; AValue: PPChar; AFixedLen: Integer);
664
// variable or fixed length?
665
if (AFixedLen < 0) then
666
inherited Create(AName, etString, _StringVariable)
668
inherited Create(AName, etString, _StringVariableFixedLen);
670
// store pointer to string
672
FFixedLen := AFixedLen;
675
function TStringVariable.AsPointer: PChar;
677
Result := PChar(FValue);
680
function TStringVariable.GetFixedLen: Integer;
685
function TStringVariable.LenAsPointer: PInteger;
687
Result := @FFixedLen;
690
{ TDateTimeVariable }
692
constructor TDateTimeVariable.Create(AName: string; AValue: PDateTimeRec);
694
inherited Create(AName, etDateTime, _DateTimeVariable);
698
function TDateTimeVariable.AsPointer: PChar;
700
Result := PChar(FValue);
705
constructor TIntegerVariable.Create(AName: string; AValue: PInteger);
707
inherited Create(AName, etInteger, _IntegerVariable);
711
function TIntegerVariable.AsPointer: PChar;
713
Result := PChar(FValue);
716
{$ifdef SUPPORT_INT64}
718
{ TLargeIntVariable }
720
constructor TLargeIntVariable.Create(AName: string; AValue: PLargeInt);
722
inherited Create(AName, etLargeInt, _LargeIntVariable);
726
function TLargeIntVariable.AsPointer: PChar;
728
Result := PChar(FValue);
735
constructor TBooleanVariable.Create(AName: string; AValue: PBoolean);
737
inherited Create(AName, etBoolean, _BooleanVariable);
741
function TBooleanVariable.AsPointer: PChar;
743
Result := PChar(FValue);
748
function TLeftBracket.GetResultType: TExpressionType;
750
Result := etLeftBracket;
755
function TRightBracket.GetResultType: TExpressionType;
757
Result := etRightBracket;
762
function TComma.GetResultType: TExpressionType;
769
constructor TExpressList.Create;
773
FShortList := TExpressShortList.Create;
776
destructor TExpressList.Destroy;
782
procedure TExpressList.Add(Item: Pointer);
788
{ remember we reference the object }
789
Inc(TExprWord(Item).FRefCount);
791
{ also add ShortName as reference }
792
if Length(TExprWord(Item).ShortName) > 0 then
794
FShortList.Search(FShortList.KeyOf(Item), I);
795
FShortList.Insert(I, Item);
799
function TExpressList.Compare(Key1, Key2: Pointer): Integer;
801
Result := StrIComp(PChar(Key1), PChar(Key2));
804
function TExpressList.KeyOf(Item: Pointer): Pointer;
806
Result := PChar(TExprWord(Item).Name);
809
procedure TExpressList.FreeItem(Item: Pointer);
811
Dec(TExprWord(Item).FRefCount);
812
FShortList.Remove(Item);
813
if TExprWord(Item).FRefCount = 0 then
817
function TExpressList.Search(Key: Pointer; var Index: Integer): Boolean;
821
Result := inherited Search(Key, Index);
824
Result := FShortList.Search(Key, SecIndex);
826
Index := IndexOf(FShortList.Items[SecIndex]);
830
function TExpressShortList.Compare(Key1, Key2: Pointer): Integer;
832
Result := StrIComp(PChar(Key1), PChar(Key2));
835
function TExpressShortList.KeyOf(Item: Pointer): Pointer;
837
Result := PChar(TExprWord(Item).ShortName);
840
procedure TExpressShortList.FreeItem(Item: Pointer);
846
procedure TExprCollection.Check;
851
for I := 0 to Count - 1 do
853
case TExprWord(Items[I]).ResultType of
854
etLeftBracket: Inc(brCount);
855
etRightBracket: Dec(brCount);
859
raise EParserException.Create('Unequal brackets');
862
procedure TExprCollection.EraseExtraBrackets;
867
if (TExprWord(Items[0]).ResultType = etLeftBracket) then
871
while (I < Count) and (brCount > 0) do
873
case TExprWord(Items[I]).ResultType of
874
etLeftBracket: Inc(brCount);
875
etRightBracket: Dec(brCount);
879
if (brCount = 0) and (I = Count) and (TExprWord(Items[I - 1]).ResultType =
882
for I := 0 to Count - 3 do
883
Items[I] := Items[I + 1];
885
EraseExtraBrackets; //Check if there are still too many brackets
892
constructor TFunction.Create(AName, AShortName, ATypeSpec: string; AMinFuncArg: Integer; AResultType: TExpressionType;
893
AExprFunc: TExprFunc; Descr: string);
895
//to increase compatibility don't use default parameters
896
FDescription := Descr;
897
FShortName := AShortName;
898
InternalCreate(AName, ATypeSpec, AMinFuncArg, AResultType, AExprFunc, false, 0);
901
constructor TFunction.CreateOper(AName, ATypeSpec: string; AResultType: TExpressionType;
902
AExprFunc: TExprFunc; AOperPrec: Integer);
904
InternalCreate(AName, ATypeSpec, -1, AResultType, AExprFunc, true, AOperPrec);
907
procedure TFunction.InternalCreate(AName, ATypeSpec: string; AMinFuncArg: Integer; AResultType: TExpressionType;
908
AExprFunc: TExprFunc; AIsOperator: Boolean; AOperPrec: Integer);
910
inherited Create(AName, AExprFunc);
912
FMaxFunctionArg := Length(ATypeSpec);
913
FMinFunctionArg := AMinFuncArg;
914
if AMinFuncArg = -1 then
915
FMinFunctionArg := FMaxFunctionArg;
916
FIsOperator := AIsOperator;
917
FOperPrec := AOperPrec;
918
FTypeSpec := ATypeSpec;
919
FResultType := AResultType;
922
if FMaxFunctionArg > MaxArg then
923
raise EParserException.Create('Too many arguments');
926
function TFunction.GetDescription: string;
928
Result := FDescription;
931
function TFunction.GetIsOperator: Boolean;
933
Result := FIsOperator;
936
function TFunction.GetMinFunctionArg: Integer;
938
Result := FMinFunctionArg;
941
function TFunction.GetMaxFunctionArg: Integer;
943
Result := FMaxFunctionArg;
946
function TFunction.GetResultType: TExpressionType;
948
Result := FResultType;
951
function TFunction.GetShortName: string;
953
Result := FShortName;
956
function TFunction.GetTypeSpec: string;
961
function TFunction.IsFunction: Boolean;
968
function TVaryingFunction.GetCanVary: Boolean;
975
constructor TDynamicType.Create(DestMem, DestPos: PPChar; Size: PInteger);
980
FMemoryPos := DestPos;
984
procedure TDynamicType.Rewind;
986
FMemoryPos^ := FMemory^;
989
procedure TDynamicType.AssureSpace(ASize: Integer);
992
if ((FMemoryPos^) - (FMemory^) + ASize) > (FSize^) then
993
Resize((FMemoryPos^) - (FMemory^) + ASize, False);
996
procedure TDynamicType.Resize(NewSize: Integer; Exact: Boolean);
999
bytesCopy, pos: Integer;
1001
// if not exact requested make newlength a multiple of ArgAllocSize
1003
NewSize := NewSize div ArgAllocSize * ArgAllocSize + ArgAllocSize;
1004
// create new buffer
1005
GetMem(tempBuf, NewSize);
1007
bytesCopy := FSize^;
1008
if bytesCopy > NewSize then
1009
bytesCopy := NewSize;
1010
Move(FMemory^^, tempBuf^, bytesCopy);
1011
// save position in string
1012
pos := FMemoryPos^ - FMemory^;
1016
FMemory^ := tempBuf;
1019
FMemoryPos^ := FMemory^ + pos;
1022
procedure TDynamicType.Append(Source: PChar; Length: Integer);
1024
// make room for string plus null-terminator
1025
AssureSpace(Length+4);
1027
Move(Source^, FMemoryPos^^, Length);
1028
Inc(FMemoryPos^, Length);
1033
procedure TDynamicType.AppendInteger(Source: Integer);
1035
// make room for number
1037
Inc(FMemoryPos^, GetStrFromInt(Source, FMemoryPos^));