Autor Beitrag
F34r0fTh3D4rk
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 06.02.07 20:41 
hi, ich habe einen kleinen rekursiven Matheparser geschrieben (ich weiß, die dinger sind net so gut, aber dafür relativ übersichtlich).

naja, probleme macht dieser ausdruck:

ausblenden Quelltext
1:
10^2-(4+3*(4+5))*sin(90)					


sin(90) darf nicht am ende stehen, weil dann knallts ;)

er rechnet:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
10^2-(4+3*(4+5))*sin(90)
10^2
10
2
(4+3*(4+5))*sin(90)
(4+3
(4

3
(4+5))*sin(90)
(4+5))
4+5)



dann kommt ein Fehler:

Zitat:

---------------------------
Project1
---------------------------
'4+5)' ist kein gültiger Gleitkommawert.
---------------------------
OK
---------------------------



ich kann mir den fehler nicht genau erklären, hier der source:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
function ParseEx(astr: string): single;
  function ParseA(op: char): stringbegin result := copy(astr, 1, pos(op, astr) - 1); end;
  function ParseB(op: char): stringbegin result := copy(astr, pos(op, astr) + 1, length(astr) - pos(op, astr)); end;
  function ExpCheck(op: char): integer;
  var
    i, count: integer;
  begin
    count := 0;
    for i := length(astr) downto 1 do
    begin
      if astr[i] = '(' then inc(count);
      if astr[i] = ')' then dec(count);
      if (count = 0and (astr[i] = op) then
      begin
       result := i;
       exit;
      end;
    end;
    result := 0;
  end;
begin
  form1.memo1.Lines.add(astr);
  if ExpCheck('+') > 0 then result := ParseEx(ParseA('+')) + ParseEx(ParseB('+')) else
  if ExpCheck('-') > 0 then result := ParseEx(ParseA('-')) - ParseEx(ParseB('-')) else
  if ExpCheck('*') > 0 then result := ParseEx(ParseA('*')) * ParseEx(ParseB('*')) else
  if ExpCheck('/') > 0 then result := ParseEx(ParseA('/')) / ParseEx(ParseB('/')) else
  if ExpCheck('^') > 0 then result := power(ParseEx(ParseA('^')), ParseEx(ParseB('^'))) else
  if copy(astr, 13) = 'sin' then
    result := sin(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else
  if copy(astr, 13) = 'cos' then
    result := cos(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else
  if copy(astr, 13) = 'tan' then
    result := tan(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else
  if (length(astr) > 0and (astr[1] = '('then
  begin
    astr := copy(astr, 2, length(astr) - 2);
    result := ParseEx(astr)
  end else
  if astr = '' then
    result := 0 else
      result := strtofloat(astr);
end;


vielen dank, mfg

Gelöst
Allesquarks
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 510

Win XP Prof
Delphi 7 E
BeitragVerfasst: Di 06.02.07 23:32 
müsste es nicht heißen:

10^2-(4+3*(4+5))*sin(90)
10^2
10
2
(4+3*(4+5))*sin(90)
(4+3*(4+5))
4+3*(4+5)//evt auch ohne diesen Zwischenschritt

4
3*(4+5)
3

(4+5)
4+5

4
5

sin(90)
sin
(90)
90
ssb-blume
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 375
Erhaltene Danke: 7

XP, W7, W8
Deutschland
BeitragVerfasst: Mi 07.02.07 11:01 
Das Parsen sollte eine polnische Notation erzeugen, mal Googlen!
Bei der Klammerung, aber auch beim Wechsel der Prioritaet muss das Zwischenergebnis in einen Stack geschoben werden (mit Typ!!).
Achtung! ein allein stehendes - (oder +) am Anfang wird bei allen mir bekannten (veroeffentlichten) Parsern nicht beachtet!

_________________
Brain: an apparatus with which we think we think.
Allesquarks
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 510

Win XP Prof
Delphi 7 E
BeitragVerfasst: Mi 07.02.07 11:10 
Doch bei meinem parser aber der erzeugt auch keinen Stack sondern nen Baum
ssb-blume
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 375
Erhaltene Danke: 7

XP, W7, W8
Deutschland
BeitragVerfasst: Mi 07.02.07 18:29 
kann keinen Baum sehen, auch keinen Wald.
Das ist eine rekursive Anwendung!

_________________
Brain: an apparatus with which we think we think.
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Mi 07.02.07 18:42 
ich hab das ja soweit gelöst, jetzt fehlt mir nur noch die beachtung von vorzeichen bei multiplikation, division und bei potenzen ;)

mfg
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 07.02.07 21:19 
Kannst ja mal deine aktuelle Lösung posten ... Dann schauen wir einfach mal ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Do 08.02.07 21:16 
Die Lösung:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
function ParseEx(astr: string): extended;
  // Prüfen, ob sich ein Operator in einer Klammer befindet
  function ExpCheck(op: char): integer;
  var
    i, count: integer;
  begin
    Result := 0;
    count := 0;
    for i := 1 to length(astr) do
    begin
      if astr[i] = '(' then inc(count);
      if astr[i] = ')' then dec(count);
      if (count = 0and (astr[i] = op) then
      begin
        result := i;
          if (i > 1AND (op in ['-''+']) Then
          begin
            if astr[i-1in ['+''-''*''/''^'then
            begin
              result := 0;
              continue;
            end;
          end;
          exit;
      end;
      if (Count < 0then
        Result := 0;
    end;
    if count <> 0 then
      result := 0;
  end;
  function ParseA(op: char): stringbegin result := copy(astr, 1, ExpCheck(op) - 1); end;
  function ParseB(op: char): stringbegin result := copy(astr, ExpCheck(op) + 1, length(astr) - ExpCheck(op)); end;
// mathematische Konstanten
const
  e = 2.71828182845904523536028747135266249;
begin
  // Klammern
  if (length(astr) = ExpCheck(')')) and (Copy(astr, 11) = '('then
    result := ParseEx(copy(astr, 2, ExpCheck(')') - 2)) else
// GRUNDRECHENARTEN
  if ExpCheck('+') > 0 then result := ParseEx(ParseA('+')) + ParseEx(ParseB('+')) else
  if ExpCheck('-') > 0 then result := ParseEx(ParseA('-')) - ParseEx(ParseB('-')) else
  if ExpCheck('*') > 0 then result := ParseEx(ParseA('*')) * ParseEx(ParseB('*')) else
  if ExpCheck('/') > 0 then result := ParseEx(ParseA('/')) / ParseEx(ParseB('/')) else
  // Potenzen
  if ExpCheck('^') > 0 then result := power(ParseEx(ParseA('^')), ParseEx(ParseB('^'))) else
// FUNKTIONEN
  // sin cos tan
  if copy(astr, 13) = 'sin' then
    result := sin(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else
  if copy(astr, 13) = 'cos' then
    result := cos(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else
  if copy(astr, 13) = 'tan' then
    result := tan(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else
  // sqrt
  if copy(astr, 14) = 'sqrt' then
    result := sqrt(ParseEx(copy(astr, 5, length(astr) - 4))) else
// KONSTANTEN
  // pi
  if copy(astr, 12) = 'pi' then
    result := pi else
  // e
  if copy(astr, 12) = 'e' then
    result := e else
  // Alle Zahlen + ''
  if astr = '' then
    result := 0 else
      result := strtofloat(astr);
end;


danke user profile iconBenBE