13.6.2009

Computerprogramm und Programmiersprache (2)

Themenanfang

Aus Sicht der Maschine kann man sagen: ein Programm ist die Differenz zwischen einer Datei und einem Programm. Dabei kann man den Begriff des Programms (als re-entry im Sinne George Spencer Browns) rekursiv wieder in die Definition einspeisen: die Differenz zwischen Programm und Datei wird wieder von einem Programm realisiert.[1]

Aus der Sicht des Programmierers ist ein Programm aber keine binäre, maschinenlesbare Datei, sondern ein für Menschen lesbarer Text in Form von Sourcecode. Dabei gibt es eine Reihe unterschiedlicher Stufen von Abstraktionen vom Binärcode - und dann noch prinzipiell die Frage, was einen Text zum Sourcecode werden läßt.

Die erste Stufe, vom Binärcode zu abstrahieren und ihn für Menschen lesbar zu machen, nennt sich Maschinensprache, oder Assembler. Dabei wird jeder Befehl, den ein Prozessor verstehen kann, mit einem Namen versehen. Statt einer Zahl kann man jetzt ein Kürzel aufschreiben, und zwar in eine reine Textdatei, die ein Programm (ein sog. Assembler) hinterher in Binärcode übersetzt. Dabei ändert das nichts daran, daß der Programmierer direkt in Maschinenlogik denkt. Für jeden Assemblerbefehl gibt es ein konkretes Gegenstück in der Zahlenwelt; die Anweisungen werden in genau der Reihenfolge aufgeschrieben, in der sie der Prozessor hinterher „liest”.

Einen großen Schritt weiter gehen sog. Hochsprachen. Sie vergeben nicht nur Namen für Zahlen, sondern führen eigene logische Strukturen ein, die der Prozessor nicht mehr direkt umsetzen kann. Der Sourcecode muß erst durch ein Programm (einen sog. Compiler) übersetzt werden, welches teilweise äußerst komplexe Operationen durchführt, um binären Code zu erzeugen. Ein Konstrukt wie eine „if-else”-Anweisung, mit der ein Programmierer ausdrücken kann, daß bestimmte Codebereiche nur aufgrund von bestimmten Bedingungen durchlaufen werden sollen, ist – aus der Sicht der Prozessorlogik – schlicht nicht möglich. Der Compiler muß das erst in eine Folge von Sprungbefehlen zerlegen, die der Prozessor ausführen kann. Ähnliches gilt für eine ganze Reihe weiterer Konstrukte, die alle Hochsprachen mehr oder weniger ähnlich implementieren: der Sourcecode sieht erheblich anders aus, als der Text in Assembler, den der Compiler erzeugt.

Ein dritter Schritt führt zu den sog. objektorientierten Sprachen. Hochsprachen wie „C” oder „Pascal” definieren Abläufe, denen das Programm folgt. Das ist noch nicht allzu weit entfernt von der eigenen Logik des Prozessors, der zwar keine Abläufe kennt, wohl aber Sprünge. Wesentlich komplexer werden die Verhältnisse, wenn in „C++” oder „Lisp” sog. Klassen zum Grundbestand des Programmierens werden. Classes (ich benutze das englische Wort, wenn ich Klassen in objektorientierter Software meine) sind Konstrukte, mit denen sich Objekte der realen Welt virtuell nachbilden lassen. Der Programmierer definiert etwa eine Class, mit der sich ein Rechteck auf dem Bildschirm beschreiben läßt. Diese Definition umfaßt sowohl Daten, um Koordinaten, Breite und Höhe zu speichern, als auch Methoden, um diese Daten zu manipulieren - z.B. um ein Rechteck größer oder kleiner zu machen, oder zu plazieren. Eine andere Class könnte einen virtuellen Pinsel beschreiben, der Atribute wie z.B. eine Farbe bekommt, und mit dem man ein (durch erstgenannte Class beschriebenes) Rechteck auf dem Bildschirm „malen” kann. - Etc., es kommt mir hier nicht darauf an, objektorientiertes Programmieren zu beschreiben, sondern ich will deutlich machen, daß man sich von der Maschinenlogik hier ganz erheblich entfernt. In welchem Maß dies geschieht, kann man allein an der Komplexität ermessen, die die Compiler annehmen. Einen C-Compiler zu schreiben, ist eine nicht gerade triviale Aufgabe. Einen Compiler zu schreiben, der das objektorientierte Gegenstück C++ übersetzt, dürfte mehr Probleme bereiten als die Konstruktion einer Rakete zum Mars.[2]

Im letzten Schritt schließlich gibt es Texte, die unverzichtbar für die Programmierarbeit sind, die aber nur noch ansatzweise von Programmen les- oder übersetzbar sind, sondern sich direkt an die Menschen richten. Das betrifft zum einen die Dokumentation im und über den Sourcecode, ohne die sich bestimmte Konstruktionen und Designs kaum erschließen lassen. Sourcecode ist zwar für den Programmierer lesbar, muß aber teilweise mühsam entziffert und in einen Zusammenhang gebracht werden, um einen Sinn zu ergeben. Dokumentation ist dafür gedacht, diesen Prozeß abzukürzen. Zum anderen gibt es eine Reihe von Tools und Verfahren, die den Designprozeß unterstützen sollen, ohne daß die dort erstellten Texte direkt zum Computerprogramm werden. Dies sind z.B. Prototypen in Pseudo-Code, oder auch UML-Grafiken. Bei letzteren verläßt man bereits die rein textuelle Ebene und landet bei Grafiken, die mit einer stark formalisierten Symbolik die Vorbereitung von Code-Strukturen erleichtern oder - beginnend mit einer bestimmten Komplexität des Programmdesigns - überhaupt erst ermöglichen.

  1. [1] Den „Trick”, einen Begriff zu definieren, indem man ihn selbst verwendet, um ihn hinterher ein drittes Mal rekursiv auf sich selbst zu beziehen, habe ich jetzt hoffentlich richtig kapiert. - Mehr findet sich bei der Hyperkommunikation.
  2. [2] Das ist jetzt kein ironischer Seitenhieb in Richtung Microsoft, wo man es nach wie vor nicht hinbekommt, einen C++-Compiler auf den Markt zu werfen, der alle Standards einhält, sondern der Versuch, einen Satz aufzuschreiben, der die Realität beschreibt.

(Kommentarfunktion z.Zt. deaktiviert.)