Code Generator via XML Dateien
Übersicht

![]() |
FirstdeathmakerBetreff: Code Generator via XML Dateien |
![]() Antworten mit Zitat ![]() |
---|---|---|
Der CodeGenerator erzeugt aus XML Dateien schnell Blitzmax Sourcecode. Das besondere daran ist, dass er automatisch Getter&Setter für Field's erzeugen kann, und auch Verknüpfungen zwischen zwei Objekten erzeugen sowie zerstören und einen kompletten Destruktor anlegen kann.
Näheres dazu in den paar Tut1-4.xml Dateien, in welchen ich ein paar Beispiele gemacht habe und welche der Downloadversion beiliegen. Zum ausführen die CodeGenerator.exe starten und den Dateinamen der zu übersetzenden xml-Datei eintippen (inklusive Dateiendung). Als Verknüpfungen zwischen 2 Objekten habe ich bisher: Ein Objekt verweist auf ein Anderes (a.b->b) linkType="mono121" Beide Objekte verweisen auf das Gegenüber (a.b->b b.a->a) linkType="bi121" Viele Objekte verweisen auf eines (a.d->d, b.d->d. c.d->d) (Per Linked List) linkType="monoM12" Man kann damit zwar nicht alles machen, aber man kann sich am Anfang eine Menge Tipparbeit sparen. <Hier> gibt es eine kompilierte Windows Version mit den Tutorial Beispielen und dem Source. Achtung, zum kompilieren dieses Codes braucht man das libxml mod von bruce, das man sich <hier> runterladen kann. Code: [AUSKLAPPEN] 'This BMX file was edited with BLIde ( http://www.blide.org )
SuperStrict Import bah.libxml Local cg:TCodeGenerator = New TCodeGenerator Local file:String = Input("File to parse: ") cg.start(file) Print "<Program shuts down in 3 sec>" Delay 3000 End Type TCodeGenerator Field out:TStream Field default_out:String Field types:TMap Method New() types = CreateMap() default_out = "Default.bmx" End Method Method start(filename:String) Print "Start processing file: " + filename Local doc:TxmlDoc = TxmlDoc.parseFile(filename) If doc = Null Print "Could not parse document";Return Local node:TxmlNode = doc.getRootElement() If node = Null Print "Could not get a root element"; Return out = WriteFile(node.getAttribute("out")) If out = Null out = WriteFile(default_out) Parse(node) doc.free() write() CloseFile(out) Print "Successfully finished" End Method Method parse(node:TxmlNode) If node.getName() <> "CodeGenerator" Return Local children:TList = node.getChildren() If children = Null Return For Local c:TxmlNode = EachIn children Select c.getName() Case "Type" parseType(c) Case "Connect" parseConnection(c) End Select Next End Method Method write() For Local t:DType = EachIn MapValues(Self.types) t.write(out) Next End Method Method parseType:DType(node:TxmlNode) Local t:DType If node.getName() <> "Type" Return Null Local id:String = node.getAttribute("id") Local bbdoc:Byte = Byte(node.getAttribute("bbdoc")) t = DType.Create(id) t.bbdoc = bbdoc addType(t) Local children:TList = node.getChildren() If children = Null Return t For Local c:TxmlNode = EachIn children Select c.getName() Case "Field" parseField(c, t) End Select Next Return t End Method Method addType(t:DType) MapInsert(types, t.id, t) End Method Method getType:DType(id:String) Return DType(MapValueForKey(types, id)) End Method Method parseField(node:TxmlNode, t:DType) Local f:DField If node.getName() <> "Field" Return Local id:String = node.getAttribute("id") Local datatype:String = node.getAttribute("datatype") Local val:String = node.getAttribute("value") Local set:Byte = Byte(node.getAttribute("setter")) Local get:Byte = Byte(node.getAttribute("getter")) f = DField.Create(id, datatype, val) t.addVar(f) If set Local setter:DMethod = New DMethod setter.setId("set" + Upper(Left(id, 1)) + Mid(id, 2)) setter.setBBdocText("setter for " + f.id + ":" + f.datatype) setter.addInput("val:" + f.datatype) setter.addContent("Self." + f.id + " = " + "val") t.addMethod(setter) End If If get Local getter:DMethod = New DMethod getter.setId("get" + Upper(Left(id, 1)) + Mid(id, 2)) getter.setBBdocText("getter for " + f.id + ":" + f.datatype) getter.setOutput(f.datatype) getter.addContent("Return " + f.id) t.addMethod(getter) EndIf Local children:TList = node.getChildren() If children = Null Return For Local c:TxmlNode = EachIn children Select c.getName() End Select Next End Method Method parseConnection(node:TxmlNode) If node.getName() <> "Connect" Return Local type1:DType = Self.getType("T" + node.getAttribute("type1")) Local type2:DType = Self.getType("T" + node.getAttribute("type2")) Local t1Name:String = node.getAttribute("link1Id") Local t2Name:String = node.getAttribute("link2Id") If t1Name = "" t1Name:String = Mid(type1.id, 2) If t2Name = "" t2Name:String = Mid(type2.id, 2) Local linkType:String = node.getAttribute("linkType") If linkType = "bi121" bidirectionalOneToOne(type1:DType, type2:DType, t1Name:String, t2Name:String) ElseIf linkType = "mono121" monoDirectionalOneToOne(type1:DType, type2:DType, t1Name:String, t2Name:String) ElseIf linkType = "monoM21" monoDirectionalManyToOne(type1:DType, type2:DType, t1Name:String, t2Name:String) EndIf Local children:TList = node.getChildren() If children = Null Return For Local c:TxmlNode = EachIn children Next End Method Method bidirectionalOneToOne(type1:DType, type2:DType, t1Name:String, t2Name:String) Local linkVarName:String = Lower(t2Name) + "Link" Local m1Linker:DMethod = New DMethod Local m1LinkRemover:DMethod = New DMethod If t1Name = "" t1Name:String = Mid(type1.id, 2) If t2Name = "" t2Name:String = Mid(type2.id, 2) type1.addLinkVar(DField.Create(linkVarName, type2.id)) m1Linker.setId("set" + t2Name) m1Linker.addInput("obj:" + type2.id) m1Linker.addInput("call:byte = true") m1Linker.addContent("if call obj.set" + t1Name + "(Self,false)") m1Linker.addContent(linkVarName + " = obj") type1.addMethod(m1Linker) m1LinkRemover.setId("remove" + t2Name) m1LinkRemover.addContent("if " + linkVarName + " = Null Return") m1LinkRemover.addContent("local val:" + type2.id + " = " + linkVarName) m1LinkRemover.addContent(linkVarName + " = Null") m1LinkRemover.addContent("val.remove" + t1Name + "()") type1.addMethod(m1LinkRemover) type1.destructor.addContent(m1LinkRemover.id + "()") linkVarName:String = Lower(t1Name) + "Link" Local m2Linker:DMethod = New DMethod Local m2LinkRemover:DMethod = New DMethod type2.addLinkVar(DField.Create(linkVarName, type1.id)) m2Linker.setId("set" + t1Name) m2Linker.addInput("obj:" + type1.id) m2Linker.addInput("call:byte = true") m2Linker.addContent("if call obj.set" + t2Name + "(Self,false)") m2Linker.addContent(linkVarName + " = obj") type2.addMethod(m2Linker) m2LinkRemover.setId("remove" + t1Name) m2LinkRemover.addContent("if " + linkVarName + " = Null Return") m2LinkRemover.addContent("local val:" + type1.id + " = " + linkVarName) m2LinkRemover.addContent(linkVarName + " = Null") m2LinkRemover.addContent("val.remove" + t2Name + "()") type2.addMethod(m2LinkRemover) type2.destructor.addContent(m2LinkRemover.id + "()") End Method Method monoDirectionalOneToOne(type1:DType, type2:DType, t1Name:String, t2Name:String) Local linkVarName:String = Lower(t2Name) + "Link" Local m1Linker:DMethod = New DMethod Local m1LinkRemover:DMethod = New DMethod t1Name = Upper(Left(t1Name, 1)) + Mid(t1Name, 2) t2Name = Upper(Left(t2Name, 1)) + Mid(t2Name, 2) type1.addLinkVar(DField.Create(linkVarName, type2.id)) m1Linker.setId("set" + t2Name) m1Linker.addInput("obj:" + type2.id) m1Linker.addContent(linkVarName + " = obj") type1.addMethod(m1Linker) m1LinkRemover.setId("remove" + t2Name) m1LinkRemover.addContent("if " + linkVarName + " = Null Return") m1LinkRemover.addContent(linkVarName + " = Null") type1.addMethod(m1LinkRemover) type1.destructor.addContent(m1LinkRemover.id + "()") End Method Method monoDirectionalManyToOne(type1:DType, type2:DType, t1Name:String, t2Name:String) Local linkVarName:String = Lower(t2Name) + "Link" Local collectionName:String = Lower(t1Name) + "List" Local m1Linker:DMethod = New DMethod Local m1LinkRemover:DMethod = New DMethod t2Name = Upper(Left(t2Name, 1)) + Mid(t2Name, 2) t1Name = Upper(Left(t1Name, 1)) + Mid(t1Name, 2) type1.addLinkVar(DField.Create(linkVarName, type2.id)) type1.addLinkVar(DField.Create("_" + linkVarName, "TLink")) m1Linker.setId("set" + t2Name) m1Linker.addInput("obj:" + type2.id) m1Linker.addInput("call:byte = True") m1Linker.addContent("If " + linkVarName + " <> Null self.remove" + t2Name + "()") m1Linker.addContent(linkVarName + " = obj") m1Linker.addContent("if call _" + linkVarName + " = obj.add" + t1Name + "(self,false)") type1.addMethod(m1Linker) m1LinkRemover.setId("remove" + t2Name) m1LinkRemover.addContent("if " + linkVarName + " = Null Return") m1LinkRemover.addContent(linkVarName + " = Null") m1LinkRemover.addContent("removeLink(_" + linkVarName + ")") type1.addMethod(m1LinkRemover) type1.destructor.addContent(m1LinkRemover.id + "()") type2.addLinkVar(DField.Create(collectionName, "TList", "New TList")) Local m2Linker:DMethod = New DMethod m2Linker.setId("add" + t1Name) m2Linker.addInput("obj:" + type1.id) m2Linker.addInput("call:byte = true") m2Linker.addContent("if call obj.set" + t2Name + "(self,false)") m2Linker.addContent("return " + collectionName + ".addLast(obj)") m2Linker.setOutput("TLink") type2.addMethod(m2Linker) Local m2Remover:DMethod = New DMethod m2Remover.setId("removeAll" + t1Name + "Links") m2Remover.addContent("For local obj:" + type1.id + " = eachin Self." + collectionName) m2Remover.addContent(Chr(9) + "obj.remove" + t2Name + "()") m2Remover.addContent("Next") type2.addMethod(m2Remover) type2.destructor.addContent(m2Remover.id + "()") End Method End Type Type DType Field bbdoc:Byte Field id:String Field vars:TList Field linkVars:TList Field methods:TList Field destructor:DMethod Method New() vars = New TList linkVars = New TList methods = New TList destructor = New DMethod End Method Function Create:DType(id:String) Local t:DType = New DType t.id = "T" + id t.destructor.setId("remove") Return t End Function Method write(stream:TStream) WriteLine stream, "" If bbdoc WriteLine stream, "Rem" WriteLine stream, Chr(9) + "bbdoc: " + Self.id WriteLine stream, Chr(9) + "about:" WriteLine stream, "End Rem" End If WriteLine stream, "Type " + id If Not vars.IsEmpty() WriteLine stream, "" For Local v:DField = EachIn vars v.write(stream) Next EndIf If Not linkVars.IsEmpty() WriteLine stream, "" For Local v:DField = EachIn linkVars v.write(stream) Next EndIf If Not methods.IsEmpty() WriteLine(stream, "") For Local m:DMethod = EachIn methods m.write(stream) WriteLine(stream, "") Next EndIf WriteLine(stream, "") Self.destructor.write(stream) WriteLine stream, "End Type" WriteLine stream, "" End Method Method addVar(v:DField) vars.AddLast(v) End Method Method addLinkVar(v:DField) linkVars.AddLast(v) End Method Method addMethod(m:DMethod) methods.AddLast(m) End Method End Type Type DField Field id:String Field datatype:String Field val:String Function Create:DField(id:String, datatype:String, val:String = "") Local v:DField = New DField Select datatype Case "" datatype = "Int" Case "%" datatype = "Int" Case "#" datatype = "Float" End Select v.id = id v.datatype = datatype v.val = val Return v End Function Method write(stream:TStream) Local l:String = Chr(9) + "Field " + id + ":" + datatype If val <> "" If Lower(datatype) = "string" l:+" = " + Chr(34)+val+Chr(34) Else l:+" = " + val EndIf EndIf WriteLine stream, l End Method End Type Type DMethod Field bbdoc:Byte Field bbdocText:String Field id:String Field inputs:TList Field output:String Field content:TList Method New() inputs = New TList output = "" content = New TList End Method Method setId(id:String) Self.id = id End Method Method addContent(line:String) content.AddLast(line) End Method Method addInput(line:String) inputs.AddLast(line) End Method Method setOutput(line:String) output = line End Method Method setBBdocText(txt:String) Self.bbdocText = txt Self.bbdoc = True If bbdocText = "" bbdocText = Self.id End Method Method write(stream:TStream) If bbdoc WriteLine stream, Chr(9) + "Rem" WriteLine stream, Chr(9) + Chr(9) + "bbdoc: " + bbdocText For Local l:String = EachIn inputs WriteLine stream, Chr(9) + Chr(9) + "var: " + l Next WriteLine stream, Chr(9) + "End Rem" End If Local l:String l = Chr(9) + "Method " + id If output <> "" l:+":" + output l:+"(" While inputs.Count() > 0 Local v:String = String(inputs.RemoveFirst()) If inputs.IsEmpty() l:+v Else l:+v + " , " EndIf Wend l:+")" WriteLine stream, l For l = EachIn content WriteLine stream, Chr(9) + Chr(9) + l Next WriteLine stream, Chr(9) + "End Method" End Method End Type Kleines Anwendungsbeispiel Man schreibt einfach: Code: [AUSKLAPPEN] <CodeGenerator out="Tut4.bmx">
<Type id="WorldManager" bbdoc="1"/> <Type id="Driver"> <Field id="name" datatype="String" value="Default" /> <Field id="age" datatype="int"/> </Type> <Type id="Car"> <Field id="brand" datatype="String"/> </Type> <Connect type1="Driver" type2="Car" link1Id="Owner" link2Id="Car" linkType="mono121" /> <Connect type1="Car" type2="WorldManager" link1Id="Thing" link2Id="world" linkType="monoM21" /> </CodeGenerator> Jagd das ganze durch das Programm, und erhält Code: [AUSKLAPPEN] Type TCar Field brand:String Field worldLink:TWorldManager Field _worldLink:TLink Method setWorld(obj:TWorldManager , call:Byte = True) If worldLink <> Null Self.removeWorld() worldLink = obj If call _worldLink = obj.addThing(Self,False) End Method Method removeWorld() If worldLink = Null Return worldLink = Null RemoveLink(_worldLink) End Method Method remove() removeWorld() End Method End Type Type TDriver Field name:String = "Default" Field age:Int Field carLink:TCar Method setCar(obj:TCar) carLink = obj End Method Method removeCar() If carLink = Null Return carLink = Null End Method Method remove() removeCar() End Method End Type Rem bbdoc: TWorldManager about: End Rem Type TWorldManager Field thingList:TList = New TList Method addThing:TLink(obj:TCar , call:Byte = True) If call obj.setWorld(Self,False) Return thingList.addLast(obj) End Method Method removeAllThingLinks() For Local obj:TCar = EachIn Self.thingList obj.removeWorld() Next End Method Method remove() removeAllThingLinks() End Method End Type |
||
www.illusion-games.de
Space War 3 | Space Race | Galaxy on Fire | Razoon Gewinner des BCC #57 User posted image |
![]() |
Geeecko |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ich glaube es wäre interessanter, einen "Generator" zu schreiben,
der <nachdem auf F5 gedürckt worden ist, also vor dem eigentlichen compilervorgang> den quellcode so manipulieren würde, das für bestimmte types pro variable zwei funktionen erstellt werden (set und get). Hier mal ein Beispiel: Anfang: Code: [AUSKLAPPEN] TCar Field speed:Int Method setSpeed(value:Int) If(Value < 0) Then Self.speed = value Else self.speed = 0 EndIf End Method Method getSpeed............. ....... End Method End Type Local myCar:TCar = new TCar myCar.speed = 5 Print myCar.speed Generator: Code: [AUSKLAPPEN] ... Local myCar:TCar = new TCar myCar.setSpeed(5) Print myCar.getSpeed() |
||
![]() |
Firstdeathmaker |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hmm, das ist natürlich auch interessant, aber besser wäre es da vielleicht, das in den Editor zu integrieren. Ich persönlich habe mir dazu die community-edition etwas umgeschrieben, welche mir jetzt einen zusätzlichen Dialog anbietet mit welchem ich getter und setter erzeugen kann.
Aber mein Program da oben geht ja noch viel weiter: Es stellt Funktionen zum Assoziationsmanagement bereit. |
||
www.illusion-games.de
Space War 3 | Space Race | Galaxy on Fire | Razoon Gewinner des BCC #57 User posted image |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group