1 Wie ist eine Programmiersprache aufgebaut?

1.1 Kann Delphi lesen?
1.2 Formale Sprachen
1.3 Syntax-Diagramme

Zum Inhaltsverzeichnis Zum nächsten Kapitel


1.1 Kann Delphi lesen?

Haben Sie sich auch schon gelegentlich über die Fehlermeldungen von Delphi gewundert? Da verkündet uns dieses Programm zum Beispiel: und stellt dann alle weiteren Aktivitäten ein, bis wir den Fehler behoben haben. Woher "weiß" Delphi, was an dieser Stelle "zu erwarten" ist? Wie kann ein Programm überhaupt eine Erwartungshaltung aufbauen? Gehört dazu nicht viel mehr Bewusstsein und Überblick, als wir üblicherweise einer Maschine (oder einem Programm) zuschreiben wollen?

Erstaunlicherweise hat Delphi mit der obigen Fehlermeldung meistens recht. Zwar steht der Cursor im Quelltext in der Regel nicht direkt an der Stelle, an der wir das fehlende ";" einfügen werden, sondern in der folgenden Zeile, aber die Fehlermeldung ist durchaus korrekt: es fehlt wirklich ein Semikolon! Offenbar "versteht" Delphi den Programmtext in einer bestimmten Art und Weise tatsächlich; und anscheinend kann der Compiler auch eine "Erwartungshaltung" aufbauen, aus der heraus er die realen Gegebenheiten unseres Programmtextes "in intelligenter Weise" zu bewerten imstande ist. Der Compiler geht also durch den Programmtext durch und stoppt an genau der Stelle, an der er ihn nicht mehr versteht. An dieser Stelle wird der Text also sinnlos - zum Beispiel, weil das jetzt ein ";" kommen müsste, aber ein anderes Zeichen kommt!

Wie kann ein Programm den Sinn eines Textes erfassen? Alles in uns sträubt sich gegen die Vorstellung, dass eine Maschine (oder ein Programm - ist das ein wesentlicher Unterschied?) imstande sein sollte, den Sinn eines Textes zu erfassen, mithin also "mit Verstand" zu lesen. Das sollte doch uns Menschen vorbehalten bleiben, oder nicht? Trotzdem: Delphi versteht nachgewiesenermaßen in vielen Fällen mehr von Object Pascal als wir. Man ist gut beraten, beim Programmieren die Fehlermeldungen des Compilers sehr aufmerksam zu studieren. Delphi ist im Grunde sogar der beste Experte für Object Pascal, der denkbar ist!

Aber damit ist auch die Grenze des Erkenntnishorizonts von Delphi markiert: während wir neben Pascal-Quelltexten auch "Die Buddenbrocks" von Thomas Mann lesen können, wäre Delphi damit völlig überfordert. Es würde schon in der ersten Zeile eine Fehlermeldung ausgeben, zum Beispiel:
oder irgend eine andere Meldung, je nach dem, an welcher Stelle des Quelltextes wir den Romantext einfügen würden. In jedem Fall offenbart uns die Fehlermeldung durch ihre offensichtliche Unsinnigkeit, dass Delphi diesen Text "nicht versteht" (wobei man die Anführungszeichen eigentlich auch weglassen kann).

Was aber ist der wesentliche Unterschied zwischen einem Pascal-Quelltext und den "Buddenbrocks"? Es ist die Struktur des Textes. Pascal-Quelltexte müssen nach ganz bestimmten, sehr eng gefassten Regeln aufgebaut sein, während es in der "normalen Sprache" (und erst recht in der von Thomas Mann!) eine viel größere Gestaltungsfreiheit gibt. Somit reicht der Verständnishorizont des Delphi-Compilers also nur bis an den Rand der Sprache Object Pascal; alles was darüber hinaus geht, ist für den Compiler im wahrsten Sinne des Wortes "sinnlos".





1.2 Formale Sprachen

Die Menge der Regeln, denen eine Sprache gehorcht, nennt man die Syntax dieser Sprache. Für die natürliche Sprache gehören dazu die üblichen Regeln über Rechtschreibung, Satzzeichen und Grammatik. Ein typisches Merkmal lebender Sprachen ist aber, dass die Regeln oft nicht global gelten. Wer eine Fremdsprache lernt, weiß um die berüchtigten Ausnahmen, wie zum Beispiel die "unregelmäßigen(!) Verben". Solche Regelverstöße verkomplizieren das Erlernen der Sprache und erschweren die umfassende Darstellung der möglichen Sprachstrukturen.

Pascal ist demgegenüber eine künstliche Sprache, deren Syntax nur Regeln ohne Ausnahmen kennt. Aufgrund dieser Regeln kann von jedem beliebigen Text entschieden werden, ob er in "korrektem Pascal" geschrieben ist oder nicht. Eine solche Sprache nennt man eine "formale Sprache".

Wenn man die Regeln einer formalen Sprache kennt, dann kann man in der Tat ohne großen Aufwand eine Erwartungshaltung aufbauen. Als Beispiel betrachten wir in Pascal eine WHILE-Schleife. Umgangssprachlich formuliert hat sie stets die folgende Struktur:
  1. Als erstes kommt das Schlüsselwort "WHILE".
  2. Es folgt eine (Durchführungs-) Bedingung.
  3. Dann kommt das Schlüsselwort "DO".
  4. Es folgt eine Anweisung.
  5. Zum Schluß kommt das Zeichen ";"

Diese Struktur ist bei allen WHILE-Schleifen in allen Pascal-Programmen gleich. Was sich ändert, sind die Inhalte der jeweiligen Bedingung und der Anweisung im Schleifenrumpf. Die Abfolge der 5 oben aufgeführten logischen Sprachelemente bleibt aber stets dieselbe. Wenn Sie es übers Herz bringen, mal für kurze Zeit in Gedanken in die Rolle eines Delphi-Compilers zu schlüpfen, dann können Sie nachvollziehen, wie dieser eine WHILE-Schleife wahrnimmt:
Solange der Kompilierungsvorgang erfolgreich verläuft, "weiß" der Compiler also, was er zu "erwarten" hat, weil dies in den ihm "bekannten" Syntax-Regeln der Sprache Pascal festgelegt ist! In diesem Sinne kann Delphi einen korrekten Pascal-Quelltext tatsächlich verstehen - und diesmal wirklich und absichtlich ohne Anführungszeichen! Der Delphi-Compiler beweist uns nämlich, dass er den Quelltext wirklich verstanden hat, indem er das zu diesem Quelltext gehörende Maschinenprogramm auf die Festplatte schreibt! "Verstehen" heißt: "sinnvoll reagieren können". Und genau das tut der Compiler, wenn er aus Ihrem Quelltext eine Serie von Prozessorbefehlen erzeugt!

Für die Skeptiker, denen der Compiler in dieser Beschreibung zu anthropomorphe Züge trägt, sei noch folgendes klargestellt: es wird nicht etwa behauptet, dass der Compiler die im Quelltext niedergelegten Algorithmen versteht, sondern nur, dass er den ihm vorgelegten Quelltext versteht. Er könnte diesen natürlich nicht selbst schreiben! In kluger Selbstbeschränkung haben die Konstrukteure des Compilers ja sogar darauf verzichtet, ihn das erwartete, aber fehlende Semikolon in Eigenregie hinzufügen zu lassen - und das ist gut so! Warum wohl?




1.3 Syntax-Diagramme


Zur Darstellung der Syntaxregeln einer formalen Sprache haben sich die Mathematiker verschiedene Verfahren ausgedacht. Besonders anschaulich und leicht verständlich sind die Syntax-Diagramme. Wie solche Diagramme beschaffen sind, wollen wir anhand einiger Beispiele klären. Dabei wählen wir eine formale Sprache, die wir schon gut kennen, nämlich Pascal. Sie wissen, dass es in einer Programmiersprache nur wenige sprachlogische Grundstrukturen gibt (nämlich Sequenz, Entscheidung und Wiederholung), und wir haben diese in einem früheren Kapitel schon mit Hilfe von Struktogrammen dargestellt. Hier wollen wir sie nun mit Hilfe der Syntax-Diagramme nochmals veranschaulichen.

Nehmen wir als erstes Beispiel die WHILE-Schleife, deren Pascal-Syntax wir im vorigen Abschnitt schon verbal beschrieben haben. Hier nochmals die Beschreibung, aber nur im Telegrammstil:
In dieser Beschreibung gibt es zwei verschiedene Sorten von "Symbolen":
  1. in Anführungszeichen stehende Zeichenketten
  2. normale Zeichenketten
Von den ersten wissen wir, dass das, was da in den Anführungszeichen steht, genau so, Zeichen für Zeichen, im Programmtext auftauchen muss. Solche Zeichenketten heißen Terminalsymbole. Anstelle des Wortes "Bedingung" oder "Anweisung" wird jedoch in kaum zwei WHILE-Schleifen das gleiche stehen - schließlich haben die Schleifen üblicherweise unterschiedliche Aufgaben zu erledigen! Symbole, die für jeweils spezifische bzw. noch näher zu spezifizierende Inhalte stehen, bezeichnen wir als Nicht-Terminal-Symbole. Wenn wir Terminalsymbole mit einem runden (bzw. abgerundeten) Rahmen umgeben, Nicht-Terminal-Symbole hingegen mit einem rechteckigen, dann kann man die Struktur der WHILE-Schleife auf die folgende naheliegende Art veranschaulichen:

Syntax-Diagramm 'WHILE'

Eine solche Darstellung nennt man ein Syntax-Diagramm: es wird stets längs der Verbindungslinien durchlaufen, wobei wir zu Beginn von links kommen und das Diagramm schließlich nach rechts verlassen. (Bei komplizierteren Syntax-Diagrammen kann die Reise unterwegs durchaus auch mal von rechts nach links gehen - soweit es die eingezeichneten Verbindungslinien eben erlauben.) Alle Verbindungslinien sind als Einbahnstraßen gemeint. Die Richtung, in der sie "offen" sind, ergibt sich beim Durchlaufen aus der Regel, dass scharfe Knicke der Bahn zu vermeiden sind. Gelegentlich werden die Verbindungen zur Verdeutlichung mit Orientierungspfeilen versehen; wir verzichten jedoch hier auf diese kosmetischen Ergänzungen und vertrauen auf das geometrische Einfühlungsvermögen des Lesers. Beim vorliegenden Syntax-Diagramm der WHILE-Schleife ist dies auch kein Problem, weil es ja ohnehin nur einen linearen Weg gibt, auf dem die vorgeschriebenen Elemente von links nach rechts abgearbeitet werden müssen.

Als zweites Beispiel wollen wir uns die Entscheidung in Pascal durch ein Syntax-Diagramm veranschaulichen. Sie beginnt stets mit dem Schlüsselwort "IF", dem eine Bedingung folgt. Danach kommt stets das Schlüsselwort "THEN", gefolgt von einer Anweisung. Möglicherweise ist damit die Entscheidung schon beendet und es folgt der abschließende Strichpunkt. Es kann aber auch das Schlüsselwort "ELSE" kommen und dann eine weitere "Anweisung". Insgesamt erhält man also das folgende Syntax-Diagramm:

Syntax-Diagramm 'IF-THEN'

Nach der Anweisung des THEN-Teils haben wir nun eine Verzweigung in unserem Diagramm: entweder wir gehen geradeaus zum ";" und verzichten auf einen ELSE-Teil oder wir gehen zum Terminalsymbol "ELSE", dem dann aber notwendigerweise eine Anweisung und der abschließende Strichpunkt folgen muss.

Syntax-Diagramme bieten eine sehr elegante Möglichkeit, sich schnell einen Überblick über die Strukturen einer Programmiersprache zu verschaffen. Sie helfen darüber hinaus auch bei der Entscheidung, ob ein gegebener Programmtext "syntaktisch korrekt" ist, d.h. den Sprachregeln entspricht:

In einer formalen Sprache ist ein Text genau dann syntaktisch korrekt, wenn er auf einem zulässigen Weg durch die Syntax-Diagramme dieser Sprache erzeugt werden kann.

So ist zum Beispiel eine IF-Konstruktion ohne ELSE-Teil korrekt, wohingegen ein ";" vor dem ELSE-Teil einen Fehler darstellt: es gibt keine Möglichkeit, das Syntax-Diagramm der Entscheidung so zu durchlaufen, dass nach der Anweisung des THEN-Teils ein ";" kommt und danach noch ein ELSE-Teil folgt!





Aufgaben:

  1. Die Repeat-Schleife

    Entwerfen Sie ein Syntax-Diagramm für die REPEAT-Schleife. Sie können zunächst vereinfachend annehmen, dass der Schleifenrumpf wie bei der WHILE-Schleife nur aus genau einer Anweisung besteht. Wenn Sie diese vereinfachte Version erfolgreich erledigt haben, sollten Sie das Diagramm aber erweitern und eine Sequenz von Anweisungen zwischen REPEAT und UNTIL zulassen.
    [Lösungsvorschlag]


  2. Die LAL-Sprache

    Die folgenden Regeln beschreiben, wie die Wörter der LAL-Sprache aufgebaut sind:
    1. Jedes LAL-Wort beginnt mit einem 'L'.
    2. Wenn nach einem 'L' noch etwas kommt, dann ist es entweder ein LAL-Wort oder ein 'A'.
    3. Nach jedem 'A' kommt ein 'L'.
    Zeichnen Sie ein Syntax-Diagramm (oder Syntax-Diagramme?) für die LAL-Wörter.
    Prüfen Sie dann, ob 'LAL', 'LALAL', 'LALLAL', 'LLALLAL', 'LLLALAL' und 'LALALA' gültige Wörter der LAL-Sprache sind.
    [Lösungsvorschlag]





Zum Inhaltsverzeichnis Zum nächsten Kapitel