Autor |
Beitrag |
F34r0fTh3D4rk
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: 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:
Quelltext 1:
| 10^2-(4+3*(4+5))*sin(90) |
sin(90) darf nicht am ende stehen, weil dann knallts
er rechnet: 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:
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): string; begin result := copy(astr, 1, pos(op, astr) - 1); end; function ParseB(op: char): string; begin 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 = 0) and (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, 1, 3) = 'sin' then result := sin(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else if copy(astr, 1, 3) = 'cos' then result := cos(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else if copy(astr, 1, 3) = 'tan' then result := tan(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else if (length(astr) > 0) and (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
      
Beiträge: 510
Win XP Prof
Delphi 7 E
|
Verfasst: 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
      
Beiträge: 375
Erhaltene Danke: 7
XP, W7, W8
Deutschland
|
Verfasst: 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
      
Beiträge: 510
Win XP Prof
Delphi 7 E
|
Verfasst: Mi 07.02.07 11:10
Doch bei meinem parser aber der erzeugt auch keinen Stack sondern nen Baum
|
|
ssb-blume
      
Beiträge: 375
Erhaltene Danke: 7
XP, W7, W8
Deutschland
|
Verfasst: 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 
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: 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
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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 
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Do 08.02.07 21:16
Die Lösung:
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; 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 = 0) and (astr[i] = op) then begin result := i; if (i > 1) AND (op in ['-', '+']) Then begin if astr[i-1] in ['+', '-', '*', '/', '^'] then begin result := 0; continue; end; end; exit; end; if (Count < 0) then Result := 0; end; if count <> 0 then result := 0; end; function ParseA(op: char): string; begin result := copy(astr, 1, ExpCheck(op) - 1); end; function ParseB(op: char): string; begin result := copy(astr, ExpCheck(op) + 1, length(astr) - ExpCheck(op)); end; const e = 2.71828182845904523536028747135266249; begin if (length(astr) = ExpCheck(')')) and (Copy(astr, 1, 1) = '(') then result := ParseEx(copy(astr, 2, ExpCheck(')') - 2)) 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 := ParseEx(ParseA('/')) / ParseEx(ParseB('/')) else if ExpCheck('^') > 0 then result := power(ParseEx(ParseA('^')), ParseEx(ParseB('^'))) else if copy(astr, 1, 3) = 'sin' then result := sin(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else if copy(astr, 1, 3) = 'cos' then result := cos(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else if copy(astr, 1, 3) = 'tan' then result := tan(degtorad(ParseEx(copy(astr, 4, length(astr) - 3)))) else if copy(astr, 1, 4) = 'sqrt' then result := sqrt(ParseEx(copy(astr, 5, length(astr) - 4))) else if copy(astr, 1, 2) = 'pi' then result := pi else if copy(astr, 1, 2) = 'e' then result := e else if astr = '' then result := 0 else result := strtofloat(astr); end; |
danke BenBE
|
|
|