AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Parser: Operatoren

Ein Thema von blablab · begonnen am 13. Apr 2012 · letzter Beitrag vom 16. Apr 2012
Antwort Antwort
Seite 1 von 2  1 2      
blablab

Registriert seit: 3. Jan 2006
509 Beiträge
 
Delphi 7 Enterprise
 
#1

Parser: Operatoren

  Alt 13. Apr 2012, 06:39
Hallo!

Ich programmiere gerade an einem Parser und ich stehe bei den überladenen Operatoren ziemlich auf dem Schlauch. Zum Beispiel der Operator "-" ist ja normalerweise überladen: Sowohl "1-1" als auch "1*(-1)" ist möglich. Beim ersten hab ich Argumente auf beiden Seiten und beim zweiten nur eins auf der rechten Seite. Ein anderes Beispiel wäre "x!" und "!x" (Fakultät und Subfakultät). Theoretisch sind also überladene Operatoren möglich, die alle drei Möglichkeiten ausschöpfen: Argument links, rechts und auch auf beiden Seiten.
Dazu kommt noch dass Operatoren wegen dem Datentyp überladen sein können, zB "True and False = False" und "1 and 3 = 1".
Das bedeutet wenn ich 2 Datentypen habe könnte ein einziger Operator aus 6 Überladungen bestehen! Und jede Überladung könnte ihren eigenen Rang haben (mit Rang meine ich die Rangfolge von Operatoren wie z.B "Punkt vor Strich").

Angenommen ich habe nur solche Psycho-Operatoren (davon muss ich ja ausgehen wenn ich ein fehlerfreies Programm haben möchte), wie soll ich dann vorgehen???

1 A A A 1 = (((1 A) A) A 1) oder (1 A (A (A 1))) oder ((1 A) A (A 1))
Und dummerweise entstehen auch Möglichkeiten wie:
(1 A) (A (A 1)) die dann zu einem Fehler führen

Das bedeutet mein erstes Problem ist es erst einmal herauszufinden ob es überhaupt eine gültige Lösung gibt. Und dann stellt sich die Frage welche davon unter Berücksichtigung des Rangs die korrekte ist.

Ich weiß leider nicht mal wirklich wo ich hier anfangen soll. Könnt ihr mir vielleicht weiterhelfen?

Grüße
blablab
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#2

AW: Parser: Operatoren

  Alt 13. Apr 2012, 07:53
Ich glaube, Du bringst da etwas durcheinander.

Das Minus ist einerseits Operator, andererseits Vorzeichen. Da kann man nichts mißverstehen: A-B ist eindeutig, A--B auch. Der Tokeinzer liefert dir eh nur 'MINUS', weil er das Symbol erkannt hat. der Rest ergibt sich aus der Grammatik.

Beim Ausrufungszeichen defnierst Du, welche Bindung (links, rechts) stärker ist.

Allerdings gibt es Mehrdeutigkeiten, z.B. bei Pascal des 'dangling else' Problem
  Mit Zitat antworten Zitat
idefix2

Registriert seit: 17. Mär 2010
Ort: Wien
1.027 Beiträge
 
RAD-Studio 2009 Pro
 
#3

AW: Parser: Operatoren

  Alt 13. Apr 2012, 07:56
Hallo!

Die Rangfolge der Operatoren ist doch definiert. Bei gleichem Rang ist definiert, ob von links nach rechts oder von rechts nach links abgearbeitet wird.

Das Scannen erledigst mit Hilfe einer Reihe von wechselseitig rekursiven boolean functions, z.B. A1,A2,A3, etc., wobei A1 alle Teilausdrücke der Form
o1 x
x o1
x o1 y
erkennt, dabei sind x und y entweder elementare Operanden, oder Klammerausdrücke, oder Teilausdrücke, die von der Funtion A2 erkannt werden, o1 ist ein beiebiger Operator der Rangstufe 1. Normalerweise sollten sich auf einer gegebenen Rangstufe allerdings nur unäre oder nur binäre Operanden befinden.

Der Gesamtausdruck wird an A1 zum Scannen übergeben.

A1 sucht je nach vorgegebener Richtung von rechts oder von links den ersten Operator mit Rangstufe 1, teilt an der Stelle den Gesamtausdruck in zwei Teile und wendet auf jeden Teilausdruck wieder die Prozedur A1 an. Findest Du beim Scannen Klammern, dann wird der Bereich zwischen den Klammern auf dieser Rekursionsstufe natürlich nicht gescannt, sondern als ein Operand betrachtet und auf den Inhalt zwischen den Klammern wieder A1 angewendet. Findet A1 keinen Operator mit Rangstufe 1, dann übergibt A1 den ganzen Ausdruck an A2. Liefert A2 für einen Teilausdruck false, dann sucht A1 nach einem weiteren Operator der Rangstufe 1 und versucht dort erneut, den Ausdruck zu teilen.

Wenn nach der Rekursion nichts übrigbleibt, hast Du automatisch das einzige richtige Ergebnis. Diese Vorgangsweise ist natürlich in keiner Weise optimiert, aber dafür leicht zu implementieren.

@ Furtbichler:
Vom Standpunkt eines Parsers gesehen ist ein Vorzeichen genauso ein Operator wie alle anderen, eben ein unärer Operator. Normalerweise haben unäre Operatoren die höchste Priorität, das ist aber Definitionssache und müsste nicht sein.
Eine unären Operator erkannt der Scanner daran, dass im Ausdruck auf einer der beiden Seiten kein Operand, sondern nichts oder ein Operator steht (Ein Operand kann natürlich auch ein Teilausdruck sein, der mit einem Operator endet).
Echte Mehrdeutigkeiten gibt es insofern nicht, als ihre Auflösung durch die Vorgabe einer Auswertungsrichtung gegeben ist.

Geändert von idefix2 (13. Apr 2012 um 08:22 Uhr)
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#4

AW: Parser: Operatoren

  Alt 13. Apr 2012, 08:26
@ Furtbichler:
Vom Standpunkt eines Parsers gesehen ist ein Vorzeichen genauso ein Operator wie alle anderen, eben ein unärer Operator.
Diese Aussage verstehe ich nicht. Vom Standpunkt des Parsers ist ein Operator kein Vorzeichen. Das Token ist das gleiche, aber im Kontext eines Terms wird das Token MINUS als Operator erkannt. Während des Parsens eines Wertes dagegen als Vorzeichen. Mit "Look ahead ist da nichts.
Zitat:
Eine unären Operator erkannt der Scanner daran, dass im Ausdruck auf einer der beiden Seiten kein Operand,
Der Scanner erkennt hier nichts, er macht kein Look ahead. Er unterscheidet zwischen terminalen und nicht terminalen Symbolen und liefert Token. Hier ist ein '-' ein MINUS, egal in welchem Kontext.

Durch spezielle Zeichen des Alphabets kann es sein, das ein Look Ahead durchgeführt werden muss.

Bei Pascal z.B. betrifft dies den '.' (wie in 7.1) und '..' (wie in [1..2]). Beim erkennen eines '.' muss das nächste Zeichen geprüft werden, um zu entscheiden, ob sich im Eingabestream um ein DOT oder ein DOTDOT-Symbol (=Token) handelt.

Zitat:
Echte Mehrdeutigkeiten gibt es insofern nicht, als ihre auflösung durch die Vorgabe einer Auswertungsrichtung gegeben ist.
Grammatikalisch schon, siehe 'dangling else'. Dort kann die Grammatik als solche keine Eindeutigkeit liefern. Das macht die Implementierung des Parsers.
  Mit Zitat antworten Zitat
idefix2

Registriert seit: 17. Mär 2010
Ort: Wien
1.027 Beiträge
 
RAD-Studio 2009 Pro
 
#5

AW: Parser: Operatoren

  Alt 13. Apr 2012, 08:41
Zitat:
Vom Standpunkt des Parsers ist ein Operator kein Vorzeichen
Nimm statt -1 einfach -x. dann ist - kein Vorzwichen, sondern ein unärer Operator.
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#6

AW: Parser: Operatoren

  Alt 13. Apr 2012, 10:37
Bei Pascal z.B. betrifft dies den '.' (wie in 7.1) und '..' (wie in [1..2]).
Beim rekursiven parsen in einen Grammatikbaum (Term von aussen nach innen) weiss der Parser, dass er eine eckige Klammer betreten hat wenn er deren Inhalt weiter zerlegt, und kann entsprechend andere Regeln anwenden, die in diesem Fall z.B. das Look-Ahead unnötig machen (keine Floats in Mengen zulässig).
Die gleiche Vorgehensweise erlaubt auch das Behandeln von "-". Nehme ich den Term "2--X" finde ich zuerst das erste "-", und gehe in die Rekursion mit "2" und "-X" als Restterme. Schalte ich meinem Tokenizer ein einfaches if TermString[1] = '-then TermString := '0'+TermString; vor, kann ich das Vorzeichen wie ein ganz normales Minus behandeln.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Bjoerk

Registriert seit: 28. Feb 2011
Ort: Mannheim
1.384 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Parser: Operatoren

  Alt 13. Apr 2012, 16:34
Bei der Division funzt das allerdings nicht: 2/-3 <> 2/0-3

Wenn du als Grundlage den Parser von Joachim Mohr benutzt, da habe ich das seinerzeit eingearbeitet.
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#8

AW: Parser: Operatoren

  Alt 13. Apr 2012, 16:56
Doch das geht prima, weil man den "/" eher erkennt als das "-" (Punktrechnung vor Strichrechnung).

So in etwa:
Delphi-Quellcode:
function Parse(s: String): TParseTreeNode;
begin
  if s[1] = '-then s := '0'+s;
  if FindToken('*', s) then
    result := TParseTreeNode.Create(opMul, Parse(PartBeforeToken('*', s)), Parse(PartAfterToken('*', s)))
  else
  if FindToken('/', s) then
    result := TParseTreeNode.Create(opDiv, Parse(PartBeforeToken('*', s)), Parse(PartAfterToken('*', s)))
  else
  if FindToken('+', s) then
    result := TParseTreeNode.Create(opAdd, Parse(PartBeforeToken('*', s)), Parse(PartAfterToken('*', s)))
  else
  if FindToken('-', s) then
    result := TParseTreeNode.Create(opSub, Parse(PartBeforeToken('*', s)), Parse(PartAfterToken('*', s)))
  else
  begin
    try
      result := TParseTreeNode.Create(opConst, StrToFloat(s));
    except
      raise Exception.Create('Grammar Error');
    end;
  end;
end;
Alles was oben im if-then-else-Wurm Steht bindet stärker.

Was die Bools angeht, so habe ich die bei mir nicht separat implementiert, sondern nutze ganz normale Zahlenwerte (0 und 1), womit die Operatoren in den selben Ablauf passen. Verliert etwas Typsicherheit, klappt aber wie ne eins.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)

Geändert von Medium (13. Apr 2012 um 16:59 Uhr)
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#9

AW: Parser: Operatoren

  Alt 13. Apr 2012, 17:30
Hmm, aber dein Parser sucht „aktiv“ nach Tokens mithilfe von Pos() bzw. einer ähnlichen Funktion, oder? Normalerweise baut man Parser doch als State-Machine auf – dachte ich zumindest (ich habe es jedenfalls immer so gemacht – bin aber auch (noch) kein Informatiker). Wenn man mit einer State-Machine arbeitet, arbeitet man sich ja zeichenweise durch den String, d.h. man kennt an sich ja nur das aktuelle Zeichen und den Zustand des Automaten, weiß aber nicht, was danach kommt (das wäre sonst ein Look-Ahead). [edit]D.h. man kann nicht einfach den ersten Punkt-Operator (*, /) suchen und mitten in den String rein springen und ihn zerteilen Quatsch, aber:[/edit] (und sobald Klammern vorkommen, müsste der Ansatz eigentlich auch versagen).

Aber im Falle des Minus ist der Fall doch eigentlich klar:
  1. Das Minus ist ein Operator, wenn davor ein Bezeichner oder eine Zahl steht.
  2. Das Minus ist ein Vorzeichen, wenn davor ein Operator oder eine Klammer steht.
  3. Mehrere aufeinanderfolgende Vorzeichen werden zu einem einzigen Vorzeichen verschmolzen (je nachdem ob gerade oder ungerade Anzahl).
Zumindest sind diese Regeln bei Parsern so üblich... in der Mathematik ist es ja normalerweise nicht erlaubt, dass Operatoren oder mehrere Vorzeichen aufeinander folgen...

Bei Fakultät und Subfakultät müsste es so ähnlich sein.

Solche Regeln muss man eben finden/festlegen.

Auch wie die interne Klammerung aussieht (um dein Beispiel zu nehmen „(((1 A) A) A 1) oder (1 A (A (A 1)))“) ist von vornherein festgelegt – darum muss sich dein Parser also gar nicht kümmern. Ist deine Sprache linksassoziativ, gilt „(((1 A) A) A 1)“, ist sie rechtsassoziativ, gilt „(1 A (A (A 1)))“.

Geändert von Namenloser (13. Apr 2012 um 17:36 Uhr)
  Mit Zitat antworten Zitat
Bjoerk

Registriert seit: 28. Feb 2011
Ort: Mannheim
1.384 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Parser: Operatoren

  Alt 13. Apr 2012, 17:51
Doch das geht prima, weil man den "/" eher erkennt als das "-" (Punktrechnung vor Strichrechnung).
Vorausgesetzt, du macht die Klammern zuerst. Bei (2+3)/(4+5) muß der Parser zuerst die Additionen durchführen.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:50 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz