Programmiersprache
Eine Programmiersprache ist eine formale Sprache zur Darstellung (Notation) von Computerprogrammen. Sie vermittelt dem Computersystem durch von einem Menschen geschriebenen Text genaue Angaben zu einer Kette von internen Verarbeitungsschritten, beteiligten Daten und deren Struktur in Abhängigkeit von internen oder externen Ereignissen.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 haben sich 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. Eine weitere technische Einrichtung übersetzt dann diese Angaben in interne Daten, einfachste Datenänderungsbefehle und Kontrollanweisungen, die der Computer dann schließlich ausführt.
Wird ein Programmtext als Ganzes übersetzt, spricht man in Bezug auf den Übersetzungsmechanismus von einem Compiler. Der Compiler ist selbst 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.
Eine logische Abfolge von Befehlen in einer Programmiersprache nennt man allgemein Programm, Programmcode oder Quelltext. (Quelltext betont besonders die Lesbarkeit). Dieser wird von Programmierern verfasst.
Die meisten Befehle einer Programmiersprache lassen sich auf 5 Hauptkategorien zurückführen:
Elemente einer Programmiersprache
Daten von der Tastatur, von einer Datei oder anderswo her übernehmen.
Daten ausgeben: auf den Monitor, auf einen Drucker oder in eine Datei
Eine mathematische Berechnung, wie Addition oder Multiplikation oder Ähnliches, durchführen.
Bestimmte Bedingungen überprüfen und anhand des Ergebnisses entscheiden, welche Befehle als nächstes ausgeführt werden.
Eine Befehlsfolge wiederholt durchführen, meist mit einer gewissen Variation.
Eine andere Kategorisierung sieht wie folgt aus:
- Arbeiten mit Variablen
- Elementare Mathematik
- Bedingte Verzweigung
- Schleifen
- Blockbildung
- Umgang mit nicht mathematischen Elementen
- Kommentare
Jede Programmiersprache hält Vereinbarungen bezüglich Syntax, Vokabular und Bedeutung bereit für:
- Daten und Datenstrukturen
- Befehle und Befehlsgruppen
- Bezugnahmemechanismen und Wiederverwendung
- zumeist eine primäre Designphilosophie
Daten und Datenstrukturen
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 (Objektorientiert)z.B. sind Objekte FCCs, in LISP (Funktional) ist jedes Stück Programm FCC, in Perl sind es Zeichenketten, Arrays und Hashes.
Konzeptionell ist ein programmierbarer Rechner weit mehr als eine Sammlung von Daten und auch keine starre Rechenmaschine.
Vielmehr wird angegeben, wie der Computer mit variablen internen oder externen Daten zu verfahren hat.
Elementare Anweisungen geben über Schlüsselwörter (key words) an, WANN WAS WIE geändert werden soll.
Jede Sprache enthält eine WENN-DANN-artige Anweisung, die letztlich zusammen mit dem Sprungbefehl (Goto) die Universalität bereitstellt, um allgemein auf vielfältigste Fälle reagierende Programme schreiben zu können.
Falls Konstrukte für Schleifen mit Bedingungen (Bedingung zuerst, dann Anweisungsgruppe, oder: erst Anweisungsgruppe und dann Bedingung) zur Verfügung stehen, kann auf den Sprungbefehl vollständig verzichtet werden. Niklaus Wirth hat dies mit Modula-2 gezeigt.
Der Kern der Bezugnahme ist die Benennung von Speicherplatz als so genannte ''Variable'\'. Weitere Bezugnahmen sind Zeiger auf solche Variablen oder Variablengruppen.
Auch Befehlsgruppen werden im Programm per Namensaufruf als Prozedur oder Funktionsaufruf verfügbar gemacht.
Auf diese Weise wird durch Symbole einerseits eine große Variabilität erreicht und durch Referenz auf vorhandene Programm- oder Datenteile andererseits ein hohes Maß an Wiederverwendbarkeit erreicht.
Viele anwendungsbezogene Sprachen integrieren typische Aufgaben als aufrufbare Befehle.
Für die oben genannten Zwecke hat jede Sprache meist eine besondere Philosophie entwickelt.
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 ist.
Einige wenige Sprachen bieten große gestalterische Freiheiten bis hin zum sich selbst verändernden Programm:
dazu gehört Maschinensprache und auch LISP.
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.
Meilensteine sind ca. 1937 Patente von Konrad Zuse, die die Architektur beschreiben, die später als Von-Neumann-Maschine bekannt wird sowie 1945 die Fertigstellung von Plankalkül durch Zuse. Die ersten praktisch eingesetzten Programmiersprachen sind FORTRAN (1954, John Backus), COBOL (1959, Grace Hopper), LISP (1959, McCarthy), ALGOL-60 (1960, Strukturierte Programmierung)) und weitere (siehe Tabelle).
Inzwischen ist eine riesige Zahl von Sprachen entstanden und es gibt einen evolutionären Prozess mit gegenseitiger Adaptierung.
Eine wichtige Rolle spielen dabei auch die Standardisierungs-Organisationen (ISO).
Die vorgenannten Sprachen existieren bis heute.
Programmiersprachen werden geschichtlich auch in verschiedene Generationen eingeteilt:
1. Generation: Maschinensprachen
Befehle werden direkt in einer Maschinensprache notiert, d.h. als Folge von Zahlencodes. Da sich der Befehlssatz von Rechner mit unterschiedlichen Prozessoren im allgemeinen unterscheidet, sind in Maschinensprache geschriebene Programme nur sehr schwer übertragbar. Die direkte Programmierung in einer Maschinensprache wird heute kaum noch verwendet.
Einige Programmiersysteme für höhere Programmiersprachen gestatten es, Maschinenbefehle in den Quelltext zu integrieren. Die Anwendung beschränkt sich dann auf solche Fälle, in denen es aus funktionalen oder Effektivitätsgründen unumgänglich oder nützlich ist, maschinennah zu programmieren.
2. Generation: Assembler
Anstelle von Zahlencodes wird mit Hilfe von symbolischen Bezeichnern codiert. Eine Assembleranweisung wird in genau einen Maschinenbefehl umgesetzt. Auch Assemblerprogramme sind deshalb im allgemeinen an einen bestimmten Prozessortyp gebunden.
Makroassembler gestatten die Bildung von parametrisierbaren Befehlsgruppen. Eine Makroanweisung wird im allgemeinen in mehr als einen Maschinenbefehl umgesetzt.
Der Anteil der Assemblerprogrammierung ist im Sinken. Der Möglichkeit der Erstellung effektiver Programme steht die erschwerte Wartbarkeit von Assemblerprogrammen gegenüber. Maschinennahe Programmierung - die Domäne von Assembler - kann heute überwiegend durch höhere Programmiersprachen abgedeckt werden.
Einige Programmiersysteme für höhere Programmiersprachen gestatten es, Assemblerbefehle in den Quelltext zu integrieren. Die Anwendung kann sich dann auf die Situationen beschränken, in denen es aus funktionalen oder Effektivitätsgründen notwendig oder nützlich ist, maschinennah zu programmieren.
3. Generation: höhere Programmiersprachen (high level language)
Sprachen der 3. Generation unterstützen unmittelbar die Notation von Algorithmen, sie sind weitgehend anwendungsneutral und maschinenunabhängig.
Erste höhere Programmiersprachen entstanden ab Mitte der fünfziger Jahre (FORTRAN, COBOL, ALGOL-60). Weitere Sprachen dieser Generation sind zum Beispiel PASCAL, MODULA-2, PL1, C, ADA, BASIC, SIMULA.
4. Generation: Fourth Generation Language (4GL)
Sprachen der 4. Generation sind anwendungsbezogen (applikative Sprachen). Sie stellen i.a. die wichtigsten Gestaltungsmittel von Sprachen der 3. Generation zur Verfügung, zusätzlich jedoch Sprachmittel zur Auslösung von relativ komplexen, anwendungsbezogenen Operationen, beispielsweise zum Zugriff auf Datenbanken und zur Gestaltung von Benutzeroberflächen (SQL).
5. Generation: (Very High Level Language, VHLL)
Sprachen der 5.Generation gestatten das Beschreiben von Sachverhalten, von 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.
Bekanntestes Beispiel für eine Sprache der 5. Generation ist PROLOG.
00-Generation: Objektorientierte Programmiersprachen
Objektorientierte Programmiersprachen passen nicht in das bisherige Generationen-Modell. Sie werden daher in der Literatur oft als "00-Generation" bezeichnet.
Die Geschichte der Programmierung (vor allem die Entwicklung von Unix) hat dazu geführt, dass sich imperative Sprachen (allen voran C mit der Erweiterung C++) für allgemeine Anwendungen durchgesetzt haben. Große Bedeutung erlangt hat das "objektorientierte" programmieren, das Daten-, Prozedur- und Referenzaspekte in dem einzigen Konzept des Objekts vereinigt.
In letzter Zeit haben vorgefertigte Komponenten und Softwarebibliotheken mit wiederverwendbarem Code an Bedeutung gewonnen. XML z.B. ist eine Technik, die nur darauf abzielt, bestimmte Teile von Programmen zu standardisieren.
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.
Dazu kann objektorientierte Methodik auch die Übersichtlichkeit von Programmen erheblich verbessern.
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.
Im Folgenden werden diverse Klassen von Programmiersprachen, unterteilt nach Anwendungsbereich oder zugrundeliegendem Paradigma, vorgestellt.
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.
Daneben wird der Begriff Visuelle Programmierung auch für Programmiersprachen benutzt, bei denen graphisch in Diagrammen (in der regel Statechart-Dialekte) programmiert wird. Beispiele hierfür: Esterel (mit Esterel Studio, http://www.esterel-technologies.com), Statemate (http://www.ilogix.com/statemate/statemate.cfm), Matlab mit Simulink, LabView.
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, Einführung, Dokumentation, Konsolidierung.
Erheblichen Aufwand nimmt auch das so genannte Debuggen ein, also die Diagnose oder Fehlersuche.
Berufe: Softwareentwickler, Anwendungsentwickler, Systemprogrammierer, Organisationsprogrammmierer, ...
Siehe auch: Liste der Programmiersprachen, Algorithmus, Datenbanksysteme, Informatik, Softwaretechnik, Hallo Welt, Quine
Befehle und Befehlsstrukturen
Bezugnahmemechanismen und Wiederverwendung
Entwurfsphilosophie
Geschichte
Anfänge
Erste Arbeiten stammen bereits von Lady Ada, Countess of Lovelace (1815-1852, Assistentin von Charles Babbage), die als erste das Prinzip der variablen Programmierbarkeit erkannte.
Dies entwickelte sich erst spürbar weiter mit Entwicklung der ersten elektronischen Rechenmaschinen und der Verwendung der booleschen Algebra.Kurze Zeittafel
Siehe auch die ausführliche Zeittafel der Programmiersprachen.Aktuelle Entwicklungen
Besondere Ausprägungen
Maschinensprache
Maschinensprache ist der direkt auf einem Prozessor ausführbare Code und in diesem Sinne keine Programmiersprache. Jede Prozessorarchitektur hat eine eigene, unterschiedliche Maschinensprache. Assemblersprachen
Assemblersprachen gehören immer direkt zu ihrer entsprechenden Maschinensprache.
Die Maschinenbefehle werden jedoch in einer menschenlesbaren Form geschrieben.
Weiter wird mittels Symbolen adressiert, die absoluten Adressen werden vom Assembler errechnet.
Auch können symbolische Konstanten benutzt und Makros, die häufig wiederkehrende Befehlsfolgen repräsentieren, definiert werden.Datenstrukturen
Logische Sprachen
Prolog orientiert sich in der Beschreibung der Programme an der Prädikatenlogik. 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.Prozedurale Sprachen
AWK, BASIC, C, COBOL, FORTRAN, Pascal, PL/1, REXX sind Vertreter der prozeduralen Familie, in der Anweisungen hintereinander abgearbeitet werden.Objektorientierte Sprachen
Smalltalk, Eiffel, Modula-3, C++, Objective-C, Java, C#, Delphi/ObjectPascal und Oberon sind objektorientierte Sprachen.
In objektorientierten Programmiersprachen werden Datenstrukturen und Methoden, die auf diesen Datenstrukturen operieren in Klassen gekapselt.Funktionale Sprachen
LISP (Hybridsprache), Logo (Programmiersprache), ML (Programmiersprache), Scheme, HaskellRegelbasierte Sprachen
Bei regelbasierten Sprachen wie OPS-5 oder Prolog werden Regeln gegen eine Datenmenge auf ihre Instanziierbarkeit geprüft.
Aus allen Regelinstanziierungen wird eine (mehrere, alle) ausgewählt und die zur Regel gehörenden Anweisungen werden ausgeführt.Visuelle Programmierumgebungen
Die Programmierung wird erleichtert, da zwischen
unterschieden wird.
Beispiele: Visual Basic, Visual C++, Delphi (Sprache: Pascal), Kylix (Delphi/C++ für Linux), KDevelop (Sprache: C++), Microsoft Visual Studio. Ein sehr mächtiges Beispiel ist auch das Open Source-Projekt Eclipse_(IDE), das sich konzeptionell nicht auf eine bestimmte Sprache festlegt."Esoterische" Programmiersprachen
Sprachen, die nicht für Real-Welt-Programmierung, sondern meistens als anspruchsvolle Scherze gedacht sind.
Beispiele: Brainfuck, Ook, False, ShakespeareAnwendungsbezogene Sprachen und Systeme
Datenbanksysteme: dBase, Clipper (Programmiersprache), Paradox (Programmiersprache)
. EASYProgrammieren
Programmieren ist eine anspruchsvolle Tätigkeit und erfordert Disziplin, Ausdauer, abstraktes Denkvermögen, Kreativität und hohe Lernbereitschaft.
Unterschiedlichste Aufgaben müssen in die Symbole der Programmiersprache transferiert werden. Weblinks