09.03.2014 Aufrufe

Programmierrichtlinien (PDF)

Programmierrichtlinien (PDF)

Programmierrichtlinien (PDF)

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 1<br />

<strong>Programmierrichtlinien</strong> für<br />

Modula-2<br />

Diese <strong>Programmierrichtlinien</strong> sind für alle Modula-2-Programme, die im Rahmen des<br />

Programmierkurses entstehen, verbindlich.<br />

Inhaltsverzeichnis<br />

1 Motivation......................................................................................................................... 2<br />

2 Programmkonstrukte ...................................................................................................... 2<br />

2.1 Module......................................................................................................................... 2<br />

2.2 Prozeduren.................................................................................................................. 4<br />

2.3 Variable........................................................................................................................ 4<br />

2.4 Konstanten .................................................................................................................. 4<br />

2.5 Typen ........................................................................................................................... 5<br />

2.6 Verwendung von Modula-2-Konstrukten.............................................................. 5<br />

2.7 Verschachtelung und Länge von Programmteilen ............................................... 6<br />

3 Namenskonventionen..................................................................................................... 7<br />

3.1 Allgemeines................................................................................................................. 7<br />

3.2 Module......................................................................................................................... 8<br />

3.3 Prozeduren.................................................................................................................. 8<br />

3.4 Variablen ..................................................................................................................... 8<br />

3.5 Konstanten .................................................................................................................. 8<br />

3.6 Typen ........................................................................................................................... 8<br />

4 Formatierung .................................................................................................................... 8<br />

4.1 Allgemeines................................................................................................................. 9<br />

4.2 Einrückungen, Abstände, Ausrichtung .................................................................. 9<br />

4.3 Kontrollstrukturen ................................................................................................... 12<br />

4.4 Importe ......................................................................................................................13<br />

4.5 Deklarationen ........................................................................................................... 13<br />

4.6 Prozeduren................................................................................................................ 14<br />

4.7 Module.......................................................................................................................15<br />

5 Kommentierung ............................................................................................................. 15<br />

5.1 Allgemeine Hinweise zur Kommentierung ......................................................... 15<br />

5.2 Kopfkommentare ..................................................................................................... 16<br />

5.3 Eingeschobene Kommentare .................................................................................. 20<br />

5.4 Erläuterungen ........................................................................................................... 21<br />

6 Beispiele .......................................................................................................................... 21<br />

6.1 Hauptmodul HelloWorld.mod .............................................................................. 21<br />

6.2 Definitionsmodul Stacks.def .................................................................................. 22<br />

6.3 Implementierungsmodul Stacks.mod................................................................... 24


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 2<br />

1 Einleitung<br />

1.1 Zielsetzung<br />

Ziel dieser Richtlinie ist es, in allen Modula-2-Projekten einen möglichst einheitlichen<br />

und verständlichen Programm-Code zu erhalten. Die Programme sollen von anderen<br />

Entwicklern verstanden, geprüft, gewartet und verändert werden können. Das soll<br />

durch eine einheitliche Darstellung der Programmtexte unterstützt werden.<br />

Den einzelnen Vorgaben liegen folgende grundsätzlichen Überlegungen zugrunde:<br />

• Einfachheit: Die Programme sind verständlich zu formulieren sowie ausreichend<br />

zu kommentieren und zu dokumentieren. Trickreiche Programme, die<br />

nur mit großem Aufwand zu verstehen sind, helfen niemandem!<br />

• Einheitlichkeit: Für alle Belange, für die Richtlinien existieren, sollen diese auch<br />

verwendet werden. Ist ein Punkt nicht klar geregelt, soll im Geiste dieser Richtlinie<br />

verfahren werden.<br />

• Stabilität, Verständlichkeit und Änderbarkeit sind in jedem Fall wichtiger als die<br />

Effizienz eines Programms. Optimierungen zu Lasten der Verständlichkeit sollten<br />

nur dann durchgeführt werden, wenn es nicht anders geht. Dann bedürfen<br />

sie besonders ausführlicher Kommentierung.<br />

• Portabilität: Programme dürfen grundsätzlich keine Besonderheiten von benutzten<br />

Compilern, Betriebssystemen oder zugrundeliegenden Bibliotheken verwenden!<br />

Falls dies einmal nicht zu umgehen ist, so ist das in der Dokumentation<br />

zum Code genau zu erklären.<br />

Eine Programmierrichtlinie ist immer ein Kompromiss zwischen konkurrierenden<br />

Zielen. Je nach dem eingenommenen Blickwinkel scheinen die Richtlinien zu detailliert<br />

und zu einschränkend – oder aber zu nachlässig und zu unpräzise. Man kann<br />

beliebig lange über einzelne Details streiten; im Endeffekt handelt es sich um<br />

Geschmacksfragen, aber de gustibus non est disputandum 1 . Es kommt vor allem darauf<br />

an, überhaupt über Richtlinien zu verfügen. Nur dann kann man in den Genuss<br />

der Vorteile kommen.<br />

1.2 Anwendung<br />

Richtlinien sind keine Dogmen. Sie sollten immer unter Anwendung gesunden Menschenverstands<br />

verwendet werden. Es gibt immer – wenn auch selten – Situationen,<br />

in denen eine buchstabengetreue Befolgung sinnlos oder zumindest fraglich ist. In<br />

einer solchen Situation kann von den Richtlinien abgewichen werden. Die Abweichung<br />

sollte aber immer dokumentiert und begründet werden.<br />

2 Programmkonstrukte<br />

Dieser Abschnitt legt fest, wie einzelne Programmkonstrukte von Modula-2 verwendet<br />

werden sollen. Dabei werden die Möglichkeiten, die Modula-2 bietet, etwas eingeschränkt.<br />

1. lat.: Über Geschmack soll man nicht streiten.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 3<br />

2.1 Module<br />

Grundsätze. Alle Programme sollen in möglichst sinnvolle Module zergliedert werden.<br />

Das Hauptmodul 1 soll nur aus wenigen Zeilen (maximal 20) bestehen und keine<br />

Prozeduren enthalten. 2<br />

Die Bestandteile eines Programms werden nach dem folgenden Schema auf Dateien<br />

verteilt:<br />

• Das Hauptmodul (module) wird in eine eigene Datei geschrieben. Diese Datei<br />

trägt den Namen des Hauptmoduls (und damit des ausführbaren Programms),<br />

gefolgt von der Endung .mod, z.B. HelloWorld.mod.<br />

• Jedes Definitionsmodul (definition module) kommt vollständig in eine eigene<br />

Datei. Diese trägt den Modulnamen und hat die Endung .def, z.B.<br />

Stacks.def.<br />

• Jedes Implementierungsmodul (implementation module) kommt vollständig in<br />

eine eigene Datei. Diese trägt den Modulnamen und hat die Endung .mod, z.B.<br />

Stacks.mod.<br />

Module werden verwendet, um<br />

• zusammengehörige Funktionalitäten zu gruppieren,<br />

• globale Deklarationen zusammenzufassen,<br />

• abstrakte Datentypen und Datenkapseln zu realisieren.<br />

Jedes Modul (mit Ausnahme des Hauptmoduls) besteht aus einem Definitionsmodul<br />

und einem Implementierungsmodul.<br />

Aufbau. Das Definitionsmodul untergliedert sich wie folgt:<br />

1. Importe<br />

2. Definition von Konstanten, die zur Typdefinition notwendig sind<br />

3. Typdefinitionen<br />

4. Konstantendefinitionen<br />

5. Variablendeklarationen<br />

6. Prozedurdeklarationen<br />

Die Schnittstelle, die durch das Definitionsmodul beschrieben wird, soll möglichst<br />

wenige Typen und Operationen haben und möglichst stabil bleiben. In das Definitionsmodul<br />

gehören nur Angaben, die nach außen wirklich sichtbar sein müssen.<br />

Das Implementierungsmodul untergliedert sich in:<br />

1. Importe<br />

2. Definition von Konstanten, die zur Typdefinition notwendig sind<br />

3. Typdefinitionen<br />

1. Hauptmodul ist das Modul, in dessen Rumpf die eigentliche Programmausführung beginnt.<br />

Es steht an der Spitze der Import-Hierarchie.<br />

2. Ausnahme: Programme mit weniger als 100 ausführbaren Programmzeilen dürfen ohne Zergliederung<br />

in kleinere Module entwickelt werden. Das Programm wird in diesem Fall in Prozeduren<br />

gegliedert, die direkt im Hauptmodul untergebracht sind.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 4<br />

4. Konstantendefinitionen<br />

5. Variablendeklarationen<br />

6. Definition interner Prozeduren<br />

7. Definition der Prozeduren des Definitionsmoduls (in der gleichen Reihenfolge<br />

wie im Definitionsmodul)<br />

8. Rumpf<br />

Ein Hauptmodul wird analog zu einem Implementierungsmodul aufgebaut.<br />

2.2 Prozeduren<br />

Grundsätze. Jedes Modul sollte in sinnvolle Prozeduren zergliedert werden. Jede<br />

Prozedur sollte eine klar definierte Aufgabe besitzen und übersichtlich sein. Daher ist<br />

es häufig sinnvoll, Teilfunktionalitäten in weitere Prozeduren auszulagern.<br />

Aufbau. Ebenso wie in Modulen muss auch in Prozeduren die Reihenfolge der einzelnen<br />

Deklarationen eingehalten werden.<br />

1. Konstantendefinitionen<br />

2. Variablendeklarationen<br />

3. Definitionen lokaler Prozeduren<br />

4. Rumpf<br />

Typdefinitionen sollten nicht innerhalb von Prozeduren erfolgen, sondern immer im<br />

Modul. Ebenso sollen Konstanten nur in Ausnahmefällen innerhalb einer Prozedur<br />

definiert werden.<br />

Parameterübergabe. Der Typ eines formalen Parameters muss so restriktiv wie möglich<br />

angegeben werden. Wertparameter sind Referenzparametern (VAR-Parameter)<br />

vorzuziehen.<br />

Seiteneffekte. Funktionsprozeduren sollen nach Möglichkeit keine Seiteneffekte<br />

(Nebenwirkungen, z.B. auf globale Variable) haben.<br />

2.3 Variable<br />

Globale Variable. Globale Variablen sollen nur sehr sparsam verwendet werden. Ihre<br />

Sichtbarkeit soll möglichst stark eingeschränkt sein. Eine Übergabe von Werten an<br />

Prozeduren über globale Variablen ist verboten (stattdessen Parameter verwenden!),<br />

ebenso der Informationsfluss aus Prozeduren heraus über globale Variablen (stattdessen<br />

Rückgabewerte oder VAR-Parameter verwenden!).<br />

Sichtbarkeit. Variablen sollen von Modulen nur dann exportiert werden, wenn es<br />

unbedingt notwendig ist. Besser als eine allgemeine Sichtbarkeit einer globalen Variablen<br />

sind in jedem Fall Zugriffsprozeduren (Grundsatz der Kapselung).<br />

Typ. Der Typ einer Variablen soll möglichst genau an den vorgesehenen Einsatzzweck<br />

angepasst sein. Es sollte zum Beispiel für eine Zählvariable für Werte zwischen 1 und<br />

100 nicht einfach der Typ INTEGER verwendet werden, sondern ein geeigneter<br />

Bereichstyp.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 5<br />

2.4 Konstanten<br />

Anstelle von festen Zahlen (und Zeichenketten) im Programmtext sollen (sofern sinnvoll)<br />

Konstanten verwendet werden. Je nach Bedeutung sind diese<br />

• im Implementierungsmodul (interne Konstanten des jeweiligen Moduls) oder<br />

• im Definitionsmodul (für die Verwendung des Moduls notwendige Konstanten)<br />

definiert.<br />

Die Verwendung von Konstanten erleichtert eine Änderung des Programms, da nur<br />

der Wert der Konstanten verändert werden muss und nicht alle Verwendungen des<br />

Werts. Wird eine Konstante nur innerhalb einer Prozedur benötigt, kann sie auch zu<br />

dieser lokal deklariert werden.<br />

2.5 Typen<br />

Die Typen von Variablen sollen immer explizit erzeugt werden (benannte Typen).<br />

Anonyme Typen, d.h. direkt bei der Deklaration der Variablen definierte Typen, sind<br />

verboten. Beispielsweise soll statt<br />

VAR inputLine: ARRAY[1 .. 256] OF CHAR; (*anonymous type!*)<br />

Folgendes geschrieben werden:<br />

CONST MaxBufferLength = 256;<br />

TYPE Buffer: ARRAY[1 .. MaxBufferLength] OF CHAR;<br />

VAR inputLine: Buffer;<br />

Für Typdefinitionen gilt das oben für Konstanten gesagte: Sie sollen je nach ihrer Verwendung<br />

innerhalb eines Definitionsmoduls, innerhalb eines Implementierungsmoduls<br />

oder innerhalb einer Prozedur definiert werden.<br />

2.6 Verwendung von Modula-2-Konstrukten<br />

2.6.1 Ausdrücke<br />

Ausdrücke sollen so lesbar wie möglich gestaltet werden. Komplexe oder trickreiche<br />

Ausdrücke bedürfen eines Kommentars zur Erklärung. Klammern sollen verwendet<br />

werden, wenn für das Verständnis explizites Wissen über die Auswertungsreihenfolge<br />

nötig ist. 1 Eine deutliche Klammerung ist in jedem Fall einer undurchsichtigen<br />

Abhängigkeit von der Auswertungsreihenfolge vorzuziehen.<br />

Logische Ausdrücke sollen nach Möglichkeit positiv ausgedrückt werden, da Negationen<br />

schlechter verständlich sind. Das beeinflusst bereits die Wahl der Variablen und<br />

deren Aussage. So sollte zum Beispiel anstelle von<br />

besser<br />

IF (NOT fileFound) THEN ...<br />

IF fileMissing THEN ...<br />

verwendet werden. Allerdings sollen für die Einhaltung dieser Regel nicht zusätzliche<br />

Variablen eingeführt werden. Eine Negation ist dann das kleinere Übel.<br />

1. Zum Beispiel ist eine Klammerung für Punkt vor Strich nicht notwendig, logische Operatoren<br />

sollten hingegen geklammert werden.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 6<br />

2.6.2 CASE-Anweisung<br />

Die CASE-Anweisung ist verschachtelten IF-Anweisungen vorzuziehen. Es sollen<br />

keine Bereiche von Aufzählungstypen in CASE-Anweisungen angegeben werden, da<br />

sich bei einer Änderung des Aufzählungstyps dessen Semantik verändert (stattdessen<br />

explizite Aufzählung).<br />

Der Programmierer soll explizit alle Auswahlmöglichkeiten abfragen, also wenn<br />

möglich auf den ELSE-Zweig verzichten. Die Verwendung des ELSE-Zweigs ist allerdings<br />

angebracht, wenn man für alle übrigen Fälle eine Fehlermeldung generieren<br />

möchte oder die CASE-Anweisung dazu dient, zwei oder drei spezielle Werte aus<br />

einem großen Wertebereich herauszufiltern.<br />

2.6.3 Schleifen<br />

FOR-Schleifen sind anderen Schleifen vorzuziehen, da sie immer terminieren. Die<br />

nächstbeste Wahl sind WHILE- und REPEAT-Schleifen. In sehr komplexen Fällen können<br />

LOOP-Schleifen verwendet werden. Dabei ist allerdings darauf zu achten, dass<br />

die Schleife an möglichst wenigen Stellen durch EXIT-Anweisungen verlassen wird.<br />

EXIT-Anweisungen in WHILE- und REPEAT-Schleifen sind nur in Ausnahmefällen<br />

erlaubt.<br />

2.6.4 RETURN-Anweisung<br />

Funktionsprozeduren sollen an möglichst wenigen Stellen (normalerweise nur an<br />

einer einzigen) durch eine RETURN-Anweisung verlassen werden. Falls zu diesem<br />

Zweck allerdings eine zusätzliche Variable eingeführt werden muss, um den Rückgabewert<br />

zu speichern, kann die Regel gebrochen werden. Es wird empfohlen, der Variablen,<br />

die den Rückgabewert speichert, den Namen result zu geben.<br />

Normale Prozeduren sollen gar keine RETURN-Anweisung enthalten.<br />

2.7 Verschachtelung und Länge von Programmteilen<br />

Aus Gründen der Lesbarkeit dürfen Konstrukte nicht beliebig verschachtelt und Programmteile<br />

nicht beliebig lang sein. Wenn hier von Zeilen gesprochen wird, so sind<br />

logische Programmzeilen gemeint. Dabei bildet jede Anweisung oder Deklaration<br />

eine eigene Zeile, unabhängig von der tatsächlichen Formatierung in der Datei.<br />

• Die maximale Schachtelungstiefe von Prozeduren ist zwei. Das bedeutet, dass<br />

höchstens eine Prozedur in eine Prozedur in einem Modul eingeschachtelt werden<br />

darf.<br />

• Innerhalb von Prozeduren sollen maximal fünf Konstrukte (IF, WHILE, REPEAT,<br />

FOR, LOOP, CASE, WITH) ineinander geschachtelt werden.<br />

• Jede Anweisung und jede Deklaration steht in einer eigenen Zeile.<br />

• Eine Prozedur soll aus höchstens 40 Zeilen bestehen.<br />

• Ein Implementierungsmodul soll maximal 800 Zeilen umfassen.<br />

• Ein Definitionsmodul soll maximal 25 Funktionen, Variablen und Konstanten<br />

umfassen. Diese Restriktion ist allerdings nicht in allen Fällen wirklich sinnvoll<br />

(z.B. in Modulen, die nur Konstanten exportieren) und darf dann auch übergangen<br />

werden.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 7<br />

• Eine Prozedur soll höchstens fünf Parameter besitzen. Ausnahmen sind nur in<br />

begründeten Fällen zulässig.<br />

3 Namenskonventionen<br />

Dieser Abschnitt beschreibt, wie Namen vergeben werden sollen. Namen sind dabei<br />

Bezeichner für Variablen, Konstanten, Typen, Prozeduren, Module, usw. Der erste<br />

Abschnitt beschreibt die gemeinsamen Merkmale, die folgenden Abschnitte die<br />

Besonderheiten einzelner Klassen von Namen.<br />

3.1 Allgemeines<br />

Alle Namen sind in Englisch. Namen dürfen sich nur aus großen oder kleinen Buchstaben<br />

und aus Ziffern zusammensetzen. Der Unterstrich soll nicht verwendet werden,<br />

außer um die Lesbarkeit ansonsten verwirrender Bezeichner zu erhöhen. Dann<br />

darf er nur zwischen Worten stehen.<br />

Namen sollen grundsätzlich so gestaltet werden, dass sie leicht lesbar, gut verständlich<br />

und weitgehend selbsterklärend sind (sprechende Bezeichner). Außerdem sollen<br />

sie dazu beitragen, dass der Programmtext in seiner Gesamtheit leicht lesbar und verständlich<br />

ist. Es gelten die folgenden Regeln:<br />

• Namen werden aus kurzen Wörtern zusammengesetzt, die die Bedeutung des<br />

Bezeichners deutlich machen. Die Wörter werden direkt hintereinandergeschrieben.<br />

Beispiel: NamingExample.<br />

• Jedes Wort eines Namens beginnt mit einem Großbuchstaben, der Rest des<br />

Worts wird klein geschrieben. Einzige Ausnahme ist das erste Wort des Bezeichners<br />

einer Variablen oder eines formalen Parameters. Dieses wird vollständig<br />

klein geschrieben. Beispiel: anotherNamingExample.<br />

• Abkürzungen ermöglichen kürzere, aber dennoch verständliche und aussagekräftige<br />

Bezeichner. Die Verwendung von Abkürzungen wird empfohlen; sie<br />

müssen allerdings im Kommentar erklärt werden. Beispiel: otherNamingExpl.<br />

• Da lange Bezeichnern zwar eine gute Erklärung liefern, aber die Programme<br />

unleserlich und nicht mehr vernünftig formatierbar machen, ist ein Kompromiss<br />

bei der Bezeichnerlänge nötig. Als Richtwert wird eine maximale Bezeichnerlänge<br />

von 15 Zeichen vorgeschlagen.<br />

• Bezeichner aus einem oder zwei Buchstaben sind nur in einem sehr lokalen Kontext<br />

zulässig, z.B. für Schleifenvariablen. Ansonsten sind derart aussagearme<br />

Bezeichner zu vermeiden.<br />

• Die Überdeckung sichtbarer Bezeichner durch lokale Bezeichner soll vermieden<br />

werden, da es zu Verwirrung führen kann.<br />

• Für unterschiedliche Aufgaben sollen nicht dieselben Bezeichner verwendet<br />

werden, auch wenn sich die Bezeichner durch die Sichtbarkeitsregeln von Prozeduren<br />

und Modulen nicht überdecken können.<br />

• Ziffern sollen in Bezeichnern nur sehr sparsam eingesetzt werden.<br />

Wie bei vielen Dingen kommt es auch bei der Wahl der Bezeichner auf eine konsistente,<br />

nachvollziehbare Verwendung und eine gute Dokumentation an.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 8<br />

3.2 Module<br />

Modulnamen stehen für eine Kategorie von Dingen. Sie sollen mit Substantiven<br />

bezeichnet werden. Beispiel: Terminal. Für ein Modul, das einen abstrakten Datentyp<br />

exportiert, ist es oft sinnvoll, die Pluralform des Typnamens zu wählen. Beispiel:<br />

Lists, Stacks.<br />

3.3 Prozeduren<br />

Prozeduren tun etwas. Daher sollen Prozedurnamen Verbkonstruktionen sein. Der<br />

Bezeichner gibt eine kurze, anschauliche Beschreibung der Aktion in Befehlsform.<br />

Beispiel: ClearScreen, CountSheep, Pop.<br />

Funktionsprozedurnamen stehen für den Wert, den die Funktionsprozedur zurückgibt.<br />

Der Name kann zusätzlich mit dem Präfix Get versehen werden. Beispiele:<br />

ScreenNumber, GetDate.<br />

3.4 Variablen<br />

Variablennamen machen Aussagen darüber, welche Bedeutung der Wert der Variable<br />

im aktuellen Kontext hat. Beispiele: speed, result, freeMemory. Kurze Variablennamen<br />

wie i, j sind nur in sehr begrenztem Kontext erlaubt, z.B. als Namen einer<br />

Schleifenvariable.<br />

Parameternamen und die Namen von RECORD-Komponenten sind wie Variablennamen<br />

zu bilden.<br />

3.5 Konstanten<br />

Der Name einer Konstante sagt aus, welche Bedeutung ihr Wert hat. Konstantennamen<br />

sind in der Regel Substantive mit Adjektiven. Beispiel: MaxLength.<br />

3.6 Typen<br />

Ein Typname beschreibt eine Wertemenge. Daher soll es sich um ein Substantiv handeln.<br />

Es ist zur Unterscheidung von Variablen des Typs oft sinnvoll, das Wort Type<br />

anzuschließen. Beispiele: Stack, TreePointer, TreeNodeType. Die Elemente eines<br />

Aufzählungstyps sind wie Konstanten zu behandeln.<br />

4 Formatierung<br />

In diesem Abschnitt wird festgelegt, wie die einzelnen Programmkonstrukte zu formatieren<br />

sind.<br />

4.1 Allgemeines<br />

Eine einheitliche, lesbare und übersichtliche Darstellung des Programmcodes erleichtert<br />

dem Leser das Verständnis und fördert den Überblick. Die folgenden Regeln dienen<br />

daher einer möglichst einheitlichen Gestaltung.<br />

Die Formatierung verfolgt die folgenden Ziele:<br />

• Die Gliederung des Programmtextes soll der logischen Struktur des Programms<br />

folgen und diese optisch unterstützen.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 9<br />

• Das Programm soll sowohl am Bildschirm als auch auf Papier gut lesbar und<br />

bearbeitbar sein.<br />

• Die optische Darstellung soll in gewissem Rahmen mit dem intuitiven Verständnis<br />

des Lesers korrespondieren.<br />

4.2 Einrückungen, Abstände, Ausrichtung<br />

Die Zeilenlänge ist auf 79 1 Zeichen beschränkt. Auf diese Weise ist der Programmtext<br />

auf den meisten Terminals, in den meisten Editoren und über die meisten Drucker auf<br />

Papier relativ problemlos ohne lästige Umbrüche oder abgeschnittene Teile darzustellen.<br />

4.2.1 Einrückung und Schachtelung<br />

Jede Einrückung erfolgt mit zwei zusätzlichen Leerzeichen, also pro Stufe um zwei<br />

Zeichen. Die oberste Stufe beginnt in der ersten Spalte. Für die Einrückungen dürfen<br />

nur Leerzeichen verwendet werden. Tabulatoren sind nicht erlaubt, da sie nicht auf<br />

allen Geräten zur selben Einrückung führen.<br />

Für die Einrückung gilt die folgende Regel: Bei Verschachtelungen wird pro Stufe um<br />

die oben angesprochenen zwei Zeichen eingerückt. Dabei werden die Schlüsselwörter,<br />

die die Einschachtelung umschließen, noch nicht eingerückt.<br />

BEGIN<br />

WHILE IsBusy(printer) DO<br />

Wait(10); (* wait 10 seconds *)<br />

END;<br />

PrintFile(printer,file);<br />

END;<br />

Kommentare werden genauso weit eingerückt wie die zugehörigen Programmzeilen.<br />

4.2.2 Umbruch zusammengehörender Zeilen<br />

Fortgesetzte Zeilen werden wie Schachtelungen eingerückt. Allerdings soll die Einrückung<br />

eine weitere Stufe tiefer erfolgen, wenn eine logische Struktur (z.B. Klammern<br />

in einem Ausdruck oder die Bedingung in einer IF-Anweisung) dies impliziert.<br />

endNumber := middleNumber + nextNumber<br />

+ anotherNumber; (* indentation is 2 blanks *)<br />

IF ((endNumber + middleNumber)<br />

< anotherNumber) THEN (* indentation is 4 blanks *)<br />

Beim Trennen von Zeilen soll an einer möglichst sinnvollen Stelle getrennt werden.<br />

Normalerweise stehen an der Trennstelle Operatoren; diese werden an den Anfang<br />

der fortgesetzten Zeile gesetzt. Auf diese Weise ist diese leicht als Fortsetzung zu<br />

erkennen und wird beim schnellen Lesen nicht als eigene Anweisung angesehen.<br />

1. Diese Zahl ergibt sich aus der üblichen Zeilenlänge von 80 Zeichen, wenn man berücksichtigt,<br />

dass viele Editoren (z.B. Emacs) das 80. Zeichen bereits in die nächste Zeile umbrechen,<br />

damit sie in der Spalte 80 diesen Umstand durch ein Sonderzeichen anzeigen können.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 10<br />

4.2.3 Horizontale Abstände<br />

Horizontale Abstände, also Leerraum zwischen einzelnen Bezeichnern, Trennern, Operatoren<br />

usw., erhöhen die Lesbarkeit des Programmtextes und implizieren eine gewissen<br />

Gruppierung. Grundsätzlich sollen die Abstände so gewählt werden, wie man<br />

dies von üblichem Prosa-Text und mathematischen Formeln gewohnt ist. Die<br />

Abstände werden aber auch zu einer gewissen Gruppierung verwendet, vor allem in<br />

Formeln.<br />

Die folgende Regeln für das Setzen von horizontalen Abständen werden empfohlen:<br />

• Vor und hinter folgenden Operatoren und Trennern steht Leerraum:<br />

+ - * / < = > = # := .. |.<br />

• Hinter den unären Operatoren ~, + und - steht kein Leerraum, jedoch davor.<br />

• Nach einem Komma, einem Doppelpunkt oder einem Semikolon steht Leerraum,<br />

davor nicht. Leerraum hinter einem Komma kann weggelassen werden.<br />

• Klammern stehen grundsätzlich ohne führenden oder folgenden Leerraum.<br />

d := RealMath.sqrt((a * a) + (b * b));<br />

Leerraum hinter öffnenden und vor schließenden Klammern ist zulässig, um<br />

verschachtelte Ausdrücke oder Aufrufe besser strukturieren zu können.<br />

( -b - sqrt( (b * b) - (4.0 * a * c) ) ) / (2.0 * a)<br />

• Zwischen dem Prozedurnamen und seiner Parameterliste steht kein Leerraum.<br />

Normalerweise werden horizontale Abstände durch ein Leerzeichen (oder einen Zeilenumbruch)<br />

gebildet. Zur vertikalen Ausrichtung von Operatoren können auch<br />

mehrere Leerzeichen eingefügt werden.<br />

4.2.4 Vertikale Abstände<br />

Vertikale Abstände werden durch Leerzeilen gebildet. Hier gilt es im wesentlichen zwei<br />

Effekte abzuwägen. Zum einen wird der Programmtext durch Leerzeilen lockerer<br />

und besser gegliedert. Zusammenhängende Programmteile sind leicht zu erkennen.<br />

Auf der anderen Seite aber nehmen Leerzeilen sehr viel Raum in Anspruch, so dass<br />

auf einer Bildschirmseite und vor allem auf einem Blatt Papier nur ein kleiner Ausschnitt<br />

des Programms zu sehen ist. Darunter leidet die Übersichtlichkeit und die<br />

schnelle Erfassung der Zusammenhänge.<br />

Leerzeilen sollen dazu benutzt werden, logische Einheiten des Programmtextes zu<br />

gruppieren. Da sich hierfür nur sehr schwer allgemeingültige Regeln aufstellen lassen,<br />

folgen hier einige Regeln und Empfehlungen:<br />

• Vor und hinter Prozedur- und Funktionsdeklarationen (einschließlich dem<br />

zugehörigem Kopfkommentar) muss eine Leerzeile stehen.<br />

• Die einzelnen Bestandteile von Modulen (Importe, Typdefinition, Variablendeklarationen,<br />

Konstanten usw.) sollen durch Leerzeilen getrennt werden.<br />

• Je länger eine Einheit ist, desto mehr Leerzeilen verträgt sie. So sollen Prozeduren,<br />

die selbst wieder Prozeduren enthalten, wie Module behandelt werden, d.h.<br />

die einzelnen Deklarationsteile können hier ebenfalls durch Leerzeilen getrennt<br />

werden.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 11<br />

• In Definitionsmodulen können einzelne Prozedur-, Variablen-, Typ- und Konstantengruppen<br />

wieder durch Leerzeilen in Untergruppen aufgeteilt werden. Es<br />

ist jedoch nicht sinnvoll, dass vor und hinter jeder Deklaration eine Leerzeile<br />

steht.<br />

4.2.5 Ausrichtung von Operatoren und Begrenzern<br />

Programmtext wird leichter lesbar, wenn in zusammenhängenden Programmteilen<br />

korrespondierende Operatoren und Begrenzer direkt untereinander stehen.<br />

temp := field1;<br />

field1 := field2;<br />

field2 := temp;<br />

Die Ausrichtung der Zuweisungsoperatoren soll nur dann erfolgen, wenn zwischen<br />

den Zeilen ein inhaltlicher Zusammenhang besteht. Gegenbeispiel:<br />

val := (A * B) + C;<br />

fileAtEOF := TRUE;<br />

Die Ausrichtung von Operatoren und Klammern bietet sich natürlich besonders bei<br />

Formeln an, die über mehrere Zeilen gehen. Auf diese Weise kann in langen und komplexen<br />

Formeln eine zusätzliche Gruppierung erreicht werden. Schreibfehler fallen so<br />

auch besser auf.<br />

Deklarationen sollen nach Möglichkeit immer vertikal an den Doppelpunkten oder<br />

Gleichheitszeichen ausgerichtet werden.<br />

VAR<br />

val : REAL;<br />

counter: INTEGER;<br />

Analog hierzu sollen auch die Deklarationsteile von Record-Deklarationen ausgerichtet<br />

werden (vgl. Abschnitt 4.5.2).<br />

Eine entsprechende Ausrichtung soll auch in den Parameterlisten von Prozedur- und<br />

Funktionsdeklarationen verwendet werden. Dort werden die Doppelpunkte, die<br />

Parametermodi und die Bezeichner vertikal ausgerichtet.<br />

PROCEDURE DisplayMenu( title : Text;<br />

VAR choice: ChoiceType);<br />

4.3 Kontrollstrukturen<br />

Die folgenden Muster geben die Formatierung verschiedener Kontrollstrukturen vor.<br />

Platzhalter für Bezeichner oder anderen Code sind kursiv gesetzt. Man beachte, dass<br />

ein Teil der hier gezeigten Syntaxelemente (z.B. der ELSE-Zweig in der IF-Anweisung)<br />

optional ist.<br />

4.3.1 Blöcke<br />

BEGIN<br />

Anweisungen<br />

END;


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 12<br />

4.3.2 Bedingte Anweisungen<br />

IF Bedingung THEN<br />

Anweisungen<br />

ELSIF Bedingung THEN<br />

Anweisungen<br />

ELSE<br />

Anweisungen<br />

END;<br />

CASE Ausdruck OF<br />

| ErsteAuswahl:<br />

Anweisungen<br />

| ZweiteAuswahl:<br />

Anweisungen<br />

...<br />

ELSE<br />

Anweisungen<br />

END;<br />

4.3.3 Schleifen<br />

Hier wird am Beispiel einer WHILE- und REPEAT-Schleife das Prinzip demonstriert.<br />

Die anderen Schleifen (FOR, LOOP) werden analog formatiert. Die WITH-Anweisung<br />

wird analog zu den Schleifen formatiert.<br />

WHILE Bedingung DO<br />

Anweisungen<br />

END;<br />

REPEAT<br />

Anweisungen<br />

UNTIL Bedingung;<br />

4.4 Importe<br />

Für jedes importierte Modul ist eine IMPORT-Anweisung zu formulieren. Importe von<br />

Modulen sind wie folgt zu formatieren:<br />

IMPORT AnotherModule;<br />

IMPORT YetAnotherModule;<br />

Der Import einzelner Prozeduren aus einem Modul sieht wie folgt aus:<br />

FROM FirstModule IMPORT<br />

FirstProcedure, SecondProcedure;<br />

Wird nur eine Prozedur importiert, kann statt eines Zeilenumbruchs ein Leerzeichen<br />

verwendet werden.<br />

FROM FirstModule IMPORT SingleProcedure;<br />

4.5 Deklarationen<br />

Deklarationen und Instantiierungen gleichartiger Strukturen (z.B. aller Felder eines<br />

Records) werden tabellenartig notiert. Die notwendige horizontale Ausrichtung<br />

wurde in Abschnitt 4.2.5 bereits angesprochen.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 13<br />

4.5.1 Allgemeines<br />

Die Deklarationen werden wie alle übrigen Blöcke unter dem Schlüsselwort eingerückt.<br />

Deklarationen sind hier Variablen- (VAR), Konstanten- (CONST) und Typdeklarationen<br />

(TYPE).<br />

TYPE<br />

Deklaration1;<br />

Deklaration2;<br />

Falls nur eine Element deklariert werden soll, kann dieses auch direkt hinter dem<br />

Schlüsselwort stehen.<br />

CONST MaxLength = 100;<br />

Oft sind die Werte von Konstanten recht umfangreich. Dies gilt insbesondere für Zeichenketten.<br />

Sollten diese nicht mehr in eine Zeile passen, so werden sie doppelt eingerückt<br />

in eine neue Zeile geschrieben. Der Zuweisungsoperator bleibt dabei in der ersten<br />

Zeile.<br />

CONST<br />

LongText =<br />

"This is a text that goes on and on and on.";<br />

MaxLength = 100;<br />

Alle Deklarationen werden dabei weiterhin auf den Doppelpunkt bzw. das Gleichheitszeichen<br />

vertikal ausgerichtet.<br />

4.5.2 Records<br />

Hier wird die Formatierung eines Record ohne und mit variantem Teil gezeigt. Bei<br />

varianten Records wird der eingeschachtelte CASE-Teil analog zur CASE-Anweisung<br />

formatiert. Der variante Teil muss als erste Komponente des Record deklariert werden.<br />

TYPE<br />

Name = RECORD<br />

eineKomponente : Typ;<br />

weitereKomponente: Typ;<br />

END;<br />

TYPE<br />

Name = RECORD<br />

CASE markenFeld: Typ OF<br />

| ErsteAuswahl:<br />

eineKomponente1 : Typ;<br />

weitereKomponente1: Typ;<br />

| ZweiteAuswahl:<br />

eineKomponente2 : Typ;<br />

weitereKomponente2: Typ;<br />

...<br />

END;<br />

eineKomponente : Typ;<br />

weitereKomponente: Typ;<br />

END;


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 14<br />

4.6 Prozeduren<br />

Prozeduren und Funktionsprozeduren werden (bis auf die Angabe des Rückgabewertes)<br />

gleich formatiert.<br />

PROCEDURE ProzedurName(Parameterliste);<br />

Deklarationen<br />

BEGIN<br />

Anweisungen<br />

END Name;<br />

PROCEDURE FunktionName(Parameterliste): Rückgabetyp;<br />

Deklarationen<br />

BEGIN<br />

Anweisungen<br />

END Name;<br />

Bei Prozedurdeklarationen im Definitionsmodul wird natürlich der Rumpf weggelassen.<br />

Die Parameterlisten werden folgendermaßen formatiert (hier beispielhaft):<br />

PROCEDURE Equal(left : List;<br />

right: List): BOOLEAN;<br />

Wertparameter müssen zuerst aufgeführt werden, dann folgen die Referenzparameter.<br />

Hier gibt es allerdings eine Ausnahme: Bei Prozeduren eines abstrakten Datentyps,<br />

die einen Parameter vom abstrakten Typ erhalten, wird dieser Parameter immer<br />

als erster notiert, auch wenn er ein Referenzparameter ist. Damit soll klar werden, auf<br />

welchem Objekt die Aktion stattfindet.<br />

Für jeden Parameter sollte der Typs explizit hingeschrieben werden; Parameter desselben<br />

Typs sollten daher nicht durch Kommata aufgezählt werden. Statt<br />

besser<br />

PROCEDURE InsertAt(VAR list: List;<br />

item, pos : CARDINAL);<br />

PROCEDURE InsertAt(VAR list: List;<br />

item: CARDINAL;<br />

pos : CARDINAL);<br />

schreiben, dann kann man besser erkennen, wieviele und welche Parameter eine Prozedur<br />

hat.<br />

4.7 Module<br />

Module sind wie folgt formatiert (hier am Beispiel eines Hauptmoduls)<br />

MODULE Name;<br />

Importe<br />

Deklarationen<br />

BEGIN<br />

Anweisungen<br />

END Name.<br />

Die Importe und Deklarationen werden wie oben beschrieben aufgebaut und durch<br />

Leerzeilen gegliedert.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 15<br />

5 Kommentierung<br />

Dieser Abschnitt beschreibt den Aufbau von Kommentaren innerhalb eines Programms.<br />

5.1 Allgemeine Hinweise zur Kommentierung<br />

Wenn Programme nach einiger Zeit weiterentwickelt, gewartet oder verstanden werden<br />

sollen, ist eine Kommentierung unerlässlich. Grundsätzlich gilt, dass undokumentierte<br />

Programme nicht akzeptabel sind. Andererseits sollten Programme immer<br />

so geschrieben sein, dass erklärende Kommentare zum Code weitgehend überflüssig<br />

sind. Dies in den meisten Fällen möglich, wenn auch häufig nur durch mehrere Überarbeitungen<br />

des Codes.<br />

Alle Kommentare sind in Englisch. Es dürfen nur die Zeichen des ASCII-Zeichensatzes<br />

(7-Bit-ASCII) verwendet werden. Damit sind alle Sonderzeichen aus einem erweiterten<br />

ASCII-Zeichensatz unzulässig. Auf diese Weise entfallen die typischen Probleme<br />

beim Drucken, bei der Bildschirmdarstellung und bei der Eingabe.<br />

In den folgenden Abschnitten wird angegeben, wie Kommentare zu formatieren sind.<br />

Es soll dabei aber immer darauf geachtet werden, dass sich Kommentar und Programm<br />

deutlich voneinander abheben und nicht verwechselt werden können. Im<br />

Notfall ist zusätzlicher Leerraum zur Trennung einzufügen.<br />

Kommentare ergänzen den Programmcode. Es gelten daher folgende Grundregeln:<br />

• Kommentare sollen klar, kurz und verständlich sein. Ziel ist eine knappe, stichwortartige<br />

Vermittlung der notwendigen Informationen zum Programm.<br />

• Kommentare bilden die einzige Chance des Programmierers, seine Überlegungen,<br />

seine Intention und seine Entscheidungen dem Leser mitzuteilen. Davon<br />

soll reichlich Gebrauch gemacht werden.<br />

• Alle Kommentare sollen immer auf dem aktuellen Stand gehalten werden und<br />

nicht erst nachträglich eingefügt oder angepasst werden.<br />

• Kommentare erklären im Allgemeinen, warum etwas so programmiert wurde.<br />

Wenn nicht aus dem Code klar hervorgeht, wie eine Aufgabe gelöst wird, soll<br />

dies in kurzen Kommentaren erläutert werden. Es kann dabei zum Beispiel auch<br />

auf andere Quellen (z.B. Algorithmenbücher) verwiesen werden.<br />

• Kopfkommentare und eingeschobene Kommentare strukturieren den Code und<br />

erklären abschnittsweise, was der folgende Teil tut.<br />

• Kommentare geben einen Überblick über den Aufbau des Programms und<br />

beschreiben auch Zusammenhänge, die sich nicht direkt aus dem Programm<br />

ergeben oder über mehrere Dateien, Module oder Prozeduren verteilt sind.<br />

• Kommentare geben nicht direkt ersichtliche Voraussetzungen an, von denen an<br />

einer bestimmten Stelle ausgegangen wird. Wenn der Programmierer solche<br />

Bedingungen im Hinterkopf hat, soll er sie für den Leser des Programms sichtbar<br />

machen, indem er sie in einem Kommentar niederlegt.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 16<br />

5.2 Kopfkommentare<br />

Durch Kopfkommentare werden die verschiedenen Einheiten eines Programms gegliedert.<br />

Kopfkommentare erläutern grob den Inhalt der folgenden Einheit und helfen<br />

dem Leser und Programmierer beim Navigieren innerhalb der verschiedenen Programmdateien.<br />

Kopfkommentare haben zusätzlich eine administrative Aufgabe. Sie<br />

geben den Erstellungszeitpunkt, den Autor und Ähnliches an.<br />

Kopfkommentare beginnen in der Spalte, in der auch der nachfolgende Code beginnt.<br />

Sie haben im Gegensatz zu den anderen Kommentaren ein festes Layout, das in den<br />

folgenden Unterabschnitten beschrieben wird. Jeder Teil eines Kopfkommentars wird<br />

durch ein besonderes Schlüsselwort eingeleitet, gefolgt von einem Doppelpunkt. Der<br />

zugehörige Text beginnt in der folgenden Zeile und wird unter dem Schlüsselwort<br />

eingerückt. Falls der Text kurz genug ist, kann er auch direkt hinter das Schlüsselwort<br />

geschrieben werden.<br />

Die Anmerkung ‚(optional)‘ bedeutet, dass der betreffende Teil nicht zwingend erforderlich<br />

ist. Falls es zu diesem Punkt aber Wichtiges zu sagen gibt, sollte der Teil in den<br />

Kopfkommentar aufgenommen werden.<br />

5.2.1 Module<br />

Im Kopfkommentar jedes Moduls, egal ob Hauptmodul, Definitionsmodul oder<br />

Implementierungsmodul, sind folgende Informationen niederzulegen:<br />

1. FILE: Name der Datei. Dies ist hilfreich, um einen Papier-Ausdruck einer Datei<br />

zuordnen zu können.<br />

2. PROJECT: Projektidentifikation. Im Rahmen des Programmierkurses ist dies die<br />

Aufgabenblatt- und Aufgabennummer.<br />

3. CREATED: Erstellungsdatum der Datei.<br />

4. VERSION (optional): Aktuelle Version der Datei mit Datum. Diese Information<br />

wird normalerweise von Werkzeugen zum Configuration Management aktualisiert<br />

1 , eine Aktualisierung von Hand ist etwas mühsam. Es wird dennoch empfohlen,<br />

diese Information im Kopfkommentar zu haben und mitzuführen.<br />

5. AUTHOR: Name des oder der Autoren. Im Rahmen des Programmierkurs auch<br />

die Gruppennummer.<br />

6. DESCRIPTION: Beschreibung des Moduls. An dieser Stelle wird der Zweck des<br />

Moduls und dessen Leistungsumfang beschrieben.<br />

7. RESTRICTIONS (optional): Restriktionen. Welche Einschränkungen oder Sonderfälle<br />

sind zu beachten?<br />

8. NOTES (optional): Bemerkungen aller Art.<br />

9. MODIFICATIONS: Die Änderungshistorie. Hier werden unter Angabe des<br />

Datums und des Autorenkürzels die Veränderungen tabellarisch aufgelistet. Die<br />

entsprechenden Erläuterungen werden dabei recht knapp gehalten.<br />

Definitionsmodul. Der Kopfkommentar eines Definitionsmoduls soll alle Informationen<br />

enthalten, die ein Verwender des Moduls benötigt (mit Ausnahme der Beschrei-<br />

1. Zum Beispiel kann man bei VERSION den String $Id$ eintragen, dann wird von RCS automatisch<br />

beim Ein- und Auschecken die komplette Versionsinformation eingefügt.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 17<br />

bung der Prozeduren, die bei den einzelnen Prozeduren erfolgt). Bei Definitionsmodulen<br />

soll daher die Beschreibung (unter DESCRIPTION) ausführlich ausfallen.<br />

Folgende Punkte sollen dort zusätzlich beschrieben werden.<br />

• Verwendung des Paketes: Eine grobe Beschreibung der Anwendung des Paketes.<br />

Diese beschäftigt sich vor allem mit der sinnvollen und vorgeschriebenen<br />

Reihenfolge der Funktionsaufrufe.<br />

• (optional) Hinweise auf die Behandlung globaler, also mehrere Teile des Paketes<br />

betreffender Fehler. Hier geht es um prinzipielle Fehler und Fehlerbehandlungsstrategien<br />

aus Anwendersicht.<br />

(*<br />

FILE : ~reissing/modula/lib/Lists.def<br />

PROJECT: ADTs for the Programming Course<br />

CREATED: Fri Oct 11 15:38:01 MET DST 1996<br />

VERSION: 1.3, Fri Nov 28 11:34:23 MET 1997<br />

AUTHOR : Ralf Reissing<br />

DESCRIPTION:<br />

ADT List with a lot of operations.<br />

'Create' creates an empty list and should be called<br />

before any other operation<br />

NOTES:<br />

Caution! Interface is under construction!<br />

MODIFICATIONS:<br />

1997/11/28 RR renamed procedure GetItem to ItemAt<br />

1997/10/22 RR added procedures IsEmpty and Size<br />

*)<br />

DEFINITION MODULE Lists;<br />

Implementierungsmodul. Die Kommentierung des Implementierungsteils<br />

beschränkt sich auf die Beschreibung der Realisierung. Im Kopfkommentar des<br />

Implementierungsmodul soll das Wartungspersonal und der Programmierer die notwendigen<br />

Informationen finden. Informationen aus dem Definitionsmodul brauchen<br />

nicht wiederholt zu werden. Im Folgenden werden die Besonderheiten des Kopfkommentars<br />

für ein Implementierungsmodul beschrieben.<br />

Der Punkt IMPLEMENTATION ersetzt den Punkt DESCRIPTION.<br />

• IMPLEMENTATION: Angaben zur Implementierung. In diesem Abschnitt soll<br />

kurz die Grundidee der Realisierung des Moduls beschrieben werden. Der<br />

Abschnitt ist nicht optional und muss daher auch dann im Kopf verbleiben,<br />

wenn es absolut nichts zur Realisierung und der dahintersteckenden Strategie<br />

zu sagen gibt.<br />

Der Punkt RESTRICTIONS gibt hier Auskunft über Einschränkungen der Implementierung<br />

gegenüber der Definition.<br />

5.2.2 Prozeduren<br />

Prozeduren erhalten Kopfkommentare, die sie als Ganzes beschreiben. Da auch bei<br />

Prozeduren zwischen Deklaration (im Definitionsmodul) und Definition (im Implementierungsmodul)<br />

unterschieden wird und es andererseits auch lokale Prozeduren<br />

ohne Deklaration geben kann, gibt es drei leicht unterschiedliche Kopfkommentarstrukturen.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 18<br />

Deklaration. Im Kopfkommentar einer Deklaration werden analog zum Kopfkommentar<br />

eines Definitionsmoduls alle Informationen übermittelt, die für die Verwendung<br />

der Prozedur notwendig sind.<br />

1. PROCEDURE (optional): Der Name der Prozedur. Bei längeren Kopfkommentaren<br />

muss man erst am Ende nachschauen, um welche Prozedur es überhaupt<br />

geht. Daher ist es häufig sinnvoll, bereits zu Beginn des Kopfkommentars anzugeben,<br />

um welche Prozedur es sich handelt.<br />

2. DESCRIPTION: Beschreibung der Funktionalität der Prozedur aus der Sicht<br />

eines Benutzers, der das Innenleben der Prozedur nicht kennt. Die Beschreibung<br />

soll ausreichen, um zu verstehen, was die Prozedur leistet.<br />

3. PARAMETERS: Auflistung der Parameter (nur Name) und ihrer Bedeutung.<br />

4. RETURNS (nur bei Funktionsprozeduren): Auflistung der möglichen Rückgabewerte<br />

und deren Bedeutung.<br />

5. PRE (optional): Vorbedingungen geben an, welche Bedingungen erfüllt sein<br />

müssen, damit die Prozedur erfolgreich ausgeführt werden kann.<br />

6. POST (optional): Nachbedingungen geben an, welche Bedingungen erfüllt sind,<br />

nachdem die Prozedur erfolgreich ausgeführt werden konnte.<br />

Vor- und Nachbedingung sind vor allem bei der Deklaration von Operationen auf<br />

einem abstrakten Datentyp sinnvoll. Der Wert eines Parameters p zum Zeitpunkt des<br />

Aufrufs wird mit p, zum Zeitpunkt des Verlassens mit p' notiert. Der Rückgabewert<br />

einer Funktionsprozedur kann durch result benannt werden.<br />

(*<br />

PROCEDURE:<br />

ItemAt<br />

DESCRIPTION:<br />

returns the pos-th item in the list (1 = first)<br />

PARAMETERS:<br />

list: the list<br />

pos : the element position in the list<br />

RETURNS:<br />

the pos-th item of the list<br />

PRE:<br />

1


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 19<br />

2. DESCRIPTION: Beschreibung der Prozedur. An dieser Stelle reicht ein kurzer<br />

Hinweis auf die Funktionalität, eine Wiederholung des Textes aus dem Spezifikationsteil<br />

ist nicht erforderlich.<br />

3. IMPLEMENTATION (optional): Erläuterung der Arbeitsweise der Prozedur. An<br />

dieser Stelle wird die Prozedur aus realisierungstechnischer Sicht beschrieben.<br />

Wichtig ist vor allem eine überblickartige Beschreibung des Vorgehens, der<br />

Intentionen und Entwurfsentscheidungen, sowie eine Erklärung des zugrundeliegenden<br />

Algorithmus.<br />

4. NOTES (optional): Allgemeine Hinweise. Unter diese Überschrift können alle<br />

Anmerkungen abgelegt werden, die einem Programmierer helfen könnten, die<br />

Prozedur zu verstehen, zu verändern, zu ergänzen oder zu portieren.<br />

(*<br />

PROCEDURE:<br />

ItemAt<br />

DESCRIPTION:<br />

returns the pos-th item in the list (1 = first)<br />

IMPLEMENTATION:<br />

advances list to pos-th item (i.e. pos-1 steps)<br />

and returns it<br />

NOTES:<br />

no checks if pos is in bounds (guaranteed by precond.)<br />

*)<br />

PROCEDURE ItemAt(list: List;<br />

pos : CARDINAL): INTEGER;<br />

VAR i: CARDINAL;<br />

BEGIN<br />

FOR i := 1 TO (pos - 1) DO (* advance to pos-th item *)<br />

list := list^.next;<br />

END;<br />

RETURN list^.item;<br />

END ItemAt;<br />

Lokale Prozeduren. Einen Spezialfall bildet die Kommentierung von Prozeduren, die<br />

keine Trennung zwischen Deklaration und Implementierung kennen. Dies sind üblicherweise<br />

lokale Prozeduren in Modulen und in anderen Prozeduren. Der Kopfkommentar<br />

muss daher ein Art Vereinigung der oben gezeigten Köpfe bilden. Dieser Aufwand<br />

ist in der Regel jedoch nur bei Prozeduren in Modulen gerechtfertigt, nicht<br />

jedoch bei eingeschachtelten Prozeduren.<br />

Ein vollständiger Prozedurkopfkommentar besteht aus den Teilen DESCRIPTION,<br />

PARAMETERS und RETURNS der Deklaration und optional aus den Teilen IMPLEMEN-<br />

TATION und NOTES der Definition.<br />

Bei optionalen Teilen sollte man in jedem Einzelfall entscheiden, welche Abschnitte<br />

wirklich gebraucht werden. Oft sind die Prozeduren einfach genug, um auch in einem<br />

kurzen Kopfkommentar alle wichtigen Informationen zu vermitteln. Dies gilt insbesondere<br />

für eingeschachtelte Prozeduren.


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 20<br />

5.3 Eingeschobene Kommentare<br />

Eingeschobene Kommentare (oder Überschriften) beginnen in der Spalte, in der auch der<br />

nachfolgende Programmtext beginnt. Sie gehen meist nur über wenige Zeilen und<br />

erläutern die folgenden Programmzeilen.<br />

In eingeschobenen Kommentaren wird eine Zusammenfassung des folgenden Algorithmus<br />

gegeben, der Sinn des Programmabschnitts erklärt oder der aktuelle ‘Status’<br />

(angenommene Vorbedingungen usw.) aufgezeigt. Beispiel:<br />

(* The unsorted elements are now sorted using the<br />

QuickSort-Algorithm. See Sedgewick: “Algorithms” for<br />

details about this algorithm. *)<br />

5.4 Erläuterungen<br />

Erläuterungen (oder Anmerkungen) sind kurze Kommentare zu einzelnen Programmzeilen.<br />

Sie stehen direkt hinter den betreffenden Zeilen und werden mit mindestens<br />

zwei Leerzeichen vom Programm abgetrennt. Stehen mehrere Erläuterungen untereinander,<br />

so sollten diese in der gleichen Spalte beginnen. Ansonsten sind die Erläuterungen<br />

möglichst weit nach rechts auszurücken. Muss eine Erläuterung in der nächsten<br />

Zeile fortgesetzt werden, so wird diese ebenfalls eingerückt. Allerdings steht in<br />

dieser Zeile dann kein Programmtext.<br />

average := (val1 + val2) / 2;<br />

(* calculate average*)<br />

Erläuterungen sind normalerweise sehr kurz und stichwortartig abgefasst. Sie<br />

beschreiben nur die Aktion in der betreffenden Zeile. Auf diese Weise werden in der<br />

Regel auch Variablendeklarationen und Typdefinitionen kommentiert.<br />

6 Beispiele<br />

Am Beispiel eines (etwas übertriebenen) HelloWorld-Programms und eines abstrakten<br />

Datentyps Stack kann das Aussehen eines richtlinienkonformen Programms nachvollzogen<br />

werden.<br />

6.1 Hauptmodul HelloWorld.mod<br />

(*<br />

FILE:<br />

~reissing/prokurs/examples/HelloWorld.mod<br />

PROJECT:<br />

Beispiele zum Programmierkurs<br />

CREATED:<br />

Mon Nov 3 10:26:55 MET 1997<br />

VERSION:<br />

$Id: HelloWorld.mod,v 1.5 1998/10/23 08:03:21 reissing Exp reissing $<br />

AUTHOR:<br />

Ralf Reissing<br />

DESCRIPTION:<br />

Hello World program: outputs “Hello World” and exits<br />

The output is defined in constant HelloWorldString;<br />

output is done using procedure WriteLine<br />

*)<br />

MODULE HelloWorld;


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 21<br />

IMPORT InOut;<br />

CONST HelloWorldString = “Hello World”;<br />

(* DESCRIPTION:<br />

Prints the parameter string followed by a line break<br />

PARAMETERS:<br />

string - the string to be printed<br />

*)<br />

PROCEDURE WriteLine(string: ARRAY OF CHAR);<br />

BEGIN<br />

InOut.WriteString(string);<br />

InOut.WriteLn;<br />

END WriteLine;<br />

BEGIN<br />

WriteLine(HelloWorldString);<br />

END HelloWorld.<br />

6.2 Definitionsmodul Stacks.def<br />

(*<br />

FILE:<br />

~reissing/prokurs/examples/Stacks.def<br />

PROJECT:<br />

Programmierkurs, Styleguide Example<br />

CREATED:<br />

Wed Dec 11 17:08:31 MET 1996<br />

VERSION:<br />

$Id: Stacks.def,v 1.7 1998/10/23 08:04:13 reissing Exp reissing $<br />

AUTHOR:<br />

Ralf Reissing<br />

DESCRIPTION:<br />

Standard stack datatype (Last-In-First-Out container)<br />

Item type is currently set to CHAR, may be changed to any other type<br />

Use Create to create a new stack, Destroy to get rid of one;<br />

Push adds an item to the stack, pop removes one<br />

Introduction to formal notation:<br />

A stack can be denoted by a list of items. The leftmost item in the<br />

list is the topmost item of the stack<br />

e.g. if stack = c b a then the top item of stack is ‘c’<br />

Let |stack| be the number of items on a stack.<br />

MODIFICATIONS:<br />

1997/11/06 RR Pop doesn’t return a value anymore<br />

1997/11/06 RR Empty renamed to IsEmpty<br />

1997/11/06 RR PROCEDURE entry added to head comments of procedures<br />

1997/10/29 RR bug in formal notation example fixed:<br />

top element was ‘a’, should be ‘c’<br />

1997/10/27 RR Introduction to formal notation moved into module comment<br />

*)<br />

DEFINITION MODULE Stacks;<br />

TYPE<br />

Item = CHAR; (* or any other simple/opaque type *)<br />

Stack;<br />

(*<br />

PROCEDURE:<br />

Create<br />

DESCRIPTION:


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 22<br />

Creates a new empty stack<br />

PARAMETERS:<br />

none<br />

RETURNS:<br />

a new empty stack<br />

PRE:<br />

TRUE<br />

POST:<br />

Empty(result)<br />

*)<br />

PROCEDURE Create(): Stack;<br />

(*<br />

PROCEDURE:<br />

Destroy<br />

DESCRIPTION:<br />

Destroys a stack and releases associated memory<br />

PARAMETERS:<br />

stack: the stack to be destroyed<br />

PRE:<br />

TRUE<br />

POST:<br />

stack’ undefined, memory released<br />

*)<br />

PROCEDURE Destroy(VAR stack: Stack);<br />

(*<br />

PROCEDURE:<br />

Push<br />

DESCRIPTION:<br />

pushes an item on top of a stack<br />

PARAMETERS:<br />

stack: the stack the item is to be pushed on<br />

item : the item to be pushed on the stack<br />

PRE:<br />

TRUE<br />

POST:<br />

Top(stack’)=item<br />

let stack = c b a, then stack’ = item c b a<br />

*)<br />

PROCEDURE Push(VAR stack: Stack;<br />

item: Item);<br />

(*<br />

PROCEDURE:<br />

Pop<br />

DESCRIPTION:<br />

pops top item from the stack<br />

PARAMETERS:<br />

stack: the stack to be popped from<br />

PRE:<br />

NOT Empty(stack)<br />

POST:<br />

Size(stack’)=Size(stack)-1<br />

let stack = c b a, then stack’ = b a<br />

*)<br />

PROCEDURE Pop(VAR stack: Stack);<br />

(*<br />

PROCEDURE:<br />

Top


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 23<br />

DESCRIPTION:<br />

returns top item of the stack<br />

PARAMETERS:<br />

stack: the stack<br />

RETURNS:<br />

top item of the stack<br />

PRE:<br />

NOT Empty(stack)<br />

POST:<br />

let stack = c b a, then result = c<br />

*)<br />

PROCEDURE Top(stack: Stack): Item;<br />

(*<br />

PROCEDURE:<br />

Size<br />

DESCRIPTION:<br />

returns the number of items on the stack<br />

PARAMETERS:<br />

stack: the stack<br />

RETURNS:<br />

number of items on stack<br />

PRE:<br />

TRUE<br />

POST:<br />

result = |stack|<br />

*)<br />

PROCEDURE Size(stack: Stack): CARDINAL;<br />

(*<br />

PROCEDURE:<br />

IsEmpty<br />

DESCRIPTION:<br />

tells whether a stack is empty, i.e. if there are no items in it<br />

PARAMETERS:<br />

stack: the stack<br />

RETURNS:<br />

TRUE if Size(stack) > 0, else FALSE<br />

PRE:<br />

TRUE<br />

POST:<br />

result = (Size(stack) > 0)<br />

*)<br />

PROCEDURE IsEmpty(stack: Stack): BOOLEAN;<br />

END Stacks.<br />

6.3 Implementierungsmodul Stacks.mod<br />

(*<br />

FILE:<br />

~reissing/prokurs/examples/Stacks.mod<br />

PROJECT:<br />

Programmierkurs, Styleguide Example<br />

CREATED:<br />

Wed Dec 11 17:34:46 MET 1996<br />

VERSION:<br />

$Id: Stacks.mod,v 1.6 1998/10/23 08:04:54 reissing Exp reissing $<br />

AUTHOR:<br />

Ralf Reissing<br />

IMPLEMENTATION:


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 24<br />

stack is implemented using a simple linked list<br />

top item is front element of the list<br />

empty stack is represented by a NIL value<br />

MODIFICATIONS:<br />

1997/11/06 RR changed IMPORT-Format from FROM ... IMPORT To IMPORT ...<br />

1997/11/06 RR adapted implementation of Pop and IsEmpty<br />

to the interface changes<br />

*)<br />

IMPLEMENTATION MODULE Stacks;<br />

IMPORT Storage;<br />

TYPE<br />

Stack = POINTER TO StackType;<br />

StackType = RECORD<br />

item: Item;<br />

next: Stack;<br />

END;<br />

CONST StackTypeSize = SIZE(StackType);<br />

(*<br />

DESCRIPTION:<br />

Creates a new empty stack<br />

*)<br />

PROCEDURE Create(): Stack;<br />

BEGIN<br />

RETURN NIL;<br />

END Create;<br />

(*<br />

DESCRIPTION:<br />

Destroys a stack and releases associated memory<br />

IMPLEMENTATION:<br />

Destroys stack by popping all items<br />

*)<br />

PROCEDURE Destroy(VAR stack: Stack);<br />

BEGIN<br />

WHILE NOT IsEmpty(stack) DO<br />

Pop(stack);<br />

END;<br />

(* stack = NIL here *)<br />

END Destroy;<br />

(*<br />

DESCRIPTION:<br />

pushes an item on top of the stack<br />

*)<br />

PROCEDURE Push(VAR stack: Stack;<br />

item: Item);<br />

VAR newElement: Stack; (* stores newly created element *)<br />

BEGIN<br />

Storage.ALLOCATE(newElement,StackTypeSize);<br />

newElement^.item := item; (* store item *)<br />

newElement^.next := stack; (* prepend new element to stack list *)<br />

stack := newElement;<br />

END Push;<br />

(*<br />

DESCRIPTION:<br />

pops top item from the stack


<strong>Programmierrichtlinien</strong> für Modula-2 RR, 15.10.1999 25<br />

*)<br />

PROCEDURE Pop(VAR stack: Stack);<br />

VAR<br />

auxiliary: Stack; (* stores item to be deallocated *)<br />

BEGIN<br />

auxiliary := stack; (* store element to be deallocated *)<br />

stack := stack^.next; (* switch stack to next element *)<br />

Storage.DEALLOCATE(auxiliary,StackTypeSize); (* dealloc 1st element *)<br />

END Pop;<br />

(*<br />

DESCRIPTION:<br />

returns top item of the stack<br />

*)<br />

PROCEDURE Top(stack: Stack): Item;<br />

BEGIN<br />

RETURN stack^.item;<br />

END Top;<br />

(*<br />

DESCRIPTION:<br />

returns the number of items in the stack<br />

IMPLEMENTATION:<br />

recursive solution: stack is virtually popped until it is empty<br />

each successful virtual pop increments size by one<br />

*)<br />

PROCEDURE Size(stack: Stack): CARDINAL;<br />

BEGIN<br />

IF IsEmpty(stack) THEN<br />

RETURN 0;<br />

ELSE<br />

RETURN 1 + Size(stack^.next);<br />

END;<br />

END Size;<br />

(*<br />

DESCRIPTION:<br />

tells whether the stack is empty, i.e. if there are no items in it<br />

*)<br />

PROCEDURE IsEmpty(stack: Stack): BOOLEAN;<br />

BEGIN<br />

RETURN (stack = NIL);<br />

END IsEmpty;<br />

END Stacks.

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!