rm_parser.pas

来自「胜天进销存源码,国产优秀的进销存」· PAS 代码 · 共 865 行 · 第 1/2 页

PAS
865
字号

{*****************************************}
{                                         }
{          Report Machine v2.0            }
{             Report Pars                 }
{                                         }
{*****************************************}

unit RM_Parser;

{$I RM.INC}

interface

uses
  Windows, SysUtils, Classes, Forms, DB
  {$IFDEF Delphi6}, Variants{$ENDIF};

type
  TRMGetPValueEvent = procedure(aVariableName: string; var aValue: Variant) of object;
  TRMFunctionEvent = procedure(aFunctionName: string; aParams: array of Variant;
    var val: Variant; var aFound: Boolean) of object;

  // TRMVariables is tool class intended for storing variable name and its
  // value. Value is of type Variant.
  // Call TRMVariables['VarName'] := VarValue to set variable value and
  // VarValue := TRMVariables['VarName'] to retrieve it.

  PRMVariable = ^TRMVariable;
  TRMVariable = record
    Value: Variant;
    IsExpression: Boolean;
  end;

  { TRMVariables }
  TRMVariables = class(TObject)
  private
    FList: TStringList;

    function GetVariable(const Name: string): Variant;
    function GetValue(Index: Integer): Variant;
    function GetName(Index: Integer): string;
    function GetCount: Integer;
    function GetSorted: Boolean;

    procedure SetVariable(const Name: string; Value: Variant);
    procedure SetStringVariable(const Name: string; Value: Variant);
    procedure SetValue(Index: Integer; Value: Variant);
    procedure SetName(Index: Integer; Value: string);
    procedure SetSorted(Value: Boolean);
  public
    constructor Create;
    destructor Destroy; override;

    function IndexOf(const Name: string): Integer;
    procedure Assign(Value: TRMVariables);
    procedure Clear;
    procedure Delete(Index: Integer);
    procedure Insert(Index: Integer; const Name: string);

    property Items: TStringList read FList;
    property Variable[const Name: string]: Variant read GetVariable write SetVariable; default;
    property Value[Index: Integer]: Variant read GetValue write SetValue;
    property Name[Index: Integer]: string read GetName write SetName;
    property AsString[const Name: string]: Variant read GetVariable write SetStringVariable;
    property Count: Integer read GetCount;
    property Sorted: Boolean read GetSorted write SetSorted;
  end;

  // TRMParser is intended for calculating expressions passed as string
  // parameter like '1 + 2 * (a + b)'. Expression can contain variables and
  // functions. There is two events in TfrParser: OnGetValue and OnFunction
  // intended for substitute var/func value instead of var/func name.
  // Call TRMParser.Calc(Expression) to get expression value.

   { TRMParser }
  TRMParser = class
  private
    FInScript: Boolean;
    FParentReport: TComponent;
    FOnGetValue: TRMGetPValueEvent;
    FOnFunction: TRMFunctionEvent;
    function GetIdentify(const s: string; var i: Integer): string;
    function GetString(const s: string; var i: Integer): string;
    procedure GetParameters(const s: string; var Index: Integer; var params: array of Variant);
  public
    function Str2OPZ(s: string): string;
    function CalcOPZ(const s: string): Variant;
    function Calc(s: Variant): Variant;

    property ParentReport: TComponent read FParentReport write FParentReport;
    property OnGetValue: TRMGetPValueEvent read FOnGetValue write FOnGetValue;
    property OnFunction: TRMFunctionEvent read FOnFunction write FOnFunction;
    property InScript: Boolean read FInScript write FInScript;
  end;

  // TRMFunctionSplitter is internal class, you typically don't need to use it.
  // It intended for splitting expression onto several parts and checking
  // if it contains some specified functions.
  // TRMFunctionSplitter used when checking if objects has aggregate functions
  // inside.

  TRMFunctionSplitter = class
  protected
    FMatchFuncs, FSplitTo: TStrings;
    FParser: TRMParser;
    FVariables: TRMVariables;
  public
    constructor Create(MatchFuncs, SplitTo: TStrings; Variables: TRMVariables);
    destructor Destroy; override;
    procedure Split(s: string);
  end;

implementation

uses RM_Const, RM_Utils, RM_Class;

const
  ttGe = #1;
  ttLe = #2;
  ttNe = #3;
  ttOr = #4;
  ttAnd = #5;
  ttInt = #6;
  ttFrac = #7;
  ttUnMinus = #9;
  ttUnPlus = #10;
  ttStr = #11;
  ttNot = #12;
  ttMod = #13;
  ttRound = #14;

  {------------------------------------------------------------------------------}
  {------------------------------------------------------------------------------}
  {TRMVariables}

constructor TRMVariables.Create;
begin
  inherited Create;
  FList := TStringList.Create;
  FList.Duplicates := dupIgnore;
end;

destructor TRMVariables.Destroy;
begin
  Clear;
  FList.Free;
  inherited Destroy;
end;

procedure TRMVariables.Clear;
begin
  while FList.Count > 0 do
    Delete(0);
end;

procedure TRMVariables.Assign(Value: TRMVariables);
var
  i: Integer;
begin
  Clear;
  for i := 0 to Value.Count - 1 do
    SetVariable(Value.Name[i], Value.Value[i]);
end;

procedure TRMVariables.SetVariable(const Name: string; Value: Variant);
var
  i: Integer;
  p: PRMVariable;
begin
  i := IndexOf(Name);
  if i <> -1 then
    p := PRMVariable(FList.Objects[i])
  else
  begin
    New(p);
    FList.AddObject(Name, TObject(p));
  end;
  p^.Value := Value;
  p^.IsExpression := True;
end;

procedure TRMVariables.SetStringVariable(const Name: string; Value: Variant);
var
  i: Integer;
  p: PRMVariable;
begin
  i := IndexOf(Name);
  Value := '''' + Value + '''';
  if i >= 0 then
    p := PRMVariable(FList.Objects[i])
  else
  begin
    New(p);
    FList.AddObject(Name, TObject(p));
  end;
  p^.Value := Value;
  p^.IsExpression := True;
end;

function TRMVariables.GetVariable(const Name: string): Variant;
var
  i: Integer;
begin
  i := IndexOf(Name);
  if i >= 0 then
    Result := PRMVariable(FList.Objects[i]).Value
  else
    Result := Null;
end;

procedure TRMVariables.SetValue(Index: Integer; Value: Variant);
begin
  if (Index < 0) or (Index >= FList.Count) then Exit;
  PRMVariable(FList.Objects[Index])^.Value := Value;
end;

function TRMVariables.GetValue(Index: Integer): Variant;
begin
  Result := 0;
  if (Index < 0) or (Index >= FList.Count) then Exit;
  Result := PRMVariable(FList.Objects[Index])^.Value;
end;

function TRMVariables.IndexOf(const Name: string): Integer;
begin
  Result := FList.IndexOf(Name);
end;

procedure TRMVariables.Insert(Index: Integer; const Name: string);
begin
  SetVariable(Name, 0);
  FList.Move(FList.IndexOf(Name), Index);
end;

function TRMVariables.GetCount: Integer;
begin
  Result := FList.Count;
end;

procedure TRMVariables.SetName(Index: Integer; Value: string);
begin
  if (Index < 0) or (Index >= FList.Count) then Exit;
  FList[Index] := Value;
end;

function TRMVariables.GetName(Index: Integer): string;
begin
  Result := '';
  if (Index < 0) or (Index >= FList.Count) then Exit;
  Result := FList[Index];
end;

procedure TRMVariables.Delete(Index: Integer);
var
  p: PRMVariable;
begin
  if (Index < 0) or (Index >= FList.Count) then Exit;
  p := PRMVariable(FList.Objects[Index]);
  Dispose(p);
  FList.Delete(Index);
end;

procedure TRMVariables.SetSorted(Value: Boolean);
begin
  FList.Sorted := Value;
end;

function TRMVariables.GetSorted: Boolean;
begin
  Result := FList.Sorted;
end;

{------------------------------------------------------------------------------}
{------------------------------------------------------------------------------}
{TRMParser}

function TRMParser.CalcOPZ(const s: string): Variant;
var
  i, j, k, i1, st: Integer;
  s1: string;
  lParams: array[0..10] of Variant;
  nm: array[1..11] of Variant;
  v: Double;
  lFound: Boolean;

  procedure _RMSetNullValue;

    procedure _SetValue(var aValue1: Variant; const aValue2: Variant);
    begin
      if (TVarData(aValue2).VType = varString) or (TVarData(aValue2).VType = varOleStr) then
        aValue1 := ''
      else if TVarData(aValue2).VType = varBoolean then
        aValue1 := False
      else
        aValue1 := 0;
    end;

  begin
		if (FParentReport = nil) or TRMReport(FParentReport).ConvertNulls then Exit;
//    if not RMUseNull then Exit;

    if (nm[st - 2] = Null) or (nm[st - 1] = Null) then
    begin
      if nm[st - 2] = Null then
      begin
        _SetValue(nm[st - 2], nm[st - 1]);
      end
      else if nm[st - 1] = Null then
      begin
        _SetValue(nm[st - 1], nm[st - 2]);
      end;
    end;
  end;

begin
  st := 1;
  i := 1;
  nm[1] := 0;
  while i <= Length(s) do
  begin
    j := i;
    case s[i] of
      '+', ttOr:
        begin
          _RMSetNullValue;
          nm[st - 2] := nm[st - 2] + nm[st - 1];
        end;
      '-':
        begin
          _RMSetNullValue;
          nm[st - 2] := nm[st - 2] - nm[st - 1];
        end;
      '*', ttAnd:
        begin
          _RMSetNullValue;
          nm[st - 2] := nm[st - 2] * nm[st - 1];
        end;
      '/':
        begin
          _RMSetNullValue;
          if nm[st - 1] <> 0 then
            nm[st - 2] := nm[st - 2] / nm[st - 1]
          else
            nm[st - 2] := 0;
        end;
      '>':
        begin
          _RMSetNullValue;
          if nm[st - 2] > nm[st - 1] then
            nm[st - 2] := 1
          else
            nm[st - 2] := 0;
        end;
      '<':
        begin
          _RMSetNullValue;
          if nm[st - 2] < nm[st - 1] then
            nm[st - 2] := 1
          else
            nm[st - 2] := 0;
        end;
      '=':
        begin
          _RMSetNullValue;
          if nm[st - 2] = nm[st - 1] then
            nm[st - 2] := 1
          else
            nm[st - 2] := 0;
        end;
      ttNe:
        begin
          _RMSetNullValue;
          if nm[st - 2] <> nm[st - 1] then
            nm[st - 2] := 1
          else
            nm[st - 2] := 0;
        end;
      ttGe:
        begin
          _RMSetNullValue;
          if nm[st - 2] >= nm[st - 1] then
            nm[st - 2] := 1
          else
            nm[st - 2] := 0;
        end;
      ttLe:
        begin
          _RMSetNullValue;
          if nm[st - 2] <= nm[st - 1] then
            nm[st - 2] := 1
          else
            nm[st - 2] := 0;
        end;
      ttInt:
        begin
          _RMSetNullValue;
          v := nm[st - 1];
          if Abs(Round(v) - v) < 1E-10 then
            v := Round(v)
          else
            v := Int(v);
          nm[st - 1] := v;
        end;
      ttFrac:
        begin
          _RMSetNullValue;
          v := nm[st - 1];
          if Abs(Round(v) - v) < 1E-10 then
            v := Round(v);
          nm[st - 1] := Frac(v);
        end;
      ttRound:
        begin
          if nm[st - 1] = Null then
            nm[st - 1] := 0;

          nm[st - 1] := Integer(Round(nm[st - 1]));
        end;
      ttUnMinus:
        begin
          if nm[st - 1] = Null then
            nm[st - 1] := 0;

          nm[st - 1] := -nm[st - 1];
        end;
      ttUnPlus: ;
      ttStr:
        begin
          if nm[st - 1] <> Null then
            s1 := nm[st - 1]
          else
            s1 := '';

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?