-
Notifications
You must be signed in to change notification settings - Fork 0
1 Ohm S
Als Parser für unseren PrettyPrinter nutzen wir Ohm/S.
Hier ein kleiner Einstieg in die, aus unserer Sicht für OmegaPrint, relevantesten Details.
Ein guter Einstieg ist, sich zunächst einmal anzuschauen, wie ein Parsingergebnis aussieht. Dazu parsen wir zunächst eine kleine Beispielmethode im Workspace.
code := 'methodheader statement1. statement2.'
matchResult := OhmExplicitSendsSmalltalk match: code startingFrom: #MethodDeclaration.
Jetzt kann man das matchResult
inspizieren. Mit matchResult cst
bekommt man den Concrete Syntax Tree (CST). So sieht dieser im Anfang dann beispielsweise aus:

Hier kann man bereits sehen, dass die Einstiegsregel MethodDeclaration aus MethodHeader, Pragmas und ExecutableCode besteht. Das wird auch aus der Grammatik ersichtlich.
Die genutzte Grammatik OhmExplicitSendsSmalltalk
liegt in dem Paket Ohm-Grammars. Dort gibt es klassenseitig eine Methode OhmExplicitSendsSmalltalk >> serializedGrammar
. Wenn man dann zu MethodDeclaration geht, sieht man folgendes: . In diesem Bild ist also zu sehen, dass die Regel MethodDeclaration aus den oben genannten Bestandteilen in dieser Reihenfolge besteht. Dementsprechend sehen wir auch die Kinder von MethodDeclaration im CST. Es ist immer wieder nützlich sich den CST anzuschauen, um herauszufinden, wozu einzelne Bestandteile geparsed werden.
Wir benutzen die Grammatik OhmExplicitSendsSmalltalk
. Einen kleinen Einblick darin habt ihr bereits weiter oben bekommen. Diese Grammatik findet ihr im Paket Ohm-Grammars. Klassenseitig gibt es dann die Methode OhmExplicitSendsSmalltalk >> serializedGrammar
.
Um einen besseren Eindruck für die Grammatik zu bekommen, schauen wir uns einmal die Regel UnaryMessageSend an.
UnaryMessageSend =
UnaryMessageReceiver UnaryMessage -- message
| Operand -- base
-
|
bedeutet "Oder". Ein UnaryMessageSend besteht also aus einem UnaryMessageReceiver und einer UnaryMessage oder aus einem Operand. -
Weiterhin sind diese beiden Fälle benannt: Es gibt also den Fall UnaryMessageSend_message und den Fall UnaryMessageSend_base.
-
Weitere wichtige Sonderzeichen sind
~
für "nicht",?
für optional,+
für mindestens einmal und*
für 0 bis beliebig oft vorhanden.
Die bisher betrachteten Regeln sind großgeschrieben, aber weiter unten in der Grammatik findet man auch kleingeschriebene Regeln. Großgeschriebene Regeln sind Syntaktische Regeln, sie lassen sich also in kleinere Bestandteile zerlegen. Währenddessen sind kleingeschriebene Regeln lexikalische Regeln und bilden damit die Grundbausteine der Grammatik.
Eine besondere Regel ist die spaces-Regel: Dabei wird die spaces-Regel der Übergrammatik mit dem +=
um comment erweitert. Überall wo in der Grammatik also ein Leerzeichen vorkommt, kann auch ein Kommentar vorkommen. Beim Parsen werden die Leerzeichen allerdings übersprungen und tauchen nicht mit im CST auf. Über die OhmIntervalle und die Methode OhmNode >> skippedSpacesString
lassen sich einige wiederherstellen.
Um so einen CST traversieren zu können, kann man sich einen evaluator erstellen.
code := 'methodheader statement1. statement2.'.
matchResult := OhmExplicitSendsSmalltalk match: code startingFrom: #MethodDeclaration.
cst := matchResult cst.
evaluator := OhmExplicitSendsSmalltalk synthesizedAttribute: OPPrinter new.
evaluator value: cst
Hier erstellen wir also einen neuen evaluator. Der Aufruf von value
in OPPrinter ruft durch super value:
die Methode OhmSynthesizedAttribute >> value:
auf, welche wiederum OhmAttributes >> value:
aufruft und sich das Ergebnis speichert (Memoization). Die Methoden OhmAttributes >> value:
ist interessant, da sie zeigt, wie der Baum mittels Metaprogramming traversiert wird. Es wird also geschaut, ob es eine Methode gibt, welche den gleichen Namen, wie die Regel hat und die richtige Anzahl an Parametern. Mit Strg+P kann man sich jetzt das Ergebnis ausgeben lassen, was bei der Auswertung des Codes durch den evaluator herauskommt.
Unsere ersten Eindrücke zu Ohm haben wir während unseres Spikes und in den Notizen zu einem Gespräch mit Patrick festgehalten.
Ansonsten schaut euch auch die Dokumentation von Ohm/S und Ohm/JS an.