Kann mir jemand auf einige Dokumentation verweisen, wie man Skripte in Python (oder Perl oder einer anderen Linux-freundlichen Skriptsprache) schreibt, die C++ - Code aus XML- oder py-Dateien von der Kommandozeile erzeugen. Ich würde gerne in der Lage sein, einige XML-Dateien zu schreiben und dann einen Shell-Befehl auszuführen, der diese Dateien liest und .h-Dateien mit vollständig inlined Funktionen erzeugt, z. Streaming-Operatoren, Konstruktoren usw.C++ - Codegenerierung mit Python
Antwort
Ich arbeite tatsächlich mit einer älteren Entwicklungsumgebung "4GL", die etwas ähnliches tut, und viele Modelle auf dem alten 4GL-Paradigma verwenden C und C++ als die Sprache, die sie ausgeben generated code in.
Das heißt, 4GL ist ziemlich resigniert auf den Staubhaufen der Geschichte. Das Problem ist, dass Sie bei der Generierung des C-Codes durch die Maschine die Leistungssteigerungen verlieren, die sich aus der Verwendung von C ergeben hätten, und der Code ist äußerst schwierig zu warten. Könnte auch nur das Programm in Python schreiben.
Ich suche keinen Programmkonverter. Ich suche nach einem Dokument, wie ich mein eigenes Python/Perl/etc-Skript schreibe, das einfach C++ - Datentypen mit grundlegenden Funktionen wie Streaming-Operatoren basierend auf einer kurzen Datentypspezifikation generiert. Die Spezifikation würde nur den Klassennamen, seine Mitglieder, eine Basisklasse und eine einfache Dokumentation für jedes Mitglied auflisten. Die Ausgabe wäre eine Header-Datei mit einer vollständig inlinierten Klassendefinition. Ich denke, Python oder Perl sollte das leicht machen können. – user357525
Sie könnten einen Blick auf Shedskin werfen, ein Projekt, das C++ - Code aus Python-Code generiert.
Je nachdem, was Ihre Gründe sind, kann es ein wenig sinnlos sein, wie Satanicpuppy darauf hinwies.
Ich bin mehr daran interessiert, nur ein paar einfache Shell-Skripte zu schreiben, um grundlegende Parsing und Code-Gen, wenn möglich zu tun. Wenn nicht, werde ich einfach die Grundkurse selbst schreiben. – user357525
Ich kenne nichts einfacher als Shedskin - Sie würden wahrscheinlich nur Ihre eigenen rollen wollen, obwohl einige Leute XML-Parser erwähnt haben. Ich kann mir vorstellen, dass es ziemlich trivial wäre, etwas ziemlich Einfaches zu schaffen. –
Werfen Sie einen Blick auf Cheetah. Es ist eine in Python geschriebene Vorlagen-Engine.
Ich habe Gepard schon ein paar Mal angeschaut. Obwohl es besagt, dass es für die C++ - Generierung verwendet wird, gibt es keine Beispiele dafür und keine Dokumentation, wie es für C++ verwendet wird. Ich möchte meinen eigenen einfachen Generator für grundlegende Datentypen schreiben. Wenn sich das als zu kompliziert herausstellt, werde ich mich nicht mit irgendeinem Code-Gen-Tool beschäftigen. – user357525
Ich fürchte, Sie werden keine bereits eingebaute Lösung finden, die Ihre speziellen XML- oder Python-Dateien übernimmt und sie "out-of-the-box" in Ihre benötigte Ausgabe umwandelt.
Sie müssen das Parsing, die Datenverarbeitung und die Ausgabe selbst implementieren. Nicht ganz allein. Hier sind einige Hinweise zum Parsen und zur Ausgabe.
Python kommt mit 2 verschiedenen XML-Parsern (SAX and DOM -scroll down, um einige Beispiele zu sehen). Sie müssen einen von ihnen verwenden, um die Quelldateien zu lesen.
Um die Ausgabe einfacher zu erstellen, können Sie wahrscheinlich eine Templating-Bibliothek wie StringTemplate verwenden oder den Code manuell generieren, wenn er klein ist.
Zusätzlich zu StringTemplate gibt es viele andere Templating-Lösungen, die ursprünglich für Templating-Webseiten gedacht waren (zum Beispiel Jinja2), die relativ einfach dafür verwendet werden können. – jleahy
https://github.com/kblomqvist/yasha - Jinja2 für diesen Zweck neu gedacht :) – kblomqvist
Vor ein paar Jahren arbeitete ich an einem Projekt zur Vereinfachung der Interprozess Shared Memory Management für große Simulationssysteme. Wir verwendeten einen verwandten Ansatz, bei dem das Layout von Daten im Shared Memory in XML - Dateien und einem in python geschriebenen Code - Generator definiert wurde, den XML - Code ausspuckte und eine Reihe von Headerdateien ausspuckte, die Strukturen und zugehörige Funktionen/Operatoren/etc definierten XML-Beschreibung Zu der Zeit sah ich mir mehrere Templating-Engines an und zu meiner Überraschung stellte ich fest, dass es einfacher und sehr einfach war, es einfach "von Hand" zu machen.
Während Sie die XML-Datei lesen, füllen Sie einfach eine Reihe von Datenstrukturen aus, die Ihrem Code entsprechen. Header-Dateiobjekte enthalten Klassen und Klassen enthalten Variablen (die anderen Klassen angehören können). Geben Sie jedem Objekt eine printSelf()
-Methode, die über ihren Inhalt iteriert und printSelf()
für jedes Objekt aufruft, das es enthält.
Es scheint zunächst ein wenig entmutigend, aber sobald Sie anfangen, ist es ziemlich einfach. Oh, und ein Tipp, der mit dem generierten Code hilft, fügt ein Einrückungsargument zu printSelf()
hinzu und erhöht es auf jeder Ebene. Es macht den generierten Code viel einfacher zu lesen.
Okay, ich werde das ausprobieren und auch StringTemplate anschauen. – user357525
In der Tat ist die Verwendung von Strings für Templating Bits von dem, was Sie generieren, wesentlich. Ich habe den Großteil meines Codes mit dem einfachen Operator% gemacht und es hat gut geklappt, aber das neue (ja, der Code ist alt ;-) StringTemplates sollten es noch einfacher machen. – Rakis
Wenn Sie dies einfach mit Standard-Python-Kram machen möchten, könnten Sie versuchen, Vorlagendateien zu erstellen, die die Python-3-Zeichenkettenformatierung verwenden.Zum Beispiel könnte eine Klassenvorlage wie folgt aussehen:
{className}::{className}()
{{
}}
{className}::~{className}()
{{
}}
{className}::{className}(const {className}& other)
{{
}}
{className}& {className}::operator=(const {className}& other)
{{
return *this;
}}
Dann wird Ihr Python-Code ist super einfach:
d = {}
d['className'] = 'MyCPlusPlusClassName'
with open(yourTemplateFile, 'r') as ftemp:
templateString = ftemp.read()
with open(generatedFile, 'w') as f:
f.write(templateString.format(**d))
Natürlich können Sie viele andere Felder neben ‚classname‘ hinzufügen können mit dem gleichen Trick. Wenn Sie keine Dinge wie bedingte Code-Generierung benötigen, können Sie aus so etwas ganz einfach eine Menge Geld herausholen.
Aus meiner eigenen Erfahrung kann ich Jinja2 (http://jinja.pocoo.org/docs/dev/) empfehlen. Obwohl die Hauptzielsprache von Jinja HTML ist, funktioniert es ziemlich gut für C++. Und das ist nicht nur meine Meinung, siehe https://www.chromium.org/developers/jinja :). Es gibt eine eigenständige Version (https://github.com/filwaitman/jinja2-standalone-compiler), die nützlich sein könnte, da Jinja2 selbst nur eine API ist. Ich benutze die Stand-alone-Version für mein Projekt hier https://github.com/TomSmartBishop/avl mit benutzerdefinierten Umgebungseinstellungen, so dass die Jinja2 öffnenden und schließenden Tags mehr C++ - Stil entsprechen.
Hoffe, dass es für jemanden nützlich sein wird (Sie win32 Zwischenablage in Daten verwenden können, lesen)
import sys, string
import win32clipboard
import re
data = '''
enum FeedTypeT
{
AA,
BB,
DDD,
F
};
'''
def get_from_clippord():
# get clipboard data
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
return data
def enum_type(inenum):
inenum = inenum.replace('\r\n', '\n')
inenum = re.sub(r'\s', r'', inenum)
inenum = re.sub(r'^(.*)\{.*$', r'\1', inenum)
return inenum
def cleanup_enum(inenum):
inenum = inenum.replace('\r\n', '\n')
# inenum = inenum.replace('enum', '')
inenum = re.sub(r'\s', r'', inenum)
# inenum = re.sub(r'^.*\{(.+)[|,]\}.*$', r'\1', inenum)
inenum = re.sub(r'^.*\{(.+)\}.*$', r'\1', inenum)
inenum = inenum.split(',')
return inenum
def get_element(inlist):
for element in inlist:
[one, two] = element.split('=')
print('{0:20} ==> {1:>20}'.format(one, two)) # right align
# one = element.split('=')
# print('{0:20} ==> {1:10}'.format(one[0], one[1]))
def print_switch(typename):
retstr = 'const std::string toString(' + typename + ' type)'
retstr += '\n{\n switch(type)\n {'
return retstr
def print_case_line(instr, w):
retstr = ' case ' + '{:{fw}}'.format(instr + ':', fw = w) + ' return "' + instr + '";'
return retstr
def print_switch_end(w):
retstr = ' default: ' + ' '*(w-4) + ' return "undef";\n }\n}\n'
return retstr
def main():
#data = get_from_clippord()
ll = cleanup_enum(data)
print (ll)
print ("="*80 + "\n\n")
print (print_switch(enum_type(data)))
w = 25
# pick right with for formating, based on the lenght of elements of enum
for line in ll:
if w < len(line):
w = len(line) + 2
for line in ll:
print (print_case_line(line, w))
print (print_switch_end(w))
if __name__ == '__main__':
main()
Ausgang:
['AA', 'BB', 'DDD', 'F']
================================================================================
const std::string toString(enumFeedTypeT type)
{
switch(type)
{
case AA: return "AA";
case BB: return "BB";
case DDD: return "DDD";
case F: return "F";
default: return "undef";
}
}
Check out http://www.altova.com/xmlspy /xml-code-generation.html – schoetbi