Wikipedia · einfach zusammengefasst · Stand
Programmiersprache
Bei deklarativen Programmiersprachen ist der Ausführungsalgorithmus schon vorab festgelegt und wird nicht im Quelltext ausformuliert/beschrieben, sondern es …
Inhalt5 Abschnitte
Grundidee und Ausführung
Eine Programmiersprache ist eine formale Sprache, mit der Datenstrukturen und Algorithmen, also von Computern ausführbare Rechenvorschriften, formuliert werden. Programme bestehen üblicherweise aus schrittweisen Anweisungen nach erlaubten Textmustern; diese Regeln heißen Syntax. Der mit einem Texteditor erzeugte Programmtext heißt Quelltext oder Quellcode.
Frühe Programmiersprachen waren unmittelbar an die Eigenschaften eines Rechners gebunden. Heute werden meist problemorientierte oder höhere Programmiersprachen verwendet. Sie sind maschinenunabhängiger und für Menschen leichter verständlich. Visuelle Programmiersprachen gewinnen ebenfalls an Bedeutung, weil sie den Zugang erleichtern.
Damit ein Prozessor ein Programm ausführen kann, muss der Quelltext in Maschinensprache überführt werden. Maschinensprache ist schwer lesbarer Binärcode. Bei „Programmierung in Maschinensprache“ ist heute meist Assemblersprache gemeint. Ein Compiler übersetzt vor der Ausführung, ein Interpreter oder JIT-Compiler zur Laufzeit. Häufig wird zunächst ein Zwischencode erzeugt und erst in einer Laufzeitumgebung in Maschinencode überführt. Das macht denselben Zwischencode auf unterschiedlichen Plattformen ausführbar; Beispiele sind Java-Bytecode und Common Intermediate Language.
Zu den üblichen Grundmitteln einer Sprache gehören Ein- und Ausgabe, Variablen und Felder zum Zwischenspeichern, mathematische und Zeichenkettenfunktionen sowie Steueranweisungen für Bedingungen, Wiederholungen, Unterfunktionen und Bibliotheken. Daraus lassen sich höhere Funktionen als wiederverwendbare Bibliotheken bilden. Spezialsprachen können Produktivität und Portabilität erhöhen; meist sinken jedoch Verarbeitungsgeschwindigkeit und Mächtigkeit der Sprache. Je höher und komfortabler eine Sprache ist, desto stärker ist der Programmierer an ihre vorgesehenen Wege gebunden.
Arten von Sprachen und Anweisungen
Programmiersprachen haben unterschiedliche Nähe zur Hardware und unterschiedliche Einsatzzwecke. Maschinensprache, Assemblersprachen und C erlauben hardwarenahe Programmierung. Höhere Programmiersprachen ermöglichen komfortableres und schnelleres Programmieren. Skriptsprachen dienen zur einfachen Steuerung von Rechnern, etwa bei Stapelverarbeitung. Visuelle Programmierumgebungen erleichtern die grafische Gestaltung von Benutzeroberflächen; grafische Programmiersprachen können Programme aus Verarbeitungsblöcken zusammenklicken lassen. Minisprachen sollen Kinder früh ans Programmieren heranführen. Esoterische Programmiersprachen experimentieren mit ungewöhnlichen Konzepten oder etwa dem ästhetischen Aussehen des Quellcodes.
Nicht jede Sprache, die umgangssprachlich so genannt wird, ist eine Allzweck-Programmiersprache zur Beschreibung von Algorithmen und allgemeiner Datenverarbeitung. Auszeichnungs-, CNC-, Datenbank-, Seitenbeschreibungs- und Stylesheet-Sprachen dienen jeweils besonderen Aufgaben und zählen zu den domänenspezifischen Sprachen.
Anweisungen lassen sich in Kategorien gliedern: Ein- und Ausgabe-Befehle lesen Daten etwa von Tastatur oder Datei ein beziehungsweise geben sie auf Bildschirm, Datei oder Drucker aus. Zuweisungen und Berechnungen erzeugen oder verändern Daten. Kontrollflussanweisungen bestimmen abhängig von Daten die nächste Ausführung: dazu zählen Entscheidungen beziehungsweise Verzweigungen, Iterationen und Sprünge. Deklarationen reservieren Speicher für Variablen oder Datenstrukturen unter einem Namen. Außerdem können externe Unterroutinen oder Module, etwa Systemfunktionen wie „Read“ oder Module anderer Programmiersprachen, aufgerufen werden.
Übersetzungswerkzeuge
Quellcode besteht aus Zeichenfolgen wie „A = B + 100 * C“, die ein Prozessor nicht versteht. Deshalb muss eine äquivalente Folge von Maschinenbefehlen entstehen. Werkzeuge hierfür heißen unter anderem Compiler, Interpreter, Precompiler und Linker.
Ein Compiler übersetzt einen Programmtext als Ganzes und liefert Maschinencode, etwa Objectcode oder eine EXE-Datei, oder einen Zwischencode. Bei einer interpretierten Sprache werden während der Ausführung passende Maschinencodeblöcke ausgeführt; das Programm läuft in einer Laufzeitumgebung, beispielsweise einer veralteten JVM.
Mischformen sind verbreitet. Bei Just-in-Time-Kompilierung wird der Programmtext unmittelbar vor jedem Lauf neu übersetzt oder einzelne Abschnitte werden erst während eines interpretierten Laufs kompiliert. Ein Compiler kann zunächst nicht ausführbaren Code erzeugen: Plattformunabhängiger Zwischencode dient beispielsweise der Software-Verteilung, während plattformgebundener Objektcode mit weiteren Modulen zu ausführbarem Code beziehungsweise einem Lademodul verbunden wird. Precompiler bearbeiten zusätzliche, in der Sprache nicht vorgesehene Syntax, etwa Entscheidungstabellen, und fügen sie vorübersetzt in den Quellcode ein. Zusätzliche Compiler-Anweisungen und Einstellungen eines Projekterstellungsprozesses können den Übersetzungsvorgang steuern.
Programmierparadigmen
Programmierparadigmen sind Kategorien, die sich in der Entwicklung von Programmiersprachen gebildet haben. Grundlegend sind strukturierte, imperative, deklarative und objektorientierte Programmierung; eine Sprache kann Merkmale mehrerer Paradigmen unterstützen. So wird C als imperativ genannt, Prolog als deklarativ und logisch; Scheme, Haskell und Scala können mehrere Paradigmen verbinden.
Strukturierte Programmierung wurde Anfang der 1970er Jahre, auch wegen der Softwarekrise, populär. Sie zerlegt Programme in Unterprogramme, also prozedurale Programmierung, und beschränkt den Kontrollfluss auf Anweisungs-Reihenfolge, Verzweigung und Wiederholung.
Imperative Programme bestehen aus Anweisungen, die beschreiben, wie ein Ergebnis erzeugt wird, beispielsweise Wenn-dann-Folgen, Schleifen oder Multiplikationen. Deklarative Programmierung beschreibt dagegen, welche Bedingungen die Ausgabe erfüllen muss, also das Was. Wie das Ergebnis entsteht, wird etwa durch einen Interpreter festgelegt. SQL ist ein Beispiel. Bedingungen können durch mathematische Logik formuliert werden, dann spricht man von logischer Programmierung, oder durch mathematische Funktionen, dann von funktionaler Programmierung. Programme müssen dabei nicht als Anweisungsliste vorliegen; möglich sind auch grafische Ansätze wie bei der in der Automatisierung verwendeten Plattform STEP 7.
Die objektorientierte Programmierung richtet den Blick zunächst auf Daten beziehungsweise Dinge der Real- oder Außenwelt. Objektklassen beschreiben deren Attribute; Methoden beschreiben, was mit einem Objekt getan werden kann oder was es für das Programm tun kann. Daten und Methoden werden in Objekten oder Objektklassen zusammengefasst. Objektorientierung soll Komplexität verringern, Wiederverwendung verbessern und Realität meist genauer abbilden als rein prozedurale Programmierung.
Wichtige Prinzipien sind Datenkapselung, Vererbung und Polymorphie. Datenkapselung verbirgt Implementierungsdetails: Nach außen stehen nur festgelegte Methoden zur Verfügung. Bei Vererbung besitzt eine abgeleitete Klasse Methoden und Attribute einer Basisklasse und kann zusätzliche erhalten; gemeinsame Funktionalität mehrerer Klassen kann in eine Basisklasse ausgelagert werden. Polymorphie bedeutet, dass ein Objekt einer Spezialklasse auch als Objekt der Basisklasse behandelt und in einer entsprechenden Variablen gespeichert werden kann.
Typen, Daten und typische Beispiele
Variablen sind benannte Speicherorte für Werte. In vielen Sprachen legt ein Datentyp fest, welche Art von Wert sie enthalten. Häufig sind Ganzzahlen, Gleitkommazahlen und Zeichenketten. In typisierten Sprachen wie C++ oder Java unterscheiden sich etwa Short, Integer und Long im Wertebereich und können vorzeichenlos oder vorzeichenbehaftet sein. Float und Double sind Gleitkommatypen, Char speichert einzelne Zeichen und String Zeichenketten.
Statische Typisierung prüft Typen bereits bei der Übersetzung, dynamische Typisierung zur Laufzeit. Eine Sprache heißt typsicher, wenn sie Typfehler spätestens zur Laufzeit erkennt. Bei statischer Prüfung kann die Prüfung umgangen werden oder nicht vollständig durchsetzbar sein, etwa wenn Daten vom Massenspeicher gelesen werden. Bei dynamischer Prüfung werden manche Fehler erst zu spät erkannt. Für eine Änderung des Datentyps ist ein expliziter Umwandlungsbefehl nötig.
Typenlose Sprachen wie JavaScript oder Prolog haben keine differenzierten Datentypen; der Typ einer Variablen wird zur Laufzeit bestimmt. Eine Zuweisung eines anderen Typs wandelt die Variable in den neuen Typ um. Solche Sprachen behandeln oft alle Einheiten als Zeichenketten und verwenden für zusammengesetzte Daten eine allgemeine Liste. Typangaben erleichtern Speicherzugriffe, etwa bei Feldern, und können Operationen verbieten, beispielsweise Zugriffe über Feldgrenzen hinaus. Typen ermöglichen zudem das Überladen von Bezeichnern. Neue Typen können meist vereinbart werden.
Die Datenformen, die direkt verwendet werden können, heißen Bürger erster Klasse (First class Citizens, FCCs) und können auf ein Paradigma hinweisen: In Java sind dies Objekte, in Lisp ist jedes Stück Programm FCCs, in Perl Zeichenketten, Arrays und Hashes. LISP nutzt Listen als Hauptstruktur; auch Programme sind Listen von Befehlen, die andere Listen verändern. Forth nutzt Stacks, Stack-Operationen und ein zur Laufzeit erweiterbares Wörterbuch von Definitionen und führt in den meisten Implementationen keine Typprüfungen durch.
Ein verbreiteter Einstieg ist das Hallo-Welt-Programm: Es gibt den Text „Hello World“ beziehungsweise „Hallo Welt“ auf einem Ausgabegerät aus.