Bin2c

Code-Stücke können hier veröffentlicht werden.
Antworten
stuhlbein
User
Beiträge: 89
Registriert: Freitag 9. Januar 2009, 16:08

Nur eine Python version für Bin2c, einem "Allesmögliche-zu-C"-Konverter.
Ich weiss nicht obs bereits eine in Python gibt, aber wenn nicht, gibts jetzt eine (Versionen in anderen sprachen gibts ja bereits mehr als genügend ;P). =)

Herunterladen kann man das ganze Hier.

EDIT: Kleine änderung, welche Dateinamen in C-kompatible variablen-namen konvertiert, falls notwendig.
EDIT2: die generierte Doku findet sich hier.
EDIT3: Jetzt wird zumindest schon Java, C, C++, und D unterstützt.
EDIT4: Da gist aus irgendeinem grund nicht den vollständigen Paste speichert, wird das skript jetzt Hier herunterladbar sein.
Zuletzt geändert von stuhlbein am Freitag 18. September 2009, 19:13, insgesamt 3-mal geändert.
BlackJack

@stuhlbein: Warum bei `writefile()` der Modus 'w+'? Das '+' wird doch gar nicht verwendet.

Der Test ob ein Zeichen eine Ziffer ist, geht auch ohne `string.digits`, nämlich direkt auf der Zeichenkette selbst: ``if name[0].isdigit():``.

Das Umwandeln von `char` in `getchar()` und `datastring` in `gettemplate()` in Zeichenketten ist überflüssig -- das sind doch schon welche.

Die Ermittlung von `basename` funktioniert nicht, wenn der Dateiname mehr als einen '.' enthäht. Zum Trennen von Dateiname und Erweiterung gibt's `os.path.splitext()`. Man sollte IMHO das Ergebnis von `convert_name()` auch testen, ob da wirlich ein gültiger C-Bezeichner heraus kommt, denn Dateinamen können ja alles mögliche enthalten was in C nicht in einem Bezeichner erlaubt ist.

Das formatieren von Werten in Zeichenketten über Dictionaries finde ich hier ziemlich übertrieben, und mal machst Du es und mal nicht.

`gettemplate()` ist als Name falsch. Die Funktion gibt kein Template zurück.

Das ``position += 1`` hat keinen Effekt und kann ersatzlos gestrichen werden.

Zeichenketten in Schleifen mit ``+=`` aufbauen ist unpythonisch, weil das quadratische Laufzeit haben kann. Zeichenketten sind nicht veränderbar, also wird bei jedem ``+=`` eine neue Zeichenkette erzeugt und die beiden Anderen werden dafür im Speicher kopiert. Idiomatisch wäre das sammeln von Zeichenketten in einer Liste, die man dann am Ende mit `str.join()` zu einer Zeichenkette zusammenfasst. Ich hätte an der Stelle statt dem hantieren mit `position` die Eingabe in Blöcke zu 15 Zeichen zerlegt und die mit ``','.join(map(convert_char, block))`` zu einer Zeile zusammengesetzt und am Ende dann die ganzen Zeilen mit ``',\n'.join(lines)``.

Oder man könnte das Ganze auch als Datenstrom-orientierte Lösung schreiben, also nicht alles in den Speicher laden, sondern Vorspann rausschreiben, dann immer Blöcke von 15 Bytes aus der Eingabe lesen und konvertiert in die Ausgabedatei schreiben, und danach dann das kleine `main()` rausschreiben. Damit ist man relativ unabhängig vom Hauptspeicher und der Dateigrösse. Falls jemand mal ein DVD-Image in ein C-Programm einbetten möchte. ;-)

Erweiterungsvorschlag: Mehr als nur C unterstützen, Python fehlt zum Beispiel ganz offensichtlich :-), und auch verschiedene Formate bei den einzelnen Werten. Und die Optionen mit `optparse` verarbeiten.
stuhlbein
User
Beiträge: 89
Registriert: Freitag 9. Januar 2009, 16:08

BlackJack hat geschrieben:@stuhlbein: Warum bei `writefile()` der Modus 'w+'? Das '+' wird doch gar nicht verwendet.
Ich versteh nicht was du meinst? `w+` setzt den Zeiger auf den anfang der Datei (deswegen ja auch der Hinweis dass die datei überschrieben wird).
Der Test ob ein Zeichen eine Ziffer ist, geht auch ohne `string.digits`, nämlich direkt auf der Zeichenkette selbst: ``if name[0].isdigit():``.


Das Umwandeln von `char` in `getchar()` und `datastring` in `gettemplate()` in Zeichenketten ist überflüssig -- das sind doch schon welche.

Die Ermittlung von `basename` funktioniert nicht, wenn der Dateiname mehr als einen '.' enthäht. Zum Trennen von Dateiname und Erweiterung gibt's `os.path.splitext()`.


Das formatieren von Werten in Zeichenketten über Dictionaries finde ich hier ziemlich übertrieben, und mal machst Du es und mal nicht.

Das ``position += 1`` hat keinen Effekt und kann ersatzlos gestrichen werden.
gefixt in der neusten revision.
Man sollte IMHO das Ergebnis von `convert_name()` auch testen, ob da wirlich ein gültiger C-Bezeichner heraus kommt, denn Dateinamen können ja alles mögliche enthalten was in C nicht in einem Bezeichner erlaubt ist.
ich hab die funktion mit jeder denkabren art von Namen durchgetestet, und kann getrost behaupten dass sie valide C-bezeichner wiedergibt. wenn dir aber ein bug auffällt, kannst du ihn natürlich melden ;P
`gettemplate()` ist als Name falsch. Die Funktion gibt kein Template zurück.
stimmt, seh ich ein. Praktischerweise hab ich die funktion in `bin2c()` umbenannt ;)
Zeichenketten in Schleifen mit ``+=`` aufbauen ist unpythonisch, weil das quadratische Laufzeit haben kann. Zeichenketten sind nicht veränderbar, also wird bei jedem ``+=`` eine neue Zeichenkette erzeugt und die beiden Anderen werden dafür im Speicher kopiert. Idiomatisch wäre das sammeln von Zeichenketten in einer Liste, die man dann am Ende mit `str.join()` zu einer Zeichenkette zusammenfasst. Ich hätte an der Stelle statt dem hantieren mit `position` die Eingabe in Blöcke zu 15 Zeichen zerlegt und die mit ``','.join(map(convert_char, block))`` zu einer Zeile zusammengesetzt und am Ende dann die ganzen Zeilen mit ``',\n'.join(lines)``.

Oder man könnte das Ganze auch als Datenstrom-orientierte Lösung schreiben, also nicht alles in den Speicher laden, sondern Vorspann rausschreiben, dann immer Blöcke von 15 Bytes aus der Eingabe lesen und konvertiert in die Ausgabedatei schreiben, und danach dann das kleine `main()` rausschreiben. Damit ist man relativ unabhängig vom Hauptspeicher und der Dateigrösse. Falls jemand mal ein DVD-Image in ein C-Programm einbetten möchte. ;-)
Ich denke ich versteh schon was du meinst, aber ein direktes problem seh ich nicht... Die idee das mit StringIO zu machen kam mir aber auch schon, und würde das persönlich auch einer Liste vorziehen.

Erweiterungsvorschlag: Mehr als nur C unterstützen, Python fehlt zum Beispiel ganz offensichtlich :-), und auch verschiedene Formate bei den einzelnen Werten. Und die Optionen mit `optparse` verarbeiten.
Mittlerweile unterstützt es C, C++, und D. Ich kenn mich leider nicht mit Java, BASIC, pascal oder Fortran aus um diese einzubauen, aber vielleicht les ich mich ja ein. ;P

Und den tipp mit optparse hab ich selbstverständlich auch beachtet (selber link, neueste revision).
lunar

Auch "w" alleine setzt den Zeiger auf den Anfang der Datei. Lies mal in der Doku nach, was der tatsächliche Unterschied zwischen "w" und "w+" ist.
stuhlbein
User
Beiträge: 89
Registriert: Freitag 9. Januar 2009, 16:08

lunar hat geschrieben:Auch "w" alleine setzt den Zeiger auf den Anfang der Datei. Lies mal in der Doku nach, was der tatsächliche Unterschied zwischen "w" und "w+" ist.
stimmt, gefixt.
BlackJack

@stuhlbein: Ich denke bei der Mehrsprachenversion sollte man mit Templates arbeiten, also zum Beispiel mit `string.Template` und nicht mit einem ``if`` bzw. ``elif`` pro Sprache.

Ausserdem passt jetzt der Name der Funktion schon wieder nicht. ;-)
stuhlbein
User
Beiträge: 89
Registriert: Freitag 9. Januar 2009, 16:08

BlackJack hat geschrieben:@stuhlbein: Ich denke bei der Mehrsprachenversion sollte man mit Templates arbeiten, also zum Beispiel mit `string.Template` und nicht mit einem ``if`` bzw. ``elif`` pro Sprache.
Ich versteh nicht inwiefern string.Template besser als ein paar if/elif zweige sein soll. Nicht jede Sprache auf diesem planeten hat C syntax.
Ausserdem passt jetzt der Name der Funktion schon wieder nicht. ;-)
Sag bloss dass bin2c() kein passender name für das Modul bin2c, dessen haupt-funktion bin2c() ist? hmm, nenn mich kleinkariert... :D
BlackJack

@stuhlbein: Nein, nicht jede Sprache hat C-Syntax, aber was hat das damit zu tun? Es ist halt sauberer Daten und Code ein wenig zu trennen, dann lassen sich auch einfacher neue Sprachen hinzufügen. Im einfachsten Fall in dem man einfach ein neues Template und ein Sprachkürzel einem Dictionary hinzufügt. Und nicht wie jetzt, indem man einen Haufen Quelltext in einen neuen ``elif``-Zweig kopiert und anpasst.

`bin2c` ist auch ein unpassender Name für das Modul. Nenn mich kleinkariert, aber von so einem Modul würde ich nur erwarten, dass da C herauskommt. Für so eine allgemeine Funktion fänd' ich `bin2source()` halt passender und `bin2c()` zum generieren von D-Quelltext unpassend. :-)
stuhlbein
User
Beiträge: 89
Registriert: Freitag 9. Januar 2009, 16:08

BlackJack hat geschrieben:@stuhlbein: Nein, nicht jede Sprache hat C-Syntax, aber was hat das damit zu tun? Es ist halt sauberer Daten und Code ein wenig zu trennen, dann lassen sich auch einfacher neue Sprachen hinzufügen. Im einfachsten Fall in dem man einfach ein neues Template und ein Sprachkürzel einem Dictionary hinzufügt. Und nicht wie jetzt, indem man einen Haufen Quelltext in einen neuen ``elif``-Zweig kopiert und anpasst.
gut, ist ein argument. Leider hab ich nur keine ahnung wie genau du das nun meinst. Beispiel?
`bin2c` ist auch ein unpassender Name für das Modul. Nenn mich kleinkariert, aber von so einem Modul würde ich nur erwarten, dass da C herauskommt. Für so eine allgemeine Funktion fänd' ich `bin2source()` halt passender und `bin2c()` zum generieren von D-Quelltext unpassend. :-)
Richtig, aber ich glaube, die meisten haben das programm einfach als bin2c im Kopf. und ohne jede sprach-angaben spuckt das programm ohnehin nur C code aus, weshalb ich mit dem namen durchaus leben kann. Die anderen sprach-varianten sind ohnehin mehr ein proof of concept, ich persönlich brauch zb nur die C, bzw, C++ variante. =)
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Du könntest zb eine Klasse "Language" anlegen und alle Fälle, bei denen du etwas ersetzen musst, als string.Template Klassen übergeben lassen. Dann legst du ein (globales, konstantes) Dict an welches Sprachnamen zu Language Exemplaren zuordnet.
stuhlbein
User
Beiträge: 89
Registriert: Freitag 9. Januar 2009, 16:08

str1442 hat geschrieben:Du könntest zb eine Klasse "Language" anlegen und alle Fälle, bei denen du etwas ersetzen musst, als string.Template Klassen übergeben lassen. Dann legst du ein (globales, konstantes) Dict an welches Sprachnamen zu Language Exemplaren zuordnet.
Stimmt. an sich auch eine gute idee. =)
Der wartbarkeit halber habe ich aber nun doch D und Java aus dem Code entfernt.
Zudem besitzen sowohl Java (durch JAR pakete) als auch D (die `import()` funktion) bereits native möglichkeiten, um Media dateien in der resultierenden ausführbaren datei einzubetten.
Antworten