Direkt zum Hauptbereich

Das Initialisieren von Klassen in Xbase..

Folgendes Problem:
Gegeben sei eine auf Xbase basierte Grammatik in Xtext, in der structs definiert werden. Diese werden definiert wie in plain old C:

struct Student {
  String firstName;
  String secondName;
  int age;
};
Selbstverständlich verwenden wir hier die Java Datentypen und keine char*-Arrays für Strings wie in C ;-). Die structs - in meiner Grammatik Composition genannt - sehen wie folgt aus

Composition :
	{Composition} "type" name=ID ":" "structure" "{" (attributes+=Attribute)* "}" 
;

Attribute:
	{Attribute}
	"attribute" name=ID ":" type=JvmTypeReference ";"
;
Ich möchte in meiner generierten DSL also beispielsweise folgendes schreiben können:

type Student : structure {
  attribute firstName : String;
  attribute secondName : String;
  attribute age : int;
}
Durch das Implementieren des Xbase-Inferrer, der den Java-Code daraus generiert, soll folgendes Vorgehen realisiert werden:
  • Jede Composition wird in eine Java Klasse abgebildet. Diese wird separat erzeugt, also keine innere Klasse.
  • Die Felder in den Klassen sind public. Es wird nicht über Getter-/Setter-Operationen gearbeitet.
  • Die Compositions sollen automatisch als leeres Objekt instantiiert werden. Dadurch wird die Objektorientierte Implementierung vom Endnutzer abstrahiert.
Die Variablendeklaration geschieht hierbei über eine Überschriebene Variante der XVariableDeclaration. Hierbei wurde nur die Syntax angepasst. Wenn diese nun in einer Methode aufgerufen wurde, sieht der generierte Java Code folgendermaßen aus:

  Student student = null; // anstatt von Student student = new Student();



In jeder Operation wird das struct per default als null initialisiert. Das ist das Standardverfahren von Xbase und gilt für alle Variablentypen. So wird bspw. der String analog initialisiert. Ich implementiere eine Sprache, die prozedural und für Programmieranfänger geeignet sein soll. Durch das genannte Verfahren entstehen viele unerklärliche Nullpointerexceptions. Diese sind vor allem zu Beginn des Erlernens eher verwirrend als Hilfreich. Dementsprechend ist die automatische Instantiierung unumgänglich. Hierfür gibt es zwei Möglichkeiten:
  • Man ändert die Codegenerierung direkt im Inferrer. Hierbei entsteht das Problem, dass man sämtliche Methodenbodyerzeugungen umschreiben muss. Damit ist der Vorteil, der durch die Nutzung des Inferrers entsteht, hinfort.
  • Eine Erweiterung des XbaseCompiler. Dies ist der zu bevorzugende Schritt
Der Inferrer zum erzeugen einer Operation sieht also (weiterhin) so aus:

for (method : element.methods) { 
  documentation = method.documentation
  var type = method.type 
  if(method.type === null){
    type = typeRef(Void.TYPE)
  }
  members += method.toMethod(method.name, type) [
  for (param : method.params) {
    parameters += method.toParameter(param.name, param.parameterType)
  }
  static = true
  body = method.body
  ]			
}

Im Hauptprojekt der Sprache muss nun ein CustomCompiler implementiert werden, der vom XbaseCompiler erbt und die _toJavaStatement(..) Methode überschreiben. Dies sieht dann folgendermaßen aus:

override _toJavaStatement(XVariableDeclaration vr, ITreeAppendable a, boolean isReferenced) {
  a.newLine()	
  var type = appendVariableTypeAndName(vr, a);
  if (type.simpleName.equals('int') || type.simpleName.equals("double") || type.simpleName.equals("float") ||
    type.simpleName.equals("boolean") /* ... */) {  
    a.append(";")
  } else {
    a.append("= new " + type + "();")
  }
}
Hierbei wird dem ITreeAppendable zunächst eine Leerzeile hinzugefügt und anschließend der Typ der Variabledeklaration berechnet. Abhängig vom (simpleType)Name des Typens wird dann ein weiterer Anhang an den ITreeAppendable hinzugefügt. Entspricht dies einem der Standard Java Typen, wird der Wert nicht initialisiert, enthält also den Standardwert. Entspricht es keinem der Standardnamen, wird ein = new (); hinzugefügt, also ein leeres Objekt erzeugt. Dadruch werden Nullpointerexceptions durch nicht initialisierte Strings oder Structs vermieden. Das mag nicht die schönste Lösung sein, aber sie funktioniert :-).
Der Compiler muss dann selbstverständlich noch im RuntimeModule gebunden werden.

Kommentare

Beliebte Posts aus diesem Blog

Einführung in Xbase mit Xtext : Javatypen in Xtext

Folgendes Problem: Ich hab irgendwo Xtext gelernt. In der Uni, in einem Internet-Tutorial oder beim Surfen auf dem Pott. "Warum nicht einfach mal ne Sprache entwickeln, die statt der bekannten Keywords, Scrubs-Zitate benutzt? Da ist Xtext schließlich da!" - Das ist korrekt. Allerdings muss man dann ja das komplette Scoping, Typenberechnung, Validierung und Codegeneration selbst übernehmen. Möchte ich das? Nein. Eine mögliche Lösung hierfür ist Xbase . Was ist Xbase? Xbase ist eine Erweiterung von Xtext. Hierbei wird das Javatypsystem benutzt, um die Vorteile dessen zu nutzen. Die Typisierung, das Scoping und auch die Validierung ("Kann ich dieser Variable diesen Wert zuordnen?") wird hierbei bereits von Haus aus vorgegeben. Weiterhin werden auch IDE-Features wie der Debugger out-of-the-box mitgeliefert. Weitere Details hierzu sind in der Dokumentation hier zu finden. Erste Schritte in Xbase 1. Voraussetzungen Zunächst wird eine laufende Version von Eclipse

Konzepte: Smartpointer in C++

Heute habe ich mich, seit längerer Zeit, im Rahmen einer Vorlesung mal wieder mit C++ befasst. Neben der Syntax zur Initialisierung von Klassen (insbesondere der Zuweisung der Inhalte an die Membervariablen, was das Konstruktorschreiben wesentlich erleichtert) waren Smartpointer ein relevantes Thema. Besonders befasst habe ich mit mit unique_ptr bzw. auto_ptr und shared_ptr , auf deren Konzepte ich kurz genauer eingehen möchte. Smartpointer? Smartpointer sind Pointer, die die normalen C-Referenzen wrappen und dadurch eine gewisse Garbage-Collection darstellen. Sie versuchen sicher zu stellen, dass keine mehrfachen deletes auf Zeiger aufgerufen werden oder Speicherlecks durch fehlende deletes zu vermeiden. Unique-ptr Unique-pointer, bzw. in älteren Fassungen auto-ptr (Referenz: Hier ) dienen dazu, einen eindeutigen Eigentümer für Pointer zu bestimmen. Mehrere Eigentümer sollten nicht erlaubt sein. Das Konzept ist aber nur hilfreich, wenn der Besitzer klar bestimmbar ist. Ein ei

Basic Type Mapping mit Xbase

Folgendes Problem: Die Bezeichnungen "int" oder "double" sind einfach hässlich. Welcher "normale" Mensch weiß denn, was double bedeutet? .. Ok, ich gehe davon aus, dass jeder Leser hier tatsächlich weiß, wofür das steht. Dennoch möchte man eventuell den primitiven Datentypen andere Namen geben. Zum Beispiel zum Entwicklung einer Programmiersprache bestehend aus "How I Met Your Mother"-Zitaten, bei der "Ted" für den Datentyp "int" und "Robin" für "double". steht. Nun zum technischen: Zunächst muss die Variablendeklaration definiert werden. Diese wird anschließend als zusätzliche XPrimaryExpression hinzugefügt. Variable returns XVariableDeclaration: {Variable} writeable?='variable' simpleName=ID ':' typing=('Ted'|'Robin' /* more types */); Normalerweise wird bei Xbase im feld type der XVariableDeclaration eine JvmTypeReference gesetzt, die auf den Java Typen zeigt. D