Parsing.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:13k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1995, 1996 AO ROSNO             }
  6. {         Copyright (c) 1997, 1998 Master-Bank          }
  7. {                                                       }
  8. {*******************************************************}
  9. unit Parsing;
  10. interface
  11. {$I RX.INC}
  12. uses SysUtils, Classes;
  13. type
  14.   TParserFunc = (pfArcTan, pfCos, pfSin, pfTan, pfAbs, pfExp, pfLn, pfLog,
  15.     pfSqrt, pfSqr, pfInt, pfFrac, pfTrunc, pfRound, pfArcSin, pfArcCos,
  16.     pfSign, pfNot);
  17.   ERxParserError = class(Exception);
  18. {$IFDEF WIN32}
  19.   TUserFunction = function(Value: Extended): Extended;
  20. {$ELSE}
  21.   TUserFunction = Pointer;
  22. {$ENDIF}
  23.   TRxMathParser = class(TObject)
  24.   private
  25.     FCurPos: Cardinal;
  26.     FParseText: string;
  27.     function GetChar: Char;
  28.     procedure NextChar;
  29.     function GetNumber(var AValue: Extended): Boolean;
  30.     function GetConst(var AValue: Extended): Boolean;
  31.     function GetFunction(var AValue: TParserFunc): Boolean;
  32.     function GetUserFunction(var Index: Integer): Boolean;
  33.     function Term: Extended;
  34.     function SubTerm: Extended;
  35.     function Calculate: Extended;
  36.   public
  37.     function Exec(const AFormula: string): Extended;
  38.     class procedure RegisterUserFunction(const Name: string; Proc: TUserFunction);
  39.     class procedure UnregisterUserFunction(const Name: string);
  40.   end;
  41. function GetFormulaValue(const Formula: string): Extended;
  42. {$IFNDEF WIN32}
  43. function Power(Base, Exponent: Extended): Extended;
  44. {$ENDIF}
  45. implementation
  46. uses RxTConst;
  47. const
  48.   SpecialChars = [#0..' ', '+', '-', '/', '*', ')', '^'];
  49.   FuncNames: array[TParserFunc] of PChar =
  50.     ('ARCTAN', 'COS', 'SIN', 'TAN', 'ABS', 'EXP', 'LN', 'LOG',
  51.     'SQRT', 'SQR', 'INT', 'FRAC', 'TRUNC', 'ROUND', 'ARCSIN', 'ARCCOS',
  52.     'SIGN', 'NOT');
  53. { Parser errors }
  54. procedure InvalidCondition(Str: Word);
  55. begin
  56.   raise ERxParserError.Create(LoadStr(Str));
  57. end;
  58. { IntPower and Power functions are copied from Borland's MATH.PAS unit }
  59. function IntPower(Base: Extended; Exponent: Integer): Extended;
  60. {$IFDEF WIN32}
  61. asm
  62.         mov     ecx, eax
  63.         cdq
  64.         fld1                      { Result := 1 }
  65.         xor     eax, edx
  66.         sub     eax, edx          { eax := Abs(Exponent) }
  67.         jz      @@3
  68.         fld     Base
  69.         jmp     @@2
  70. @@1:    fmul    ST, ST            { X := Base * Base }
  71. @@2:    shr     eax,1
  72.         jnc     @@1
  73.         fmul    ST(1),ST          { Result := Result * X }
  74.         jnz     @@1
  75.         fstp    st                { pop X from FPU stack }
  76.         cmp     ecx, 0
  77.         jge     @@3
  78.         fld1
  79.         fdivrp                    { Result := 1 / Result }
  80. @@3:
  81.         fwait
  82. end;
  83. {$ELSE}
  84. var
  85.   Y: Longint;
  86. begin
  87.   Y := Abs(Exponent);
  88.   Result := 1.0;
  89.   while Y > 0 do begin
  90.     while not Odd(Y) do begin
  91.       Y := Y shr 1;
  92.       Base := Base * Base;
  93.     end;
  94.     Dec(Y);
  95.     Result := Result * Base;
  96.   end;
  97.   if Exponent < 0 then Result := 1.0 / Result;
  98. end;
  99. {$ENDIF WIN32}
  100. function Power(Base, Exponent: Extended): Extended;
  101. begin
  102.   if Exponent = 0.0 then Result := 1.0
  103.   else if (Base = 0.0) and (Exponent > 0.0) then Result := 0.0
  104.   else if (Frac(Exponent) = 0.0) and (Abs(Exponent) <= MaxInt) then
  105.     Result := IntPower(Base, Trunc(Exponent))
  106.   else Result := Exp(Exponent * Ln(Base))
  107. end;
  108. { User defined functions }
  109. type
  110. {$IFDEF WIN32}
  111.   TFarUserFunction = TUserFunction;
  112. {$ELSE}
  113.   TFarUserFunction = function(Value: Extended): Extended;
  114. {$ENDIF}
  115. var
  116.   UserFuncList: TStrings;
  117. function GetUserFuncList: TStrings;
  118. begin
  119.   if not Assigned(UserFuncList) then begin
  120.     UserFuncList := TStringList.Create;
  121.     with TStringList(UserFuncList) do begin
  122.       Sorted := True;
  123.       Duplicates := dupIgnore;
  124.     end;
  125.   end;
  126.   Result := UserFuncList;
  127. end;
  128. procedure FreeUserFunc; far;
  129. begin
  130.   UserFuncList.Free;
  131.   UserFuncList := nil;
  132. end;
  133. { Parsing routines }
  134. function GetFormulaValue(const Formula: string): Extended;
  135. begin
  136.   with TRxMathParser.Create do
  137.   try
  138.     Result := Exec(Formula);
  139.   finally
  140.     Free;
  141.   end;
  142. end;
  143. { TRxMathParser }
  144. function TRxMathParser.GetChar: Char;
  145. begin
  146.   Result := FParseText[FCurPos];
  147. end;
  148. procedure TRxMathParser.NextChar;
  149. begin
  150.   Inc(FCurPos);
  151. end;
  152. function TRxMathParser.GetNumber(var AValue: Extended): Boolean;
  153. var
  154.   C: Char;
  155.   SavePos: Cardinal;
  156.   Code: Integer;
  157.   IsHex: Boolean;
  158.   TmpStr: string;
  159. begin
  160.   Result := False;
  161.   C := GetChar;
  162.   SavePos := FCurPos;
  163.   TmpStr := '';
  164.   IsHex := False;
  165.   if C = '$' then begin
  166.     TmpStr := C;
  167.     NextChar;
  168.     C := GetChar;
  169.     while C in ['0'..'9', 'A'..'F', 'a'..'f'] do begin
  170.       TmpStr := TmpStr + C;
  171.       NextChar;
  172.       C := GetChar;
  173.     end;
  174.     IsHex := True;
  175.     Result := (Length(TmpStr) > 1) and (Length(TmpStr) <= 9);
  176.   end
  177.   else if C in ['+', '-', '0'..'9', '.', DecimalSeparator] then begin
  178.     if (C in ['.', DecimalSeparator]) then TmpStr := '0' + '.'
  179.     else TmpStr := C;
  180.     NextChar;
  181.     C := GetChar;
  182.     if (Length(TmpStr) = 1) and (TmpStr[1] in ['+', '-']) and
  183.       (C in ['.', DecimalSeparator]) then TmpStr := TmpStr + '0';
  184.     while C in ['0'..'9', '.', 'E', 'e', DecimalSeparator] do begin
  185.       if C = DecimalSeparator then TmpStr := TmpStr + '.'
  186.       else TmpStr := TmpStr + C;
  187.       if (C = 'E') then begin
  188.         if (Length(TmpStr) > 1) and (TmpStr[Length(TmpStr) - 1] = '.') then
  189.           Insert('0', TmpStr, Length(TmpStr));
  190.         NextChar;
  191.         C := GetChar;
  192.         if (C in ['+', '-']) then begin
  193.           TmpStr := TmpStr + C;
  194.           NextChar;
  195.         end;
  196.       end
  197.       else NextChar;
  198.       C := GetChar;
  199.     end;
  200.     if (TmpStr[Length(TmpStr)] = '.') and (Pos('E', TmpStr) = 0) then
  201.       TmpStr := TmpStr + '0';
  202.     Val(TmpStr, AValue, Code);
  203.     Result := (Code = 0);
  204.   end;
  205.   Result := Result and (FParseText[FCurPos] in SpecialChars);
  206.   if Result then begin
  207.     if IsHex then AValue := StrToInt(TmpStr)
  208.     { else AValue := StrToFloat(TmpStr) };
  209.   end
  210.   else begin
  211.     AValue := 0;
  212.     FCurPos := SavePos;
  213.   end;
  214. end;
  215. function TRxMathParser.GetConst(var AValue: Extended): Boolean;
  216. begin
  217.   Result := False;
  218.   case FParseText[FCurPos] of
  219.     'E':
  220.       if FParseText[FCurPos + 1] in SpecialChars then
  221.       begin
  222.         AValue := Exp(1);
  223.         Inc(FCurPos);
  224.         Result := True;
  225.       end;
  226.     'P':
  227.       if (FParseText[FCurPos + 1] = 'I') and
  228.         (FParseText[FCurPos + 2] in SpecialChars) then
  229.       begin
  230.         AValue := Pi;
  231.         Inc(FCurPos, 2);
  232.         Result := True;
  233.       end;
  234.   end
  235. end;
  236. function TRxMathParser.GetUserFunction(var Index: Integer): Boolean;
  237. var
  238.   TmpStr: string;
  239.   I: Integer;
  240. begin
  241.   Result := False;
  242.   if (FParseText[FCurPos] in ['A'..'Z', 'a'..'z', '_']) and
  243.     Assigned(UserFuncList) then
  244.   begin
  245.     with UserFuncList do
  246.       for I := 0 to Count - 1 do begin
  247.         TmpStr := Copy(FParseText, FCurPos, Length(Strings[I]));
  248.         if (CompareText(TmpStr, Strings[I]) = 0) and
  249.           (Objects[I] <> nil) then
  250.         begin
  251.           if FParseText[FCurPos + Cardinal(Length(TmpStr))] = '(' then
  252.           begin
  253.             Result := True;
  254.             Inc(FCurPos, Length(TmpStr));
  255.             Index := I;
  256.             Exit;
  257.           end;
  258.         end;
  259.       end;
  260.   end;
  261.   Index := -1;
  262. end;
  263. function TRxMathParser.GetFunction(var AValue: TParserFunc): Boolean;
  264. var
  265.   I: TParserFunc;
  266.   TmpStr: string;
  267. begin
  268.   Result := False;
  269.   AValue := Low(TParserFunc);
  270.   if FParseText[FCurPos] in ['A'..'Z', 'a'..'z', '_'] then begin
  271.     for I := Low(TParserFunc) to High(TParserFunc) do begin
  272.       TmpStr := Copy(FParseText, FCurPos, StrLen(FuncNames[I]));
  273.       if CompareText(TmpStr, StrPas(FuncNames[I])) = 0 then begin
  274.         AValue := I;
  275.         if FParseText[FCurPos + Cardinal(Length(TmpStr))] = '(' then begin
  276.           Result := True;
  277.           Inc(FCurPos, Length(TmpStr));
  278.           Break;
  279.         end;
  280.       end;
  281.     end;
  282.   end;
  283. end;
  284. function TRxMathParser.Term: Extended;
  285. var
  286.   Value: Extended;
  287.   NoFunc: TParserFunc;
  288.   UserFunc: Integer;
  289.   Func: Pointer;
  290. begin
  291.   if FParseText[FCurPos] = '(' then begin
  292.     Inc(FCurPos);
  293.     Value := Calculate;
  294.     if FParseText[FCurPos] <> ')' then InvalidCondition(SParseNotCramp);
  295.     Inc(FCurPos);
  296.   end
  297.   else begin
  298.     if not GetNumber(Value) then
  299.       if not GetConst(Value) then
  300.         if GetUserFunction(UserFunc) then begin
  301.           Inc(FCurPos);
  302.           Func := UserFuncList.Objects[UserFunc];
  303.           Value := TFarUserFunction(Func)(Calculate);
  304.           if FParseText[FCurPos] <> ')' then InvalidCondition(SParseNotCramp);
  305.           Inc(FCurPos);
  306.         end
  307.         else if GetFunction(NoFunc) then begin
  308.           Inc(FCurPos);
  309.           Value := Calculate;
  310.           try
  311.             case NoFunc of
  312.               pfArcTan: Value := ArcTan(Value);
  313.               pfCos: Value := Cos(Value);
  314.               pfSin: Value := Sin(Value);
  315.               pfTan:
  316.                 if Cos(Value) = 0 then InvalidCondition(SParseDivideByZero)
  317.                 else Value := Sin(Value) / Cos(Value);
  318.               pfAbs: Value := Abs(Value);
  319.               pfExp: Value := Exp(Value);
  320.               pfLn:
  321.                 if Value <= 0 then InvalidCondition(SParseLogError)
  322.                 else Value := Ln(Value);
  323.               pfLog:
  324.                 if Value <= 0 then InvalidCondition(SParseLogError)
  325.                 else Value := Ln(Value) / Ln(10);
  326.               pfSqrt:
  327.                 if Value < 0 then InvalidCondition(SParseSqrError)
  328.                 else Value := Sqrt(Value);
  329.               pfSqr: Value := Sqr(Value);
  330.               pfInt: Value := Round(Value);
  331.               pfFrac: Value := Frac(Value);
  332.               pfTrunc: Value := Trunc(Value);
  333.               pfRound: Value := Round(Value);
  334.               pfArcSin:
  335.                 if Value = 1 then Value := Pi / 2
  336.                 else Value := ArcTan(Value / Sqrt(1 - Sqr(Value)));
  337.               pfArcCos:
  338.                 if Value = 1 then Value := 0
  339.                 else Value := Pi / 2 - ArcTan(Value / Sqrt(1 - Sqr(Value)));
  340.               pfSign:
  341.                 if Value > 0 then Value := 1
  342.                 else if Value < 0 then Value := -1;
  343.               pfNot: Value := not Trunc(Value);
  344.             end;
  345.           except
  346.             on E: ERxParserError do raise
  347.             else InvalidCondition(SParseInvalidFloatOperation);
  348.           end;
  349.           if FParseText[FCurPos] <> ')' then InvalidCondition(SParseNotCramp);
  350.           Inc(FCurPos);
  351.         end
  352.         else InvalidCondition(SParseSyntaxError);
  353.   end;
  354.   Result := Value;
  355. end;
  356. function TRxMathParser.SubTerm: Extended;
  357. var
  358.   Value: Extended;
  359. begin
  360.   Value := Term;
  361.   while FParseText[FCurPos] in ['*', '^', '/'] do begin
  362.     Inc(FCurPos);
  363.     if FParseText[FCurPos - 1] = '*' then
  364.       Value := Value * Term
  365.     else if FParseText[FCurPos - 1] = '^' then
  366.       Value := Power(Value, Term)
  367.     else if FParseText[FCurPos - 1] = '/' then
  368.       try
  369.         Value := Value / Term;
  370.       except
  371.         InvalidCondition(SParseDivideByZero);
  372.       end;
  373.   end;
  374.   Result := Value;
  375. end;
  376. function TRxMathParser.Calculate: Extended;
  377. var
  378.   Value: Extended;
  379. begin
  380.   Value := SubTerm;
  381.   while FParseText[FCurPos] in ['+', '-'] do begin
  382.     Inc(FCurPos);
  383.     if FParseText[FCurPos - 1] = '+' then Value := Value + SubTerm
  384.     else Value := Value - SubTerm;
  385.   end;
  386.   if not (FParseText[FCurPos] in [#0, ')', '>', '<', '=', ',']) then
  387.     InvalidCondition(SParseSyntaxError);
  388.   Result := Value;
  389. end;
  390. function TRxMathParser.Exec(const AFormula: string): Extended;
  391. var
  392.   I, J: Integer;
  393. begin
  394.   J := 0;
  395.   Result := 0;
  396.   FParseText := '';
  397.   for I := 1 to Length(AFormula) do begin
  398.     case AFormula[I] of
  399.       '(': Inc(J);
  400.       ')': Dec(J);
  401.     end;
  402.     if AFormula[I] > ' ' then FParseText := FParseText + UpCase(AFormula[I]);
  403.   end;
  404.   if J = 0 then begin
  405.     FCurPos := 1;
  406.     FParseText := FParseText + #0;
  407.     if (FParseText[1] in ['-', '+']) then FParseText := '0' + FParseText;
  408.     Result := Calculate;
  409.   end
  410.   else InvalidCondition(SParseNotCramp);
  411. end;
  412. class procedure TRxMathParser.RegisterUserFunction(const Name: string;
  413.   Proc: TUserFunction);
  414. var
  415.   I: Integer;
  416. begin
  417.   if (Length(Name) > 0) and (Name[1] in ['A'..'Z', 'a'..'z', '_']) then
  418.   begin
  419.     if not Assigned(Proc) then UnregisterUserFunction(Name)
  420.     else begin
  421.       with GetUserFuncList do begin
  422.         I := IndexOf(Name);
  423.         if I < 0 then I := Add(Name);
  424. {$IFDEF WIN32}
  425.         Objects[I] := @Proc;
  426. {$ELSE}
  427.         Objects[I] := Proc;
  428. {$ENDIF}
  429.       end;
  430.     end;
  431.   end
  432.   else InvalidCondition(SParseSyntaxError);
  433. end;
  434. class procedure TRxMathParser.UnregisterUserFunction(const Name: string);
  435. var
  436.   I: Integer;
  437. begin
  438.   if Assigned(UserFuncList) then
  439.     with UserFuncList do begin
  440.       I := IndexOf(Name);
  441.       if I >= 0 then Delete(I);
  442.       if Count = 0 then FreeUserFunc;
  443.     end;
  444. end;
  445. initialization
  446.   UserFuncList := nil;
  447. {$IFDEF WIN32}
  448. finalization
  449.   FreeUserFunc;  
  450. {$ELSE}
  451.   AddExitProc(FreeUserFunc);
  452. {$ENDIF}
  453. end.