📄 dbf_prscore.pas
字号:
end;
function TCustomExpressionParser.ResultCanVary(ExprRec: PExpressionRec):
Boolean;
var
I: Integer;
begin
with ExprRec^ do
begin
Result := ExprWord.CanVary;
if not Result then
for I := 0 to ExprWord.MaxFunctionArg - 1 do
if (ArgList[I] <> nil) and ResultCanVary(ArgList[I]) then
begin
Result := true;
Exit;
end
end;
end;
procedure TCustomExpressionParser.RemoveConstants(var ExprRec: PExpressionRec);
var
I: Integer;
begin
if not ResultCanVary(ExprRec) then
begin
if not ExprRec^.ExprWord.IsVariable then
begin
// reset current record so that make list generates new
FCurrentRec := nil;
FExpResultPos := FExpResult;
MakeLinkedList(ExprRec, @FExpResult, @FExpResultPos, @FExpResultSize);
try
// compute result
EvaluateCurrent;
// make new record to store constant in
ExprRec := MakeRec;
// check result type
with ExprRec^ do
begin
case ResultType of
etBoolean: ExprWord := TBooleanConstant.Create(EmptyStr, PBoolean(FExpResult)^);
etFloat: ExprWord := TFloatConstant.CreateAsDouble(EmptyStr, PDouble(FExpResult)^);
etString: ExprWord := TStringConstant.Create(FExpResult);
end;
// fill in structure
Oper := ExprWord.ExprFunc;
Args[0] := ExprWord.AsPointer;
FConstantsList.Add(ExprWord);
end;
finally
DisposeList(FCurrentRec);
FCurrentRec := nil;
end;
end;
end else
with ExprRec^ do
begin
for I := 0 to ExprWord.MaxFunctionArg - 1 do
if ArgList[I] <> nil then
RemoveConstants(ArgList[I]);
end;
end;
procedure TCustomExpressionParser.DisposeTree(ExprRec: PExpressionRec);
var
I: Integer;
begin
if ExprRec <> nil then
begin
with ExprRec^ do
begin
if ExprWord <> nil then
for I := 0 to ExprWord.MaxFunctionArg - 1 do
DisposeTree(ArgList[I]);
if Res <> nil then
Res.Free;
end;
Dispose(ExprRec);
end;
end;
procedure TCustomExpressionParser.DisposeList(ARec: PExpressionRec);
var
TheNext: PExpressionRec;
I: Integer;
begin
if ARec <> nil then
repeat
TheNext := ARec^.Next;
if ARec^.Res <> nil then
ARec^.Res.Free;
I := 0;
while ARec^.ArgList[I] <> nil do
begin
FreeMem(ARec^.Args[I]);
Inc(I);
end;
Dispose(ARec);
ARec := TheNext;
until ARec = nil;
end;
procedure TCustomExpressionParser.MakeLinkedList(var ExprRec: PExpressionRec;
Memory: PPChar; MemoryPos: PPChar; MemSize: PInteger);
var
I: Integer;
begin
// test function type
if @ExprRec^.ExprWord.ExprFunc = nil then
begin
// special 'no function' function
// indicates no function is present -> we can concatenate all instances
// we don't create new arguments...these 'fall' through
// use destination as we got it
I := 0;
while ExprRec^.ArgList[I] <> nil do
begin
// convert arguments to list
MakeLinkedList(ExprRec^.ArgList[I], Memory, MemoryPos, MemSize);
// goto next argument
Inc(I);
end;
// don't need this record anymore
Dispose(ExprRec);
ExprRec := nil;
end else begin
// inc memory pointer so we know if we are first
ExprRec^.ResetDest := MemoryPos^ = Memory^;
Inc(MemoryPos^);
// convert arguments to list
I := 0;
while ExprRec^.ArgList[I] <> nil do
begin
// save variable type for easy access
ExprRec^.ArgsType[I] := ExprRec^.ArgList[I]^.ExprWord.ResultType;
// check if we need to copy argument, variables in general do not
// need copying, except for fixed len strings which are not
// null-terminated
// if ExprRec^.ArgList[I].ExprWord.NeedsCopy then
// begin
// get memory for argument
GetMem(ExprRec^.Args[I], ArgAllocSize);
ExprRec^.ArgsPos[I] := ExprRec^.Args[I];
ExprRec^.ArgsSize[I] := ArgAllocSize;
MakeLinkedList(ExprRec^.ArgList[I], @ExprRec^.Args[I], @ExprRec^.ArgsPos[I],
@ExprRec^.ArgsSize[I]);
// end else begin
// copy reference
// ExprRec^.Args[I] := ExprRec^.ArgList[I].Args[0];
// ExprRec^.ArgsPos[I] := ExprRec^.Args[I];
// ExprRec^.ArgsSize[I] := 0;
// FreeMem(ExprRec^.ArgList[I]);
// ExprRec^.ArgList[I] := nil;
// end;
// goto next argument
Inc(I);
end;
// link result to target argument
ExprRec^.Res := TDynamicType.Create(Memory, MemoryPos, MemSize);
// link to next operation
if FCurrentRec = nil then
begin
FCurrentRec := ExprRec;
FLastRec := ExprRec;
end else begin
FLastRec^.Next := ExprRec;
FLastRec := ExprRec;
end;
end;
end;
function TCustomExpressionParser.MakeTree(Expr: TExprCollection;
FirstItem, LastItem: Integer): PExpressionRec;
{
- This is the most complex routine, it breaks down the expression and makes
a linked tree which is used for fast function evaluations
- it is implemented recursively
}
var
I, IArg, IStart, IEnd, lPrec, brCount: Integer;
ExprWord: TExprWord;
begin
// remove redundant brackets
brCount := 0;
while (FirstItem+brCount < LastItem) and (TExprWord(
Expr.Items[FirstItem+brCount]).ResultType = etLeftBracket) do
Inc(brCount);
I := LastItem;
while (I > FirstItem) and (TExprWord(
Expr.Items[I]).ResultType = etRightBracket) do
Dec(I);
// test max of start and ending brackets
if brCount > (LastItem-I) then
brCount := LastItem-I;
// count number of bracket pairs completely open from start to end
// IArg is min.brCount
I := FirstItem + brCount;
IArg := brCount;
while (I <= LastItem - brCount) and (brCount > 0) do
begin
case TExprWord(Expr.Items[I]).ResultType of
etLeftBracket: Inc(brCount);
etRightBracket:
begin
Dec(brCount);
if brCount < IArg then
IArg := brCount;
end;
end;
Inc(I);
end;
// useful pair bracket count, is in minimum, is IArg
brCount := IArg;
// check if subexpression closed within (bracket level will be zero)
if brCount > 0 then
begin
Inc(FirstItem, brCount);
Dec(LastItem, brCount);
end;
// check for empty range
if LastItem < FirstItem then
begin
Result := nil;
exit;
end;
// get new record
Result := MakeRec;
// simple constant, variable or function?
if LastItem = FirstItem then
begin
Result^.ExprWord := TExprWord(Expr.Items[FirstItem]);
Result^.Oper := Result^.ExprWord.ExprFunc;
exit;
end;
// no...more complex, find operator with lowest precedence
brCount := 0;
IArg := 0;
IEnd := FirstItem-1;
lPrec := -1;
for I := FirstItem to LastItem do
begin
ExprWord := TExprWord(Expr.Items[I]);
if (brCount = 0) and ExprWord.IsOperator and (TFunction(ExprWord).OperPrec > lPrec) then
begin
IEnd := I;
lPrec := TFunction(ExprWord).OperPrec;
end;
case ExprWord.ResultType of
etLeftBracket: Inc(brCount);
etRightBracket: Dec(brCount);
end;
end;
// operator found ?
if IEnd >= FirstItem then
begin
// save operator
Result^.ExprWord := TExprWord(Expr.Items[IEnd]);
Result^.Oper := Result^.ExprWord.ExprFunc;
// recurse into left part if present
if IEnd > FirstItem then
begin
Result^.ArgList[IArg] := MakeTree(Expr, FirstItem, IEnd-1);
Inc(IArg);
end;
// recurse into right part if present
if IEnd < LastItem then
Result^.ArgList[IArg] := MakeTree(Expr, IEnd+1, LastItem);
end else
if TExprWord(Expr.Items[FirstItem]).IsFunction then
begin
// save function
Result^.ExprWord := TExprWord(Expr.Items[FirstItem]);
Result^.Oper := Result^.ExprWord.ExprFunc;
Result^.WantsFunction := true;
// parse function arguments
IEnd := FirstItem + 1;
IStart := IEnd;
brCount := 0;
if TExprWord(Expr.Items[IEnd]).ResultType = etLeftBracket then
begin
// opening bracket found, first argument expression starts at next index
Inc(brCount);
Inc(IStart);
while (IEnd < LastItem) and (brCount <> 0) do
begin
Inc(IEnd);
case TExprWord(Expr.Items[IEnd]).ResultType of
etLeftBracket: Inc(brCount);
etComma:
if brCount = 1 then
begin
// argument separation found, build tree of argument expression
Result^.ArgList[IArg] := MakeTree(Expr, IStart, IEnd-1);
Inc(IArg);
IStart := IEnd + 1;
end;
etRightBracket: Dec(brCount);
end;
end;
// parse last argument
Result^.ArgList[IArg] := MakeTree(Expr, IStart, IEnd-1);
end;
end else
raise EParserException.Create('Operator/function missing');
end;
procedure TCustomExpressionParser.ParseString(AnExpression: string; DestCollection: TExprCollection);
var
isConstant: Boolean;
I, I1, I2, Len, DecSep: Integer;
W, S: string;
TempWord: TExprWord;
procedure ReadConstant(AnExpr: string; isHex: Boolean);
begin
isConstant := true;
while (I2 <= Len) and ((AnExpr[I2] in ['0'..'9']) or
(isHex and (AnExpr[I2] in ['a'..'f', 'A'..'F']))) do
Inc(I2);
if I2 <= Len then
begin
if AnExpr[I2] = FDecimalSeparator then
begin
Inc(I2);
while (I2 <= Len) and (AnExpr[I2] in ['0'..'9']) do
Inc(I2);
end;
if (I2 <= Len) and (AnExpr[I2] = 'e') then
begin
Inc(I2);
if (I2 <= Len) and (AnExpr[I2] in ['+', '-']) then
Inc(I2);
while (I2 <= Len) and (AnExpr[I2] in ['0'..'9']) do
Inc(I2);
end;
end;
end;
procedure ReadWord(AnExpr: string);
var
OldI2: Integer;
constChar: Char;
begin
isConstant := false;
I1 := I2;
while (I1 < Len) and (AnExpr[I1] = ' ') do
Inc(I1);
I2 := I1;
if I1 <= Len then
begin
if AnExpr[I2] = HexChar then
begin
Inc(I2);
OldI2 := I2;
ReadConstant(AnExpr, true);
if I2 = OldI2 then
begin
isConstant := false;
while (I2 <= Len) and (AnExpr[I2] in ['a'..'z', 'A'..'Z', '_', '0'..'9']) do
Inc(I2);
end;
end
else if AnExpr[I2] = FDecimalSeparator then
ReadConstant(AnExpr, false)
else
case AnExpr[I2] of
'''', '"':
begin
isConstant := true;
constChar := AnExpr[I2];
Inc(I2);
while (I2 <= Len) and (AnExpr[I2] <> constChar) do
Inc(I2);
if I2 <= Len then
Inc(I2);
end;
'a'..'z', 'A'..'Z', '_':
begin
while (I2 <= Len) and (AnExpr[I2] in ['a'..'z', 'A'..'Z', '_', '0'..'9']) do
Inc(I2);
end;
'>', '<':
begin
if (I2 <= Len) then
Inc(I2);
if AnExpr[I2] in ['=', '<', '>'] then
Inc(I2);
end;
'=':
begin
if (I2 <= Len) then
Inc(I2);
if AnExpr[I2] in ['<', '>', '='] then
Inc(I2);
end;
'&':
begin
if (I2 <= Len) then
Inc(I2);
if AnExpr[I2] in ['&'] then
Inc(I2);
end;
'|':
begin
if (I2 <= Len) then
Inc(I2);
if AnExpr[I2] in ['|'] then
Inc(I2);
end;
':':
begin
if (I2 <= Len) then
Inc(I2);
if AnExpr[I2] = '=' then
Inc(I2);
end;
'!':
begin
if (I2 <= Len) then
Inc(I2);
if AnExpr[I2] = '=' then //support for !=
Inc(I2);
end;
'+':
begin
Inc(I2);
if (AnExpr[I2] = '+') and FWordsList.Search(PChar('++'), I) then
Inc(I2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -