Rekursiv absteigender Parser

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

Code: Alles auswählen

\$[\da-f]*
lieber so, wer rechnet schon gerne mit "$"

Code: Alles auswählen

\$[\da-f]+


Code: Alles auswählen

[()^\*/+-.,]
Hier sollte das "-" am Anfang stehen, da es sich sonst um "von ... bis" handelt.



Bei CreateRegularExpression haengst du besser noch ein ",1" an, das
ist das Flag fuer Gross und Kleinschreibung ignorieren.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

> \$[\da-f]+
Fast perfekt, lieber so:

Code: Alles auswählen

\$[\da-fA-F]+
> Bei CreateRegularExpression haengst du besser noch ein ",1" an, das ist das Flag fuer Gross und Kleinschreibung ignorieren
Ja, oder füge an den Anfang ein, ignoriert auch Groß- und Kleinschreibung. Würde ich bevorzugen, solange es noch keine offiziellen Konstanten gibt.

Übrigens, edel! ich finde den Thread mit den RegExp-Konstanten nicht wieder. Hast du den Link parat?

Ach ja, und nebenbei: (?U) steht ja für ungreedy (ungierig, genügsam). Wie kann ich wieder zurückschalten auf greedy? Wollte ich mal in Zusammenhang mit mit Gruppen machen.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Little John

Beitrag von Little John »

Danke für die Hinweise auf Groß-/Kleinschreibung. Hier spielt das allerdings keine Rolle, denn gleich am Anfang des Programms wird der auszuwertende String mit LCase() "klein gemacht".

edel hat geschrieben:

Code: Alles auswählen

[()^\*/+-.,]
Hier sollte das "-" am Anfang stehen, da es sich sonst um "von ... bis" handelt.
Habe ich jetzt geändert, vielen Dank!

edel hat geschrieben:

Code: Alles auswählen

\$[\da-f]*
lieber so, wer rechnet schon gerne mit "$"

Code: Alles auswählen

\$[\da-f]+
So hatte ich es zuerst. :-)
Beispielsweise liefert dann $-3 das Ergebnis -3. Ich möchte aber, dass eine Fehlermeldung wie "Ungültige Hexadezimalzahl" erzeugt wird. Wenn -- wie es jetzt ist -- auch $ als Token erkannt wird, kann der Code der das anschließend zu sehen bekommt den Fehler erkennen und behandeln.

Ich habe viele gültige mathematische Ausdrücke getestet, sie wurden alle korrekt berechnet. Das Hauptproblem dass ich im Moment mit meiner "Regular Expression"-Version habe, ist die Erkennung von ungültigen Zeichen. So habe ich z.B. bei "[<>=!]+" extra das ! mit aufgenommen, damit es als ungültiges Zeichen behandelt werden kann, und nicht einfach "verschluckt" wird. Soll ich alle anderen ungültigen Zeichen auch noch auflisten, oder wie können diese am besten behandelt werden?

Gruß, Little John
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Also mein genialer Gedanke war folgender:
Alle Teilterme, die unterstützt werden, werden in einen Regulären Ausdruck gepackt. Und zwar in einer einzig gültigen Notation.

Ich finde es zwar eine gute Idee, Groß- und Kleinschriebung zu ignorieren. Aber möglicherweise ist das in künftigen Versionen hinderlich. Wie wäre es zum Beispiel, wenn wir später noch Unterstützung für Variablen einbauen?
Zum Beispiel kann der User x=5 setzen und später den Ausdruck x+7 ausrechnen lassen. Somit wären wir beispielsweise beim Kapitel Funktionen. Wäre es nicht praktisch, in einer For x=-5 to 5-Schleife einen kleinen Funktionsverlauf bzw. Graphen ermitteln zu können?

Ich würde deshalb die Groß- und Kleinschreibung nicht unterstützen, weil es ja vielleicht Probleme geben könnte, Variablen von Funktionen und anderen Variablen zu unterscheiden:

Code: Alles auswählen

f*f(5)+x^n
Hier zum Beispiel gibt's die Variable f und die Funktion f(). Ist nur ein Beispiel, mir fällt gerade kein anderes ein.

Und wenn, dann würde ich den Mathematischen Ausdruck (MathExp :wink: ) nicht mit LCase() klein machen, sondern die Groß- und Kleinschriebung mittels edel's Flag oder (?i) im Regulären Ausdruck ignorieren. So hat man zur Not hinterher immer noch den Originalstring zur Verfügung.

>Soll ich alle anderen ungültigen Zeichen auch noch auflisten, oder wie können diese am besten behandelt werden?
(Man, wie man abschweifen kann... :shock: ) Zum eigentlichen Problem: Meine oben angesprochene Idee war folgende:

Code: Alles auswählen

_________________________________________________________________________________________________

CreateRegularExpression(#PB_Any, "(?i)(\d(|\.\d+)+|\$[\da-f]+|\*|/|-|\+|(sin|cos|tan|)\(|\)|\^)")
                                        ------1---- ----2----- 3  4 5  6 -------7-------  8  9
0. Ignoriert Groß- und Kleinschreibung
1. Erkennt ganze als auch Dezimalzahlen
2. Erkennt Hexadezimalezahlen
3.-6. Als Beispiel hier mal die einfachsten Rechenoperationen
7. Erkennt öffnende Klammern. Optional darf sin, cos oder tan davor stehen, was die Klammer zu einer Funktion macht
8. Schließende Klammern
9. Potenzen
...alle Unterstützen Operationen, Funktionen, Operatoren, etc. würden hier folgen.

Wenn man alles Erlaubte wie hier in einen Ausdruck packt, braucht mannicht noch extra die ungültigen Sachen definieren. Wenn ich 'ne Pommes weiß will, bestell ich auch nicht extra Ketschup um allen zu zeigen: "Den Ketschup will ich nicht essen."

Dann gibt es 2 Möglichkeiten:

Code: Alles auswählen

If ReplaceRegularExpression(rex, MathExp$, "")
   Debug "Fehler"
EndIf

; oder

Dim Token.s(0)
Define length, n, AnzahlToken=ExtractRegularExpression(rex, MathExp$, Token())
For n=1 to AnzahlToken
   length=Len(Token(n-1))
Next
If length <> Len(MathExp$)
   Debug "Fehler
EndIf
1. Entweder man ersetzt alle gültigen Zeichen durch "" (nichts) und prüft dann ob was übrig bleibt (das snd dann ungültige Zeichen).
2. Oder man geht das Token-Array durch und summiert deren einzelne Stringllängen; anschließend vergleicht man diese Stringlänge mit der Länge des MathExp$.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

Funktionen lassen sich sehr einfach durch ein look-ahead finden.

Code: Alles auswählen

pattern.s = "\w+\s*(?=[(]).*?\)|\w|."
subject.s = "a+a()+b"

If CreateRegularExpression(0,pattern)
Dim Result$(0)
NbFound = ExtractRegularExpression(0, subject, Result$())
For k = 0 To NbFound-1
  Debug Result$(k)
Next
Else
  Debug RegularExpressionError()
EndIf
Hier wird durch "?=[(]" geprueft ob das naechste Zeichen eine oeffnende
Klammer ist, dann wird alles eingelesen bis zur schliessenden Klammer.

Greedy wird durch das ? vor \) abgeschaltet. Sonst wuerde die ganze
Zeile eingelesen werden.
Little John

Beitrag von Little John »

Schreibung
Das Ignorieren von Groß- und Kleinschriebung ist nicht in künftigen Versionen hinderlich. Das ist schlicht eine Design-Entscheidung. Es gibt Programmiersprachen die unterscheiden dazwischen, andere nicht. Deshalb sind die einen nicht besser oder besser ausbaufähig als die anderen.
Wer gern eine Unterscheidung zwischen Groß- und Kleinschreibung haben möchte, braucht nur LCase() in der Prozedur Calc() zu löschen.

Variablen
An Unterstützung für Variablen habe ich auch schon gedacht, das hat für mich aber zur Zeit eine geringe Priorität.
(Ich habe im Moment nicht mehr viel Zeit für dieses Projekt, und muss mich jetzt daher auf das wichtigste beschränken.)

Reguläre Ausdrücke
2AND51:
Wie gesagt habe ich das mit den Regulären Ausdrücken extra für Dich als "Vorlage" geschrieben, weil Du daran interessiert warst. Jetzt bin ich gespannt auf Deine Weiterentwicklungen in Form von vollständigem lauffähigen Code. :D Er muss mindestens diese Tests bestehen.

Gruß, Little John
Antworten