home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / turbo4 / mcparser.pas < prev    next >
Pascal/Delphi Source File  |  1987-12-08  |  14KB  |  565 lines

  1.  
  2. {           Copyright (c) 1985, 87 by Borland International, Inc.     }
  3.  
  4. unit MCPARSER;
  5.  
  6. interface
  7.  
  8. uses Crt, Dos, MCVars, MCUtil, MCDisply;
  9.  
  10. function CellValue(Col, Row : Word) : Real;
  11. { Berechnet den Wert einer Zelle }
  12.  
  13. function Parse(S : String; var Att : Word) : Real;
  14. { Bewertet den String s und liefert seinen Wert als Funktionsergebnis. Das Feld
  15.   Att erhält einen der Werte: TXT = 0, CONSTANT = 1, FORMULA = 2, +4 = ERROR. }
  16.  
  17. implementation
  18.  
  19. const
  20.   PLUS = 0; MINUS = 1; TIMES = 2; DIVIDE = 3; EXPO = 4;  { +, -, *, /, ^ }
  21.   COLON = 5;                 { Doppelpunkt (für Zellbereiche) }
  22.   OPAREN = 6; CPAREN = 7;    { Klammer auf, Klammer zu }
  23.   NUM = 8;
  24.   CELLT = 9;
  25.   FUNC = 10;
  26.   EOL = 11;   { Formel-Ende }
  27.   BAD = 12;
  28.   MAXFUNCNAMELEN = 5;
  29.  
  30. type
  31.   TokenRec = record
  32.     State : Byte;
  33.     case Byte of
  34.       0 : (Value : Real);
  35.       1 : (Row, Col : Word);
  36.       2 : (FuncName : String[MAXFUNCNAMELEN]);
  37.   end;
  38.  
  39. var
  40.   Stack : array [1..PARSERSTACKSIZE] of TokenRec;
  41.   CurToken : TokenRec;
  42.   StackTop, TokenType : Word;
  43.   MathError, TokenError, IsFormula : Boolean;
  44.   Input : IString;
  45.  
  46. function IsFunc(S : String) : Boolean;
  47. { Prüft, ob der übergebene String eine legale Funktion ist und liefert TRUE,
  48.   wenn ja; ansonsten FALSE }
  49. var Len : Word;
  50. begin
  51.   Len := Length(S);
  52.   if Pos(S, Input) = 1 then
  53.   begin
  54.     CurToken.FuncName := Copy(Input, 1, Len);
  55.     Delete(Input, 1, Len);
  56.     IsFunc := True;
  57.   end
  58.   else
  59.     IsFunc := False;
  60. end;
  61.  
  62. function NextToken : Word;   { Liefert das jeweils nächste Token }
  63. var
  64.   NumString : String[80];
  65.   FormLen, Place, Len, NumLen, Check : Word;
  66.   FirstChar : Char;
  67.   Decimal : Boolean;
  68. begin
  69.   if Input = '' then
  70.   begin
  71.     NextToken := EOL;
  72.     Exit;
  73.   end;
  74.   while (Input <> '') and (Input[1] = ' ') do
  75.     Delete(Input, 1, 1);
  76.   if Input[1] in ['0'..'9', '.'] then
  77.   begin
  78.     NumString := '';
  79.     Len := 1;
  80.     Decimal := False;
  81.     while (Len <= Length(Input)) and
  82.           ((Input[Len] in ['0'..'9']) or
  83.            ((Input[Len] = '.') and (not Decimal))) do
  84.     begin
  85.       NumString := NumString + Input[Len];
  86.       if Input[1] = '.' then
  87.         Decimal := True;
  88.       Inc(Len);
  89.     end;
  90.     if (Len = 2) and (Input[1] = '.') then
  91.     begin
  92.       NextToken := BAD;
  93.       Exit;
  94.     end;
  95.     if (Len <= Length(Input)) and (Input[Len] = 'E') then
  96.     begin
  97.       NumString := NumString + 'E';
  98.       Inc(Len);
  99.       if Input[Len] in ['+', '-'] then
  100.       begin
  101.         NumString := NumString + Input[Len];
  102.         Inc(Len);
  103.       end;
  104.       NumLen := 1;
  105.       while (Len <= Length(Input)) and (Input[Len] in ['0'..'9']) and
  106.             (NumLen <= MAXEXPLEN) do
  107.       begin
  108.         NumString := NumString + Input[Len];
  109.         Inc(NumLen);
  110.         Inc(Len);
  111.       end;
  112.     end;
  113.     if NumString[1] = '.' then
  114.       NumString := '0' + NumString;
  115.     Val(NumString, CurToken.Value, Check);
  116.     if Check <> 0 then
  117.       MathError := True;
  118.     NextToken := NUM;
  119.     Delete(Input, 1, Length(NumString));
  120.     Exit;
  121.   end
  122.   else if Input[1] in LETTERS then
  123.   begin
  124.     if IsFunc('ABS') or
  125.        IsFunc('ATAN') or
  126.        IsFunc('COS') or
  127.        IsFunc('EXP') or
  128.        IsFunc('LN') or
  129.        IsFunc('ROUND') or
  130.        IsFunc('SIN') or
  131.        IsFunc('SQRT') or
  132.        IsFunc('SQR') or
  133.        IsFunc('TRUNC') then
  134.     begin
  135.       NextToken := FUNC;
  136.       Exit;
  137.     end;
  138.     if FormulaStart(Input, 1, CurToken.Col, CurToken.Row, FormLen) then
  139.     begin
  140.       Delete(Input, 1, FormLen);
  141.       IsFormula := True;
  142.       NextToken := CELLT;
  143.       Exit;
  144.     end
  145.     else begin
  146.       NextToken := BAD;
  147.       Exit;
  148.     end;
  149.   end
  150.   else begin
  151.     case Input[1] of
  152.       '+' : NextToken := PLUS;
  153.       '-' : NextToken := MINUS;
  154.       '*' : NextToken := TIMES;
  155.       '/' : NextToken := DIVIDE;
  156.       '^' : NextToken := EXPO;
  157.       ':' : NextToken := COLON;
  158.       '(' : NextToken := OPAREN;
  159.       ')' : NextToken := CPAREN;
  160.       else
  161.         NextToken := BAD;
  162.     end;
  163.     Delete(Input, 1, 1);
  164.     Exit;
  165.   end; { case }
  166. end; { NextToken }
  167.  
  168. procedure Push(Token : TokenRec); { Legt ein neues Token auf den Stack }
  169. begin
  170.   if StackTop = PARSERSTACKSIZE then
  171.   begin
  172.     ErrorMsg(MSGSTACKERROR);
  173.     TokenError := True;
  174.   end
  175.   else begin
  176.     Inc(StackTop);
  177.     Stack[StackTop] := Token;
  178.   end;
  179. end;
  180.  
  181. procedure Pop(var Token : TokenRec);  { Holt ein Token vom Stack herunter }
  182. begin
  183.   Token := Stack[StackTop];
  184.   Dec(StackTop);
  185. end; { Pop }
  186.  
  187. function GotoState(Production : Word) : Word;
  188. { Legt den neuen Status anhand der soeben abgeschlossenen Operation
  189.   und des obersten Stack-Elements fest }
  190. var State : Word;
  191. begin
  192.   State := Stack[StackTop].State;
  193.   if (Production <= 3) then
  194.   begin
  195.     case State of
  196.       0 : GotoState := 1;
  197.       9 : GotoState := 19;
  198.       20 : GotoState := 28;
  199.     end; { case }
  200.   end
  201.   else if Production <= 6 then
  202.   begin
  203.     case State of
  204.       0, 9, 20 : GotoState := 2;
  205.       12 : GotoState := 21;
  206.       13 : GotoState := 22;
  207.     end; { case }
  208.   end
  209.   else if Production <= 8 then
  210.   begin
  211.     case State of
  212.       0, 9, 12, 13, 20 : GotoState := 3;
  213.       14 : GotoState := 23;
  214.       15 : GotoState := 24;
  215.       16 : GotoState := 25;
  216.     end; { case }
  217.   end
  218.   else if Production <= 10 then
  219.   begin
  220.     case State of
  221.       0, 9, 12..16, 20 : GotoState := 4;
  222.     end; { case }
  223.   end
  224.   else if Production <= 12 then
  225.   begin
  226.     case State of
  227.       0, 9, 12..16, 20 : GotoState := 6;
  228.       5 : GotoState := 17;
  229.     end; { case }
  230.   end
  231.   else begin
  232.     case State of
  233.       0, 5, 9, 12..16, 20 : GotoState := 8;
  234.     end; { case }
  235.   end;
  236. end; { GotoState }
  237.  
  238. function CellValue;  { Berechnet den Wert einer Zelle }
  239. var
  240.   CPtr : CellPtr;
  241. begin
  242.   CPtr := Cell[Col, Row];
  243.   if (CPtr = nil) then
  244.     CellValue := 0
  245.   else begin
  246.     if (CPtr^.Error) or (CPtr^.Attrib = TXT) then
  247.       MathError := True;
  248.     if CPtr^.Attrib = FORMULA then
  249.       CellValue := CPtr^.FValue
  250.     else
  251.       CellValue := CPtr^.Value;
  252.   end;
  253. end;
  254.  
  255. procedure Shift(State : Word);  { Schiebt ein Token auf den Stack }
  256. begin
  257.   CurToken.State := State;
  258.   Push(CurToken);
  259.   TokenType := NextToken;
  260. end;
  261.  
  262. procedure Reduce(Reduction : Word);  { Komplettiert eine Reduktion }
  263. var
  264.   Token1, Token2 : TokenRec;
  265.   Counter : Word;
  266. begin
  267.   case Reduction of
  268.     1 : begin
  269.       Pop(Token1);
  270.       Pop(Token2);
  271.       Pop(Token2);
  272.       CurToken.Value := Token1.Value + Token2.Value;
  273.     end;
  274.     2 : begin
  275.       Pop(Token1);
  276.       Pop(Token2);
  277.       Pop(Token2);
  278.       CurToken.Value := Token2.Value - Token1.Value;
  279.     end;
  280.     4 : begin
  281.       Pop(Token1);
  282.       Pop(Token2);
  283.       Pop(Token2);
  284.       CurToken.Value := Token1.Value * Token2.Value;
  285.     end;
  286.     5 : begin
  287.       Pop(Token1);
  288.       Pop(Token2);
  289.       Pop(Token2);
  290.       if Token1.Value = 0 then
  291.         MathError := True
  292.       else
  293.         CurToken.Value := Token2.Value / Token1.Value;
  294.     end;
  295.     7 : begin
  296.       Pop(Token1);
  297.       Pop(Token2);
  298.       Pop(Token2);
  299.       if Token2.Value <= 0 then
  300.         MathError := True
  301.       else if (Token1.Value * Ln(Token2.Value) < -EXPLIMIT) or
  302.               (Token1.Value * Ln(Token2.Value) > EXPLIMIT) then
  303.         MathError := True
  304.       else
  305.         CurToken.Value := Exp(Token1.Value * Ln(Token2.Value));
  306.     end;
  307.     9 : begin
  308.       Pop(Token1);
  309.       Pop(Token2);
  310.       CurToken.Value := -Token1.Value;
  311.     end;
  312.     11 : begin
  313.       Pop(Token1);
  314.       Pop(Token2);
  315.       Pop(Token2);
  316.       CurToken.Value := 0;
  317.       if Token1.Row = Token2.Row then
  318.       begin
  319.         if Token1.Col < Token2.Col then
  320.           TokenError := True
  321.         else begin
  322.           for Counter := Token2.Col to Token1.Col do
  323.             CurToken.Value := CurToken.Value + CellValue(Counter, Token1.Row);
  324.         end;
  325.       end
  326.       else if Token1.Col = Token2.Col then
  327.       begin
  328.         if Token1.Row < Token2.Row then
  329.           TokenError := True
  330.         else begin
  331.           for Counter := Token2.Row to Token1.Row do
  332.             CurToken.Value := CurToken.Value + CellValue(Token1.Col, Counter);
  333.         end;
  334.       end
  335.       else
  336.         TokenError := True;
  337.     end;
  338.     13 : begin
  339.       Pop(CurToken);
  340.       CurToken.Value := CellValue(CurToken.Col, CurToken.Row);
  341.     end;
  342.     14 : begin
  343.       Pop(Token1);
  344.       Pop(CurToken);
  345.       Pop(Token1);
  346.     end;
  347.     16 : begin
  348.       Pop(Token1);
  349.       Pop(CurToken);
  350.       Pop(Token1);
  351.       Pop(Token1);
  352.       if Token1.FuncName = 'ABS' then
  353.         CurToken.Value := Abs(CurToken.Value)
  354.       else if Token1.FuncName = 'ATAN' then
  355.         CurToken.Value := ArcTan(CurToken.Value)
  356.       else if Token1.FuncName = 'COS' then
  357.         CurToken.Value := Cos(CurToken.Value)
  358.       else if Token1.FuncName = 'EXP' then
  359.       begin
  360.         if (CurToken.Value < -EXPLIMIT) or (CurToken.Value > EXPLIMIT) then
  361.           MathError := True
  362.         else
  363.           CurToken.Value := Exp(CurToken.Value);
  364.       end
  365.       else if Token1.FuncName = 'LN' then
  366.       begin
  367.         if CurToken.Value <= 0 then
  368.           MathError := True
  369.         else
  370.           CurToken.Value := Ln(CurToken.Value);
  371.       end
  372.       else if Token1.FuncName = 'ROUND' then
  373.       begin
  374.         if (CurToken.Value < -1E9) or (CurToken.Value > 1E9) then
  375.           MathError := True
  376.         else
  377.           CurToken.Value := Round(CurToken.Value);
  378.       end
  379.       else if Token1.FuncName = 'SIN' then
  380.         CurToken.Value := Sin(CurToken.Value)
  381.       else if Token1.FuncName = 'SQRT' then
  382.       begin
  383.         if CurToken.Value < 0 then
  384.           MathError := True
  385.         else
  386.           CurToken.Value := Sqrt(CurToken.Value);
  387.       end
  388.       else if Token1.FuncName = 'SQR' then
  389.       begin
  390.         if (CurToken.Value < -SQRLIMIT) or (CurToken.Value > SQRLIMIT) then
  391.           MathError := True
  392.         else
  393.           CurToken.Value := Sqr(CurToken.Value);
  394.       end
  395.       else if Token1.FuncName = 'TRUNC' then
  396.       begin
  397.         if (CurToken.Value < -1E9) or (CurToken.Value > 1E9) then
  398.           MathError := True
  399.         else
  400.           CurToken.Value := Trunc(CurToken.Value);
  401.       end;
  402.     end;
  403.     3, 6, 8, 10, 12, 15 : Pop(CurToken);
  404.   end; { case }
  405.   CurToken.State := GotoState(Reduction);
  406.   Push(CurToken);
  407. end;
  408.  
  409. function Parse;   { Syntaktische Analyse ("parsing") des Strings }
  410. var
  411.   FirstToken : TokenRec;
  412.   Accepted : Boolean;
  413.   Counter : Word;
  414. begin
  415.   Accepted := False;
  416.   TokenError := False;
  417.   MathError := False;
  418.   IsFormula := False;
  419.   Input := UpperCase(S);
  420.   StackTop := 0;
  421.   FirstToken.State := 0;
  422.   FirstToken.Value := 0;
  423.   Push(FirstToken);
  424.   TokenType := NextToken;
  425.   repeat
  426.     case Stack[StackTop].State of
  427.       0, 9, 12..16, 20 : begin
  428.         if TokenType = NUM then
  429.           Shift(10)
  430.         else if TokenType = CELLT then
  431.           Shift(7)
  432.         else if TokenType = FUNC then
  433.           Shift(11)
  434.         else if TokenType = MINUS then
  435.           Shift(5)
  436.         else if TokenType = OPAREN then
  437.           Shift(9)
  438.         else
  439.           TokenError := True;
  440.       end;
  441.       1 : begin
  442.         if TokenType = EOL then
  443.           Accepted := True
  444.         else if TokenType = PLUS then
  445.           Shift(12)
  446.         else if TokenType = MINUS then
  447.           Shift(13)
  448.         else
  449.           TokenError := True;
  450.       end;
  451.       2 : begin
  452.         if TokenType = TIMES then
  453.           Shift(14)
  454.         else if TokenType = DIVIDE then
  455.           Shift(15)
  456.         else
  457.           Reduce(3);
  458.       end;
  459.       3 : Reduce(6);
  460.       4 : begin
  461.        if TokenType = EXPO then
  462.          Shift(16)
  463.        else
  464.          Reduce(8);
  465.       end;
  466.       5 : begin
  467.         if TokenType = NUM then
  468.           Shift(10)
  469.         else if TokenType = CELLT then
  470.           Shift(7)
  471.         else if TokenType = FUNC then
  472.           Shift(11)
  473.         else if TokenType = OPAREN then
  474.           Shift(9)
  475.         else
  476.           TokenError := True;
  477.       end;
  478.       6 : Reduce(10);
  479.       7 : begin
  480.         if TokenType = COLON then
  481.           Shift(18)
  482.         else
  483.           Reduce(13);
  484.       end;
  485.       8 : Reduce(12);
  486.       10 : Reduce(15);
  487.       11 : begin
  488.         if TokenType = OPAREN then
  489.           Shift(20)
  490.         else
  491.           TokenError := True;
  492.       end;
  493.       17 : Reduce(9);
  494.       18 : begin
  495.         if TokenType = CELLT then
  496.           Shift(26)
  497.         else
  498.           TokenError := True;
  499.       end;
  500.       19 : begin
  501.         if TokenType = PLUS then
  502.           Shift(12)
  503.         else if TokenType = MINUS then
  504.           Shift(13)
  505.         else if TokenType = CPAREN then
  506.           Shift(27)
  507.         else
  508.           TokenError := True;
  509.       end;
  510.       21 : begin
  511.         if TokenType = TIMES then
  512.           Shift(14)
  513.         else if TokenType = DIVIDE then
  514.           Shift(15)
  515.         else
  516.           Reduce(1);
  517.       end;
  518.       22 : begin
  519.         if TokenType = TIMES then
  520.           Shift(14)
  521.         else if TokenType = DIVIDE then
  522.           Shift(15)
  523.         else
  524.           Reduce(2);
  525.       end;
  526.       23 : Reduce(4);
  527.       24 : Reduce(5);
  528.       25 : Reduce(7);
  529.       26 : Reduce(11);
  530.       27 : Reduce(14);
  531.       28 : begin
  532.         if TokenType = PLUS then
  533.           Shift(12)
  534.         else if TokenType = MINUS then
  535.           Shift(13)
  536.         else if TokenType = CPAREN then
  537.           Shift(29)
  538.         else
  539.           TokenError := True;
  540.       end;
  541.       29 : Reduce(16);
  542.     end; { case }
  543.   until Accepted or TokenError;
  544.   if TokenError then
  545.   begin
  546.     Att := TXT;
  547.     Parse := 0;
  548.     Exit;
  549.   end;
  550.   if IsFormula then
  551.     Att := FORMULA
  552.   else
  553.     Att := VALUE;
  554.   if MathError then
  555.   begin
  556.     Inc(Att, 4);
  557.     Parse := 0;
  558.     Exit;
  559.   end;
  560.   Parse := Stack[StackTop].Value;
  561. end;
  562.  
  563. begin         { keine Initialisierung }
  564. end.
  565.