Generierung von Sekundär-Quelltexten

Generierung von Sekundär-Quelltexten

Inhalt


Topic:.SourceCodeGen.

Generierte Quelltexte, Quellcodes oder Sourcecodes sind eigentlich keine Quellen, sondern Generate. Da sie aber meist nicht anders aussehen als handgeschriebene Quellen und sich im Generierprozess auch daneben einordnen, als Quelle für die weitere Generierung (Compiler, Linker) dienen, ist die Bezeichnung Quelltext nicht grundfalsch. Für eine eindeutige Bezeichnung kann von Sekundärquellen sprechen.


1 Retrospective C und Assembler

Topic:.SourceCodeGen.C2Asm.

Ein C-Compiler übersetzt nicht direkt in Maschinencode des Zielprozessors, sondern immer zuerst in Assembler. Danach erfolgt der Assemblerlauf, meist verbunden mit einer nochmaligen Codeoptimierung. Den Assember-Sekundärquelltext kann man sich ansehen, im List-File. Dieser Vorgang ist meist verborgen, es sieht so aus, als dass C direkt in einen Object-File übersetzt. Niemand würde heutzutage auf die Idee kommen, den vom C-Compiler erzeugten Assemblercode nochmal nachzuarbeiten. Es handelt es sich hier um eine langjährig bewährte Praxis einer Quellcode-Generierung. Man kann diese Praxis betrachten und daraus Schlussfolgerung für Quellcodegenerierungen ziehen, die noch nicht gängige Praxis sind aber es werden können.

C und Assembler sind relativ gut aufeinander abgebildet. Das ist eine These. Gemeint ist folgendes: Eine Zuweisung in C ist auch eine Zuweisung in Assembler (zu Registern oder Beschreiben von Speicherbereichen), wird nur etwas anders geschrieben. Ein Subroutinenaufruf in C hat auch in Assembler sein entsprechendes Gegenstück: Ein paar mehr Befehle, Argumente in den Stack laden, dann ein call-Befehl, aber im Grunde ist es das gleiche. Man kann C programmierend gut darüber nachdenken, was die CPU in etwa für Maschinenbefehle bekommt.

C ist aber viel eleganter schreib- und lesbar als Assembler. Das ist einer der Gründe für eine Assembler-Quellcodegenerierung aus der höheren Form C. Es ist gegebenfalls der wichtigste Grund für den Programmierer, aber nicht der Hauptgrund dieser Entwicklung.

Ein C-Quellcode ist unabhängig von der Ablaufumgebung, Assembler-Sourcen sind es nicht. Dieser Grund ist ein wichtiger. Mit C gelingt die portable Programmierung. Ein C-Quelltext kann funktionell erstmal am PC vorgetestet werden, bevor er in eine Embedded-Control-Zielhardware eingebracht wird. Der selbe Algorithmus kann mit unverändertem Quelltext woanders wiederverwendet werden. Die Anpassung an die Ziel-Plattform leistet der zielsystemspezifische C-Compiler.

In Assembler müssen Dinge bedacht und durchdacht werden, die der C-Compiler automatisch übernehmen kann. Das sind im wesentlichen die Entscheidung, was in welche CPU-Register geladen wird. In der Assemblerprogrammierung nehmen diese Überlegungen einen nicht unbedeutenden Teil der Programmierarbeit in Anspruch. Ein C-Compiler hat Algorithmen, mit denen er diese Dinge selbst und gegebenenfalls besser entscheiden kann. Ein weiteres Beispiel ist die Reihenfolge von Maschinenbefehlen, um möglichst optimal zu arbeiten. Auch hier ist ein Algorithmus meist besser als ein durchschnittlich guter Assemblerprogrammierer.

C kennt wichtige programmierunterstützende Regeln, der C-Compiler testet diese, Assembler nicht. Gemeint sind hier die Regeln der Strukturierten Programmierung und die der Sichtbarkeit und Strukturierung von Variablen (auch an C++ gedacht). In Assembler ist das alles sehr frei, man kann sonstwas für verzwackte Dinge programmieren.

Die Gründe, eine andere Sprache zu verwenden und die notwendige Zwischensprache (hier Assembler) daraus zu generieren sollten sind als gegeben. Der Generator (hier C-Compiler) enthalt einiges an Intelligenz, die sonst per Hand eingebracht werden müsste. Man kann aber nicht sagen, dass damit die Programmierung beschränkt sei. Die Freiheiten, die man in Assembler hätte gegenüber C, braucht man in der Regel nicht. Andererseits bietet C genügend Spielraum zur Lösung anstehender Probleme. Letzlich ist es möglich und nicht ungewöhnlich, dass bestimmte Dinge in einer C-Umgebung doch noch in Assembler formuliert werden, dort wo notwendig.


2 Schlussfolgerungen bzw. Forderungen, was muss eine Sekundär-Quellcodegenerierung leisten

Topic:.SourceCodeGen.Requirements.


3 Anwendungs-Gebiete für Sekundäre-Quellcodegenerierungen

Topic:.SourceCodeGen.ApplicationScopes.

Als erstes sind hierbei Spezial-Progammiersprachen - Domain-Specific Languages (DSL) zu nennen: Für bestimmte Programmieraufgaben wird ein Set von Anweisungen definiert, mit dem ausgedrückt werden kann was für die Anwendungen notwendig ist. Solch ein Set ist viel weniger universell als beispielsweise C, C++ oder Java, aber der Anwender kann damit auch nicht beliebige Fehler machen. Sehr oft ist damit auch eine grafische Programmierung verbunden, da aus einer gezeichneten Grafik Datengehalte gelesen und in das spezielle Set konvertiert werden können. Um auf ein Zielsystem zu kommen, wird dann meist C oder C++ generiert, was unbesehen dann dem C-Compiler angeboten wird.

Eine Quellcodegenerierung aus UML-Modellen soll nicht zu den Anwendungsgebieten für Sekundär-Quellcodegenerierung dazugezählt werden. Denn: Zwei bis drei wichtige Forderung sind nicht erfüllt:

Die Quellcodegenerierung aus UML scheitert grundsätzlich daran, dass UML eben nicht eine andere Programmiersprache oberhalb der textuell-prozeduralen Sprachen ist, sondern UML beziehungweise die Modellbasierende Softwareentwicklung öffet andere Betrachtungsebenen der Software, die parallel zur Quelltext-Programmierung stehen.

Eine Umsetzung Java2C soll hier nicht unerwähnt bleiben. Der Vorteil hier ist: Man kann vollständig objektorientiert in Java programmieren und testen, um dann auf einer Zielplattform diese Algorithmen in einer C-Umgebung zu implementieren. Typische C-Programmierfehler sind ausgeschlossen, da der der Java2C-Translator solche Fehler nicht vorsieht bzw. an Stellen, an denen etwa Type-Castings erfolgen, entweder die Richtigkeit des Castings algorithmisch im Java vorgetestet ist oder Befehle zur Überprüfung adäquat Java auch in C eingebaut werden. Man kann dies nicht vergessen oder nicht wollen, der Translator macht es. Bestimmte für C wichtige Dinge wie eine C-gemäße Datenorganisation werden in Java über Annotations in den Kommentaren mitgeteilt, die Richtigkeit wird wiederum vom Java2C-Translator gewährleistet beziehungsweise überprüft. Mit Einsatz dieser Technik kann ein erheblicher Testaufwand eingespart werden, wenn ansonsten eine Implementierung in C oder C++ notwendig ist.

Eine Generierung ist auch angebracht, wenn gemeinsame Schnittstellen in zwei Programmiersprachen notwendig sind. Man kann gegebenfalls die Schnittstellen quellenmäßig in der einen Sprache pflegen, um sie nach Generierung auch in der anderen Sprache verfügbar zu haben. Ein Beispiel dafür ist der Übersetzer C-Headerfiles zu Java-Code, der javadoc:_org/vishia/byteData/ByteDataAccess implementiert. Man kann auf diesem Weg Byte-Datenorganisationen in Telegrammen oder Binärfiles in als C-struct beschreiben und über die daraus generiertem Java-Sourcen auch in Java direkt darauf zugreifen.

Interessant ist es oft, einen Mix aus generiertem Quellcode plus ergänzend manuellem primären Quellcode in einer niedrigeren Programmiersprache zu vereinen.