Programmierrichtlinien (PDF)
Programmierrichtlinien (PDF)
Programmierrichtlinien (PDF)
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.