Advertisement
Guest User

Untitled

a guest
Mar 11th, 2012
466
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 12.12 KB | None | 0 0
  1. (*
  2.  Moduł do obliczania wyrażeń matematycznych za pomocą tzw."stacji rozrządowej"
  3.  By Patryk Wychowaniec (patryk432@onet.eu)
  4.  
  5.  Wersja 0.4
  6. *)
  7. Unit ExpressionUnit;
  8.  
  9.  Interface
  10.  Uses Classes, Dialogs, SysUtils, Math, Windows;
  11.  Const ERROR_OK                 = 0;
  12.        ERROR_TOO_MANY_BRACKETS  = 1;
  13.        ERROR_TOO_FEW_BRACKETS   = 2;
  14.        ERROR_INVALID_FUNCTION   = 3;
  15.        ERROR_INVALID_FUNC_PARAM = 4;
  16.        ERROR_WRONG_OPERATORS    = 5;
  17.  
  18.  Type TParam = Array of Extended;
  19.  Type TExecute = Function (Param: TParam): Extended;
  20.  
  21.  Type TFunction = Record
  22.                    Name   : String;
  23.                    Param  : Integer;
  24.                    Execute: TExecute;
  25.                   End;
  26.                  
  27.  Type TExpressionParser = Class
  28.                            Private
  29.                             List     : TStringList;
  30.                             Functions: Array of TFunction;
  31.  
  32.                             Function ParseFunction(Num: Integer): Extended;
  33.                            
  34.                             Function PopInt: Extended;
  35.                             Function PeekInt: Extended;
  36.                             Procedure PushInt(Int: Extended);
  37.  
  38.                             Function PopStr: String;
  39.                             Function PeekStr: String;
  40.                             Procedure PushStr(Str: String);
  41.  
  42.                             Procedure ClearError;
  43.                             Procedure SetError(Code, Info: Integer; Str: String);
  44.  
  45.                             Function GetFunctionNum(Str: String): Integer;
  46.                             Function isFunction(Str: String): Boolean;
  47.                            Public
  48.                             ErrorCode, ErrorInfo: Integer;
  49.                             ErrorString         : String;
  50.                             RPN                 : String;
  51.  
  52.                             Constructor Create;
  53.  
  54.                             Function ExprToRPN(Expr: String): String;
  55.                             Function EvalRPN: Extended;
  56.                             Function EvalExpr(Expr: String): Extended;
  57.  
  58.                             Procedure AddFunction(Name: String; Param: Integer; Execute: TExecute);
  59.                           End;
  60.  
  61.  Implementation
  62. Const Numbers       = ['0'..'9', '.'];
  63.       Operations    = ['+', '-', '*', '/', '%', '^', '>', '<'];
  64.       OperStr       = '+-*/%^';                              
  65.       NumbStr       = '0123456789';
  66.       Accepted      = ['a'..'z','A'..'Z'];
  67.  
  68. (* ====== Domyślne dostępne funkcje ====== *)
  69.  
  70. Function f_SQRT(Param: TParam): Extended;
  71. Begin
  72.  Result := sqrt(Param[0]);
  73. End;
  74.  
  75. Function f_SIN(Param: TParam): Extended;
  76. Begin
  77.  Result := sin(Param[0]);
  78. End;
  79.  
  80. Function f_COS(Param: TParam): Extended;
  81. Begin
  82.  Result := cos(Param[0]);
  83. End;
  84.  
  85. Function f_TAN(Param: TParam): Extended;
  86. Begin
  87.  Result := tan(Param[0]);
  88. End;
  89.  
  90. Function f_ASIN(Param: TParam): Extended;
  91. Begin
  92.  Result := arcsin(Param[0]);
  93. End;
  94.  
  95. Function f_ACOS(Param: TParam): Extended;
  96. Begin
  97.  Result := arccos(Param[0]);
  98. End;
  99.  
  100. Function f_ATAN(Param: TParam): Extended;
  101. Begin
  102.  Result := arctan(Param[0]);
  103. End;
  104.  
  105. Function f_MIN(Param: TParam): Extended;
  106. Begin
  107.  Result := min(Param[0], Param[1]);
  108. End;
  109.  
  110. Function f_MAX(Param: TParam): Extended;
  111. Begin
  112.  Result := max(Param[0], Param[1]);
  113. End;
  114.  
  115. Function f_NWW(Param: TParam): Extended;
  116.  
  117.   Function NWW(A, B: Integer): Integer;
  118.   Var Dz: Integer;
  119.   Begin
  120.    Dz := 1;
  121.    While (Dz*A mod B <> 0) Do
  122.     Inc(Dz);
  123.    Result := Dz*A;
  124.   End;
  125.  
  126. Begin
  127.  Result := NWW(round(Param[0]), round(Param[1]));
  128. End;
  129.  
  130. Function f_NWD(Param: TParam): Extended;
  131.  
  132.   Function NWD(A, B: Integer): Integer;
  133.   Var Param: TParam;
  134.   Begin
  135.    SetLength(Param, 2);
  136.    Param[0] := A;
  137.    Param[1] := B;
  138.    Result   := (A*B) div round(f_NWW(Param));
  139.   End;
  140.  
  141. Begin
  142.  Result := NWD(round(Param[0]), round(Param[1]));
  143. End;
  144.  
  145. Function f_SQR(Param: TParam): Extended;
  146. Begin
  147.  Result := sqr(Param[0]);
  148. End;
  149.  
  150. Function f_ROUND(Param: TParam): Extended;
  151. Begin
  152.  Result := round(Param[0]);
  153. End;
  154.  
  155. Function f_PI(Param: TParam): Extended;
  156. Begin
  157.  Result := PI;
  158. End;
  159.  
  160. Function f_ABS(Param: TParam): Extended;
  161. Begin
  162.  Result := abs(Param[0]);
  163. End;
  164.  
  165.  
  166. (* ====== Do parsera ====== *)
  167.  
  168. Function GetOrder(E: String): Integer;
  169. Const Order: Array[0..2] of Array[0..1] of Char =
  170. (
  171.  ('+', '-'),
  172.  ('*', '/'),
  173.  ('^', '^')
  174. );
  175. Var I, Q: Integer;
  176. Begin
  177.  Result := -1;
  178.  For I := Low(Order) To High(Order) Do
  179.   For Q := Low(Order[I]) To High(Order[I]) Do
  180.    if (Order[I][Q] = E) Then
  181.    Begin
  182.     Result := I;
  183.     Exit;
  184.    End;
  185. End;
  186.  
  187. Function isNumber(Str: String): Boolean;
  188. Const Numbers = ['0'..'9', '.'];
  189. Var I: Integer;
  190. Begin
  191.  Result := False;
  192.  if (Length(Str) = 0) Then
  193.   Exit;
  194.  Result := True;
  195.  For I := 1 To Length(Str) Do
  196.   if not (Str[I] in Numbers) Then
  197.    Result := False;
  198. End;
  199.  
  200. (* ===== PARSER ===== *)
  201.  
  202. Constructor TExpressionParser.Create;
  203. Begin
  204.  List := TStringList.Create;
  205.  
  206.  //sin,cos,tan,asin,acos,atan,min,max,nww,nwd,sqr,round,pi,abs
  207.  AddFunction('sqrt' , 1, @f_SQRT);
  208.  AddFunction('sin'  , 1, @f_SIN);
  209.  AddFunction('cos'  , 1, @f_COS);
  210.  AddFunction('asin' , 1, @f_ASIN);
  211.  AddFunction('acos' , 1, @f_ACOS);
  212.  AddFunction('atan' , 1, @f_ATAN);
  213.  AddFunction('min'  , 2, @f_MIN);
  214.  AddFunction('max'  , 2, @f_MAX);
  215.  AddFunction('nww'  , 2, @f_NWW);
  216.  AddFunction('nwd'  , 2, @f_NWD);
  217.  AddFunction('sqr'  , 1, @f_SQR);
  218.  AddFunction('round', 1, @f_ROUND);
  219.  AddFunction('pi'   , 0, @f_PI);
  220.  AddFunction('abs'  , 1, @f_ABS);
  221. End;
  222.  
  223.  
  224. Function TExpressionParser.GetFunctionNum(Str: String): Integer;
  225. Var I: Integer;
  226. Begin
  227.  Result := -1;
  228.  Str    := LowerCase(Str);
  229.  For I := Low(Functions) To High(Functions) Do
  230.   if (Functions[I].Name = Str) Then
  231.   Begin  
  232.    Result := I;
  233.    Exit;
  234.   End;
  235. End;
  236.  
  237. Function TExpressionParser.isFunction(Str: String): Boolean;
  238. Begin
  239.  Result := GetFunctionNum(Str) <> -1;
  240. End;
  241.  
  242. Function TExpressionParser.PopInt: Extended;
  243. Begin
  244.  Result := 0;
  245.  
  246.  if (List.Count = 0) Then
  247.   Exit;
  248.  
  249.  Result := PeekInt;
  250.  List.Delete(List.Count-1);
  251. End;
  252.  
  253. Function TExpressionParser.PeekInt: Extended;
  254. Begin
  255.  Result := 0;
  256.  
  257.  if (List.Count = 0) Then
  258.   Exit;
  259.  
  260.  Result := StrToFloat(List[List.Count-1]);
  261. End;
  262.  
  263. Function TExpressionParser.PopStr: String;
  264. Begin
  265.  if (List.Count = 0) Then
  266.   Exit;
  267.  
  268.  Result := PeekStr;
  269.  List.Delete(List.Count-1);
  270. End;
  271.  
  272. Function TExpressionParser.PeekStr: String;
  273. Begin
  274.  Result := '';
  275.  if (List.Count = 0) Then
  276.   Exit;
  277.  Result := List[List.Count-1];
  278. End;
  279.  
  280. Procedure TExpressionParser.PushInt(Int: Extended);
  281. Begin
  282.  List.Add(FloatToStr(Int));
  283. End;
  284.  
  285. Procedure TExpressionParser.PushStr(Str: String);
  286. Begin
  287.  List.Add(Str);
  288. End;
  289.  
  290. Function TExpressionParser.ParseFunction(Num: Integer): Extended;
  291. Var Param: TParam;
  292.     I    : Integer;
  293. Begin
  294.  Result := 0;
  295.  if (Num = -1) Then
  296.   Exit;
  297.  SetLength(Param, Functions[Num].Param);
  298.  For I := 0 To Functions[Num].Param-1 Do
  299.  Begin
  300.   if (List.Count = 0) Then
  301.   Begin
  302.    SetError(ERROR_INVALID_FUNC_PARAM, Functions[Num].Param, Functions[Num].Name);
  303.    Exit;
  304.   End;
  305.   Param[I] := PopInt;
  306.  End;
  307.  
  308.  Result := Functions[Num].Execute(Param);
  309. End;
  310.  
  311. Function TExpressionParser.ExprToRPN(Expr: String): String;
  312. Var Pos, I : Integer;
  313.     Ex     : Char;
  314.     Str    : String;
  315.     Tmp    : String;
  316.     Func   : String;
  317.     Step   : String;
  318.     Bracket: Integer;
  319.  
  320.     Function ReadNumber: Extended;
  321.     Var Num: String;
  322.     Begin
  323.      Num := '';
  324.      While (Expr[Pos] in Numbers) Do
  325.      Begin
  326.       Num := Num+Expr[Pos];
  327.       Inc(Pos);
  328.      End;
  329.      Result := StrToFloat(Num);
  330.     End;
  331.  
  332. Begin
  333.  ClearError;
  334.  DecimalSeparator := '.';
  335.  ErrorCode        := 0;
  336.  List.Clear;
  337.  Expr := Trim(Expr);
  338.  
  339.  if (Expr = '') Then
  340.   Expr := '0';
  341.  
  342.  if (Expr[1] = '-') Then
  343.   Insert('0', Expr, 1);
  344.  
  345.  Expr := StringReplace(Expr, '(-', '(0-', [rfReplaceAll]);
  346.  
  347.  For I := 1 To Length(NumbStr) Do
  348.   Expr := StringReplace(Expr, NumbStr[I]+'(', NumbStr[I]+'*(', [rfReplaceAll]);
  349.  
  350.  For I := 1 To Length(OperStr) Do
  351.   Expr := StringReplace(Expr, OperStr[I]+'*', OperStr[I], [rfReplaceAll]);
  352.  
  353.  if (Expr[1] = '*') Then
  354.   Delete(Expr, 1, 1);
  355.  
  356.  Result  := '';
  357.  Pos     := 1;
  358.  Step    := Expr;
  359.  Bracket := 0;
  360.  Func    := '';
  361.  Tmp     := '';
  362.  While (true) Do
  363.  Begin                                                
  364.   if (Expr[Pos] in Numbers) Then
  365.    Result := Result+FloatToStr(ReadNumber)+' ';
  366.  
  367.   if (Expr[Pos] in Operations) Then
  368.   Begin
  369.    if (Expr[Pos-1] in Operations) Then
  370.    Begin
  371.     SetError(ERROR_WRONG_OPERATORS, Pos, Expr[Pos-2]+Expr[Pos-1]+Expr[Pos]+Expr[Pos+1]);
  372.     Exit;
  373.    End;
  374.    Ex := Expr[Pos];
  375.    if (PeekStr <> #0) Then
  376.     if (GetOrder(Ex) <= GetOrder(PeekStr)) Then
  377.      Repeat
  378.       Str := PeekStr;
  379.       if (GetOrder(Ex) <= GetOrder(Str)) Then
  380.       Begin
  381.        Str    := PopStr;
  382.        Result := Result+Str+' ';
  383.       End;
  384.      Until (List.Count = 0) or (GetOrder(Str) < GetOrder(Ex));
  385.    PushStr(Ex);
  386.   End;
  387.  
  388.   if (Expr[Pos] in Accepted) Then
  389.    Func := Func+Expr[Pos];
  390.  
  391.   if (Expr[Pos] = '(') Then
  392.   Begin
  393.    if (Func <> '') Then
  394.    Begin
  395.     PushStr(Func);
  396.     Func := '';
  397.    End;
  398.    PushStr('(');
  399.    Inc(Bracket);
  400.   End;
  401.  
  402.   if (Expr[Pos] = ')') Then
  403.   Begin
  404.    if (Bracket > 0) Then
  405.    Begin
  406.     Repeat
  407.      Str := PopStr;
  408.      if (Str <> '(') Then
  409.       Result := Result+Str+' ';
  410.     Until (List.Count = 0) or (Str = '(');
  411.     if (isFunction(PeekStr)) Then
  412.     Begin
  413.      Tmp    := '';
  414.      Result := Result+PopStr+' ';
  415.     End;
  416.    End;
  417.    Dec(Bracket);
  418.   End;
  419.  
  420.   if (Pos >= Length(Expr)) Then                        
  421.    Break;
  422.   Inc(Pos);
  423.  End;
  424.  
  425.  ErrorInfo := abs(Bracket);
  426.  
  427.  if (Bracket > 0) Then
  428.   ErrorCode := ERROR_TOO_MANY_BRACKETS;
  429.  if (Bracket < 0) Then
  430.   ErrorCode := ERROR_TOO_FEW_BRACKETS;
  431.  
  432.  if (ErrorCode <> 0) Then
  433.   Exit;
  434.  
  435.  Repeat
  436.   Result := Result+PopStr+' ';
  437.  Until (List.Count = 0);
  438.  
  439.  RPN := Result;
  440. End;
  441.  
  442. Function TExpressionParser.EvalRPN: Extended;
  443. Var Pos    : Integer;
  444.     Ex     : Char;
  445.     Tmp    : String;
  446.     Func   : String;
  447.     FuncNum: Integer;
  448.     A, B   : Extended;
  449. Begin
  450.  ClearError;
  451.  RPN              := Trim(RPN)+' ';
  452.  DecimalSeparator := '.';
  453.  Result           := 0;
  454.  if (RPN = '') Then
  455.   Exit;
  456.  List.Clear;
  457.  Pos  := 1;
  458.  Tmp  := '';
  459.  Func := '';
  460.  While (true) Do
  461.  Begin
  462.   Ex := RPN[Pos];
  463.   if (Ex in Numbers) Then
  464.   Begin
  465.    Tmp := Tmp+Ex;
  466.   End Else
  467.   if (Ex in Accepted) Then
  468.   Begin
  469.    Func := Func+Ex;
  470.   End Else
  471.   Begin
  472.    if (isNumber(Tmp)) Then
  473.     PushInt(StrToFloat(Tmp));
  474.    FuncNum := -1;
  475.    if (Func <> '') Then
  476.     if (not isFunction(Func)) Then
  477.     Begin
  478.      SetError(ERROR_INVALID_FUNCTION, 0, Func);
  479.      Exit;
  480.     End Else
  481.      FuncNum := GetFunctionNum(Func);
  482.    if (Ex in Operations) Then                                        
  483.    Begin
  484.     B := PopInt;
  485.     A := PopInt;
  486.     Case Ex Of
  487.      '+': PushInt(A+B);
  488.      '-': PushInt(A-B);
  489.      '*': PushInt(A*B);
  490.      '/': PushInt(A/B);
  491.      '%': PushInt(A-B*Floor(A/B));
  492.      '^': PushInt(Power(A, B));
  493.     End;
  494.    End Else
  495.    if (FuncNum > -1) Then
  496.    Begin
  497.     PushInt(ParseFunction(FuncNum));
  498.     if (ErrorCode <> 0) Then
  499.     Begin
  500.      ErrorString := Functions[FuncNum].Name;
  501.      Exit;        
  502.     End;
  503.    End;
  504.    Tmp  := '';                        
  505.    Func := '';
  506.   End;
  507.   Inc(Pos);
  508.   if (Pos > Length(RPN)) Then
  509.    Break;
  510.  End;
  511.  Result := PopInt;
  512. End;
  513.  
  514. Function TExpressionParser.EvalExpr(Expr: String): Extended;
  515. Var RPNTemp: String;
  516. Begin
  517.  RPNTemp := RPN;
  518.  RPN     := ExprToRPN(Expr);
  519.  if (ErrorCode <> 0) Then
  520.  Begin
  521.   Result := 0;
  522.   Exit;
  523.  End;
  524.  Result  := EvalRPN;
  525.  RPN     := RPNTemp;
  526. End;
  527.  
  528. Procedure TExpressionParser.ClearError;
  529. Begin
  530.  SetError(ERROR_OK, 0, '');
  531. End;
  532.  
  533. Procedure TExpressionParser.SetError(Code, Info: Integer; Str: String);
  534. Begin
  535.  ErrorCode   := Code;
  536.  ErrorInfo   := Info;
  537.  ErrorString := Str;
  538. End;
  539.  
  540. Procedure TExpressionParser.AddFunction(Name: String; Param: Integer; Execute: TExecute);
  541. Var I: Integer;
  542. Begin
  543.  SetLength(Functions, High(Functions)+2);
  544.  I                    := High(Functions);
  545.  Functions[I].Name    := LowerCase(Name);
  546.  Functions[I].Param   := Param;
  547.  Functions[I].Execute := Execute;
  548. End;
  549. End.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement