Programmiersprache
aus Wikipedia, der freien Enzyklopädie

Eine Programmiersprache ist eine formale Sprache, die zur Erstellung von Verarbeitungsanweisungen für Rechnersysteme verwendet wird und richtet sich deshalb in Form und Funktion als Sprache an die Struktur und Bedeutung von Information. Programmiersprachen dienen der Informationsverarbeitung. Die genauere linguistische Betrachtung dieser Aspekte ist die Aufgabe der Semiotik. Programmiersprachen sind nicht die einzige Möglichkeit komplexe Abläufe für den Computer aufzubereiten. Andere Konzeptionen sind etwa Datenbanken und Tabellenkalkulation, oder im hardwarenahen Bereich speicherprogrammierbare Steuerungen.
Die Berechnungen in einem Computer können so in einer für den Menschen lesbaren und verständlichen Form notiert werden. Programmiersprachen sind notwendig, da die natürlichen Sprachen oder natürliche Zahlen (s. u.) für eine genügend detaillierte und präzise Beschreibung von algorithmischen Computerberechnungen zu vieldeutig und nicht formal genug sind oder nicht für den Menschen verständlich sind. Die Entwicklung von Programmiersprachen selbst ist eine Aufgabe der Informatik. Die syntaktische Definition einer Sprache wird meist in der formalen Notation Backus-Naur-Form sowie Kontextbedingungen angegeben. Eine vollständige Spezifikation einer Programmiersprache in einem einzigen Kalkül ist Forschungsgebiet und erst ansatzweise gelungen.
Programmieren mit einer Programmiersprache erfordert Disziplin, Ausdauer, abstraktes Denkvermögen, Kreativität und hohe Lernbereitschaft. Unterschiedlichste Aufgaben müssen in die Symbole der Programmiersprache transferiert werden. Das Programmieren als dieses reine Kodieren ist nur ein Teil der Tätigkeit eines guten Programmierers, der zum gesamten Softwareentwicklungsprozess beitragen können sollte: Analyse, Entwurf, Prototyping, Realisation, Testen, Einweisung, Dokumentation, Konsolidierung. Erheblichen Aufwand nimmt auch das so genannte Debuggen ein, also die Diagnose oder Fehlersuche. Fehler sind dann im Grundkonzept, entweder bei der Definition der Anforderungen an die Software, oder bei der Entwicklung des Softwaredesigns, auf dessen Grundlage das Programm entwickelt wird. Fehler bei der Anforderungsdefinition beruhen oft auf mangelnder Kenntnis des Fachgebietes, für das die Software geschrieben wird oder auf Missverständnissen zwischen Nutzern und Entwicklern. Fehler direkt im Softwaredesign hingegen sind oft auf mangelnde Erfahrung der Softwareentwickler oder auf Folgefehler durch Fehler in der Anforderungsspezifikation zurückzuführen. In anderen Fällen ist das Design historisch gewachsen und wird mit der Zeit unübersichtlich, was wiederum zu Designfehlern bei Weiterentwicklungen des Programms führen kann. Vielen Programmierern ist das Softwaredesign auch lästig, sodass oftmals ohne richtiges Konzept direkt entwickelt wird, was dann insbesondere bei steigendem Komplexitätsgrad der Software unweigerlich zu Designfehlern führt. Sowohl für Fehler in der Anforderungsdefinition als auch im Softwaredesign kommen darüber hinaus vielfach Kosten- oder Zeitdruck in Frage.
Inhaltsverzeichnis |
[Bearbeiten] Semiotik
Die äußere Form, in der sich eine Programmiersprache dem Programmierer repräsentiert, bezeichnet man als Syntax. Der Quelltext besteht aus Wörtern und Trennzeichen, ganz ähnlich zu geschriebenen natürlichen Sprachen. Es sind jedoch auch andere Repräsentationen von Programmiersprachen denkbar – wie in den logischen Programmiersprachen – eine Sammlung von Fakten und Regeln. Die Bedeutung eines speziellen Symbols in einer Programmiersprache nennt man dessen Semantik. Syntax und Semantik kann man der Spezifikation, teilweise auch der Dokumentation der Programmiersprache entnehmen. Beim Erstellen von Software reicht es – vor allem, wenn mehrere Personen beteiligt sind – oft nicht aus, nur den Quellcode zu schreiben: Es ist eine Beschreibung der einzelnen Funktionen und deren Parameter notwendig. Bei der objektorientierten Programmierung, wo auch Klassen und ihre frei anwendbaren öffentlichen Methoden eine Rolle spielen, ist deren Beschreibung für die Allgemeinheit im Falle einer Offenlegung ebenso unumgänglich.
Die Beschreibung ist normalerweise sehr technisch orientiert und beschreibt APIs, Datenstrukturen oder Algorithmen. Wichtig ist hier, dass die Dokumentation des Codes alles wichtige erfasst, jedoch trotzdem so kurz wie möglich ist. Die Sprache wird meist in der formalen Notation Backus-Naur-Form angegeben. Eine vollständig formal semantische Spezifikation einer Programmiersprache in einem einzigen Kalkül ist gegenwärtig Forschungsgegenstand.
[Bearbeiten] Beispiel
Die durch eine Programmiersprache ausgedrückte, von einem Menschen lesbare Beschreibung heißt Quelltext (oder auch Quellcode/Programmcode) (Beispiel „Hallo Welt!“). Jeder Benutzer muss die Bearbeitung von Problemen, die er einem Computer übergibt, in einem Programm formulieren. Das Erstellen dieser Computerprogramme nennt man Programmieren und den Ersteller Programmierer, wenn das Programmieren industriell erfolgt auch Softwaretechniker. Der entstandene Quelltext wird anschließend in eine Anweisungsfolge für den Computer übersetzt, die Maschinensprache des Computers auf dem das Programm läuft. Bevor das Programm, das der Programmierer schreibt, von einem Computer ausgeführt werden kann, muss es in eine vom Computer verständliche Folge von Bits, umgesetzt werden. Dies kann entweder offline durch einen Compiler oder – zur Laufzeit – durch einen Interpreter oder JIT-Compiler geschehen. In vielen Fällen wird mittlerweile eine Kombination aus beiden Varianten gewählt, bei der zuerst - meist vom Programmierer - der Quelltext der eigentlichen Programmiersprache in einen abstrakten Zwischencode übersetzt wird, welcher dann zur Laufzeit von einer sogenannten Laufzeitumgebung durch einen Interpreter oder JIT-Compiler in den eigentlichen Maschinencode überführt wird. Dieses Prinzip hat den Vorteil, dass ein und der selbe Zwischencode auf sehr vielen verschiedenen Plattformen ausführbar ist und somit nicht für jedes auf dem Markt übliche System eine eigene Version der Software erscheinen muss. Typische Beispiele für einen solchen Zwischencode sind der Java-Bytecode sowie die Common Intermediate Language. Mittels eines Debuggers kann die Funktionsweise des Programms zur Laufzeit verfolgt werden. Der Debugger ermöglicht in der Regel eine Ablaufverfolgung des zu untersuchenden Programmes in einzelnen Schritten oder zwischen definierten Haltepunkten und ist oft Bestandteil einer Programm-Entwicklungsumgebung.
Programmiersprachen wie C++, Java, Perl oder auch PHP arbeiten mit Begriffen, die Menschen leichter zugänglich sind. Bei der Programmierung wird dann auf der Grundlage der Begrifflichkeit der jeweiligen Programmiersprache ein so genannter Quellcode erstellt. Dieser ist im Vergleich zum Maschinencode besser verständlich, muss aber im nächsten Schritt noch in die maschinen-lesbare binäre Form gebracht werden. Im Gegensatz zur Assemblersprache oder Hochsprachen handelt es sich bei Maschinencode um einen für den Menschen kaum lesbaren Binärcode, der nur von Experten für den jeweiligen Code gelesen wird und zum Beispiel mit speziellen Programmen, so genannten Maschinensprachemonitoren (abgekürzt auch einfach Monitor genannt), bearbeitet werden kann. Der Maschinencode wird meist von einem Assembler oder Compiler erzeugt. Direkt in Maschinensprache muss nur programmiert werden, wenn kein Assembler für den Zielprozessor zur Verfügung steht. Wird von der Programmierung in Maschinensprache gesprochen, wird heute üblicherweise die Maschinenprogrammierung in Assemblersprache unter Verwendung eines Assemblers gemeint, der das als Textdatei vorliegende Assemblerprogramm in binäre Maschinenbefehle übersetzt. Das ist nicht direkt vergleichbar mit dem Übersetzen von natürlichen Sprachen, da dort aufgrund der Kulturabhängigkeit auch linguistische Phänomene eine Rolle spielen; bei Programmiersprachen dagegen kann (und wird i. A.) das Übersetzen mittels eines Übersetzungsprogramms automatisiert werden und ist so fehlersicherer im Übersetzen als eine Fremdsprache, da der Rechner die Syntax prüft. Das Endprodukt dieser Übersetzung nennt man Binärdatei, da es aus 0 und 1 besteht, der Sprache des Computers. Jede Software ist im Prinzip eine definierte, funktionale Anordnung der oben geschilderten Bausteine Berechnung, Vergleich und Bedingter Sprung, wobei die Bausteine beliebig oft verwendet werden können. Diese Anordnung der Bausteine, die als Programm bezeichnet wird, wird in Form von Daten im Speicher des Computers abgelegt. Von dort kann sie von der Hardware ausgelesen und abgearbeitet werden. Da digitale Computer intern nur die Werte 0 und 1 verarbeiten, wäre es nach heutigen Maßstäben extrem umständlich und mühsam, die vielen Formen der Informationsverarbeitung als Binärzahlen einzugeben (zu kodieren). Daher wurden in den letzten Jahrzehnten Verfahrensweisen etabliert, nach denen man häufig verwendete Zahlen und Zeichen und häufig verwendete grundlegende Operationen in symbolischen Befehlen angibt.
[Bearbeiten] Geschichte
Hauptartikel: Geschichte der Programmiersprachen
In den 1950er Jahren wurden in den USA die ersten drei weiter verbreiteten, praktisch eingesetzten höheren Programmiersprachen entwickelt. Dabei verfolgten diese sowohl imperative als auch deklarativ-funktionale Ansätze.
Die Entwicklung von Algol 60 läutete eine fruchtbare Phase vieler neuer Konzepte, wie das der prozeduralen Programmierung ein. Der Bedarf an neuen Programmiersprachen wurde durch den schnellen Fortschritt der Computertechnik gesteigert. In dieser Phase entstanden die bis heute populärsten Programmiersprachen: BASIC und C.
In der Nachfolgezeit ab 1980 konnten sich die neu entwickelten logischen Programmiersprachen nicht gegen die Weiterentwicklung traditioneller Konzepte in Form des objektorientierten Programmierens durchsetzen. Das in den 1990er Jahren immer schneller wachsende Internet forderte seinen Tribut beispielsweise in Form von neuen Skriptsprachen für die Entwicklung von Webserver-Anwendungen.
Derzeit schreitet die Integration der Konzepte der letzten Jahrzehnte voran. Größere Beachtung findet so beispielsweise der Aspekt der Codesicherheit in Form von virtuellen Maschinen. Neuere integrierte, visuelle Entwicklungsumgebungen haben deutliche Fortschritte gebracht, was Aufwand an Zeit, Kosten (und Nerven) angeht. Bedienoberflächen lassen sich meist visuell gestalten, Codefragmente sind per Klick direkt erreichbar. Dokumentation zu anderen Programmteilen und Bibliotheken ist direkt einsehbar, meist gibt es sogar "lookup" Funktionalität, die noch während des Schreibens herausfindet, welche Symbole an dieser Stelle erlaubt sind und entsprechende Vorschläge macht.
Neben der mittlerweile etablierten objektorientierten Programmierung ist die Model Driven Architecture ein weiterer Ansatz zur Verbesserung der Software-Entwicklung, in der Programme aus, meist visuellen, Modellen generiert werden. Diese Techniken markieren gleichzeitig den Übergang von einer eher 'handwerklichen', individuellen 'Kunst' zu einem industriell organisierten Prozess.
Die Tatsache, dass jedoch irgendein Programmierer irgendwann ein Programm in einer Turing-vollständigen Programmiersprache schreiben muss, hat sich trotz aller Industrialisierung nicht geändert und ist weiterhin ein Bestandteil des Selbstverständnisses vieler Programmierer.
[Bearbeiten] Grundstrukturen
[Bearbeiten] Daten, Datentypen und Typisierung
Die Definition von Daten erfolgt im Allgemeinen durch die Angabe einer konkreten Spezifikation zur Datenhaltung und der dazu nötigen Operationen. Diese konkrete Spezifikation legt das allgemeine Verhalten der Operationen fest und abstrahiert damit von der konkreten Implementation der Datenstruktur.
Um die üblichen Arten von Informationen im Computer abbilden zu können, müssen Möglichkeiten zur Definition von Daten oder Datenstrukturen bereitstehen, auch als Datentyp bezeichnet. Hierbei kann zwischen typisierten (zum Beispiel C++ oder Java) und typenlosen Sprachen (zum Beispiel JavaScript, Tcl oder Prolog) unterschieden werden. Bei typisierten Sprachen sind dies entweder vordefinierte Einheiten für einzelne Zahlen (Byte, Integer, Word, etc.) und Zeichen (Char) oder auch zusammengesetzte für Daten, Wörter, Text, sensorische Information und so weiter (Strukturen, Klassen). Zumeist besteht auch die Möglichkeit, zusammengesetzte Objekte oder Strukturen aufzubauen und als neuen Typ zu vereinbaren (etwa Arrays, Listen, Stacks, ganze Dateien). Die typenlosen Sprachen behandeln oftmals alle Einheiten als Zeichenketten und kennen für zusammengesetzte Daten eine allgemeine Liste (zum Beispiel Perl). Bei den typisierten Sprachen gibt es solche mit Typprüfungen zur Übersetzungszeit (statisch typisiert) und solche in denen Typprüfungen primär zur Laufzeit stattfinden (dynamisch typisiert, etwa Ruby, Smalltalk). Werden Typfehler spätestens zur Laufzeit erkannt, spricht man von typsicheren Sprachen. Oft wird fälschlicherweise die statische Typprüfung wegen des angenommenen qualitativen Vorteils gegenüber der dynamischen Typprüfung als „sicher“ bezeichnet.
Es kann keine allgemeine Aussage über die Tauglichkeit beider Formen der Typprüfung getroffen werden – bei statischer Typprüfung ist der Programmierer versucht, diese zu umgehen, bzw. sie wird erst gar nicht vollständig durchgesetzt (zum jetzigen Stand der Technik muss es in jeder statischen Sprache eine Möglichkeit geben, „Typlose“ Daten zu erzeugen oder zwischen Typen zu wechseln – etwa wenn Daten vom Massenspeicher gelesen werden), in Sprachen mit dynamischer Typprüfung werden manche Typfehler erst gefunden, wenn es zu spät ist. Bei dynamischer Typprüfung wird jedoch der Programmcode meist sehr viel einfacher. Oft kann an den „Bürgern erster Klasse“ („First class Citizens“ – FCCs) einer Programmiersprache – also den Formen von Daten, die direkt verwendet werden können, erkannt werden, welchem Paradigma die Sprache gehorcht. In Java z. B. sind Objekte FCCs, in LISP ist jedes Stück Programm FCC, in Perl sind es Zeichenketten, Arrays und Hashes. Auch der Aufbau der Daten folgt syntaktischen Regeln. Mit so genannten Variablen kann man bequem auf die Daten zugreifen und den dualen Charakter von Referenz und Datum einer Variable ausnutzen. Um die Zeichenketten der Daten mit ihrer (semantischen) Bedeutung nutzen zu können, muss man diese Bedeutung durch die Angabe eines Datentyps angeben. Zumeist besteht im Rahmen des Typsystems auch die Möglichkeit neue Typen zu vereinbaren. Bei Java heißen Datentypen Klassen. LISP verwendet als konzeptionelle Hauptstruktur Listen. Auch das Programm ist eine Liste von Befehlen, die andere Listen verändern. Forth verwendet als konzeptionelle Hauptstruktur Stacks und Stackoperationen.
Wird der Schwerpunkt der Betrachtung auf die konkrete Implementation der Operationen verschoben, so wird anstelle des Begriffs Datenstruktur auch häufig von einem Abstrakten Datentypen gesprochen. Der Übergang von der Datenstruktur zu einem Abstrakten Datentyp ist dabei nicht klar definiert, sondern hängt einzig von der Betrachtungsweise ab. Von den meisten Datenstrukturen gibt es neben ihrer Grundform viele Spezialisierungen, die eigens für die Erfüllung einer bestimmten Aufgabe spezifiziert wurden. So sind beispielsweise B-Bäume als Spezialisierung der Datenstruktur Baum besonders gut für Implementationen von Datenbanken geeignet.
[Bearbeiten] Compiler und Entwurfsphilosophie
Eine weitere technische Einrichtung übersetzt dann diese Angaben in interne Daten, einfachste Datenänderungsbefehle und Kontrollanweisungen, die der Computer dann schließlich ausführt. Wenn es ausführbar gemacht wurde, bezeichnet man es dann Programm oder Bibliothek. Je nachdem, ob diese Übersetzung vor oder während der Ausführung des Computerprogramms erfolgt, und ob eine spezielle Ausführungsebene einer virtuellen Maschine an der Ausführung beteiligt wird, unterscheidet man zwischen kompilierenden oder interpretierenden Übersetzungsprogrammen. Wird ein Programmtext als Ganzes übersetzt, spricht man in Bezug auf den Übersetzungsmechanismus von einem Compiler. Der Compiler selbst ist ein Programm, welches als Dateneingabe den menschenlesbaren Programmtext bekommt und als Datenausgabe den Maschinencode liefert, der direkt vom Prozessor verstanden wird (z. B. Objectcode, EXE-Datei) oder in einer Laufzeitumgebung (z. B. JVM oder .NET) ausgeführt wird. Wird ein Programmtext hingegen Schritt für Schritt übersetzt und der jeweils übersetzte Schritt sofort ausgeführt, spricht man von einem Interpreter. Interpretierte Programme laufen meist langsamer als kompilierte.
Es existieren verschiedene Meinungen, welche Eigenschaften eine Programmiersprache besitzen sollte. Allgemein wird jedoch akzeptiert, dass zumindest die grundlegende mathematische Arithmetik ausgedrückt werden können sollte und dass Schleifen, manchmal auch Sprünge, möglich sind, da sonst nicht alles Berechenbare berechnet werden kann. Oft ist der von der Programmiersprache vorgegebene Programmierstil und die Zweckgebundenheit der Programmiersprache wichtig. Es wird der eine oder andere Aspekt besonders betont. Mehr Datenstrukturen oder Freiheit in der Notation oder Raffinesse, was Zeigerstrukturen angeht. Die meisten Sprachen bieten eine gute Funktionalität, fordern aber auch ein hohes Maß an Disziplin bezüglich Fehlerfreiheit. Programmiersprachen sind nicht fehlertolerant, was durch Hilfen aber abgemildert wird. Einige wenige Sprachen bieten große gestalterische Freiheiten bis hin zum sich selbst verändernden Programm: dazu gehört Maschinensprache und auch LISP. Eine theoretische Erkenntnis ist die notwendige Eigenschaft der Turing-Vollständigkeit, falls sie die Turing-Berechenbarkeit des Computers ausnutzen soll; dies kann bis hin zum sich selbst verändernden Programm dienen.
Die Softwaretechnik hilft dabei dem Programmierer diesen Zweck eines Computerprogramms zu realisieren.
[Bearbeiten] Befehle
Ein Computer ist keine starre, nur auf eine Aufgabe spezialisierte Rechenmaschine. Vielmehr wird durch Einzelaktion in Mikroebene angegeben, wie der Computer mit welchen Daten zu verfahren hat. Durch die Reihenfolge der Befehle ist die zeitliche Abfolge vorgegeben. Das Steuerwerk enthält eine Menge von Mikroprogrammen, die jeweils aus einer Liste von Steuersignalen bestehen, die das Verhalten von Prozessorelementen - zum Beispiel der ALU und den Registern - regeln. Bei manchen Prozessoren können die Mikroprogramme auch nachträglich geändert werden. Man könnte die Mikroprogramme auch als Firmware der CPU bezeichnen. Imperative Programmiersprachen bilden dieses Konzept auf Makroebene durch Befehle ab. Um reagierende Programme schreiben zu können, gibt es Sprungbefehle, die die Abfolge der Befehle dynamisch verändern.
Befehle lassen sich semantisch nach dem EVA-Prinzip einteilen.
- Eingabe- oder Ausgabebefehle
- lesen Daten von der Tastatur, von einer Datei oder aus anderen Quellen ein oder sie geben sie auf den Monitor, auf einen Drucker oder in eine Datei aus.
- Berechnungen
- verändern Daten oder sie kombinieren Daten neu. Dies können auch mathematische Berechnungen, wie Addition oder Multiplikation sein.
- Kontrollstrukturen
- entscheiden aufgrund der vorliegenden Daten, welche Befehle als nächstes ausgeführt werden. Insbesondere kann eine Befehlsfolge wiederholt werden.
[Bearbeiten] Klassifizierungen
[Bearbeiten] Objektorientierte Programmiersprachen
Hier werden Daten und Befehle in Objekten verpackt. Objektorientierte Programmiersprachen sind sehr verbreitet und häufig. Man programmiert keine Befehlsketten mehr, sondern versucht sie in Objekte aufzuteilen und beachtet dabei eine geringe Kopplung. Beispiel: Java. Objektorientierung wird hauptsächlich im Rahmen der Objektorientierten Programmierung verwendet, um die Komplexität der entstehenden Programme zu verringern. Der Begriff existiert aber auch für andere Aspekte der Softwareentwicklung, wie die Objektorientierte Analyse und den Objektorientierten Entwurf von Software. Weiterhin gibt es Anwendungen des Konzepts auf Objektorientierte Datenbanken: In einem solchen System werden reale Gegenstände direkt durch Datenbankobjekte repräsentiert. Ihre Identifikation erfolgt über eindeutige und unveränderliche Objektidentifikatoren, welche vom System vergeben werden. Solche Datenbankobjekte können, außer den üblichen, meist numerischen oder alphanumerischen Attributen, Bestandteile haben, die ihrerseits selbst wieder Objekte sind. Sie werden deshalb auch als komplexe Objekte bezeichnet. Es existieren auch Operatoren, mit deren Hilfe mit solchen Objekten umgegangen werden kann. Wird beispielsweise die Information über einen Angestellten im relationalen Datenbankensystem (DBS) über mehrere Relationen "verstreut", so wird sie in einem OODBS als Gesamteinheit in einem Datenbankobjekt "gehalten". Möchte man nun im Relationenmodell bestimmte Informationen abrufen, so müssen diese unter Umständen aus verschiedenen Relationen zusammengesetzt werden (mit Hilfe der vergleichsweise sehr aufwendigen Verbundoperationen).
Das Konzept der objektorientierten Programmierung kann im Allgemeinen dabei helfen, Programmcode zu modularisieren. Modularisierte Quelltexte sind in vielen Fällen leichter zu warten und können bedarfsgerecht in mehreren Projekten verwendet werden (Wiederverwendbarkeit), ohne den Verwaltungsaufwand zu erhöhen. Im einfachsten Fall dienen Objekte dazu, Dinge der realen Welt zu modellieren (Abstraktion). Echte Vererbungshierarchien sind im wirklichen Leben kaum anzutreffen. Von OOP-Experten wird empfohlen, Vererbungen zu vermeiden. OOP steht mit der Objektorientierung dem Paradigma der relationalen Modellierung von relationalen Datenbanken gegenüber. Relationale Datenbanken und Assoziationen objektorientierter Modelle bilden etwa das gleiche ab. In modernen Systemen sind wegen der hohen Geschwindigkeit die Informationen aus technischer Sicht in relationalen Datenbanken abgelegt, während sie sich aus der Sicht des Anwenders wie ein Objekt verhalten. Die hohe Geschwindigkeit von Transaktionen auf Datenbanken steht dabei den intuitiv zugänglicheren Methoden von Objekten gegenüber.
Die einzelnen Bausteine, aus denen ein objektorientiertes Programm während seiner Abarbeitung besteht, werden als Objekte bezeichnet. Die Konzeption dieser Objekte erfolgt dabei in der Regel auf Basis der folgenden Paradigmen:
- Feedback
- Es steht die Kopplung als Index für den Grad des Feedback.
- Datenkapselung
- Als Datenkapselung bezeichnet man in der Programmierung das Verbergen von Implementierungsdetails.
- Vererbung
- Vererbung heißt vereinfacht, dass eine abgeleitete Klasse die Methoden und Objekte der Basisklasse ebenfalls besitzt, also „erbt“.
Weiteres dazu in: Objektorientierte Programmierung.
[Bearbeiten] Imperative Programmiersprachen und Deklarative Programmiersprachen
Die derzeit am häufigsten verwendeten, imperativen Programmiersprachen halten eine spezielle Unterscheidung in Form und Funktion für Befehle (oft auch Anweisungen genannt) und Daten und deren Wiederverwendung bereit. Dieser Programmieransatz ist nicht unbedingt notwendig, da ein Computer diese Strukturen prinzipiell nicht unterscheiden kann, hat sich jedoch historisch durchgesetzt. Einen zu den imperativen Programmiersprachen konträren Ansatz verfolgen die deklarativen Programmiersprachen. Dabei beschreibt der Programmierer, welche Bedingungen ein Programm erfüllen muss. Wie etwas zu geschehen hat, ist Aufgabe des Übersetzungsprogramms. Oder anders gesagt: Der Programmierer gibt an, welches Ergebnis gewünscht ist. Die Problemlösung wird dem Computer überlassen.
Programmtexte sind dabei nicht die einzige Möglichkeit, einem Computer mitzuteilen, welche Aufgabe er erfüllen soll. Aus der Sicht der theoretischen Informatik ist ein Programm lediglich ein Schlüssel, mit dessen Hilfe die universelle Maschine, die ein Allzweckcomputer ist, auf eine spezielle Maschinenfunktion eingestellt wird. Da die Menge der berechenbaren Funktionen abzählbar unendlich ist, kann jede abzählbar unendliche Menge als (Syntax einer) Programmiersprache dienen.
Im Extremfall reicht bereits die Angabe einer einzigen natürlichen Zahl n, um die gewünschte Maschinenfunktion zu spezifizieren. (Daher ist dieses n ein Programm und die Menge aller natürlichen Zahlen die (Syntax der) einfachste(n) Programmiersprache der Welt). Das ist keine große Einschränkung, d. h. es sind auch andere Arten von Programmen vorstellbar, deren Form nicht die einer abzählbaren Kette von Zeichen ist. Es könnten auch graphische Objekte sein. Schon gar nicht muss ein Programm eine explizite Liste von Anweisungsschritten enthalten (Imperative Programmierung); diese Idee führt u. a. zur deklarativen Programmierung.
Die Art der formulierten Bedingungen unterteilen die deklarativen Programmiersprachen in logische Programmiersprachen, die mathematische Logik benutzen und funktionale Programmiersprachen, die dafür mathematische Funktionen einsetzen. Computerprogramme zur Darstellung von Funktionen heißen Funktionenplotter. Funktionenplotter gehören auch zum Funktionsumfang von Computer-Algebra-Systemen (CAS), matrizenfähigen Programmierumgebungen wie MATLAB und anderen Systemen. Die wesentlichen Fähigkeiten eines Funktionenplotters sind auch auf einem graphikfähigen Taschenrechner verfügbar. Deklarative Programmiersprachen haben keine große Popularität und sind oftmals im akademischen Bereich zu finden.
Programmiersprachen lassen sich in verschiedener Hinsicht klassifizieren. Klassifizierung kommt in nahezu allen Bereichen von Natur und Technik vor. In der Kategorisierung werden Wahrnehmungen klassifiziert; dies ist eine Voraussetzung für Abstraktion und Begriffsbildung und damit letztlich der Intelligenz. Da erst die Klassifizierung realer Informationen geordnete Verarbeitung ermöglicht, ist die Klassifizierung auch zentraler Bestandteil vieler Anwendungen der Informatik. Dort wird die Automatische Klassifizierung als Grundlage der Mustererkennung wissenschaftlich untersucht. Häufig ist die Unterteilung nach Programmierparadigmen, nach Sprachgenerationen oder Anwendungsgebieten.
[Bearbeiten] Anwendungsgebiete
- Assemblersprachen erlauben eine hardwarenahe Programmierung.
- CNC-Programmiersprachen dienen der Erzeugung von Steuerungsinformationen für Werkzeugmaschinen.
- Datenbanksprachen sind für den Einsatz in und die Abfrage von Datenbanken gedacht.
- Skriptsprachen dienen zur einfachen Steuerung von Rechnern, wie bei der Stapelverarbeitung.
- Visuelle Programmiersprachen erleichtern die graphische Gestaltung von Benutzeroberflächen.
- Esoterische Programmiersprachen sind als anspruchsvolle Scherze gedacht.
[Bearbeiten] Programmierparadigmen
Name | funktional | imperativ | objektorientiert | deklarativ | logisch | nebenläufig |
Ada | X | X | X | X | ||
C | X | |||||
Prolog | X | X | ||||
Scheme | X | X | X | X |
Programmierparadigmen dienen zur Klassifikation von Programmiersprachen. Grundlegend sind die Paradigmen der imperativen und der deklarativen Programmierung. Alle weiteren Paradigmen sind Verfeinerungen dieser Prinzipien. Eine Programmiersprache kann mehreren Paradigmen gehorchen.
Hauptartikel: Programmierparadigma
[Bearbeiten] Sprachgenerationen
James Martin klassifiziert[1] Programmiersprachen in verschiedene Generationen. Teilweise wird damit die geschichtliche Entwicklung nachgezeichnet. Vor allem ist dies jedoch ein Ansatz, die Sprachgenerationen als semantische Level zu verstehen. Damit wird der Abstraktionsgrad von der zugrunde liegenden Technik mit jeder Generation erhöht. Die 1. Generation erfordert damit genaueste Kenntnis über die Funktionsweise der zu programmierenden Maschine, während in den höheren Generationen die Beschreibung des Problems wichtiger wird. Wie es letztlich zu lösen ist, soll in den Verantwortungsbereich des Rechners überführt werden.
1. Generation: Maschinensprache sind die direkt auf einem Prozessor ausführbaren binäre Zahlencodes, die die Befehle darstellen. Die Eingabe erfolgt direkt in binärer 0-1-Form. Die direkte Programmierung in einer Maschinensprache wird heute kaum noch verwendet.
- Beispiel: Es soll die Addition „3 + 4“ durchgeführt werden. Der Prozessor hat für die Operation „addiere“ den festgelegten Code
00011010
. 0011 und 0100 ist die Codierung der Operanden 3 und 4 im Dualsystem. Damit weist die folgende Folge in Maschinensprache den Rechner an, die Addition auszuführen:00011010 0011 0100
.
2. Generation: Assembler ersetzen die Zahlencodes der Maschinensprache durch symbolische Bezeichner (Mnemonics). Eine Assembleranweisung wird in genau einen Maschinenbefehl umgesetzt. Der Anteil der Assemblerprogrammierung ist sehr gering.
- Beispiel: Es soll die Addition „3 + 4“ durchgeführt werden. Der für den Prozessor geeignete Assembler hat den Bezeichner
ADD
für die Operation „addiere“ festgelegt.R0
undR1
sind die Speicherzellen in der die Operanden 3 und 4 stehen. Damit weist der folgende Befehl im Assembler den Rechner an, die Addition auszuführen:ADD R0 R1
.
3. Generation: Höhere Programmiersprachen (High Level Languages) führen Konzepte wie Variablen ein, um leichter verständlichen Quelltext schreiben zu können. Sprachen der 3. Generation sind weitgehend maschinenunabhängig. Die meisten praktisch eingesetzten Programmiersprachen sind höhere Programmiersprachen. Heute existieren viele unterschiedliche höhere Programmiersprachen, manche sogar für Spezialanwendungen. Das eine Extrem bilden die Allrounder der Programmiersprachen (general purpose language), die auf keinen speziellen Anwendungsfall zugeschnitten sind und allgemeine Abstraktionen bieten. Auf der anderen Seite gibt es die sog. Domänenspezifischen Sprachen (Domain Specific Languages, DSL), zur Zeit intensives Forschungsgebiet, die Abstraktionen für eine bestimmten Anwendungsfall bieten. So gibt es Sprachen für die Gleissteuerung von Zugstrecken mit teilweise grafischer Programmierung, d. h. der „Programmtext“ besteht dort aus Grafiken, die beispielsweise per Mauseingabe manipuliert werden können. Ziel einer solchen Darstellung ist, von der Textdarstellung zu abstrahieren und das Programmieren einer breiteren Anwenderbasis durch intuitive Bedienung zugänglich zu machen.
- Beispiel: Es soll die Addition „3 + 4“ durchgeführt werden. In der höheren Programmiersprache C wird direkt die mathematische Arithmetik für die Operation „addiere“ unterstützt. Es ist dafür eine Variable
Summe
vom Datentypint
nötig. Damit weist der folgende Programmcode in C den Rechner an, die Addition auszuführen:int Summe; Summe = 3 + 4;
.
Objektorientierte Sprachen sind ebenfalls Sprachen der 3. Generation. Um jedoch ihre konzeptionelle Sonderrolle zu betonen, werden sie in der Literatur oft als „OO-Generation“ bezeichnet.
4. Generation: Viertgenerationssprachen bieten einfache Sprachmittel zur Auslösung komplexer Operationen. Zumeist sind sie dabei an eine bestimmte Anwendung, wie Informationsgewinnung und Listenerzeugung gebunden.
- Beispiel: Es sollen aus einer Datensammlung alle Kundendaten herausgefunden werden. Falls die Daten in einer geeigneten Datenbankanwendung erfasst sind, kann mit der Sprache SQL die Aktion folgendermaßen erreicht werden:
SELECT kunden FROM datenbank
. Dasselbe Ergebnis ist mit einer Hochsprache nur durch eine Beschreibung von Einzelaktionen (Öffnen von Dateien etc.) zu erzielen.
Der Begriff 4GL ist nicht exakt definierbar und wird vor allem für Marketing-Zwecke eingesetzt. Gemeinsames Hauptziel aller 4GL ist es jedoch, im Vergleich mit Drittgenerationssprachen dieselbe Funktionalität mit weniger Code zu erreichen. Der Begriff wurde in den 1980er Jahren häufig verwendet. Heute wird auch der Begriff Rapid Application Development (RAD) mit überlappender Semantik angewandt. In Drittgenerationssprachen stand die Einführung von standardisierten Kontrollstrukturen im Vordergrund. In Viertgenerationssprachen liegen zusätzlich Bausteine vorgefertigt vor, die häufig in spezialisierten Anwendungen vorkommen. Nicht mehr wie ein Problem gelöst wird steht im Vordergrund, sondern was der Rechner machen muss, um dieses Problem zu lösen. Wesentliches Merkmal der Sprachen der 4. Generation ist die Abstraktionsebene, in der das Problem formuliert wird. Verlangen Höhere Programmiersprachen noch das Programmieren von prozeduralen technischen Einzelschritten, wird in Sprachen der 4. Generation die Anforderung eher problemnah formuliert und vom System in beliebigen Umgebungen unter Nutzung der technischen Möglichkeiten zur Ausführung gebracht. Weitere Merkmale sind: integrierte Gestaltung der Nutzeroberfläche, Listenerzeugung, Datenbankzugriff.
5. Generation: (Very High Level Language, VHLL) Sprachen der 5. Generation gestatten das Beschreiben von Sachverhalten und Problemen. Sie kommen vor allem im Bereich der KI (künstliche Intelligenz) zum Einsatz. Die Wahl des Problemlösungsweges kann (entsprechend dem Sprachkonzept) dem jeweiligen System (weitgehend) überlassen werden. Logikorientierte Programmiersprachen haben ungewöhnliche Eigenschaften (Backtracking, Unifikationsalgorithmen), die sie für gewisse Arten von Problemen vorherbestimmt, die mit anderen Programmiersprachen nur sehr schwer zu lösen sind. Prolog, eine der bekanntesten logischen Programmiersprachen etwa, orientiert sich in der Beschreibung der Programme an der Prädikatenlogik. Durch den Austausch der Lösungsmethode wird ein und derselbe Programmtext (Satz von Regeln) zu einem anderen Programm und liefert andere Ergebnisse (vergl. XSLT und Expertensystem). Die Verbesserung und Spezialisierung der Lösungsmethode ist seit den 1980er Jahren ein „Dauerbrenner“ in der Forschung auf einigen Gebieten der Künstliche Intelligenz.
[Bearbeiten] Siehe auch
[Bearbeiten] Literatur
- Henning, Peter A.; Vogelsang, Holger: Handbuch Programmiersprachen. Softwareentwicklung zum Lernen und Nachschlagen. Carl Hanser Verlag München 2007, ISBN 3-446-40558-5, 978-3-446-40558-5
- Henning, Peter A.; Vogelsang, Holger: Taschenbuch Programmiersprachen. Fachbuchverlag Leipzig im Carl Hanser Verlag 2004, ISBN 3-446-22580-3
- Kenneth C. Louden: Programmiersprachen: Grundlagen, Konzepte, Entwurf. Internat. Thomson Publ., Bonn, Albany [u.a.] 1994, ISBN 3-929821-03-6
[Bearbeiten] Einzelnachweise
- ↑ James Martin, 1981, Development Without Programmers, ISBN 978-0130389435
[Bearbeiten] Weblinks
Wiktionary: Programmiersprache – Bedeutungserklärungen, Wortherkunft, Synonyme und Übersetzungen |
Wikibooks: Programmierung – Lern- und Lehrmaterialien |
- 99 Bottles of Beer: Ein Programm in hunderten von Programmiersprachen bzw. Dialekten