|
@@ -715,7 +715,7 @@ Type
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TFPExpressionParser }
|
|
{ TFPExpressionParser }
|
|
-
|
|
|
|
|
|
+ TIdentifierEvent = Procedure (Sender : TObject; Const aIdentifier : String) of object;
|
|
TFPExpressionParser = class(TComponent)
|
|
TFPExpressionParser = class(TComponent)
|
|
private
|
|
private
|
|
FBuiltIns: TBuiltInCategories;
|
|
FBuiltIns: TBuiltInCategories;
|
|
@@ -725,6 +725,9 @@ Type
|
|
FIdentifiers : TFPExprIdentifierDefs;
|
|
FIdentifiers : TFPExprIdentifierDefs;
|
|
FHashList : TFPHashObjectlist;
|
|
FHashList : TFPHashObjectlist;
|
|
FDirty : Boolean;
|
|
FDirty : Boolean;
|
|
|
|
+ FOnExtractIdentifier : TIdentifierEvent;
|
|
|
|
+ FExtractIdentifiers : TStrings;
|
|
|
|
+ FUnknownIdentifier : TFPExprIdentifierDef;
|
|
procedure CheckEOF;
|
|
procedure CheckEOF;
|
|
function GetAsBoolean: Boolean;
|
|
function GetAsBoolean: Boolean;
|
|
function GetAsDateTime: TDateTime;
|
|
function GetAsDateTime: TDateTime;
|
|
@@ -732,10 +735,12 @@ Type
|
|
function GetAsCurrency: Currency;
|
|
function GetAsCurrency: Currency;
|
|
function GetAsInteger: Int64;
|
|
function GetAsInteger: Int64;
|
|
function GetAsString: String;
|
|
function GetAsString: String;
|
|
|
|
+ function GetExtractingIdentifiers: Boolean;
|
|
function MatchNodes(Todo, Match: TFPExprNode): TFPExprNode;
|
|
function MatchNodes(Todo, Match: TFPExprNode): TFPExprNode;
|
|
procedure CheckNodes(var Left, Right: TFPExprNode);
|
|
procedure CheckNodes(var Left, Right: TFPExprNode);
|
|
procedure SetBuiltIns(const AValue: TBuiltInCategories);
|
|
procedure SetBuiltIns(const AValue: TBuiltInCategories);
|
|
procedure SetIdentifiers(const AValue: TFPExprIdentifierDefs);
|
|
procedure SetIdentifiers(const AValue: TFPExprIdentifierDefs);
|
|
|
|
+ procedure AddIdentifierToStrings(Sender : TObject; Const aIdentifier : String);
|
|
Protected
|
|
Protected
|
|
procedure ParserError(Msg: String);
|
|
procedure ParserError(Msg: String);
|
|
procedure SetExpression(const AValue: String); virtual;
|
|
procedure SetExpression(const AValue: String); virtual;
|
|
@@ -758,12 +763,15 @@ Type
|
|
Property Scanner : TFPExpressionScanner Read FScanner;
|
|
Property Scanner : TFPExpressionScanner Read FScanner;
|
|
Property ExprNode : TFPExprNode Read FExprNode;
|
|
Property ExprNode : TFPExprNode Read FExprNode;
|
|
Property Dirty : Boolean Read FDirty;
|
|
Property Dirty : Boolean Read FDirty;
|
|
|
|
+ Property ExtractingIdentifiers : Boolean Read GetExtractingIdentifiers;
|
|
public
|
|
public
|
|
Constructor Create(AOwner :TComponent); override;
|
|
Constructor Create(AOwner :TComponent); override;
|
|
Destructor Destroy; override;
|
|
Destructor Destroy; override;
|
|
Function IdentifierByName(const AName : ShortString) : TFPExprIdentifierDef; virtual;
|
|
Function IdentifierByName(const AName : ShortString) : TFPExprIdentifierDef; virtual;
|
|
Procedure Clear;
|
|
Procedure Clear;
|
|
Procedure EvaluateExpression(Out Result : TFPExpressionResult);
|
|
Procedure EvaluateExpression(Out Result : TFPExpressionResult);
|
|
|
|
+ Procedure ExtractIdentifierNames(Const aExpression : String; aList : TStringList); overload;
|
|
|
|
+ Procedure ExtractIdentifierNames(Const aExpression : String; aCallback : TIdentifierEvent); overload;
|
|
function ExtractNode(var N: TFPExprNode): Boolean;
|
|
function ExtractNode(var N: TFPExprNode): Boolean;
|
|
Function Evaluate : TFPExpressionResult;
|
|
Function Evaluate : TFPExpressionResult;
|
|
Function ResultType : TResultType;
|
|
Function ResultType : TResultType;
|
|
@@ -856,6 +864,7 @@ var
|
|
FileFormatSettings: TFormatSettings;
|
|
FileFormatSettings: TFormatSettings;
|
|
|
|
|
|
Resourcestring
|
|
Resourcestring
|
|
|
|
+ SErrCannotRecursivelyExtractIdentifiers = 'Cannot recursively extract identifiers';
|
|
SBadQuotes = 'Unterminated string';
|
|
SBadQuotes = 'Unterminated string';
|
|
SUnknownDelimiter = 'Unknown delimiter character: "%s"';
|
|
SUnknownDelimiter = 'Unknown delimiter character: "%s"';
|
|
SErrUnknownCharacter = 'Unknown character at pos %d: "%s"';
|
|
SErrUnknownCharacter = 'Unknown character at pos %d: "%s"';
|
|
@@ -1590,6 +1599,12 @@ begin
|
|
FIdentifiers.Assign(AValue)
|
|
FIdentifiers.Assign(AValue)
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TFPExpressionParser.AddIdentifierToStrings(Sender: TObject; const aIdentifier: String);
|
|
|
|
+begin
|
|
|
|
+ If Assigned(FExtractIdentifiers) then
|
|
|
|
+ FExtractIdentifiers.Add(aIdentifier);
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TFPExpressionParser.EvaluateExpression(Out Result: TFPExpressionResult);
|
|
procedure TFPExpressionParser.EvaluateExpression(Out Result: TFPExpressionResult);
|
|
begin
|
|
begin
|
|
If (FExpression='') then
|
|
If (FExpression='') then
|
|
@@ -1599,6 +1614,48 @@ begin
|
|
FExprNode.GetNodeValue(Result);
|
|
FExprNode.GetNodeValue(Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+
|
|
|
|
+Procedure TFPExpressionParser.ExtractIdentifierNames(Const aExpression : String; aCallback : TIdentifierEvent); overload;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ N : TFPExprNode;
|
|
|
|
+ OldExpr : String;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if Assigned(Self.FOnExtractIdentifier) then
|
|
|
|
+ ParserError(SErrCannotRecursivelyExtractIdentifiers);
|
|
|
|
+ N:=Nil;
|
|
|
|
+ FOnExtractIdentifier:=aCallBack;
|
|
|
|
+ try
|
|
|
|
+ // for safety
|
|
|
|
+ FreeAndNil(FUnknownIdentifier);
|
|
|
|
+ // Save old data
|
|
|
|
+ OldExpr:=Expression;
|
|
|
|
+ ExtractNode(N);
|
|
|
|
+ // Parse
|
|
|
|
+ Expression:=aExpression;
|
|
|
|
+ finally
|
|
|
|
+ FOnExtractIdentifier:=Nil;
|
|
|
|
+ FreeAndNil(FUnknownIdentifier);
|
|
|
|
+ FExpression:=OldExpr;
|
|
|
|
+ FExprNode:=N;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFPExpressionParser.ExtractIdentifierNames(const aExpression: String; aList: TStringList);
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if Assigned(FExtractIdentifiers) then
|
|
|
|
+ ParserError(SErrCannotRecursivelyExtractIdentifiers);
|
|
|
|
+ FExtractIdentifiers:=aList;
|
|
|
|
+ try
|
|
|
|
+ ExtractIdentifierNames(aExpression,@AddIdentifierToStrings);
|
|
|
|
+ finally
|
|
|
|
+ FExtractIdentifiers:=Nil;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
function TFPExpressionParser.ExtractNode(Var N : TFPExprNode) : Boolean;
|
|
function TFPExpressionParser.ExtractNode(Var N : TFPExprNode) : Boolean;
|
|
begin
|
|
begin
|
|
Result:=Assigned(FExprNode);
|
|
Result:=Assigned(FExprNode);
|
|
@@ -1710,6 +1767,11 @@ begin
|
|
Result:=Res.ResString;
|
|
Result:=Res.ResString;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TFPExpressionParser.GetExtractingIdentifiers: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=Assigned(FOnExtractIdentifier);
|
|
|
|
+end;
|
|
|
|
+
|
|
{
|
|
{
|
|
Checks types of todo and match. If ToDO can be converted to it matches
|
|
Checks types of todo and match. If ToDO can be converted to it matches
|
|
the type of match, then a node is inserted.
|
|
the type of match, then a node is inserted.
|
|
@@ -1847,7 +1909,8 @@ begin
|
|
GetToken;
|
|
GetToken;
|
|
CheckEOF;
|
|
CheckEOF;
|
|
Right:=Level4;
|
|
Right:=Level4;
|
|
- CheckNodes(Result,Right);
|
|
|
|
|
|
+ if Not ExtractingIdentifiers then
|
|
|
|
+ CheckNodes(Result,Right);
|
|
Case tt of
|
|
Case tt of
|
|
ttPlus : Result:=TFPAddOperation.Create(Result,Right);
|
|
ttPlus : Result:=TFPAddOperation.Create(Result,Right);
|
|
ttMinus : Result:=TFPSubtractOperation.Create(Result,Right);
|
|
ttMinus : Result:=TFPSubtractOperation.Create(Result,Right);
|
|
@@ -1877,7 +1940,8 @@ begin
|
|
tt:=TokenType;
|
|
tt:=TokenType;
|
|
GetToken;
|
|
GetToken;
|
|
Right:=Level5;
|
|
Right:=Level5;
|
|
- CheckNodes(Result,Right);
|
|
|
|
|
|
+ if Not ExtractingIdentifiers then
|
|
|
|
+ CheckNodes(Result,Right);
|
|
Case tt of
|
|
Case tt of
|
|
ttMul : Result:=TFPMultiplyOperation.Create(Result,Right);
|
|
ttMul : Result:=TFPMultiplyOperation.Create(Result,Right);
|
|
ttDiv : Result:=TFPDivideOperation.Create(Result,Right);
|
|
ttDiv : Result:=TFPDivideOperation.Create(Result,Right);
|
|
@@ -1960,6 +2024,7 @@ Var
|
|
ID : TFPExprIdentifierDef;
|
|
ID : TFPExprIdentifierDef;
|
|
Args : TExprArgumentArray;
|
|
Args : TExprArgumentArray;
|
|
AI : Integer;
|
|
AI : Integer;
|
|
|
|
+ S : String;
|
|
|
|
|
|
begin
|
|
begin
|
|
{$ifdef debugexpr} Writeln('Primitive : ',TokenName(TokenType),': ',CurrentToken);{$endif debugexpr}
|
|
{$ifdef debugexpr} Writeln('Primitive : ',TokenName(TokenType),': ',CurrentToken);{$endif debugexpr}
|
|
@@ -1989,9 +2054,22 @@ begin
|
|
IFC:=TokenType=ttCase;
|
|
IFC:=TokenType=ttCase;
|
|
if Not (IFF or IFC) then
|
|
if Not (IFF or IFC) then
|
|
begin
|
|
begin
|
|
- ID:=self.IdentifierByName(CurrentToken);
|
|
|
|
|
|
+ S:=CurrentToken;
|
|
|
|
+ ID:=self.IdentifierByName(S);
|
|
If (ID=Nil) then
|
|
If (ID=Nil) then
|
|
- ParserError(Format(SErrUnknownIdentifier,[CurrentToken]))
|
|
|
|
|
|
+ begin
|
|
|
|
+ if Assigned(FOnExtractIdentifier) then
|
|
|
|
+ begin
|
|
|
|
+ if not Assigned(FUnknownIdentifier) then
|
|
|
|
+ FUnknownIdentifier:=TFPExprIdentifierDef.Create(Nil);
|
|
|
|
+ ID:=FUnknownIdentifier;
|
|
|
|
+ // Call only once in case of stringlist.
|
|
|
|
+ If Not (Assigned(FExtractIdentifiers) and (FExtractIdentifiers.IndexOf(S)<>-1)) then
|
|
|
|
+ FOnExtractIdentifier(Self,S);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ ParserError(Format(SErrUnknownIdentifier,[S]))
|
|
|
|
+ end
|
|
end;
|
|
end;
|
|
// Determine number of arguments
|
|
// Determine number of arguments
|
|
if Iff then
|
|
if Iff then
|
|
@@ -2070,7 +2148,8 @@ begin
|
|
FExprNode:=Level1;
|
|
FExprNode:=Level1;
|
|
If (TokenType<>ttEOF) then
|
|
If (TokenType<>ttEOF) then
|
|
ParserError(Format(SErrUnterminatedExpression,[Scanner.Pos,CurrentToken]));
|
|
ParserError(Format(SErrUnterminatedExpression,[Scanner.Pos,CurrentToken]));
|
|
- FExprNode.Check;
|
|
|
|
|
|
+ if not ExtractingIdentifiers then
|
|
|
|
+ FExprNode.Check;
|
|
end
|
|
end
|
|
else
|
|
else
|
|
FExprNode:=Nil;
|
|
FExprNode:=Nil;
|