Kapitel 1

Transcription

Kapitel 1
1
1 Einleitung
1.1
Programmiersprachen als Kommunikationsmittel
Sprache ist das wichtigste Kommunikationsmittel zwischen Menschen. Natürliche Sprachen werden sowohl mündlich als auch schriftlich zur Kommunikation angewendet. Künstliche Sprachen,
in diesem Fall Programmiersprachen, werden dagegen fast ausschließlich schriftlich verwendet.
Ihr ursprünglicher Zweck ist es, die (recht einseitige) Kommunikation zwischen einem Programmierer und einem Rechner zu ermöglichen. Daher muss eine Programmiersprache geeignet sein,
Algorithmen zu beschreiben.
Außerdem soll eine Programmiersprache lesbar sein, d. h. mehrere Programmierer sollen mit
ihrer Hilfe über Algorithmen kommunizieren können. Speziell sollte ein Programmierer mittels
einer Programmiersprache auch mit sich selbst kommunizieren können, d. h. Programmiersprachen sollen helfen, Gedachtes festzuhalten, um damit später die Möglichkeit des Verfeinerns,
Präzisierens sowie des Überprüfens zu ermöglichen.
Genauer gesagt ist eine Programmiersprache eine formale Notation zur Beschreibung von Algorithmen in einer Form, die für Rechner und Menschen lesbar ist.
Dabei gibt es selbstverständlich ein breites Spektrum von Programmiersprachen allein was den
Begriff der Lesbarkeit“ angeht. So sind z. B. Assemblersprachen für den Rechner sehr viel
”
einfacher lesbar“ als etwa eine Sprache wie Java, während für den Programmierer eher das
”
Umgekehrte gelten dürfte.
Abgesehen davon haben die Strukturen der erlernten bzw. benutzten Programmiersprache einen
großen und häufig unterschätzten Einfluss auf die Art, wie ein Programmierer von einem vorgegebenen Problem zu einem Lösungsalgorithmus gelangt (Mutterspracheneffekt). Man denke
etwa an das Problem des Durchlaufs durch einen binären Baum und an einen Programmierer,
der mit den Strukturen der funktionalen Sprache wie etwa Lisp kompetent umgeht und im Gegensatz dazu einen Programmierer, der mit einer Sprache ohne rekursive Aufrufe wie etwa Basic
groß geworden ist. Beide werden diese Aufgabe mit sehr unterschiedlichen Algorithmen lösen!
Der Rechner selbst versteht“ nur eine Programmiersprache“ , nämlich seine Maschinensprache.
”
”
Ein Programm ist in diesem Fall eine Folge von Bits, die durch technische Gegebenheiten in
Blöcken von Bits, also Bytes, Worten oder Langworten, zusammengefasst werden. Ein derartiges
Programm ist für einen Menschen äußerst kompliziert zu schreiben und zu lesen, und nur selten
wird man ein Programm in dieser Form notieren.
Jede andere Programmiersprache benötigt ein Übersetzungsprogramm, das ein in dieser Sprache
vorgelegtes Programm in die Maschinensprache übersetzt (Compiler) oder aber ein Simulationsprogramm, das einen Rechner simuliert, dessen Maschinensprache diese Programmiersprache
ist (Interpreter). Mischformen dieser beiden prinzipiellen Vorgehensweisen sind natürlich auch
möglich und werden vielfach benutzt.
Programm in einer
Programmiersprache P
Daten
Programm in einer
Programmiersprache P
-
Compiler für P
- äquivalentes
Maschinenprogramm
-
Interpreter für P
-
- Ergebnisse
2
1
EINLEITUNG
Programmiersprachen sollten eine genügend einfache“ Struktur besitzen, um einen Compi”
ler oder einen Interpreter einfach und effizient genug konstruieren zu können, auf der anderen
Seite sollten sie dem Programmierer genügend Mechanismen und sprachliche Werkzeuge zur
Verfügung stellen, um seine Algorithmen eindeutig, knapp und von anderen Menschen leicht
nachvollziehbar formulieren zu können. Wichtig für eine Programmiersprache ist also die Abstraktion von der Maschinensprache des Rechners hin zu allgemeineren Begriffen. Von besonderer
Bedeutung ist außerdem die Möglichkeit, auf bereits vorgefertigte Programmteile zugreifen und
diese einfach in das eigene Programm integrieren zu können.
1.2
Historische Entwicklung der Programmiersprachen
Die ersten niedergeschriebenen Algorithmen sind auf Tontafeln gefunden worden. Sie stammen
aus Mesopotamien, zwischen Euphrat und Tigris gelegen (heute etwa auf dem Gebiet des Irak).
Die Fundorte der Tontafeln waren in der Nähe von Babylon (in der Umgebung von Bagdad),
und die interessantesten Tafeln stammen aus der Zeit der Hammurabi Dynastie (ca. 1800–1600
vor Chr.). Die Tontafeln sind in Keilschrift beschrieben und teilweise in Museen zu besichtigen.
Die Babylonier rechneten im 60er System. Aus dieser Zeit stammen also die heutigen Winkelbzw. Stundeneinteilungen. Allerdings hatten sie keine Schreibweise für einen Exponenten bzw.
für das 60er Komma“ . Somit konnte die aus den zwei Ziffern“ 2 und 20 bestehenden Zahl
”
”
2;20 die Zahl 2 ∗ 60 + 20 = 140 oder aber auch 2 + 20 ∗ 60−1 = 2 1/3 bedeuten. Allgemein steht
also 2;20 für alle Zahlen der Form 140 ∗ 60n , wobei n eine ganze Zahl ist.
Wie beim Arbeiten mit dem Rechenschieber muss man die Größenordnung des Ergebnisses
abschätzen. Vorteilhaft ist jedoch, dass man mit einer relativ kleinen Zahl von Multiplikationsund Divisionstafeln auskommt, die das kleine 60 mal 60“ enthalten.
”
Beispiel für eine Multiplikationstafel für die Multiplikation mit 25.
1
siehe: G. Ifrah, Universalgeschichte der Zahlen
1
1.2
Historische Entwicklung der Programmiersprachen
3
Die babylonischen Mathematiker konnten aber nicht nur addieren, subtrahieren, multiplizieren
und dividieren, sie konnten auch gewisse Typen algebraischer Gleichungen lösen! Da sie keine
algebraische Notation im heutigen Sinn besaßen, gaben sie eine Schritt-für-Schritt-Methode zur
Lösung der algebraischen Gleichung, also einen Algorithmus, an. Statt Variablen, die ihnen
unbekannt waren, standen im Algorithmus Zahlen — es wurde also eine Beispielberechnung
durchgeführt.
Hier ist zunächst als Beispiel für einen derartigen Algorithmus eine Tontafel, die die Berechnung
von Teilen eines Dreiecks aus gegebenen Daten beschreibt:2
Damit man einen Eindruck von der Ausdrucksfähigkeit eines in dieser Form geschrieben Algorithmus bekommt, soll nun eine Übersetzung eines derartigen Algorithmus vorgestellt werden.
2
siehe: H. Gericke, Mathematik in Antike und Orient
4
1
EINLEITUNG
Babylonischer Algorithmus zur Berechnung von Länge und Breite einer
rechteckigen Zisterne aus deren Höhe und Volumen3
Eine (rechteckige) Zisterne.
Die Höhe ist 3;20, und ein Volumen von 27;46;40 wurde ausgegraben.
Die Länge übersteigt die Breite um 50.
(Länge l und Breite b sollen gesucht werden.)
Nimm das Reziproke der Höhe 3;20, das ist 18.
Multipliziere dies mit dem Volumen 27;46;40; das ist 8;20.
(Bem.: Das ist das Produkt Länge mal Breite;
das Problem ist auf l·b = 8;20 und l-b = 50 reduziert worden.)
Halbiere 50 und quadriere dann; das ist 10;25.
Addiere 8;20 und man erhält 8;30;25.
(Bem.: 50 ∼
= 5/6 und 8;20 ∼
= 8 1/3 bei einer realistisch angenommenen Zisterne!)
Die Quadratwurzel ist 2;55.
Mache davon zwei Kopien, addiere 25 zu der einen und subtrahiere von der anderen.
Man findet, dass 3;20 (d.h. 3 1/3) die Länge und 2;30 (d.h. 2 1/2) die Breite ist.
Das ist die Prozedur.
Dieses Konzept der Beschreibung von Algorithmen ist lange Zeit nicht weiterentwickelt worden.
Ca. 1500 Jahre später hat Euklid einen Algorithmus zur Berechnung des größten gemeinsamen
Teilers zweier Zahlen angegeben4 . Dieser Algorithmus enthält eine Iteration, war jedoch keine
wesentliche Weiterentwicklung in Bezug auf die Technik der Beschreibung eines Algorithmus.
Insgesamt gesehen haben die Mathematiker auch in den folgenden Jahrhunderten keine gute
Notation für dynamische Prozesse gefunden, während die Notationen für statische Beziehungen
sehr stark entwickelt wurden.
Die Notwendigkeit, dynamische Prozesse zu beschreiben, wurde offensichtlich, als es erforderlich war, für geplante oder wirklich realisierte Rechenmaschinen eine Reihenfolge der einzelnen
durchzuführenden Berechnungen festzulegen.
Charles Babbage (1791–1871) entwarf zwischen 1820 und 1850 zwei Rechenmaschinen, die
Difference Engine“ und die Analytical Engine“ . Beide Maschinen waren für die damalige
”
”
Handwerkskunst zu kompliziert und wurden deshalb nie vollendet5 .
Die Analytical Engine“ war ein mechanischer Computer mit Speicher, Drucker und einem
”
Rechenwerk für die vier Grundrechenarten, das Babbage Mill“ (Mühle) nannte. Gesteuert,
”
d. h. programmiert, wurde die Anlage durch eine Folge von Operationskarten zusammen mit
einer Folge von Datenkarten, die man in die Maschine eingab. Diese Karten waren Lochkarten,
wie sie bei automatischen Webstühlen von Jaquard eingeführt wurden.
Babbage wurde unterstützt von Ada Augusta, Countess of Lovelace, einer Tochter von Lord
Byron. Sie hat die ersten Programme“ für die Maschine entwickelt und dürfte daher der erste
”
Mensch gewesen sein, der ein Programm für eine Rechenmaschine entwickelt hat.
3
aus: D. E. Knuth, Ancient Babylonian Algorithms
zu finden etwa in D. E. Knuth, The Art of Computer Programming, Vol. II, Addison-Wesley 1981
5
siehe: D. D. Swade, Der mechanische Computer des Charles Babbage
4
1.2
Historische Entwicklung der Programmiersprachen
5
Die Entwicklung der ersten elektromechanischen bzw. elektronischen Rechner führte natürlich
sofort auch zu Überlegungen nach einfachen Programmiersprachen. Hier einige technische Daten
über diese ersten Rechner6 :
Z3
(Zuse) erster programmgesteuerter Rechner (1941)
2600 Relais, davon 1400 für den Speicher (64 Worte zu 22 Bits), 600 für die arithmetische
Einheit und der Rest für die Steuerlogik.
Das Programm wurde in Form eines perforierten Kinofilmes eingegeben.
Es wurden 3 - 4 Additionen pro Sekunde durchgeführt; eine Multiplikation dauerte 4–5
Sekunden. Die Maschine hatte eine Taktfrequenz von etwa 5 bis 6 Hz.
UNIVAC 1 (Eckert, Mauchly) (1949–51)
5600 Röhren, wassergekühlt, 100 Quecksilber-Verzögerungsleitungen.
Dezimal-Rechner, 1000 Worte mit jeweils 12 alphanumerischen Zeichen (z. B. Vorzeichen
und 11 Digitalstellen), 4 Akkumulatoren,
Addition 0,5 Millisekunden, Multiplikation 2 Millisekunden, Division 4 Millisekunden.
Mark I (Williams, Kilburn) (1949–51)
3800 Röhren, Taktfrequenz 100 kHz, binärer Rechner, serielle Arbeitsweise, erstmalig ein
Indexregister, 256 (schnelle) Speicherplätze (mit Williamsröhren realisiert),
16384 (langsame) Speicherplätze auf einer Magnettrommel.
Derartige Maschinen wurden fast ausschließlich in Maschinensprache programmiert, aber es gab
bereits die ersten Ansätze, die mühevolle und fehleranfällige Programmierung in Maschinensprache zu umgehen.
Um einige der ersten Programmiersprachen vorstellen zu können, soll jeweils als Beispiel (soweit
möglich) der TPK-Algorithmus programmiert werden. Dieser Algorithmus wurde von Trabb Pardo und Knuth in ihrem Artikel über alte Programmiersprachen vorgestellt, der auch Grundlage
für diesen Teil der Einleitung ist7 .
6
7
siehe: W. de Beauclair, Rechnen mit Maschinen
siehe: D. E. Knuth, L. Trabb Pardo, The Early Development of Programming Languages
6
1
EINLEITUNG
Zunächst zum Vergleich eine moderne“ Version dieses Algorithmus:
”
TPK-Algorithmus in Pascal
program TPK
var i: integer;
y: real;
a: array [0..10] of real;
function f (t: real) : real;
begin
f := sqrt(abs(t)) + 5*t*t*t
end;
begin
for i:= 0 to 10 read (a[i]);
for i:= 10 downto 0 do
begin
y := f(a[i]);
if y > 400 then
begin
write(i);
writeln(’TOO LARGE’)
end
else
write(i, y)
end
end;
Bei der Formulierung dieses Algorithmus in den verschiedenen Sprachen müssen ab und zu
einige Vereinfachungen vorgenommen werden. So sind eventuell Gleitkommazahlen, selbstdefinierte Funktionen oder auch eine Ein- und Ausgabe nicht vorhanden. In diesen Fällen wird der
Algorithmus entsprechend vereinfacht.
Da Konrad Zuse 1945 keine neuen Rechner konstruieren konnte, entwickelte er den Plankalkül, eine an Begriffen der Aussagenlogik und des Prädikatenkalküls angelehnte Programmiersprache“.
”
Er schrieb eine ganze Reihe von Programmen in dieser hypothetischen Programmiersprache, so
z. B. Sortierprogramme, eine Gleitpunktarithmetik, eine Syntaxprüfung logischer Formeln und
ein 49 Seiten langes Schachprogramm. Der Plankalkül enthielt viele Merkmale nachfolgender
Programmiersprachen, z. B. eine break- und eine continue-Anweisung, um Schleifen kontrolliert
zu beenden, wurde jedoch lange Zeit nicht implementiert. 8
Eine erste Implementation wurde aus historischen Gründen im Jahr im Rahmen einer Dissertation 1975 erstellt, weitere Implementationen folgten Ende der 90-Jahre an der FU Berlin.
8
siehe: F. L. Bauer, H. Wössner, The Plankalkül“ of Konrad Zuse
”
1.2
Historische Entwicklung der Programmiersprachen
7
Der TPK-Algorithmus in Plankalkül
A2 = (A9,A∆1)
P1
R(V)
V
0
A
∆1
=⇒ R
0
∆1
|V| + 5 × V3 =⇒ R
0
0
0
∆1
∆1
∆1
p
V
A
P2
V
A
R(V) =⇒ R
0
0
11×∆1
11×2
W2(11)
=⇒ Z
0
V
K
A
R1(V)
0 0
i
∆1
V
Z > 400 → (i,+∞) =⇒ R
0
0
K
A
∆1
V
Z > 400 → (i,
0
Z) =⇒ R
0
0
K
A
∆1
∆1
∆1
9
9
2
2
(10-i)
9
(10-i)
9
Zeile 1 erklärt den Datentyp A2, der ein Paar aus einer Integer-(A9) und einer Gleitpunktzahl
(A∆1) darstellt. Zeilen 2 bis 7 definieren die Funktion f; die restlichen Zeilen definieren das
Hauptprogramm. Da es keine Ein- und Ausgabefunktionen in Plankalkül gibt, wird hier angenommen, dass die Eingabewerte und Ergebnisse in einem Feld abgelegt werden.
Mehrere untereinanderstehende Zeilen sind als zusammengehörig zu betrachten, wobei die erste
Zeile den Namen von Variablen (R für Resultatwert, V für Variable und Z für Zwischenwert)
und die zweite den Index dieser Variablen angibt. Die dritte, mit K bezeichnete Zeile gibt,
sofern vorhanden, die Teilkomponente und die vierte, mit A bezeichnete Zeile gibt den Typ der
Variablen an.
8
1
EINLEITUNG
Für den UNIVAC (Universal Automatic Computer) entwickelte W. F. Schmitt nach Ideen von
J. W. Mauchly in den Jahren 1950–52 einen algebraischen Interpreter, Short Code genannt, der
eine verschlüsselte Eingabe las und interpretativ abarbeitete. Jede Formel wurde per Hand in
Maschinenworte übersetzt“ , und diese wurden dann vom Short Code Interpreter abgearbeitet.
”
TPK-Algorithmus in Short Code
Speicherbelegung: i = W0, t = T0, y = Y0.
Die elf Eingaben kommen nacheinander in die Speicherzellen U0,T9,. . .,T0.
Konstanten:
Labels:
Z0
Z1
Z2
Z3
Z4
Z5
=
=
=
=
=
=
000000000000
010000000051
010000000052
040000000053
TOO LARGE
050000000051
(1.0 floating decimal form)
(10.0)
(400.0)
(5.0)
0 = Zeile 1, 1 = Zeile 6, 2 = Zeile 7
Short Code:
0:
1:
2:
Maschinenworte mit Codierung
i = 10
√
y = ( abs t) +5 cube t
y 400 if ≤ to 1
i print,’TOO LARGE’ print-ret
0 0 if = to 2
i print, y print-return
T0 U0 shift
i = i-1
0 i if ≤ to 0
stop
00
T0
00
00
00
00
00
00
00
00
00
00
02
Y0
00
00
00
00
00
W0
00
00
00
07
03
00
Z4
00
Y0
00
03
00
00
W0
Z5
09
Y0
59
Z0
59
T0
W0
Z0
00
03
11
20
Z3
W0
Z0
W0
U0
01
W0
ZZ
Z2
T0
06
41
58
72
58
99
Z1
40
08
Code-Operator-Zuordnung:
01 −
06 abs value 1n
(n+2)te Potenz
02
)
07
+
03
=
08
pause
4n
if ≤ to n
04
/
09
(
58
print und tab
59
2n (n+2)te Wurzel 7n
print und return
if = to n
99 zykl. Shift des Speichers
00
no operation
1.2
Historische Entwicklung der Programmiersprachen
9
AUTOCODE wurde 1952 von A. E. Glennie für den Manchester MARK I Rechner entworfen
und war die erste Programmiersprache, die wirklich in die Maschinensprache des Rechners, die
in diesem Fall besonders abstrus war, übersetzt wurde.
TPK-Algorithmus in AUTOCODE
c@VA t@IC x@1 /2 C y@RC z@NC
INTEGERS +5 → c
→ t
+ t TESTA Z
-t
ENTRY Z
SUBROUTINE 6 → z
+ tt → y → x
+ tx → y → x
+ z + cx CLOSE WRITE 1
a@/1 /2 b@MA c@GA d@OA e@PA f@HA i@VE x@ME
INTEGERS +20 → b +10 → c +400 → d +999 → e +1 → f
LOOP 10n
n → x
+ b - x → x
x → q
SUBROUTINE 5 → aq
REPEAT n
+ c → i
LOOP 10n
+ an SUBROUTINE 1 → y
+ d - y TESTA Z
+ i SUBROUTINE 3
+ e SUBROUTINE 4
CONTROL X
ENTRY Z
+ i SUBROUTINE 3
+ y SUBROUTINE 4
ENTRY X
+ i - f → i
REPEAT n
ENTRY A CONTROL A WRITE 2 START 2
10
1
EINLEITUNG
Ein Team unter der Leitung von John Backus entwickelte 1954 bei IBM die Sprache FORTRAN
(Formula Translation) für wissenschaftliche Programmierung. Im Vordergrund stand die Frage
nach einem effizienten Objektcode — er sollte vergleichbar mit dem Code eines guten Assemblerprogrammierers sein. FORTRAN wurde im Lauf der Jahre weiterentwickelt (FORTRAN II,
FORTRAN IV, FORTRAN 66, FORTRAN 77, Fortran90, Fortran95 bis hin zu Fortran2003)
und wurde dank der Unterstützung von IBM sehr populär. Die ersten Compiler wurden 1957
ausgeliefert9 und lieferten wie auch viele der nachfolgenden FORTRAN-Compiler sehr effizienten Maschinencode. Dies ist neben der großen Zahl von in FORTRAN geschriebenen Unterprogrammpaketen speziell für numerische Anwendungen der wichtigste Grund für den Fortbestand
dieser Programmiersprache.
Durch FORTRAN wurden Felder, auf deren Elemente durch Indizes zugegriffen werden kann,
Schleifen mit Laufindex und verzweigende IF-Anweisungen eingeführt. Wichtig für den Erfolg
war auch die Einführung eines FORMAT-Interpreters für die formatierte Ein- und Ausgabe.
TPK-Algorithmus in FORTRAN 1
C
1
4
5
8
9
10
THE TPK-ALGORITHM IN FORTRAN I
FUNF(T) = SQRTF(ABSF(T))+5.0*T**3
DIMENSION A(11)
FORMAT (6F12.4)
READ 1,A
DO 10 J = 1,11
I = 11-J
Y = FUNF(A(I+1))
IF (400.0 - Y) 4,8,8
PRINT 5,I
FORMAT (I10, 10H TOO LARGE)
GO TO 10
PRINT 9,I,Y
FORMAT (I10,F12.7)
CONTINUE
STOP
1959 wurde unter der Leitung von Grace Hopper vom Verteidigungsministerium der USA in
Verbindung mit Computerherstellern und Anwendern eine neue Programmiersprache entwickelt,
die für kaufmännische Anwendungen gedacht war. Diese Sprache, COBOL (Common Business
Oriented Language) zeichnet sich durch eine starke Verbalisierung, umfangreiche Formatierungsmöglichkeiten der Daten und Einführung der Record-Struktur aus. Allerdings hatte die
Sprache kein Prozedurkonzept. COBOL war eine Zeit lang die am meisten benutzte Programmiersprache der Welt. Dies hat seine Gründe u. a. auch in der frühzeitigen Standardisierung der
Sprache und damit in der Kompatibilität zwischen verschiedenen Compilern.
9
siehe: J. Backus, The History of FORTRAN I, II and III
1.2
Historische Entwicklung der Programmiersprachen
TPK-Algorithmus in COBOL
IDENTIFICATION DIVISION.
PROGRAM-ID. TPK-Algorithmus.
AUTHOR. mak.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SPECIAL-NAMES.
CONSOLE IS CRT,
DECIMAL-POINT IS COMMA.
INPUT-OUTPUT SECTION.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
77 i PIC S99.
01 y USAGE IS COMPUTATIONAL-1.
01 a-hilf.
02 a USAGE IS COMPUTATIONAL-1 OCCURS 11 TIMES.
LINKAGE SECTION.
PROCEDURE DIVISION.
PERFORM VARYING i FROM 1 BY 1 UNTIL i > 11
ACCEPT a(i)
END-PERFORM.
PERFORM VARYING i FROM 11 BY -1 UNTIL i < 1
PERFORM BERECHNUNG
IF y > 400 THEN
DISPLAY i
DISPLAY "TOO LARGE"
ELSE
DISPLAY i
DISPLAY y
END-IF
END-PERFORM.
STOP RUN.
BERECHNUNG.
IF a (i) IS NEGATIVE THEN
COMPUTE y = (- a(i)) ** 0,5 + 5*a(i)*a(i)*a(i)
ELSE
COMPUTE y = a(i) ** 0,5 + 5*a(i)*a(i)*a(i)
END-IF.
11
12
1
EINLEITUNG
In Europa entstand etwa zur gleichen Zeit die Sprache ALGOL 60 (Algorithmic Language), die
von einem Komitee definiert wurde. Diese Sprache hatte einen gewaltigen Einfluss auf die nachfolgenden Programmiersprachen. Erstmalig gab es in einer Programmiersprache Blockstruktur,
rekursive Prozeduren, explizite Deklaration von Variablen, reservierte Wörter, dynamische Felder und eine formatfreie Eingabe. Grundlegend neu war auch, dass die Syntax von ALGOL
durch eine formale Spezifikation mit einer kontextfreien Grammatik (Backus-Nauer-Form) definiert wurde. Die Sprache wurde die Referenzsprache zur Veröffentlichung von Algorithmen;
wirtschaftlichen Erfolg hatte sie jedoch nicht.
ALGOL ist der Prototyp einer sogenannten imperativen Programmiersprache, d. h. einer Programmiersprache, die Variablen verwendet und Anweisungen bereitstellt, um die Werte von
Variablen zu verändern. Charakteristisch ist dabei die Verwendung von Wertzuweisungen. Die
meisten der heute verwendeten imperativen (man spricht auch von prozeduralen) Sprachen wie
Pascal, C, Modula-2, Ada und Java sind Weiterentwicklungen von ALGOL 60.
TPK - Algorithmus in ALGOL 60
begin
integer i; real y; real array a[0:10];
real procedure f(t); real t; value t;
f := sqrt(abs(t))+5*t↑3;
for i := 0 step 1 until 10 do read (a[i]);
for i := 10 step -1 until 0 do
begin
y := f(a[i]);
if y > 400 then write (i,’too large’)
else write (i,y)
end
end
Eine weitere wichtige Programmiersprache ganz anderen Typs wurde ebenfalls in dieser Zeit
(1958) entwickelt. John McCarthy wollte ursprünglich eine Erweiterung von FORTRAN für
Listenmanipulationen konstruieren. Daraus entwickelte sich eine eigenständige Programmiersprache, nämlich Lisp (List Processor), die speziell im Bereich der künstlichen Intelligenz große
Verbreitung fand10 . Lisp basiert auf dem mathematischen lambda Kalkül von Church und Kleene.
In Lisp werden sowohl Daten wie auch Programme als Listen in einer Klammerschreibweise dargestellt (sog. S-Ausdrücke). Die Rekursion ist in Lisp die fundamentale Steuerstruktur. Speicher
für Listenelemente wird dynamisch zur Laufzeit bereitgestellt, und es gibt ein Garbage-CollectorVerfahren, um nicht mehr benötigten Speicher wieder zugänglich zu machen. Funktionen sind
in Lisp normale“ Datenobjekte, die selbst in Form einer Listenstruktur dargestellt werden.
”
10
J. McCarthy, History of Lisp, in R. L. Wexelblet (Ed), History of Programming Languages, 1981
1.2
Historische Entwicklung der Programmiersprachen
13
Wichtigstes Merkmal von Lisp ist jedoch, dass Berechnungen allein durch Anwendungen von
Funktionen auf Daten ausgeführt werden und es keine üblichen“ Variablen gibt. Man spricht
”
aus diesem Grund auch von funktionaler oder applikativer Programmierung. Lisp ist natürlich
weiterentwickelt worden; moderne Varianten sind z. B. Scheme, Common Lisp, CLOS, ML oder
Haskell.
TPK - Algorithmus in ML
exception TooLarge;
fun tpk1(x) = if f(x) > 400.0 then
raise TooLarge
else f(x);
fun tpk2(x) = tpk1(x) handle
TooLarge => (print("too large\n");
0.0);
fun tpk(x) = map tpk2 (x);
Nachdem sich mit den ersten Programmiersprachen die Kenntnisse über Spezifikation und Übersetzung von Programmiersprachen verbreiteten, gab es eine Flut von neuen Sprachen. Zu nennen
wären unter anderem:
PL/I
1965 in der ersten Fassung als NPL bezeichnet. Ziel war die Vereinigung der wichtigsten
Konzepte von FORTRAN, COBOL und ALGOL. Herausgekommen ist eine Anhäufung
von sich teilweise widersprechenden Features“ , z. B. gibt es für Variablen wahlweise
”
eine statische Speicherzuordnung (wie in FORTRAN) oder eine Blockstruktur (wie in
ALGOL) oder aber eine dynamische Speicherzuordnung über explizite Aufrufe (wie etwa
in Pascal). Ohne die intensive Unterstützung der IBM wäre diese Sprache wohl kaum
erfolgreich geworden.
ALGOL 68
entstand durch systematische Verallgemeinerung von ALGOL 60. Es sollten wenige, aber
beliebig kombinierbare Sprachkonzepte in der Sprache Verwendung finden. Diese Sprache
hatte außerhalb der Universitäten nur geringe Akzeptanz, da die formale Definition über
zweischichtige Grammatiken festgelegt wurde, die Handbücher zur Sprache fast nicht lesbar
waren und damit der Zugang zur Sprache sehr schwierig war.
SNOBOL
von Färber, Griswold und Polonsky 1964 vorgestellt, war eine Spezialsprache für die
Zeichenkettenverarbeitung. Moderne Nachfolger sind SNOBOL 4 und ICON, aber auch
Skriptsprachen wie etwa Perl oder Tcl.
BASIC
wurde 1963 von Kurz und Kemeny vorgestellt. BASIC (Beginners All-purpose Symbolic Instruction Code) war konzipiert als eine einfache Sprache speziell für Studenten, die
nicht im technisch-naturwissenschaftlichen Bereich studieren. Weil die Sprache zu Anfang
14
1
EINLEITUNG
ausschließlich interpretativ abgearbeitet wurde und relativ klein und einfach war, eignete
sie sich gut für die ersten Home Computer“ , die auf den Markt kamen. Bill Gates hat
”
seine ersten Lorbeeren (und Dollars) in der Computerindustrie mit der Entwicklung eines
Basic-Interpreters für einen der ersten Home-Computer verdient.
Simula 67
wurde 1967 von O. J. Dahl und K. Nygaard als eine ALGOL-ähnliche Sprache vorgestellt,
die spezielle Erweiterungen für die diskrete Simulation enthielt. In dieser Sprache wurde
erstmalig das Klassenkonzept als Erweiterung des Blockkonzeptes eingeführt. Eine Klasse
besteht dabei aus einer Menge von Datenvereinbarungen und Prozeduren. Ein Objekt einer
Klasse kann dynamisch zur Laufzeit erzeugt werden und hat eine Lebensdauer, die nicht an
die Blockstruktur gebunden ist. Simula legte damit die Grundlage der objekt-orientierten
Programmierung. Diese Konzepte findet man z. B. in relativ reiner Form in Smalltalk,
oder aber auch in Verbindung mit anderen Konzepten höherer Programmiersprachen in
C++, Delphi, Eiffel, Java und Python wieder.
Smalltalk Smalltalk entstand Anfang der 70er Jahre im Xerox Forschungslabor in Palo Alto
im Rahmen des Dynabook Projekts. Das Dynabook basierte auf einer Idee von A. Kay
für einen persönlichen Rechner, der für die damaligen Zeiten eine revolutionäre graphische Benutzeroberfläche anbot. Informationen wurden in überlappenden Fenstern angezeigt und die Steuerung des Rechners geschah über eine Menüsteuerung mit Hilfe einer
Maus. Weiterhin sollte mit dem Dynabook Musik verarbeitet werden können und es sollte eine Möglichkeit geben, über Datenleitungen eine Verbindung zu anderen Geräten oder
größeren Datenbanken herzustellen. Das gesamte System wurde in einer neuen, rein objektorientierten Programmiersprache namens Smalltalk implementiert. Smalltalk Programmcode wurde von einem Compiler in einen Bytecode übersetzt und dieser wird dann von
einem Interpreter, der Smalltalk Virtual Machine“, abgearbeitet.
”
Pascal
wurde 1971 von N. Wirth als Antwort“ auf das seiner Meinung nach zu mächtige
”
ALGOL 68 konstruiert. Trotz vieler Einschränkungen in der Sprache wurde Pascal,
speziell als Ausbildungssprache, sehr beliebt. Abgelöst wurde Pascal Ende der 80er Jahre
durch Modula-2 und Oberon. Für praktische Zwecke wurde die Sprache erst durch Erweiterungen wie etwa in Borlands Turbo-Pascal brauchbar. Eine objektorientierte Erweiterung
von Pascal ist Delphi.
Prolog
wurde 1972 von A. Colmerauer entwickelt. Prolog ist eine nicht prozedurale Sprache, in
der versucht wird, einen Teil der mathematischen Logik direkt als Programmiersprache zu
nutzen. Eine Sammlung von Regeln bildet eine Datenbasis, und man kann Anfragen an
diese Datenbasis stellen. Das System versucht dann, durch logisches Schließen die Anfrage
aus der Datenbasis zu beantworten. Prolog definiert wiederum einen speziellen Typ von
Programmierung, die sogenannte logische oder auch deklarative Programmierung und ist
die wichtigste Programmiersprachen für sogenannte Expertensysteme“.
”
Ada
Anfang der 80er Jahre erschien nach langer Konzeptionszeit eine vom amerikanischen Verteidigungsministerium geforderte und initiierte Programmiersprache, nämlich Ada. Benannt wurde sie nach Ada Countess of Lovelace, der ersten Programmiererin. Wie PL/I
1.2
Historische Entwicklung der Programmiersprachen
15
wollte man eine allgemeine Sprache für ein möglichst weites Anwendungsspektrum entwickeln. Ada enthält neue Sprachkonzepte zur Kapselung von Daten (packages), zur Parallelverarbeitung (tasks) und zur Ausnahmefall-Bearbeitung (exceptions) und eignet sich
damit auch als Programmiersprache zur Steuerung komplexer technischer Systeme. Ada
wird viel im militärisch-technischen Bereich benutzt.
C und C++
C wurde 1972 von Dennis Ritchie als Programmiersprache geschaffen, um große Teile des
UNIX-Betriebssystems in einer höheren Sprache schreiben zu können. Der Erfolg von C
beruht weniger auf neuen Konzepten im Sprachentwurf, sondern mehr auf dem Erfolg von
UNIX. C erlaubt eine relativ maschinennahe Programmierung, verleitet jedoch manchmal
zur Trickprogrammierung“ . Ende 1989 wurde C vom ANSI-Komitee standardisiert. Das
”
sog. ANSI-C bietet dem Programmierer die gleiche Sicherheit“ wie etwa Pascal (z. B.
”
durch Typprüfung usw.), ohne ihm die Möglichkeiten der maschinennahen Programmierung zu nehmen. Eine Weiterentwicklung in Richtung auf objekt-orientierte Programmierung wurde Anfang der 80er Jahre durch B. Stroustrup mit der Sprache C++ vorgenommen. Sowohl C als auch C++ sind Programmiersprachen, in denen heute ein Großteil
der Betriebssystem- und Anwendungssoftware im Personal-Computer und WorkstationBereich geschrieben wird.
Java
entstand 1991 aus einer Entwicklung eines Teams um J. Gosling bei Sun Microsystems. Es
sollte versucht werden, eine plattformunabhängige, objektorientierte Software für Geräte
der Unterhaltungselektronik zu entwickeln, die z.B. über Fernsehkanäle verschickt und
dann in entsprechende Endgeräte geladen wird. Zunächst war diese Entwicklung kein
großer Erfolg, denn niemand hatte auf eine derartige Lösung gewartet. Mit der Entwicklung des World Wide Web (WWW) eröffnete sich eine neue Anwendungsmöglichkeit für
das System, das dann auch den Namen Java bekam. 1996 wurde die erste Version der
Entwicklungsumgebung Java Development Kit (JDK) vorgestellt. Java Programme werden vom Compiler in eine Zwischensprache, den Java Byte Code, übersetzt. Dieser wird
dann auf dem Zielrechner mit einem Interpreter, der Java Virtual Machine (JVM), ausgeführt. Java enthält viele wesentliche Konzepte der objektorientierten Programmierung
und basiert aus Gründen der besseren Akzeptanz auf C bzw. C++. Allerdings verzichtet Java auf einige der komplexeren Elemente von C++, etwa der Mehrfachvererbung
von Klassen. Momentan scheint Java sich als Programmiersprache für die Anwendungsprogrammierung gegenüber C bzw. C++ durchzusetzen, da die Objektorientierung eine
leichtere Wiederverwendbarkeit der Software verspricht und durch das Interpreterprinzip
eine größere Maschinenunabhängigkeit erzielt werden kann.
Einen Überblick über eine Vielzahl von Programmiersprachen und Hinweise auf weitere Informationen zu einzelnen Sprachen bekommt man über die WWW-Seiten von Éric Lévénez11 und
Bill Kinnersley12 .
11
12
http://www.levenez.com/lang/
http://people.ku.edu/~nkinners/LangList/Extras/langlist.htm