Autor Beitrag
Benutzername Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 210

Win XP Pro
Delphi 7 PE, D2005 Prof. SSL
BeitragVerfasst: So 07.08.05 16:07 
Ja, so ganz begeistert war ich von den Regular Expressions auch nicht, aber wenns funktioniert... ;)
Du sagst, man sollte das mit nem Baum lösen: Gibts da schon ne fertige Klasse in Delphi, mit der man daslösen könnte?

Und noch ne andere Frage: Angenommen ich hab jetzt einfach nen Term wie 3+6*5*7. Wie mach ich dem Parser klar, dass er doch bitte Punkt-vorStrich beachten soll? Such ich da "einfach" nach dem ersten vorkommenden * oder / -Zeichen und schau dann, welche Zahlen drumrum stehen?

Vermute ich richtig, dass ich zuerst alle Klammern von innen nach außen ausrechnen muss?
Weil dann mach ich mich zuerst mal an ne Funktion, die mir den Term in der innersten Klammer raussucht :)
LigH
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 239

Win98SE, Win2000SP4
D7
BeitragVerfasst: So 07.08.05 21:44 
Es wird sicher darauf ankommen, welche Operanden du überhaupt zuläßt (unäre, binäre, Funktionen, Klammern, evtl. noch logische?) - "Punkt vor Strich" ist ja nur eine Ebene, ich kenne Parser mit mehr als einem halben Dutzend Operanden-Hierarchie-Ebenen.

Und da - wenn du einen Zweig des Baumes als Operand ansiehst, und ein Blatt als Operator - jeder Operanden-Zweig sowohl unterschiedlich viele Verzweigungen haben kann, als auch unterschiedliche Inhalte (entweder ein Operanden-Blatt, oder einen kompletten neuen Operatoren-Zweig), wäre mit Sicherheit eine eigene Klassenheirarchie sinnvoll, so etwas dürfte man kaum fertig vorfinden.
Benutzername Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 210

Win XP Pro
Delphi 7 PE, D2005 Prof. SSL
BeitragVerfasst: So 07.08.05 23:28 
Hm, klingt recht kompliziert :? *g*
Ich werds mir bei Gelegenheit nochmal durch den Kopf gehen lassen^^

Aber ich hab nun einfach mal so drauflos geschrieben, und hab meinen Parser nun soweit, dass er * und / -Rechnungen richtig ausrechnet :)
Jetz fehlen "nurnoch" + und - Rechnungen und vielleicht Potenzen.
Und das unäre Minus muss ich noch einbauen, dass passt die Sache *g*
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mo 08.08.05 04:28 
user profile iconBenutzername hat folgendes geschrieben:
Vermute ich richtig, dass ich zuerst alle Klammern von innen nach außen ausrechnen muss?

Es gibt Parsers, die arbeiten von aussen nach innen; es gibt welche, die arbeiten von innen nach aussen. Du kannst einen Parser (iirc) sogar mit einer Finite State Maschine programmieren (à la Windows-Calculator). Es gibt bestimmt mind. 5 komplett verschiedene Ansätze, wie man das programmieren kann.
Ich bevorzuge meine rekursive Variante (keine Finite State Maschine), die den String mehr oder weniger einmal von links nach rechts passiert. Die Rekursion ist dabei so gemacht, dass man direkt die richtige Reihenfolge der Operationen für die Umwandlung zu Maschinencode erhält.

Beispiel:
1+(2+3)*(4+5)

Der Parser bringt das ganze in folgende Reihenfolge:
1 2 3 + 4 5 + * +

Zum Auswerten geht man diese Liste von links nach rechts durch. Man muss dabei lediglich zwei Regeln beachten:
- Eine Zahl wird auf den Stack gepusht.
- Eine binäre Operationen "poppt" zwei Zahlen aus dem Stack, führt die Operation durch und pusht anschliessend wieder das Ergebnis.

Beispiel:
Zeitschritt  Token   Stack        Rechnung
0                    []
1            1       [1]
2            2       [1,2]
3            3       [1,2,3]
4            +       [1]          2+3
5                    [1,5]
6            4       [1,5,4]
7            5       [1,5,4,5]
8            +       [1,5]        4+5
9                    [1,5,9]
10           *       [1]          5*9
11                   [1,45]
12           +       []           1+45
13                   [46]

(46 ist das Ergebnis)

Mein Parser beschäftigt sich also vereinfacht gesprochen mit der Aufgabenstellung
1+(2+3)*(4+5)
in
1 2 3 + 4 5 + * +
umzuwandeln.
Benutzername Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 210

Win XP Pro
Delphi 7 PE, D2005 Prof. SSL
BeitragVerfasst: Mo 08.08.05 16:15 
Ah, Danke für die Erklärung, Hintergrundwissen ist immer gut :)

Aber ich hab das jetz ohne die Postfix-Notation gemacht (so heißt die doch (bzw. UPN) ? *gg*) und auch ohne Stack.
Alles was jetzt noch fehlt, ist die Rechnung mit Potenzen und das mit den negativen Zahlen.
Wobei Potenzen schnell einzubauen sind *g*

Ich parse jetzt einfach die Klammern von innen nach außen, bis ich beim "Grundterm" angekommen bin, und löse das dann so auf, klappt auch wunderbar. Nicht-Ganzzahlen kann er auch schon, war auch kein Problem :)

Ich meld mich wieder, wenns Neuigkeiten und/oder Fragen gibt :stupid:
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mo 08.08.05 17:12 
user profile iconBenutzername hat folgendes geschrieben:
Aber ich hab das jetz ohne die Postfix-Notation gemacht (so heißt die doch (bzw. UPN) ? *gg*) und auch ohne Stack.
Yep, Infix heisst die "normale" Schreibweise und Postfix die Notation mit den nachgestellten Operatoren (aka. RPN (UPN ist wohl Deutsch)).

user profile iconBenutzername hat folgendes geschrieben:
Ich meld mich wieder, wenns Neuigkeiten und/oder Fragen gibt :stupid:


Anschliessend einige Ausdrücke, die ich testen würde:

1-(-1) = 2 (Doppelnegation)
-2^2 = -4 (Hoch vor Punkt vor Strich)
(-2)^2 = 4 (ausser bei Klammerung...)
2^3^4 = mathematisch gesehen 2.4179e+024, bei Taschenrechnern (z.B. der Firma TI) z.T. aber auch 4096
1+(-(1+2)) = -2 (Negation einer Klammer)

je nachdem sollten auch folgende Ausdrücke akzeptiert werden:
1---2 = -3 (verschachtelte Minusoperationen)
1*-2 = -2 (Negation ohne explizite Klammerung)
1e+3^2 = 1000000 ("1e+3" ist eine korrekte Float-Zahl)
9^5e-1 = 3 (ditto)
2(3) = 6 (Standardoperator = "*")
LigH
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 239

Win98SE, Win2000SP4
D7
BeitragVerfasst: Mo 08.08.05 19:06 
UPN (Umgekehrte Polnische Notation) ist das, das mit dem Stack arbeitet - "Postfix-Notation". "Infix" ist die aus der Schule gewohnte Schreibweise.
Benutzername Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 210

Win XP Pro
Delphi 7 PE, D2005 Prof. SSL
BeitragVerfasst: Mi 10.08.05 17:13 
So, er ist nun fertig :)

@delphifan: Danke für die Ausdrücke die ich testen sollte, klappt wunderbar :)

Aber zu deinem zweiten Beispiel hätt ich noch ne Frage:
Du sagtest ja, dass -2^2 = -4 ist, wegen Hoch vor Punkt vor Strich, hab ich auch verstanden :lol:
Aber angenommen, ich hätte --2^2. Wäre das dann das gleiche wie -(-2^2) oder wäre das dann -(-2)^2 ?
Da blick ich nämlich noch net ganz durch *g*

//edit: Noch was *g*
Gibts irgendwelche Vergleichswerte von der Geschwindigkeit her, wo ich in etwa liege?
Das wäre find ich ganz interessant zu wissen. :)
AXMD
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 10.08.05 17:22 
--2^2 = 2^2 = 4

nur wenn du -(-2)^2 hast, erhältst du -4.

AXMD
Benutzername Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 210

Win XP Pro
Delphi 7 PE, D2005 Prof. SSL
BeitragVerfasst: Mi 10.08.05 17:27 
Okay, Danke :)
Alles, was ich wissen wollte *g*

Dann bügel ich den Fehler noch schnell aus (war mir nämlich nicht sicher) und dann kann ich den Parser (mit Beispielprojekt) ja mal posten, wenns jemanden interessiert *g*
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mi 10.08.05 18:11 
Ich teste ihn gern aus für dich. Ich hab sicher schon 5 verschiedene Parser auf Herz und Nieren geprüft ;)

Geschwindigkeitsmässig müsste man unterscheiden zwischen Parsen und Auswerten. Mein Parser und auch andere Parser parsen zuerst den Ausdruck und erzeugen daraus einen Bytecode, Maschinencode oder sonst eine schnell auswertbare Struktur (wie z.B. Bäume). So kann ein Ausdruck schnell mehrmals ausgewertet werden (z.B. zum Graphen zeichnen).

Die eigentliche Auswertung geht dann relativ schnell; das Parsen geht etwas länger.
Benutzername Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 210

Win XP Pro
Delphi 7 PE, D2005 Prof. SSL
BeitragVerfasst: Mi 10.08.05 18:20 
Okay, dann wende ich mich mal per PN an delfiphan und wenn dann alles funktioniert, stell ich ihn hier rein :)


Zuletzt bearbeitet von Benutzername am Mi 10.08.05 18:59, insgesamt 2-mal bearbeitet
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mi 10.08.05 18:22 
Die PN schreibst du am besten an delfiphan :) ;)
Bin ja schon gespannt...