Advertisement
Guest User

Untitled

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