03.10.2013 Aufrufe

Diplomarbeit Fachbereich Informatik

Diplomarbeit Fachbereich Informatik

Diplomarbeit Fachbereich Informatik

MEHR ANZEIGEN
WENIGER ANZEIGEN

Verwandeln Sie Ihre PDFs in ePaper und steigern Sie Ihre Umsätze!

Nutzen Sie SEO-optimierte ePaper, starke Backlinks und multimediale Inhalte, um Ihre Produkte professionell zu präsentieren und Ihre Reichweite signifikant zu maximieren.

<strong>Diplomarbeit</strong><br />

Entwurf und Implementierung<br />

eines Syntheseverfahrens<br />

für while-Programme<br />

0LFKDHO&KULVWRIIHO<br />

Betreuer: Dipl.-Inform. Jochen Nessel<br />

Arbeitsgruppe Induktive Inferenz<br />

Prof. Dr. Rolf Wiehagen<br />

<strong>Fachbereich</strong> <strong>Informatik</strong><br />

Universität Kaiserslautern ⋅ Postfach 3049 ⋅ 67653 Kaiserslautern


Erklärung:<br />

Hiermit erkläre ich, daß ich die vorliegende <strong>Diplomarbeit</strong> selbständig<br />

verfaßt habe. Andere als die angegebenen Hilfsmittel und Quellen<br />

wurden von mir nicht verwendet.<br />

Kaiserslautern, den 17. Juli 1997


Vorwort<br />

In dieser Arbeit werden Methoden zur maschinellen Synthese von<br />

Algorithmen anhand von Beispielauswertungen aufgezeigt. Eine<br />

Beispielauswertung ist eine Beschreibung des Ablaufs des zu<br />

synthetisierenden Algorithmus‘ für bestimmte Eingaben. Zur Formulierung<br />

der Algorithmen und der Beispielauswertungen verwenden wir die Sprache<br />

WHILE, die trotz ihrer sehr einfachen Syntax die Beschreibung von<br />

Algorithmen für alle partiell rekursiven Funktionen ermöglicht. Kernstück<br />

der Arbeit ist die Darstellung und Diskussion von Algorithmen zur<br />

Erzeugung der Beispielauswertungen und zur Synthese von Programmen<br />

aus Beispielauswertungen. Des weiteren beinhaltet diese Arbeit einen<br />

objektorientierten Entwurf zur Implementierung dieser Algorithmen. Die<br />

Algorithmen wurden auf mehreren Rechnersystemen erfolgreich<br />

implementiert und getestet.


Danksagung<br />

Ich möchte mich an dieser Stelle bei all denen bedanken, die mich bei der<br />

Erstellung dieser Arbeit unterstützt haben, sei es durch aufmunternde<br />

Worte, sei es durch Hinweise zur Führung der Beweise, sei es durch<br />

praktische Tips zu UNIX, Motif und C++, sei es durch Vorschläge zur<br />

Verbesserung des Layouts und der Bedienung der Benutzeroberfläche<br />

meines Werkzeuges. Insbesondere möchte ich mich bei meinem Professor,<br />

Herrn Prof. Dr. Rolf Wiehagen, und meinem Betreuer, Herrn Dipl.-<br />

Inform. Jochen Nessel, für ihre Unterstützung bei der Erstellung und der<br />

Korrektur dieser Arbeit bedanken.


Inhaltsverzeichnis:<br />

ABBILDUNGSVERZEICHNIS 14<br />

TABELLENVERZEICHNIS 15<br />

1 EINLEITUNG 17<br />

1.1 Vorgeschichte und Motivation 17<br />

1.2 Erste Definition und Einführungsbeispiele 17<br />

1.3 Die Mächtigkeit der Sprache WHILE 23<br />

1.4 Ausführung von Programmen der Sprache WHILE auf einer Registermaschine 33<br />

1.5 Übersicht über die weiteren Kapitel 37<br />

2 DIE SPRACHE WHILE 39<br />

2.1 Zeichenvorrat 39<br />

2.2 Syntax 39<br />

2.3 Programme 40<br />

3 BEISPIELAUSWERTUNGEN 45<br />

3.1 Entfaltungen 45<br />

3.2 Strukturäquivalenz 47<br />

3.3 Werte von Zahlen und Variablen 53<br />

3.4 Konstruktion von Beispielauswertungen 58<br />

3.5 Äquivalente Programme 59<br />

4 AUTOMATISCHE GENERIERUNG VON BEISPIELAUSWERTUNGEN 67<br />

4.1 Variablenlisten 67<br />

4.2 Algorithmus 67<br />

4.3 Korrektheit 70<br />

4.4 Komplexität 82<br />

5 AUTOMATISCHE SYNTHESE VON KLASSE-I-PROGRAMMEN 85<br />

5.1 Idee 85<br />

6HLWH


5.2 Klasse-I-Programme 86<br />

5.3 Algorithmus 86<br />

5.4 Korrektheit 105<br />

5.5 Komplexität 165<br />

6 WEITERE PROGRAMMKLASSEN 181<br />

6.1 Einschränkungen für Klasse-I-Programme 181<br />

6.2 Lokale Variablen 189<br />

6.3 IF-Konstrukte 196<br />

6.4 weitergehende Erweiterungen 199<br />

7 ENTWURFSENTSCHEIDUNGEN 201<br />

8 DER AUFBAU VON ;6$03/( VERSION 2.0 203<br />

8.1 Namenskonventionen 205<br />

8.2 Die Komponente Interface 206<br />

8.3 Die Komponente Text 211<br />

8.4 Die Komponente SampleText 211<br />

8.5 Die Komponente ProgramText 212<br />

8.6 Die Komponente Computer 212<br />

8.7 Die Komponente Synthesizer 213<br />

8.8 Die Komponente Parser 214<br />

8.9 Erweiterungen 217<br />

9 BENUTZERSCHNITTSTELLE 219<br />

9.1 Dateien 219<br />

9.2 Kommandozeilenoptionen 220<br />

9.3 Batch-Mode 222<br />

9.4 Das Hauptformular 223<br />

9.5 Die Menüs 227<br />

9.6 Textbearbeitung 233<br />

9.7 Dialogfenster 236<br />

6HLWH


9.8 Die Syntax der Hilfetexte und Fehlermeldungen 241<br />

10 PORTIERUNGEN 243<br />

11 BEISPIELE VON PROGRAMMLÄUFEN 245<br />

11.1 Programmläufe im Batch-Modus 245<br />

11.2 Programmläufe mit der graphischen Benutzeroberfläche 247<br />

12 ZUSAMMENFASSUNG UND SCHLUßBEMERKUNGEN 255<br />

ANHANG A DIE WIDGETSTRUKTUR VON XSAMPLE 2.0 257<br />

ANHANG B RESOURCEN 263<br />

ANHANG C QUELLTEXT 275<br />

ANHANG D VERZEICHNIS DER VERWENDETEN LITERATUR 277<br />

INDEX 279<br />

6HLWH


Verzeichnis der Abbildungen:<br />

Abbildung 1 : Modell des Roboters aus Beispiel 1.2.3 _______________________________ 21<br />

Abbildung 2 : Struktur der simulierten Turingmaschine ______________________________ 31<br />

Abbildung 3 : Eine Registermaschine zur Implementation von WHILE-Programmen _______ 34<br />

Abbildung 4 : Struktur des Algorithmus’ ComputeProgram ___________________________ 68<br />

Abbildung 5 : Struktur des Algorithmus’ SampleProgram_____________________________ 87<br />

Abbildung 6 : Struktur des Beweises von Satz 5.4.1 ________________________________ 106<br />

Abbildung 7 : Struktur des Beweises von Satz 5.5.1 ________________________________ 166<br />

Abbildung 8 : Struktur von [VDPSOH 2.0 _________________________________________ 204<br />

Abbildung 9 : Struktur der Komponente Interface__________________________________ 206<br />

Abbildung 10 : Struktur der Komponente Parser __________________________________ 214<br />

Abbildung 11 : Das Hauptformular von [VDPSOH 2.0_______________________________ 224<br />

Abbildung 12 : Tear-Off-Menüs ________________________________________________ 231<br />

Abbildung 13 : Das Dialogfenster der Sicherheitsabfrage ___________________________ 237<br />

Abbildung 14 : Die Warnungsbox ______________________________________________ 237<br />

Abbildung 15 : Die Dateiauswahlbox ___________________________________________ 238<br />

Abbildung 16 : Die Hilfebox __________________________________________________ 240<br />

Abbildung 17 : Das Fehlermeldedialogfenster und das Fehlerprotokollfenster ___________ 241<br />

Abbildung 18 : Beispiel 1 - Programmauswertung _________________________________ 248<br />

Abbildung 19 : Beispiel 1 - Programmsynthese____________________________________ 249<br />

Abbildung 20 : Beispiel 2 - Programmauswertung _________________________________ 250<br />

Abbildung 21 : Beispiel 2 - Programmsynthese____________________________________ 251<br />

Abbildung 22 : Beispiel 3 - Programmauswertung _________________________________ 252<br />

Abbildung 23 : Beispiel 3 - Programmsynthese____________________________________ 253<br />

Abbildung 24 : Beispiel 4 _____________________________________________________ 254<br />

Abbildung 25 : Die Widgetstruktur des Hauptformulars von [VDPSOH 2.0 ______________ 257<br />

Abbildung 26 : Die Widgetstruktur des Hauptformulars von [VDPSOH2.0 (Fortsetzung)___ 258<br />

Abbildung 27 : Die Widetstruktur des Hauptformulars von [VDPSOH2.0 (Fortsetzung)____ 259<br />

Abbildung 28 : Die Widgetstruktur des Hauptformulars von [VDPSOH 2.0 (Fortsetzung) ___ 260<br />

Abbildung 29 : Die Widgetstruktur des Hauptformulars von [VDPSOH2.0 (Fortsetzung)___ 261<br />

Abbildung 30 : Die Widgetstruktur des Hauptformulars von [VDPSOH 2.0 (Fortsetzung) ___ 262<br />

6HLWH


Verzeichnis der Tabellen:<br />

Tabelle 1 : Die Befehle der Registermaschine ______________________________________34<br />

Tabelle 2 : Die Syntax der Sprache WHILE ________________________________________39<br />

Tabelle 3 : Erweiterte Syntax der Sprache WHILE _________________________________197<br />

Tabelle 4 : Namenskoventionen ________________________________________________205<br />

Tabelle 5 : Kommandozeilenoptionen ___________________________________________220<br />

Tabelle 6 : Die Pushbuttonezeile _______________________________________________226<br />

Tabelle 7 : Das File-Menü ____________________________________________________227<br />

Tabelle 8 : Das Edit-Menü ____________________________________________________228<br />

Tabelle 9 : Das Help-Menü____________________________________________________229<br />

Tabelle 10 : Das Popupmenü des Samplefensters __________________________________229<br />

Tabelle 11 : Das Popupmenü des Programmfensters________________________________230<br />

Tabelle 12 : Zusammenstellung der Menübefehle __________________________________231<br />

Tabelle 13 : Tastenkombination zum Löschen von Text______________________________234<br />

Tabelle 14 : Tastenkombinationen zum Bewegen des Textcursors______________________234<br />

Tabelle 15 : Die Dateien des Quellcodes _________________________________________275<br />

6HLWH


(LQOHLWXQJ<br />

1 Einleitung<br />

Das effiziente Lernen von Sprachen ist heute ein wichtiger Gegenstand der Forschung in der<br />

<strong>Informatik</strong>. Bedeutende praktische Anwendungen dieser Theorie sind unter anderem<br />

w<br />

w<br />

w<br />

das maschinelle Verstehen natürlicher Sprache,<br />

verbesserte Mensch-Maschine-Schnittstellen für Softwaresysteme und<br />

die Unterstützung des Softwareentwicklungsprozesses<br />

Diese Arbeit beschäftigt sich mit dem Lernen von Sprachen anhand von Beispielen für die<br />

Verwendung dieser Sprachen. Dabei wollen wir uns auf Programmiersprachen konzentrieren.<br />

Unsere Beispiele zur Verwendung dieser Sprachen sind somit Beschreibungen der<br />

Ausführungen von Programmen der gewählten Programmiersprache sein. Für diese<br />

Beschriebungen werden wir den Namen Beispielauswertung einführen. Ziel des Lernprozesses<br />

ist somit die Synthese der zugrundeliegenden Algorithmen aus den Beispielauswertungen.<br />

Somit überschreitet diese Arbeit die Grenzen der Lerntheorie und enthält auch Aspekte der<br />

Theorie der Programmiersprachen, des Software-Engineerings und der Robotik.<br />

Eine nicht unerhebliche Schwierigkeit beim maschinellen Lernen von Sprachen bereitet die<br />

Komplexität der Sprachen. Da die Programmsynthese aber möglichst effizient verlaufen soll,<br />

muß daher die verwendete Sprache zur Beschreibung der Algorithmen und der<br />

Beispielauswertungen möglichst einfach sein.<br />

In diesem einführenden Kapitel wird eine erste Definition der Sprache WHILE angegeben, die<br />

das Kriterium der Einfachheit erfüllt. Es wird gezeigt, daß jede durch eine Turingmaschine<br />

berechenbare Funktion auch durch ein WHILE-Programm berechnet werden kann. Ebenfalls<br />

wird eine einfache Maschine angegeben, die WHILE-Programme ausführen kann.<br />

1.1 Vorgeschichte und Motivation<br />

Der Autor dieser <strong>Diplomarbeit</strong> hatte sich bereits für seine Projektarbeit 1 mit der Thematik des<br />

Lernens von Programmiersprachen anhand von Beispielauswertungen befaßt. Damals befaßte<br />

er sich mit der Implementierung eines Ansatzes zur automatischen Programmsynthese von<br />

Efim B. Kinber von der Universität Riga 2 . Das Ergebnis der Untersuchungen entsprach jedoch<br />

nicht den Erwartungen.<br />

Motivation für diese <strong>Diplomarbeit</strong> war somit die Suche nach einem anderen Ansatz für das<br />

Problem des effizienten Lernens von Programmiersprachen anhand von Beispielauswertungen.<br />

Dieser Ansatz sollte dann ebenfalls auf einem Rechnersystem implementiert werden.<br />

1.2 Erste Definition und Einführungsbeispiele<br />

'HILQLWLRQ<br />

(LQ:+,/(3URJUDPPLVWHLQ7XSHO9(\$ZREHL<br />

9HLQH0HQJHYRQ9DULDEOHQ<br />

(⊆9GLHJHRUGQHWH0HQJHGHU(LQJDEHYDULDEOHQ<br />

\∈9GLH$XVJDEHYDULDEOH<br />

$HLQH)ROJHYRQ$QZHLVXQJHQ<br />

1 „Implementierung von Algorithmen zur Synthese von Programmen rekursiver Funktionen aus<br />

Beispielauswertungen“, eingereicht an der Arbeitsgruppe Induktive Inferenz, <strong>Fachbereich</strong><br />

<strong>Informatik</strong>, Universität Kaiserslautern (1995)<br />

2 Siehe Literatur 14<br />

6HLWH


(LQOHLWXQJ<br />

'DEHLLVWDOV$QZHLVXQJD∈$IROJHQGHVHUODXEW<br />

DGDV,QNUHPHQWHLQHU9DULDEOHQY∈9JHVFKULHEHQY<br />

EGDV'HNUHPHQWHLQHU9DULDEOHQY∈9JHVFKULHEHQY<br />

FGLH,QLWLDOLVDWLRQHLQHU9DULDEOHQY∈9JHVFKULHEHQVHWY PGDEHLGDUI<br />

PHLQH9DULDEOHDX‰HUYRGHUHLQHQDW UOLFKH=DKOVHLQ<br />

GHLQH6FKOHLIHJHVFKULHEHQ<br />

while v > 0 do<br />

A’<br />

end do<br />

'DEHLVHLY∈9XQG$HLQH)ROJHYRQ$QZHLVXQJHQ<br />

(VJHOWHQI UGLH9DULDEOHQIROJHQGH%HGLQJXQJHQ<br />

-HGH9DULDEOHY∈9PX‰HLQH,QLWLDOLVDWLRQEHVLW]HQXQGGDUIYRULKUHU<br />

,QLWLDOLVDWLRQQLFKWYHUZHQGHWZHUGHQ<br />

(LQH,QLWLDOLVDWLRQGDUIQXU<br />

ì YRUHLQHUZHLWHUHQ,QLWLDOLVDWLRQ<br />

ì YRUGHUHUVWHQ$QZHLVXQJDX‰HUHLQHU,QLWLDOLVDWLRQYRQ$<br />

ì YRUHLQHU6FKOHLIH<br />

VWHKHQ<br />

6FKUHLEZHLVH<br />

) UGDV:+,/(3URJUDPP9^[ [ Q`\^D D P`YHUZHQGHQZLUIROJHQGH<br />

1RWDWLRQ<br />

input (x 1 ,..,x n )<br />

a 1<br />

...<br />

a m<br />

output y<br />

'HILQLWLRQ<br />

6HL: ^9^[ [ Q`\$`HLQ:+,/(3URJUDPPXQGVHL1 ^Q Q Q`HLQH<br />

JHRUGQHWH0HQJHQDW UOLFKHU=DKOHQZREHLQGHU$Q]DKOGHU<br />

(LQJDEHYDULDEOHQYRQ:HQWVSULFKW'LH$XVZHUWXQJYRQ:EHL(LQJDEH1LVW<br />

GDQQGXUFKIROJHQGH9HUIDKUHQVYRUVFKULIWGHILQLHUW<br />

) UMHGHVL∈^Q`VHW]HGHQ:HUWGHU9DULDEOHQ[ L DXIQ L <br />

:HUWHGLH$QZHLVXQJVIROJH$DXV<br />

'LH$XVZHUWXQJHLQHU$QZHLVXQJVIROJHD D N ZREHLI UHLQN∈©D D N<br />

$QZHLVXQJHQLVWUHNXUVLYGHILQLHUWGXUFK<br />

)DOOVN OHHUH$QZHLVXQJVIROJHWXHQLFKWV<br />

)DOOVN! :HUWH$QZHLVXQJD DXVXQGZHUWHGDQDFKGLH<br />

$QZHLVXQJVIROJHD D N DXV<br />

) UGLH$XVZHUWXQJHLQHU$QZHLVXQJJLOW<br />

DLVW,QNUHPHQWGHU9DULDEOHQY∈9<br />

6HLFGHU:HUWGHU9DULDEOHQY6HW]HGHQ:HUWYRQYDXIF<br />

DLVW'HNUHPHQWGHU9DULDEOHQY∈9<br />

6HLWH


(LQOHLWXQJ<br />

6HLFGHU:HUWGHU9DULDEOHQY)DOOVF!VHW]HGHQ:HUWYRQYDXIF<br />

DQVRQVWHQWXHQLFKWV<br />

6HLWH


(LQOHLWXQJ<br />

DLVW,QLWLDOLVDWLRQHLQHU9DULDEOHQYHWZDVHWY P<br />

)DOOVPLVW9DULDEOHVRVHW]HGHQ:HUWGHU9DULDEOHQYDXIGHQ:HUWYRQ<br />

P<br />

)DOOVPLVWHLQHQDW UOLFKH=DKOVRVHW]HGHQ:HUWGHU9DULDEOHQYDXIP<br />

DLVW6FKOHLIHHWZD<br />

while v > 0 do<br />

A’<br />

end while<br />

ZREHLY∈9XQG$HLQH$QZHLVXQJVIROJHLVWYHUIDKUHQDFKIROJHQGHU<br />

9RUVFKULIW<br />

L)DOOVGHU:HUWGHU9DULDEOHQYLVWJHKH]XUQlFKVWHQ$QZHLVXQJ<br />

DQVRQVWHQJHKH]X3XQNWLL<br />

LL:HUWHGLH$QZHLVXQJVIROJH$DXVJHKH]X3XQNWL<br />

'HILQLWLRQ<br />

'LH$XVZHUWXQJHLQHV:+,/(3URJUDPPHVWHUPLQLHUWZHQQEHLGHU<br />

$XVZHUWXQJQDFKHQGOLFKYLHOHQ5HFKHQVFKULWWHQDOOH$QZHLVXQJHQ<br />

DXVJHZHUWHWZRUGHQVLQG<br />

'HILQLWLRQ<br />

'LH$XVZHUWXQJHLQHV:+,/(3URJUDPPHVOLHIHUWGHQ:HUWFF∈©ZHQQ<br />

DGLH$XVZHUWXQJWHUPLQLHUW<br />

EQDFK%HHQGLJXQJGHU$XVZHUWXQJKDWGLH$XVJDEHYDULDEOHGHQ:HUWF<br />

Zeigen wir nun, wie mit Hilfe eines WHILE-Programmes Algorithmen zur Addition und<br />

Multiplikation zweier natürlicher Zahlen beschreiben werden kann:<br />

Beispiel 1.2.1:<br />

Gegeben sei das folgende WHILE-Programm:<br />

input (a,b)<br />

while a > 0 do<br />

++b<br />

--a<br />

end while<br />

output b<br />

Die Schleife in obigem Programm terminiert in a Schritten, d.h. der Wert der Variablen b wird<br />

a-mal um 1 erhöht. Demnach hat die Variable b nach Beendigung der Schleife den Wert a+b.<br />

Dies ist auch der Wert der Ausgabe.<br />

6HLWH


(LQOHLWXQJ<br />

Beispiel 1.2.2:<br />

Gegeben sei das folgende WHILE-Programm:<br />

input (a,b)<br />

set (s := 0)<br />

while a > 0 do<br />

set (c := b)<br />

while c > 0 do<br />

++s<br />

--c<br />

end while<br />

--a<br />

end while<br />

output s<br />

Analog zu Beispiel 1.2.1 wird die äußere Schleife genau a-mal durchlaufen. Bei jedem<br />

Durchlauf wird die Variable s, die mit dem Wert 1 initialisiert wird, um den Betrag b erhöht.<br />

Demnach hat s nach Beendigung der äußeren Schleife den Wert a⋅b, der dann der Wert der<br />

Ausgabe ist.<br />

Beispiel 1.2.3:<br />

Wenden wir uns jetzt einem etwas anwendungsbezogenerem Beispiel zu. Dieses Beispiel soll<br />

zweierlei veranschaulichen:<br />

(1) Obwohl die Ausdrucksmöglichkeiten der Sprache sehr rudimentär sind, reichen sie für<br />

bestimmte Anwendungsgebiete aus.<br />

(2) Es kann sehr vom Nutzen sein, die Sprache zu erweitern.<br />

Abbildung 1 : Modell des Roboters aus Beispiel 1.2.3<br />

links<br />

rechts<br />

auf<br />

ab<br />

öffne<br />

schließe<br />

Ein Roboter verfüge über die folgenden Operationen:<br />

links dreht den Roboter um eine Winkeleinheit nach links<br />

rechts dreht den Roboter um eine Winkeleinheit nach rechts<br />

6HLWH


(LQOHLWXQJ<br />

auf bewegt den Arm des Roboters um eine Längeneinheit nach oben<br />

ab bewegt den Arm des Roboters um eine Längeneinheit nach unten<br />

schließe schließt die Greifhand des Roboterarmes<br />

öffne öffnet die Greifhand des Roboterarmes<br />

Die Programmierung des Roboters geschieht in der Sprache WHILE gemäß Definition 1.2.1,<br />

wobei wir als zusätzliche Anweisungen die Schlüsselworte links, rechts, auf, ab, schließe<br />

und öffne zulassen.<br />

Der Roboter erhalte folgende Aufgabe: a Holzklötzchen, die aufgetürmt an der Position (0)<br />

liegen sollen auf die Positionen (1) - (a) verteilt werden, so daß auf jeder Position genau ein<br />

Hölzchen zu liegen kommt. Zu Beginn befinde sich die Hand des Roboters an Position (0) auf<br />

der untersten Ebene. Am Ende der Aufgabe soll die Hand wieder auf dieser Position<br />

angekommen sein. Die Positionen sind alle nur eine Winkeleinheit voneinander entfernt, wobei<br />

Position (0) die rechteste der Positionen ist. Die Höhe der Klötzchen beträgt eine<br />

Längeneinheit.<br />

Dann kann die Aufgabe durch das folgende Programm gelöst werden<br />

input (a)<br />

set (b := a)<br />

set (c := 0)<br />

--b<br />

while a > 0 do<br />

while b > 0 do<br />

auf<br />

--b<br />

++c<br />

end while<br />

++c<br />

schließe<br />

while c > 0 do<br />

links<br />

--c<br />

++b<br />

end while<br />

--b<br />

while b > 0 do<br />

ab<br />

--b<br />

++c<br />

end while<br />

++c<br />

öffne<br />

while c > 0 do<br />

rechts<br />

--c<br />

++b<br />

end while<br />

--b<br />

--b<br />

--a<br />

end while<br />

output a<br />

6HLWH


(LQOHLWXQJ<br />

Auch hier ist die Korrektheit des Algorithmus' sofort einsichtig. Die äußere Schleife wird<br />

genau so oft durchlaufen, wie Klötzchen vorhanden sind, wobei die Variable a bei jedem<br />

Durchlauf um 1 vermindert wird.<br />

Vor jedem Schleifendurchlauf ruht der Arm auf der untersten Ebene von Position (0). Dann<br />

wird der Arm des Roboters um (a-1) Längenelemente nach oben bewegt, und die Hand ergreift<br />

das oberste Element des Stapels. Dann bewegt sich der Arm um a Elemente nach links, um<br />

sich um (a-1) Elemente zu senken, womit wieder die unterste Ebene erreicht wird. Die Hand<br />

öffnet sich und das Element wird auf der Position (a) abgelegt. Dann bewegt sich der Arm a<br />

Winkeleinheiten zum Ausgangspunkt.<br />

1.3 Die Mächtigkeit der Sprache WHILE<br />

'HILQLWLRQ<br />

(LQH)XQNWLRQI© N →©KHL‰W:+,/(EHUHFKHQEDUZHQQHVHLQ:+,/(<br />

3URJUDPP:JLEWVRGD‰I UMHGHV7XSHOQDW UOLFKHU=DKOHQQ Q N JLOW<br />

:HQQIQ Q N ↓GDQQOLHIHUW:EHL(LQJDEHQ Q N GHQ:HUWIQ Q N <br />

XQGZHQQIQ Q N ↑VROLHIHUW:NHLQHQ:HUW<br />

'HILQLWLRQ<br />

6HLIHLQH:+,/(EHUHFKHQEDUHNVWHOOLJH)XQNWLRQ6HL:HLQ:+,/(<br />

3URJUDPPGD‰IEHUHFKQHW:KDEHIROJHQGH*HVWDOW<br />

input (x 1 ,...,x k )<br />

a 1<br />

...<br />

a n<br />

output y<br />

GDEHLVHLHQD D Q I UHLQQ∈©:+,/($QZHLVXQJHQ<br />

'DQQKHL‰WGLH$QZHLVXQJVIROJHGHU*HVWDOW<br />

set (x 1 ← x 1 ’)<br />

set (x 2 ← x 2 ’)<br />

...<br />

set (x k ← x k ’)<br />

a 1<br />

...<br />

a n<br />

set (y’ ← y)<br />

ZREHLGLH9DULDEOHQ[ [ N \QLFKWLQD D Q YRUNRPPHQ0DNURYRQIXQG<br />

ZLUGDEJHN U]WGXUFK\←I[ [ N <br />

6DW]<br />

-HGHSULPLWLYUHNXUVLYH)XQNWLRQILVW:+,/(EHUHFKHQEDU<br />

Beweis:<br />

Wir zeigen durch Induktion über den Aufbau der Menge der primitiv rekursiven<br />

Funktionen, daß jede primitiv rekursive Funktion auch WHILE-berechenbar ist.<br />

(strukturelle Induktion)<br />

Induktionsverankerung:<br />

Konstantenfunktionen, Projektionsfunktionen und die Nachfolgerfunktion<br />

sind WHILE-berechenbar.<br />

6HLWH


(LQOHLWXQJ<br />

1. Konstantenfunktionen:<br />

Seien k und c beliebige natürliche Zahlen. Dann ist die k-stellige Funktion<br />

constc: © k →©definiert durch constc (x1,...,xk) = c für alle natürliche Zahlen<br />

x1,...,xk.<br />

Dann wird constc durch das folgende WHILE-Programm berechnet:<br />

input (x 1 ,..,x k )<br />

set (y ← c)<br />

output y<br />

2. Projektionsfunktionen:<br />

Seien k,i ∈© + mit i≤k. Dann ist die k-stellige Funktion proji: © k →©definiert<br />

durch proji (x1,...,xk) = xi für alle natürliche Zahlen x1,...,xk.<br />

Dann wird proji durch das folgende WHILE-Programm berechnet:<br />

input (x 1 ,..,x k )<br />

set (y ← x i )<br />

output y<br />

3. Nachfolgerfunktion:<br />

Die einstellige Funktion succ: © →© ist definiert durch succ(x) = x + 1 für alle<br />

x∈©. Sie wird durch das folgende WHILE-Programm berechnet:<br />

input (x)<br />

set (y ← x)<br />

++y<br />

output y<br />

Induktionvoraussetzung:<br />

Sei k∈© + und n∈© beliebig. Die primitiv rekursive Funktion g: © k →©,<br />

h1,...,hk: © n →©, c: © k-1 →© und d: © k+1 →© seien WHILE-berechenbar.<br />

Induktionsbehauptung:<br />

1. Verkettung primitiv rekursiver Funktionen<br />

Sei f: © n →© definiert durch f(x1,...,xn) =<br />

g(h1(x1,...,xn),h2(x1,...,xn),...,hk(x1,...,xn)). Dann ist f WHILE-berechenbar.<br />

2. Rekursion primitiv rekursiver Funktionen:<br />

Sei r: © k →© definiert durch<br />

r(x1,...,xk-1,0) = c(x1,...,xk)<br />

r(x1,...,xk-1,i+1) = d(x1,..,xk,i+1,r(x1,..,,xk,i)) für alle i∈©.<br />

Dann ist r WHILE-berechenbar.<br />

Induktionsschluß:<br />

1. Verkettung rekursiver Funktionen<br />

Die Funktionen g und h1,...,hk sind nach Induktionsvoraussetzung WHILEberechenbar,<br />

also können auch Makros von ihnen gebildet werden.<br />

6HLWH


(LQOHLWXQJ<br />

Das WHILE-Programm W sei folgendermaßen deklariert:<br />

input (x 1 ,,...,x n )<br />

z 1 ← h 1 (x 1 ,...,x n )<br />

...<br />

z k ← h k (x 1 ,...,x n )<br />

y ← g(z 1 ,...,z k )<br />

output y<br />

Dabei seien x1,...,xn, z1,...,zk, y Variablen, die in den Programmen für g und<br />

h1,...,hk nicht vorkommen.<br />

Nach Definition 1.3.2 enthalten die Variablen z1,..,zk die Ausgaben der<br />

WHILE-Programme für h1,...,hk für die Eingaben von W. Da die Variablen<br />

z1,..,zk als Eingaben zum Makro von g dienen, wird der Variablen y<br />

tatsächlich der Wert f(x1,..,xn) zugewiesen und als Ausgabe für W verwendet.<br />

Also ist f WHILE-berechenbar.<br />

2. Rekursion primitiv rekursiver Funktionen<br />

Nach Induktionsvoraussetzung sind die Funktionen c und d WHILEberechenbar,<br />

weswegen Makros von ihnen gebildet werden können. Nach<br />

Induktionsverankerung sind die Projektionsfunktionen WHILE-berechenbar,<br />

also können auch von ihnen Makros gebildet werden.<br />

Definiere das WHILE-Programm W folgendermaßen, wobei x1,..,.xk,i,y und z<br />

Variablen sind, die in den Programmen von c und d nicht vorkommen:<br />

input (x 1 ,...,x k ,i)<br />

y ← c(x 1 ,...,x k )<br />

while i>0 do<br />

z ← d(x 1 ,...,x k ,i,y)<br />

y ← proj 1 (z)<br />

--i<br />

end while<br />

output y<br />

Wir wollen nun durch Induktion zeigen, daß W die Funktion r berechnet.<br />

(vollständige Induktion über den Wert der Eingabevariablen i)<br />

Induktionsverankerung für i=0:<br />

Für i=0 wird die Schleife nicht durchlaufen, die Ausgabevariable y erhält<br />

den Wert des Makros von c, d.h. für die Eingabe (x1,..,xk,0) liefert der<br />

Algorithmus den Wert von r(x1,..,xk,0) = c(x1,..,xk).<br />

Induktionsvoraussetzung:<br />

Es sei nun i = m beliebig. Für die Eingabe (x1,..,xk,m) wird die Schleife m-<br />

mal durchlaufen und nach dem letzten Schleifendurchlauf hat y den Wert<br />

r(x1,..,xk,m).<br />

Induktionsbehauptung:<br />

6HLWH


(LQOHLWXQJ<br />

Für die Eingabe (x1,..,xk,m+1) wird die Schleife (m+1)-mal durchlaufen und<br />

y hat nach Beendigung des letzten Schleifendurchlaufs den Wert<br />

r(x1,..,xk,m+1).<br />

Induktionsschluß:<br />

Die Variable i kommt in den Programmen der Funktionen c und d nicht<br />

vor, genausowenig wie im Programm für proj1. Also ist die einzige<br />

Anweisung, die i verändert, die Anweisung --i. Nach genau (m+1)<br />

Schleifendurchläufen erreicht die Variable i damit den Wert 0 und die<br />

Schleife wird verlassen.<br />

Nach m Schleifendurchläufen hat die Variable y gemäß<br />

Induktionsvoraussetzung den Wert r(x1,..,xk,m). Also wird im (m+1)-ten<br />

Schleifendurchlauf der Variablen z der Wert d(x1,...,xk,m, r(x1,..,xk,m)) =<br />

r(x1,..,xk,m+1) zugeordnet. Nach Auswertung der Projektionsfunktion<br />

erhält y im (m+1)-ten Schleifendurchlauf den Wert r(x1,..,xk,m+1), der<br />

dann auch ausgegeben wird, da die Schleife verlassen wird.<br />

Nach Induktion berechnet W die Funktion r, die somit WHILE-berechenbar<br />

ist.<br />

6DW]<br />

-HGHSDUWLHOOUHNXUVLYH)XQNWLRQLVW:+,/(EHUHFKHQEDU<br />

Beweis:<br />

Da wir bereits bewiesen haben, daß jede primitiv rekursive Funktion WHILEberechenbar<br />

ist, genügt es zu zeigen, daß für eine gegebene primitiv rekursive<br />

Funktion g: © k+1 →© (k∈©) auch die (partielle) Funktion f: © k →© WHILEberechenbar<br />

ist, wobei f gegeben durch f(x1,...,xk) = minz (g(x1,..,xk,z)=0).<br />

Dazu geben wir folgendes WHILE-Programm W an:<br />

input (x 1 ,..,x n )<br />

set (y ← 0)<br />

w ← g(x 1 ,..,x k ,y)<br />

while w > 0 do<br />

++y<br />

w ← g(x 1 ,..,x k ,y)<br />

end while<br />

output y<br />

Die Variablen x1,..,xn,y und w kommen dabei im Programm für g nicht vor.<br />

Seinen x1,..,xk jetzt beliebige natürliche Zahlen.<br />

1. Fall: ∃z[g(x1,..,xk,z)=0]<br />

Dann sei m = minz [g(x1,..,xk,z)=0] = f(x1,...,xk).<br />

Für m = 0 ist g(x1,..,xk,0) = 0. Damit hat w vor dem ersten Schleifendurchlauf<br />

den Wert 0 und die Schleife wird nicht betreten und der Wert y = f(x1,...,xk) wird<br />

ausgegeben.<br />

Sei nun m > 0. Dann wird die Schleife mindestens einmal betreten. Wir zeigen<br />

zuerst, daß W mindestens m-1 Schleifendurchläufe benötigt.<br />

6HLWH


(LQOHLWXQJ<br />

Da m das Minimum ist, gilt folglich [z0]. Da y im Programm<br />

von g nicht vorkommt, kann sein Wert auch nur in der Anweisung ++y<br />

verändert werden. Da vor dem ersten Schleifendurchlauf y den Wert 0 hat,<br />

kann y in m-1 Schleifendurchläufen nur den Wert m-1 annehmen. Für<br />

y∈{0,..,m-1} ist aber g(x1,..,xk)>0. Dann erhält w bei jedem Schleifendurchlauf<br />

einen Wert ungleich 0 und die Schleife kann nicht verlassen werden.<br />

Im m-ten Schleifendurchlauf hat y als Engabe zum Makro von g den Wert m.<br />

Da g(x1,...,xk,m) = 0, wird die Schleife mit dem Wert y = m verlassen und der<br />

Wert m = f(x1,..,xk) ausgegeben.<br />

2. Fall: [z[g(x1,..,xk,z)>0]<br />

Dann gilt insbesondere g(x1,..,xk,0)>0, d.h. w hat vor der Schleife einen Wert<br />

ungleich 0 und die Schleife wird betreten. Da w aber nie den Wert 0 erreichen<br />

kann, kann die Schleife auch nicht verlassen werden. Also terminiert W nicht<br />

und gibt deswegen auch keinen Wert aus.<br />

Also berechnet W die Funktion f. Damit sind aber auch alle partiell rekursiven<br />

Funktionen WHILE-berechenbar.<br />

/HPPD<br />

6HLΣHLQ$OSKDEHWXQGV _Σ_6HLFΣ→^V`HLQHELMHNWLYH$EELOGXQJ<br />

'DQQH[LVWLHUWHLQHLQMHNWLYHWRWDOH:+,/(EHUHFKHQEDUH$EELOGXQJFRGHΣ<br />

→©<br />

Beweis:<br />

Es genügt die Angabe einer Kodierungsfunktion. Definiere code durch:<br />

k<br />

c( σ i)<br />

code(σ1...σk) = Π prim(i)<br />

i=1<br />

dabei liefert prim(i) die i-te Primzahl und σ1...σk ein Wort über Σ für ein k∈©.<br />

code ist injektiv und total. Da code außerdem primitiv rekursiv ist, ist code nach<br />

Satz 1.3.1 auch WHILE-berechenbar.<br />

/HPPD<br />

6HLΣHLQHQGOLFKHV$OSKDEHWXQGFRGHΣ→©HLQH.RGLHUXQJVIXQNWLRQ<br />

'DQQLVWGLH)XQNWLRQGHFRGH©ò→ΣGHILQLHUWGXUFKGHFRGHFRGHσ σ N L<br />

σ L I UDOOHσ σ N ∈ΣXQGL∈^N`:+,/(EHUHFKHQEDU<br />

Beweis:<br />

Sei code, prim und c wie im Beweis von Lemma 1.3.1. Definiere decode durch:<br />

decode (n,i) = c -1 ( maxz [prim(i) z | n])<br />

Sei σ1...σk und i∈{1,..,k} gegeben. Dann ist<br />

code(σ1...σk) = Π<br />

j=1<br />

k<br />

c(<br />

prim(j)<br />

σ j ) und<br />

k<br />

c(<br />

prim(j)<br />

decode (code(σ1...σk),i) = decode( Π<br />

j=1<br />

= c -1 (maxz [prim(i) z k<br />

c( σ j<br />

| Π prim(j)<br />

) ])<br />

j=1<br />

= c -1 (max {z | z ≤ c(σi)}) = c -1 (c(σi)) = σi.<br />

σ j ) ,i)<br />

6HLWH


(LQOHLWXQJ<br />

Die Funktion decode ist primitiv rekursiv und damit nach Satz 1.3.1 WHILEberechenbar.<br />

/HPPD<br />

6HLΣHLQ$OSKDEHWXQGFRGHΣ→©HLQH.RGLHUXQJVIXQNWLRQ'DQQLVWGLH<br />

)XQNWLRQFKFRGH©ò×Σ→©GHILQLHUWGXUFKFKFRGHFRGHσ σ L σ L σ L σ N Lσ<br />

FRGHσ σ L σσ L σ N I UDOOHσ σ N ∈ΣXQGL∈^N`:+,/(EHUHFKHQEDU<br />

Beweis:<br />

Sei code, prim und c wie im Beweis von Lemma 1.3.1. Definiere chcode durch:<br />

n<br />

c( σ )<br />

chcode (n,i,σ) =<br />

prim(i)<br />

z<br />

maxz[prim(i)<br />

|n]<br />

prim(i)<br />

Sei σ1...σk,σ und i∈{1,..,k} gegeben. Dann ist<br />

chcode (code(σ1...σk),i,σ) = chcode ( Π<br />

j=1<br />

=<br />

=<br />

=<br />

k<br />

prim(i)<br />

k<br />

Π prim(j)<br />

j=1<br />

prim(i)<br />

Π prim(j)<br />

c( σ )<br />

j=1<br />

k<br />

z c( σj)<br />

max [prim(i) | Π prim(j)<br />

i<br />

c( σ j )<br />

c( σ i )<br />

j=1<br />

prim(i)<br />

j<br />

c( σ )<br />

k<br />

c( σ i )<br />

c( σ )<br />

( Π prim(j) ) prim(i)<br />

j=1<br />

j≠i<br />

= code(σ1...σi-1σσi+1σk)<br />

k<br />

prim(i)<br />

c(<br />

prim(j)<br />

c( σ )<br />

σ j ) ,i,σ)<br />

(nach Lemma 1.3.2)<br />

Da chcode primitiv rekursiv, ist es nach Satz 1.3.1 auch WHILE-berechenbar.<br />

'HILQLWLRQ<br />

6HL[HLQH9DULDEOHXQGNHLQHQDW UOLFKH=DKO'DQQLVWGLHVZLWFK<br />

$QZHLVXQJ<br />

switch x<br />

case 0: A 1<br />

case 1: A 2<br />

...<br />

case k: A k<br />

otherwise A<br />

end switch<br />

ZREHL$ $ N $)ROJHQYRQ:+,/($QZHLVXQJHQIROJHQGHUPD‰HQGHILQLHUW<br />

6HLWH


(LQOHLWXQJ<br />

set (y := x)<br />

set (z := 1)<br />

while y > 0 do // 0<br />

--y<br />

while y > 0 do // 1<br />

--y<br />

while y > 0 do // 2<br />

...<br />

while y > 0 do // k-1<br />

--y<br />

while y > 0 do // k<br />

--z<br />

y ← const 0<br />

A<br />

end while // k<br />

end while // k-1<br />

while z > 0 do // k-1*<br />

--z<br />

A k<br />

end while // k-1*<br />

...<br />

end while // 2<br />

while z > 0 do // 2*<br />

--z<br />

A 2<br />

end while // 2*<br />

end while // 1<br />

while z > 0 do // 1*<br />

--z<br />

A 1<br />

end while // 1*<br />

end while // 0<br />

while z > 0 do // 0*<br />

--z<br />

A 0<br />

end while // 0*<br />

'DEHLVHLHQ\XQG]9DULDEOHQGLHLQ$$ $ N QLFKWYRUNRPPHQ<br />

/HPPD<br />

%HLGHUVZLWFK$QZHLVXQJJHPl‰'HILQLWLRQZLUGJHQDXHLQHGHU<br />

$QZHLVXQJVIROJHQ$ $ N $HLQPDODXVJHI KUWQlPOLFK$ L I U[ L<br />

L∈^N`XQG$I U[!N<br />

Beweis:<br />

Nehmen wir zuerst an, es gelte x > k. In diesem Fall hat y vor der ersten<br />

Schleife den Wert x > 0 und nach k-maligem Ausführen der Anweisung --y gilt<br />

immer noch y > 0. Dann wird die mit k markierte Schleife betreten und die<br />

Anweisungsfolge A gemäß der Behauptung ausgeführt. Da sowohl die Variable<br />

y als auch die Variable z nach Ausführung der Anweisungsfolge A den Wert 0<br />

haben, werden alle Schleifen verlassen und keine weitere Schleife betreten. Es<br />

wird also nur eine Anweisungsfolge ausgeführt, nämlich die Anweisungsfolge A,<br />

und auch diese nur einmal.<br />

6HLWH


(LQOHLWXQJ<br />

Sei nun x = i ≤ k. y hat vor dem ersten Schleifendurchlauf den Wert i und nach i-<br />

maligem Ausführen der Anweisung --y den Wert 0. Somit wird die mit i+1<br />

markierte Schleife nicht betreten. Da die Variable z aber den Wert 1 besitzt,<br />

wird die mit i* markierte Schleife betreten und die Anweisungsfolge Ai<br />

ausgeführt. Da nach Ausführung von Ai die Variablen x und z beide den Wert 0<br />

haben, werden alle Schleifen verlassen und keine weitere Schleife betreten. Es<br />

wird also nur eine einzige Anweisungsfolge ausgeführt, nämlich die<br />

Anweisungsfolge Ai einmal.<br />

'HILQLWLRQ<br />

6HL[HLQH9DULDEOHXQG$XQG%)ROJHQYRQ:+,/($QZHLVXQJHQ'LHLI<br />

$QZHLVXQJ<br />

if x > 0 then<br />

A<br />

else<br />

B<br />

end if<br />

VHLIROJHQGHUPD‰HQGHILQLHUW<br />

switch x<br />

case 0: B<br />

otherwise A<br />

end switch<br />

/HPPD<br />

%HLGHULI$QZHLVXQJJHPl‰'HILQLWLRQZLUGQXUHLQHGHUEHLGHQ<br />

$QZHLVXQJHQ$XQG%DXVJHI KUWXQG]ZDUJHQDXHLQPDO,P)DOOH[!<br />

ZLUGGLH$QZHLVXQJ$DXVJHI KUWLP)DOOH[ ZLUGGLH$QZHLVXQJ%<br />

DXVJHI KUW<br />

Beweis:<br />

folgt direkt aus Lemma 1.3.4.<br />

6DW]<br />

-HGHGXUFKHLQH7XULQJPDVFKLQHEHUHFKHQEDUH)XQNWLRQLVWDXFK:+,/(<br />

EHUHFKHQEDU<br />

Beweis:<br />

Wir führen den Beweis dadurch, daß wir zeigen, daß wir eine Turingmaschine<br />

durch ein WHILE-Programm simulieren können.<br />

6HLWH


(LQOHLWXQJ<br />

Abbildung 2 : Struktur der simulierten Turingmaschine<br />

Schreib-/Leseknopf<br />

Ein-/<br />

Ausgabeband<br />

n Zustände<br />

q 1 ,..,q n<br />

Der Einfachheit halber beschränken wir uns auf eine Turingmaschine mit nur<br />

einem halbseitig unendlichen Band. Am Anfangs der Auswertung stehe auf dem<br />

Band nur die Eingabe, ansonsten sei das Band leer. Am Ende der Auswertung<br />

steht das Ergebnis wieder auf dem Band.<br />

Sei die Turingmaschine gegeben durch T = (Σ,B,b,Q,q0,QA,δ), wobei<br />

Σ ein endliches Alphabet (Bandalphabet),<br />

B ⊂ Σ das Eingabealphabet,<br />

b ∈ Σ \ B das Leerzeichen<br />

Q = {q0,...,qn} für ein n∈© eine endliche Menge von Zuständen.<br />

q0 der Startzustand<br />

QA ⊆ Q die Menge der Endzustände<br />

δ : Q×Σ → Q×Σ×{L,R} eine Übergangsrelation.<br />

Am Anfang stehe der Schreib-/Lesekopf der Turingmaschine auf dem ersten<br />

Zeichen des Bandes und die Turingmaschine befindet sich im Zustand q0. Falls<br />

((q,σ),(q',σ',L))∈δ, wechselt T, sofern die sich im Zustand q befindet und der<br />

Schreib-/Leseknopf auf dem Symbol σ steht, in den Zustand q' über,<br />

überschreibt das Symbol σ durch das Symbol σ' und bewegt den Schreib-<br />

/Lesekopf um ein Zeichen nach links. Entsprechend würde für ((q,σ),(q',σ',R))∈δ<br />

der Schreib-/Lesekopf um ein Zeichen nach rechts gesetzt werden.<br />

Für die Simulation wollen wir das Ein-/Ausgabeband mittels der Funktion code<br />

aus Lemma 1.3.1 in der Variablen x speichern, die als Eingabevariable und als<br />

Ausgabevariable dient. Beim Aufruf des WHILE-Programmes wird der<br />

Variablen x die Kodierung des Bandes mit den Eingabedaten übergeben, beim<br />

Ende des Algorithmus' wird mit x die Kodierung des Bandes mit dem Ergebnis<br />

übergeben. In der Variablen w speichern wir die Position des Bandes.<br />

Zur Auswertung der Übergangsfunktion δ definieren wir die Funktionen nexts,<br />

nextm und nextq folgendermaßen: Falls ((qi,σ),(qj,σ,L))∈δ, so ist nexts(i,c(σ)) =<br />

c(σ), nextm(i,c(σ)) = 0 und nextq(i,c(σ)) = j, und falls ((qi,σ),(qj,σ,R))∈δ, so ist<br />

nexts(i,c(σ)) = c(σ), nextm(i,c(σ)) = 1 und nextq(i,c(σ)) = j. Wenn (qi,σ) nicht Teil<br />

der Relation δ, so soll der Funktionswert bei der Eingabe (i, c(σ)) undefiniert<br />

6HLWH


(LQOHLWXQJ<br />

sein. Da δ eine endliche Relation ist, sind diese Funktionen wohldefiniert, sogar<br />

partiell rekursiv und damit WHILE-berechenbar.<br />

Ebenfalls benötigen wir die Funktionen dc: ©²→© mit dc(x,y) = c(decode(x,y))<br />

und cc: ©³→© mit cc(x,y,z) = chcode(x,y,c -1 (z)). Da diese Funktionen primitiv<br />

rekursiv sind, existieren Makros von ihnen.<br />

Das WHILE-Programm W sei dann folgendermaßen definiert:<br />

input (x)<br />

set (a := 1)<br />

set (q := 0)<br />

set (w := 1)<br />

while a > 0 do<br />

switch q<br />

case 0 : W 0<br />

case 1 : W 1<br />

...<br />

case n : W n<br />

otherwise Fehler!<br />

end switch<br />

end while<br />

output x<br />

Dabei sind W0,...,Wn Anweisungsfolgen.<br />

Sei qi für i∈{1,...,n} ein Zustand der Turingmaschine. Definiere eine<br />

Anweisungsfolge Wi:<br />

1. Fall: qi∈QA<br />

Dann setze Wi auf:<br />

--a<br />

2. Fall: q i ∉Q A :<br />

Dann setze W i auf:<br />

set (s := 0)<br />

set (y := 0)<br />

set (n := 0)<br />

set (m := 0)<br />

s ← dc(x,w)<br />

y ← nexts(q,s)<br />

n ← nextq(q,s)<br />

m ← nextm(q,s)<br />

x ← cc(x,w,y)<br />

if m > 0 then<br />

++w<br />

else<br />

--w<br />

end if<br />

q ← proj 1 (n)<br />

6HLWH


(LQOHLWXQJ<br />

Der Zustand der Turingmaschine wird durch die Variable q repräsentiert.<br />

Gemäß Lemma 1.3.4 wird in jedem Schleifendurchlauf der äußeren Schleife im<br />

Programm W genau eine der Anweisungen W0,..,Wn ausgeführt, nämlich die<br />

Anweisung Wq, denn wenn diese Variable wirklich nur Werte aus dem Intervall<br />

[0,n] annimmt, kann der Fehlerfall im Programm W nicht auftreten Die äußere<br />

Schleife, die in jedem Fall betreten wird, kann nur verlassen werden, wenn die<br />

Variable a den Wert 0 annimmt.<br />

Zu Beginn jeder der Anweisungsfolgen Wi (0≤i≤n) hat a den Wert 1. Der Wert<br />

dieser Variablen wird nur verändert, wenn q die Nummer eines Endzustandes<br />

ist, in diesem Fall erhält a den Wert 0 und das Programm W wird verlassen. Die<br />

Ausgabe ist das kodierte Band.<br />

Falls q nicht Nummer eines akzeptierenden Zustandes ist, wird die Variable a<br />

nicht verändert. In die Variable s wird über das Makro dc der Code des Zeichens<br />

auf der Position des Schreib-/Lesekopfes w auf dem durch die Variable x<br />

kodierten Band gelesen. Falls (qq ,c -1 (s)) Element der Definitionsmenge von δ, so<br />

liefern die Makros nestq, nexts und nextm folgende Werte, sofern ein<br />

Folgezustand existiert: Das Makro nextq liefert die Nummer des nächsten<br />

Zustandes, nexts liefert die Nummer des Zeichens, das auf die Position des<br />

Schreib-/Lesezeigers zu schreiben ist und nextm liefert die Werte 0 oder 1, wobei<br />

der Wert 0 für die Bewegung des Schreib-/Lesezeigers um ein Element nach<br />

links und der Wert 1 für die Bewegung des Schreib-/Lesekopfes um ein Zeichen<br />

nach rechts bedeutet. Die Ergebisse der Makros werden in die Variablen y,n,<br />

und m geschrieben. Falls kein Folgezustand existiert, terminiert die Ausführung<br />

der Makros nicht.<br />

Das Makro cc ändert das Zeichen auf der Position w des Schreib-/Lesekopfes auf<br />

das Zeichen mit dem Code s, also dem zu schreibenden Zeichen. Gemäß Lemma<br />

1.3.5 wird die Variable w inkrementiert, wenn der Schreib-/Lesekopf um ein<br />

Element nach links bewegt werden soll und dekremntiert, wenn der Schreib-<br />

/Lesekopf um ein Element nach rechts bewegt werden soll. Als Wert der<br />

Zustandsvariablen wird schließlich der Wert n übergeben, in dem tatsächlich<br />

die Nummer des nächsten Zustandes gespeichert ist.<br />

Damit ist gezeigt, daß das Programm W die Turingmaschine T simuliert. Falls<br />

T terminiert, so terminiert auch W und liefert dasselbe Ergebnis wie T (für<br />

dieselbe Eingabe). Damit berechnet W dieselbe Funktion, die auch W berechnet.<br />

Da T beliebige Turingmaschine, ist auch jede beliebige auf einer<br />

Turingmaschine berechenbare Funktion WHILE-berechenbar.<br />

1.4 Ausführung von Programmen der Sprache WHILE auf einer<br />

Registermaschine<br />

Es bleibt die Frage, ob es überhaupt eine Maschine gibt, auf der WHILE-Programme ablaufen<br />

können. Sicherlich wird es etwas schwierig (aber nicht unmöglich) sein, die Sprache WHILE<br />

auf einer Turingmaschine zu implementieren. Wir führen statt dessen eine Registermaschine<br />

ein, die den Begebenheiten real existierender Rechner näher kommt.<br />

6HLWH


(LQOHLWXQJ<br />

Abbildung 3 : Eine Registermaschine zur Implementation von WHILE-Programmen<br />

Lesezeiger<br />

Programmspeicher<br />

Registersatz<br />

PC<br />

R0<br />

R1<br />

R2<br />

Eingabeband<br />

Schreibzeiger<br />

Ausgabeband<br />

Die Maschine besteht aus zwei einseitig unendlichen Bändern, das Eingabeband und das<br />

Ausgabeband, auf denen natürliche Zahlen geschrieben werden können, und einer unendlichen<br />

Zahl von Registern, die ebenfalls eine natürliche Zahl aufnehmen können. Eines dieser<br />

Register ist ausgezeichnet, der Program Counter (PC). Außerdem beinhaltet die<br />

Registermaschine einen Programmspeicher, in dem Maschinenbefehle stehen. Die<br />

Maschinenbefehle des Programmspeichers sind durchnumeriert, dabei steht der erste Befehl an<br />

der Adresse 0. Jede Adresse eines Maschinenbefehls im Programmspeicher kann mit einem<br />

Label versehen werden. Jeder Label darf jedoch nur einmal verwendet werden. Der Wert des<br />

Program Counters ist immer die Adresse des nächsten Befehls im Programmspeicher. Am<br />

Anfang hat der PC den Wert 0. Der Lesezeiger steht auf dem ersten Element des<br />

Eingabebandes und der Schreibzeiger steht auf dem ersten Element des Ausgabebandes.<br />

Es sind folgende Befehle erlaubt:<br />

Tabelle 1 : Die Befehle der Registermaschine<br />

Befehl<br />

Semantik<br />

NOP erhöhe den Inhalt des PC um 1<br />

READ r<br />

Schreibe Eintrag vom Eingabeband in Register r, bewege Lesezeiger um<br />

ein Element nach rechts; erhöhe Inhalt des PC um 1<br />

WRITE r<br />

Schreibe Inhalt des Registers r auf das Ausgabeband, bewege Lesezeiger<br />

um ein Element nach rechts; erhöhe Inhalt des PC um 1<br />

HALT<br />

Programmende<br />

INC r Erhöhe den Inhalt des Registers r um 1; erhöhe den Inhalt des PC um 1<br />

DEC r<br />

Falls der Inhalt des Registers r ist größer als 0, so erniedrige den Inhalt<br />

des Registers r um 1; erhöhe den Inhalt des PC um 1<br />

LOAD r,n Schreibe Zahl n in das Register r; erhöhe den Inhalt des PC um 1<br />

LOAD r 1 ,r 2<br />

Schreibe Inhalt des Registers r 2 in das Register r 1 ; erhöhe Inhalt des PC<br />

um 1<br />

JUMP l<br />

Schreibe Adresse des Labels l in den PC<br />

JUMPZ r,l<br />

Falls der Inhalt des Registers r ist 0, so schreibe die Adresse des Labels l<br />

in den PC, sonst erhöhe den Inhalt des PC um 1<br />

6HLWH


(LQOHLWXQJ<br />

6DW]<br />

-HGHV:+,/(3URJUDPPNDQQDXIGHUREHQEHVFKULHEHQHQ5HJLVWHUPDVFKLQH<br />

DXVJHI KUWZHUGHQ<br />

Beweis:<br />

Sei W ein beliebiges WHILE-Programm. Zuerst weisen wir jeder Variablen in W<br />

ein Register der Registermaschine (jedoch nicht den Program Counter) zu. Als<br />

abkürzende Schreibweise wollen wir für jede Variable x des Programmes mit<br />

R(x) das der Variablen zugeordnete Register bezeichnen.<br />

Das Programm im Programmspeicher der Registermaschine wird aus den<br />

folgenden drei Teilen bestehen:<br />

(1) Einlesen der Eingabe vom Eingabeband<br />

(2) Auswertung der Anweisungen<br />

(3) Schreiben der Ausgabe auf das Ausgabeband<br />

Wenden wir uns jetzt den drei Schritten zu. Die angegebenen Maschinenbefehle<br />

sollen der Reihe nach ab Adresse 0 hintereinander in den Programmspeicher<br />

geschrieben werden.<br />

(1) Einlesen der Eingabe von Eingabeband<br />

Seien x1,..,xn für eine natürliche Zahl n die Eingabevariablen des Programmes.<br />

Dann haben die ersten n Maschinenbefehle folgende Gestalt:<br />

(0) READ R(x 1 )<br />

(1) READ R(x 2 )<br />

...<br />

(n-1) READ R(x n )<br />

(2) Auswertung der Anweisungen<br />

Die Anweisungen des WHILE-Programmes werden nun der Reihe nach in<br />

Maschinenbefehle überführt. Sei k die letzte Adresse des Programmspeichers, in<br />

der ein Maschinenbefehl steht und a die als nächste zu übersetzende<br />

Anweisung. Für die Anweisung a gibt es jetzt vier Möglichkeiten:<br />

(i) a ist ein Inkrement<br />

(ii) a ist ein Dekrement<br />

(iii) a ist eine Initialisation<br />

(iv) a ist eine Schleife<br />

(i) a ist ein Inkrement, etwa ++v, wobei v eine Variable ist<br />

Dann trage den Maschinenbefehl<br />

(k+1)<br />

INC R(v)<br />

in die Speicherstelle k+1 ein.<br />

(ii) a ist ein Dekrement, etwa --v, wobei v eine Variable ist<br />

Dann trage den Maschinenbefehl<br />

(k+1)<br />

DEC R(v)<br />

in die Speicherstelle k+1 ein.<br />

6HLWH


(LQOHLWXQJ<br />

(iii) a ist eine Initialisation, etwa<br />

set (v := m)<br />

Dabei ist v eine Variable und m entweder eine zweite Variable oder eine<br />

natürliche Zahl.<br />

Falls m ist eine weitere Variable, trage den folgenden Maschinenbefehl in die<br />

Speicherstelle k+1 ein:<br />

(k+1)<br />

MOVE R(v),R(m)<br />

Im Falle, daß es sich bei m um eine natürliche Zahl handelt, lautet der<br />

entsprechende Maschinenbefehl:<br />

(k+1)<br />

MOVE R(v),m<br />

(iv) a ist eine Schleife<br />

Für eine Variable v und einer Folge von Anweisungen A habe die Schleife die<br />

Gestalt:<br />

while v > 0 do<br />

A<br />

end while<br />

Dann wird diese Schleife folgendermaßen in eine Folge von Maschinenbefehlen<br />

übersetzt: Seien L und M Labels, die im Rest des Maschinenprogrammes nicht<br />

vorkommen. Trage den folgenden Maschinenbefehl in die Speicherstelle k+1 an<br />

und markiere diese Speicherstelle mit dem Label L:<br />

(k+1)<br />

L:JUMPZ R(v),M<br />

Danach übersetze die Anweisungsfolge A und trage die entsprechenden<br />

Maschinenbefehle in die Speicherstellen ab Adresse k+2 ein. Die letzte von der<br />

Anweisungsfolge A in Anspruch genommene Speicherstelle sei l. Trage die<br />

folgende Anweisung in die Speicherstellen (l+1) und (l+2) ein:<br />

(l+1)<br />

(l+2)<br />

JUMP L<br />

M:NOP<br />

(3) Schreiben der Ausgabe auf das Ausgabeband<br />

Die letzte von einer Anweisung belegte Speicherstelle sei r und die<br />

Ausgabevariable sei y. Die letzten Anweisungen des Maschinenprogramms<br />

lauten an den Speicherstellen (r+1) und (r+2):<br />

(r+1)<br />

(r+2)<br />

WRITE R(y)<br />

HALT<br />

Es ist sofort zu sehen, daß das beschriebene Maschinenprogramm völlig analog<br />

dem WHILE-Programm W abläuft. Damit berechnet die Registermaschine aber<br />

dieselbe Funktion wie W. Da W beliebig gewählt wurde, ist die<br />

Registermaschine in der Lage, jedes WHILE-Programm auszuführen und damit<br />

jede WHILE-berechenbare Funktion zu berechnen.<br />

6HLWH


(LQOHLWXQJ<br />

1.5 Übersicht über die weiteren Kapitel<br />

Obwohl wir gezeigt haben, daß WHILE-Programme nach Definition 1.2.1 die Mächtigkeit der<br />

Turingmaschine besitzen, haben wir in Abschnitt 1.2 und Abschnitt 1.3 gesehen, daß<br />

Erweiterungen des Sprachumfanges, wie z.B. weitere Kontrollstrukturen, Makroaufrufe und<br />

prozedurale Aufrufe mit Seiteneffekten, die Ausdrucksfähigkeit der Sprache erhöhen können.<br />

Fügen wir eine weitere Erweiterung hinzu:<br />

'HILQLWLRQ<br />

6HLαHLQEHOLHELJHU0DNRUDXIUXIXQG$HLQHEHOLHELJH$QZHLVXQJVVHTXHQ]<br />

'DQQZLUGGLH$QZHLVXQJ<br />

while α do<br />

A’<br />

end while<br />

DOV$EN U]XQJI UGLH$QZHLVXQJVIROJH<br />

v ← α<br />

while v > 0 do<br />

A’<br />

end while<br />

'DEHLLVWYHLQHEHOLHELJH9DULDEOHGLHLQ$QLFKWYHUZHQGHWZLUGαKHL‰W<br />

GDQQ$XVGUXFNGHU6FKOHLIH<br />

Diese und andere Erweiterungen der Sprache sollte ein Synthesealgorithmus verstehen können,<br />

weswegen die Definition 1.2.1 für Programme vom praktischen Interesse zu eingeschränkt in<br />

der Syntax ist. Hinzu kommt, daß die Definition 1.2.1 viel zu unpräzise für eine<br />

Implementierung einen Compiler der Sprache WHILE ist (die wenigsten Computersysteme<br />

haben ein intuitives Verständnis einer Variablen). Auch die Auswertungen von WHILE-<br />

Programmen nach Definition 1.2.2 lassen sich schwerlich als Eingabe für einen<br />

Synthesealgorithmus nutzen. Wir benötigen also für die Algorithmen auf die Problemstellung<br />

angepaßte Definitionen von Programm und Beispielauswertung.<br />

In Kapitel 2 werden wir eine sehr freizügigen Definition der Sprache WHILE und des Begriffs<br />

eines (WHILE-) Programmes konstruieren, die sich aber als Eingabe für einen Compiler<br />

verwenden läßt. Es wird auf den ersten Blick überraschen, daß in diesem Kapitel nur die<br />

Syntax von Programmen erläutert wird, nicht aber deren Semantik. Dies hat den Grund, daß<br />

sowohl die Erzeugung von Beispielauswertungen als auch die Programmsynthese auf einer<br />

syntaktischen Ebene ablaufen. Es ist daher nicht notwendig, die Bedeutung der verwendeten<br />

Sprachmittel mehr als nötig festzulegen. Soweit dies nötig ist (z.B. Werte von Variablen),<br />

wird eine indirekte Festlegung bei der Definition der Beispielauswertungen gegeben. Durch die<br />

große Freizügigkeit der Syntax der Sprache und die nicht näher definierte Semantik wird dem<br />

Anwender des Werkzeuges die Möglichkeit gegeben die Sprache WHILE auf seine<br />

Bedürfnisse anzupassen.<br />

Kapitel 3 dient zur Einführung in den Begriff der Beispielauswertung. Beispielauswertungen<br />

werden in einer Sprache repräsentiert, die der Sprache WHILE sehr ähnelt, wodurch zum<br />

einen die Lesbarkeit und die Erstellung der Beispielauswertungen und zum anderen auch die<br />

Synthese vereinfacht wird.<br />

6HLWH


(LQOHLWXQJ<br />

In Kapitel 4 wird ein Algorithmus zur automatischen Generierung von Beispielauswertungen<br />

angegeben. Kapitel 5 folgt dann mit der Präsentation eines Algorithmus' zur automatischen<br />

Programmsynthese. Dabei wird die Menge der WHILE-Programme auf eine Teilmenge<br />

reduziert, für die die Synthese besonders leicht zu bewerkstelligen ist, die Klasse-I-<br />

Programme. In Kapitel 6 wird die Bedeutung der Einschränkungen, die durch die<br />

Beschränkung auf Klasse-I-Programme diskutiert entsteht, diskutiert und es werden Ansätze<br />

zur Erweiterung der Lernpotenz angesprochen.<br />

Die Kapitel 7 bis 10 beschäftigen sich mit der Implementierung der vorgestellten Algorithmen<br />

auf verschiedenen Rechnern, wobei insbesondere auf die Spezifikation der Komponenten des<br />

Programmes und die genaue Beschreibung der Benutzerschnittstelle eingegangen wird. Das<br />

entstanden Werkzeug trägt den Namen [VDPSOH Version 2.0.<br />

Das Kapitel 11 zeigt einige Beispiele für WHILE-Programme und Beispielauswertungen, die<br />

als Eingabe für [VDPSOH verwendet wurden und demonstriert an den Ausgaben von [VDPSOH<br />

die Funktionsweise der Algorithmen. Im abschließenden Kapitel 12 werden zusammenfassend<br />

und ausblickend die erzielten Ergebnisse diskutiert.<br />

6HLWH


'LH6SUDFKH:+,/(<br />

2 Die Sprache WHILE<br />

Da die Definition 1.2.1 aus dem vorangegangenem Kapitel für eine dem Problem<br />

entsprechende Repräsentation der Sprache WHILE nicht genügt, wollen wir uns in diesem<br />

Kapitel genauer dem Aufbau von WHILE-Programmen dienen. Die Definition soll sich nur<br />

auf die für die Programmsynthese absolut notwendigen Elemente beschränken. Deswegen<br />

wurde die Syntax sehr allgemein gehalten, wodurch dem Benutzer des Werkzeuges sehr große<br />

Möglichkeiten offenstehen, die Sprache auf sein Problem anzupassen. Aus diesem Grund<br />

wurde auch keine Semantik der Sprache angegeben. Es besteht jedoch immer die Möglichkeit,<br />

die in Kapitel 1 angegebene Semantik zu verwenden, sofern man die Syntax der Sprache<br />

wieder etwas einschränkt.<br />

Der Rest des Kapitels beschäftigt sich mit einer Definition eines WHILE-Programmes. Die<br />

hier verwendeten Definitionen für Variable und Programm mögen überraschen, sie sind aber<br />

für einen rein syntaktischen Ansatz notwendig.<br />

<br />

Zeichenvorrat<br />

Das zugrundeliegende Alphabet muß folgende Klassen von Zeichen beinhalten:<br />

w Buchstaben : a b c … A B C …<br />

Kleinbuchstaben und Großbuchstaben werden unterschieden.<br />

w Ziffern : 0 1 …<br />

w Trennzeichen : Leerzeichen, Tabulatorzeichen, Zeilenendezeichen<br />

w Sonderzeichen : + - * / ...<br />

Folgende Zeichen sind sowohl Sonderzeichen als auch werden sie zum Sprachaufbau<br />

benötigt:<br />

+ – ( ) , : = "<br />

w Schlüsselworte : input output while do with end set test skip<br />

2.2 Syntax<br />

Zur Angabe der Syntax der Sprache WHILE wird die Erweiterte Backus-Naur-Form (EBNF)<br />

verwendet. Dabei sind die Terminale durch Unterstreichung oder durch das Einschließen in<br />

Anführungszeichen ("") gekennzeichnet. Die Schreibweise {a} steht für die n-malige<br />

Konkatenation von a, wobei n∈© beliebig, d.h. ε (nichts) oder a oder aa oder aaa usw. Die<br />

Schreibweise [a] steht für die null- oder einmalige Konkatenation von a, d.h. ε oder a.<br />

Tabelle 2 : Die Syntax der Sprache WHILE<br />

3URJUDPPWH[W<br />

(LQJDEHNRQVWUXNW<br />

,QLWLDOLVDWLRQVVHTXHQ]<br />

,QLWLDOLVDWLRQVNRQVWUXNW<br />

%H]HLFKQHU<br />

=DKO<br />

$XVJDEHNRQVWUXNW<br />

$QZHLVXQJVVHTXHQ]<br />

$QZHLVXQJ<br />

(LQIDFK$QZHLVXQJ<br />

6WULQJ<br />

,QNUHPHQW<br />

'HNUHPHQW<br />

ZKLOH.RQVWUXNW<br />

$XVGUXFN<br />

(LQJDEHNRQVWUXNW,QLWLDOLVDWLRQVVHTXHQ]$QZHLVXQJVVHTXHQ]$XVJDEHNRQVWUXNW<br />

"input" "("Ã>%H]HLFKQHU^","%H]HLFKQHU`@")"<br />

^,QLWLDOLVDWLRQVNRQVWUXNW`<br />

"set" "(" %H]HLFKQHU":=" %H]HLFKQHU_=DKO")"<br />

%XFKVWDEH^%XFKVWDEH_=LIIHU`<br />

=LIIHU^=LIIHU`<br />

"output"%H]HLFKQHU<br />

^$QZHLVXQJ`<br />

(LQIDFK$QZHLVXQJ_,QNUHPHQW_'HNUHPHQW_ZKLOH.RQVWUXNW<br />

%H]HLFKQHU_=DKO_6WULQJ_6RQGHU]HLFKHQ<br />

^=LIIHU%XFKVWDEH6RQGHU]HLFKHQ7UHQQ]HLFKHQ`<br />

"++"%H]HLFKQHU<br />

"--"%H]HLFKQHU<br />

"with",QLWLDOLVDWLRQVVHTXHQ]"while"$XVGUXFN"do"<br />

$QZHLVXQJVVHTXHQ]"end while"<br />

^(LQIDFK$QZHLVXQJ`<br />

6HLWH


'LH6SUDFKH:+,/(<br />

Es gelten zusätzlich folgende Regeln:<br />

ì Ein Bezeichner muß verschieden von jedem Schlüsselwort sein.<br />

ì Folgen zwei Bezeichner direkt aufeinander, so muß zwischen ihnen ein Trennzeichen<br />

stehen.<br />

ì Folgen zwei Schlüsselworte direkt aufeinander, so muß zwischen ihnen ein Trennzeichen<br />

stehen.<br />

ì Folgen ein Bezeichner und ein Schlüsselwort direkt aufeinander oder umgekehrt, so muß<br />

zwischen ihnen ein Schlüsselwort stehen.<br />

ì Folgen ein Bezeichner bzw. ein Schlüsselwort und eine Zahl direkt aufeinander, so muß ein<br />

Trennzeichen zwischen ihnen stehen.<br />

ì Sollen einem Bezeichner, der nicht Teil eines Inkrementes oder Dekrementes ist, eine der<br />

Zeichenfolgen "++" oder "--" vorangehen, so muß ein Trennzeichen dazwischen stehen.<br />

ì Trennzeichen dürfen nicht innerhalb von Schlüsselworten, Bezeichnern, Inkrementen und<br />

Dekrementen stehen. Innerhalb der Zeichenkombination := in einem<br />

Initialisationskonstrukt sind Trennzeichen nicht zugelassen.<br />

ì Innerhalb eines Strings sind alle Zeichen des Zeichenvorrats mit Ausnahme des Zeichens "<br />

zugelassen. Sie haben dann keine syntaktische Bedeutung.<br />

ì Ansonsten dürfen Trennzeichen beliebig stehen.<br />

ì Steht innerhalb einer Zeile die Zeichenkombination "//", so werden alle Zeichen<br />

beginnend mit dem ersten Vorkommen der Zeichenkombination "//" in der Zeile bis zum<br />

Ende der Zeile überlesen.<br />

Bezeichnung:<br />

Sei "set (x := y)" ein Initialisationskonstrukt. Dann heißt x linke Seite und y rechte<br />

Seite.<br />

2.3 Programme<br />

'HILQLWLRQ<br />

(LQH=HLFKHQIROJHGHU6SUDFKH:+,/(GLHVLFKQDFKRELJHU*UDPPDWLN]XP<br />

6WDUWV\PEROUHGX]LHUHQOl‰WKHL‰W3URJUDPPWH[W<br />

'HILQLWLRQ<br />

'LH$QZHLVXQJVVHTXHQ]$HLQHV3URJUDPPWH[WHV3DX‰HUKDOEMHGHV<br />

ZKLOH.RQVWUXNWHVKHL‰W+DXSWDQZHLVXQJVVHTXHQ]YRQ3(LQH<br />

$QZHLVXQJLQQHUKDOEYRQ$GLHQLFKW7HLOHLQHVZKLOH.RQVWUXNWHVLVW<br />

KHL‰WORNDOH$QZHLVXQJYRQ3<br />

'LHJU|‰WH$QZHLVXQJVVHTXHQ]%LQQHUKDOEHLQHVZKLOH.RQVWUXNWHV:<br />

GLHDOVRQLFKWLQQHUKDOEHLQHVZHLWHUHQZKLOH.RQVWUXNWHVNOHLQHUDOV:<br />

OLHJWKHL‰W+DXSWDQZHLVXQJVVHTXHQ]YRQ:(LQH$QZHLVXQJLQQHUKDOE<br />

YRQ%GLHQLFKW7HLOHLQHVZHLWHUHQZKLOH.RQVWUXNWHVLVWNOHLQHUDOV:LVW<br />

KHL‰WORNDOH$QZHLVXQJYRQ:<br />

'HILQLWLRQ<br />

(LQ%H]HLFKQHU[KHL‰W(LQJDEHYDULDEOHLQHLQHP3URJUDPPWH[W3ZHQQ[<br />

LP(LQJDEHNRQVWUXNWYRQ3JHQDXHLQPDOYRUNRPPW'LHJHRUGQHWH0HQJH<br />

DOOHU(LQJDEHYDULDEOHQLQGHU5HLKHQIROJHLKUHV$XIWUHWHQVLP<br />

(LQJDEHNRQVWUXNWYRQ3ZLUGDOV(93JHVFKULHEHQ<br />

6HLWH


'LH6SUDFKH:+,/(<br />

'HILQLWLRQ<br />

6HL3HLQ3URJUDPPWH[WXQG.HLQ,QLWLDOLVDWLRQVNRQVWUXNW<br />

.KHL‰WJOREDOHV,QLWLDOLVDWLRQVNRQVWUXNWZHQQ.YRUGHU<br />

+DXSWDQZHLVXQJVVHTXHQ]YRQ3VWHKW<br />

6HL:HLQZKLOH.RQVWUXNWLQ3.KHL‰WORNDOHV,QLWLDOLVDWLRQVNRQVWUXNW<br />

YRQ:IDOOV.LQ:YRUGHU+DXSWDQZHLVXQJVVHTXHQ]YRQ:VWHKW<br />

'HILQLWLRQ<br />

(LQ%H]HLFKQHU[KHL‰WJOREDOH9DULDEOHLQHLQHP3URJUDPPWH[W3ZHQQHV<br />

JHQDXHLQJOREDOHV,QLWLDOLVDWLRQVNRQVWUXNW.JLEWVRGD‰<br />

[NRPPWLQ.YRU<br />

[VWHKWQXUDXIGHUOLQNHQ6HLWHYRQ.<br />

[NRPPWQLFKWLP(LQJDEHNRQVWUXNWYRU<br />

.KHL‰WGDQQ,QLWLDOLVDWLRQVNRQVWUXNWYRQ['LH0HQJHDOOHUJOREDOHQ<br />

9DULDEOHQLQ3ZLUGDOV*93JHVFKULHEHQ<br />

'HILQLWLRQ<br />

6HL:HLQZKLOH.RQVWUXNWLQQHUKDOEHLQHV3URJUDPPWH[WHV3(LQ<br />

%H]HLFKQHU[KHL‰WORNDOH9DULDEOH]X:ZHQQHVJHQDXHLQORNDOHV<br />

,QLWLDOLVDWLRQVNRQVWUXNW.YRQ:JLEWVRGD‰<br />

[NRPPWLQ.YRU<br />

[VWHKWQXUDXIGHUOLQNHQ6HLWHYRQ.<br />

[NRPPWLQ3QLFKWDX‰HUKDOEYRQ:YRU<br />

.KHL‰WGDQQ,QLWLDOLVDWLRQVNRQVWUXNWYRQ['LH0HQJHDOOHUORNDOHQ<br />

9DULDEOHQYRQ:ZLUG/9:JHVFKULHEHQ<br />

'HILQLWLRQ<br />

6HL3HLQ3URJUDPPWH[W(LQ%H]HLFKQHU[KHL‰W3URJUDPPYDULDEOHYRQ3<br />

ZHQQ[HQWZHGHUJOREDOH9DULDEOHYRQ3RGHUORNDOH9DULDEOHHLQHVZKLOH<br />

.RQVWUXNWHVLQQHUKDOEYRQ3LVW<br />

/HPPD<br />

6HL3HLQ3URJUDPPWH[WXQGYHLQH3URJUDPPYDULDEOH'DQQOLHJWGDVHUVWH<br />

9RUNRPPHQYRQYLQLKUHP,QLWLDOLVDWLRQVNRQVWUXNWDXIGHUOLQNHQ6HLWH<br />

Beweis:<br />

Sei v globale Variable. Da nach Definition 2.3.5 nicht im Eingabekonstrukt<br />

vorkommt und es genau ein globales Initialisationskonstrukt gibt, in dem v<br />

vorkommt und dies ihr Initialisationskonstrukt ist, muß dies ihr erstes<br />

Vorkommen sein. v darf nur auf der linken Seite ihres Initialisationskonstruktes<br />

vorkommen.<br />

Sei v lokale Variable zu einem while-Konstrukt W. v darf nach Definition 2.3.6<br />

nicht außerhalb von W vorkommen. Es gibt aber auch nur ein<br />

Inititialisationskonstrukt, in dem v vorkommen kann, nämlich ihr<br />

Initialisationskonstrukt. Also liegt ihr erstes Vorkommen in ihrem<br />

Initialisationskonstrukt und v darf nur auf der linken Seite stehen.<br />

6HLWH


'LH6SUDFKH:+,/(<br />

'HILQLWLRQ<br />

(LQ%H]HLFKQHU[KHL‰W9DULDEOHLQHLQHP3URJUDPPWH[W3ZHQQ[HQWZHGHU<br />

(LQJDEHYDULDEOHRGHU3URJUDPPYDULDEOHLVW(LQ%H]HLFKQHU[KHL‰W<br />

+DXSWYDULDEOHLQHLQHP3URJUDPPWH[W3ZHQQ[HQWZHGHU(LQJDEHYDULDEOH<br />

RGHUJOREDOH9DULDEOHLVW<br />

'HILQLWLRQ<br />

(LQ%H]HLFKQHUGHUQLFKW9DULDEOHLVWKHL‰W:RUW<br />

Beispiel 2.3.1:<br />

Gegeben sei folgender Programmtext P:<br />

input(a,b)<br />

set(x:=a)<br />

set(y:=3)<br />

set(z:=4)<br />

h<br />

y<br />

0<br />

with<br />

while do<br />

x<br />

0<br />

with<br />

set(c:=3)<br />

while do<br />

z<br />

d<br />

0<br />

end while<br />

end while<br />

output y<br />

Das Beispiel hat folgende Bezeichner : a,b,x,y,z,h,c,d.<br />

Davon sind<br />

ì Eingabevariablen: a,b<br />

ì Programmvariablen: x,y,z,c<br />

ì globale Variable zu P: x,y,z<br />

ì lokale Variable zum ersten while-Konstrukt: -<br />

ì lokale Variablen zum zweiten while-Konstrukt: c<br />

ì Worte: d,h<br />

Man beachte hierbei, daß die Variable c außerhalb ihres Initialisationskonstruktes nicht<br />

vorkommt.<br />

Es mag überraschen, daß für die while-Konstrukte kein Ausdruck angegeben ist. Dies ist aber<br />

unserer Grammatik nicht notwendig. Eine mögliche Semantik für ein solches Konstrukt ist<br />

eine Endlosschleife.<br />

6HLWH


'LH6SUDFKH:+,/(<br />

'HILQLWLRQ<br />

6HL3HLQ3URJUDPPWH[W<br />

(LQH=DKOFLQGHU+DXSWDQZHLVXQJVVHTXHQ]YRQ3KHL‰WJOREDOH<br />

.RQVWDQWHZHQQFLQNHLQHPZKLOH.RQVWUXNWOLHJW<br />

6HL:HLQZKLOH.RQVWUXNWLQ3(LQH=DKOFKHL‰WORNDOH.RQVWDQWHYRQ:<br />

ZHQQFLVWORNDOH$QZHLVXQJ<br />

(LQH=DKOFKHL‰W3URJUDPPNRQVWDQWHZHQQFLVWJOREDOHRGHUORNDOH<br />

.RQVWDQWH<br />

(LQH.RQVWDQWHLQQHUKDOEHLQHV,QLWLDOLVDWLRQVNRQVWUXNWHVKHL‰W<br />

,QLWLDOLVDWLRQVNRQVWDQWH<br />

Bemerkung:<br />

a) Im Gegensatz zu Variablen kann eine Zahl in Programmen als lokale Konstante zu<br />

mehreren while-Konstrukten, als globale Konstante und/oder als Initialisationskonstante<br />

auftreten.<br />

b) Punkt 2 verbietet nicht, daß c in einem while-Konstrukt kleiner W vorkommt. Es wird aber<br />

verlangt, daß c mindestens einmal außerhalb eines kleineren while-Konstruktes vorkommt.<br />

Beispiel 2.3.2:<br />

In Beispiel 2.3.1 tritt die Zahl 0 sowohl als globale Konstante, als auch als lokale Konstante<br />

zu beiden while-Konstrukten auf. Die Zahlen 3 und 4 treten als Initialisationskonstanten auf.<br />

'HILQLWLRQ<br />

(LQ3URJUDPPWH[W3KHL‰W3URJUDPPZHQQMHGHU%H]HLFKQHU<br />

LP(LQJDEHNRQVWUXNW<br />

LP$XVJDEHNRQVWUXNW<br />

LQHLQHP,QLWLDOLVDWLRQVNRQVWUXNW<br />

LQHLQHP,QNUHPHQW<br />

LQHLQHP'HNUHPHQW<br />

HLQH9DULDEOHLVW<br />

'HILQLWLRQ<br />

(LQH7HLO]HLFKHQIROJH)DXVGHU$QZHLVXQJVVHTXHQ]HLQHV3URJUDPPHV3<br />

KHL‰W3URJUDPPIUDJPHQWZHQQMHGHVZKLOH.RQVWUXNWGDVWHLOZHLVHLQ)<br />

HQWKDOWHQLVWDXFKYROOVWlQGLJLQ)HQWKDOWHQLVW<br />

Beispiel 2.3.4:<br />

Folgender Programmtext ist ein Programm P:<br />

input (x)<br />

set (y := 3)<br />

++y<br />

z<br />

with<br />

set (w := x)<br />

while do<br />

--w<br />

d<br />

end while<br />

output y<br />

6HLWH


'LH6SUDFKH:+,/(<br />

Folgende Zeichenfolge ist ein Programmfragment von P:<br />

z<br />

with<br />

set (w := x)<br />

while do<br />

--w<br />

d<br />

end while<br />

'HILQLWLRQ<br />

6HL)HLQ3URJUDPPIUDJPHQW'LH6FKDFKWHOXQJVWLHIH')LVWUHNXUVLY<br />

GHILQLHUWGXUFK<br />

(QWKlOW)NHLQZKLOH.RQVWUXNWVRLVW') <br />

$QVRQVWHQVHLGGDV0D[LPXPGHU6FKDFKWHOXQJVWLHIHQ<br />

$QZHLVXQJVVHTXHQ]HQDOOHUZKLOH.RQVWUXNWHLQ)6HW]H') G<br />

'HILQLWLRQ<br />

6HL)HLQ3URJUDPPIUDJPHQW'LH=DKOGHUORNDOHQZKLOH.RQVWUXNWHYRQ)<br />

ZLUGPLW:)EH]HLFKQHW<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

3 Beispielauswertungen<br />

In diesem Kapitel wird der Begriff der Beispielauswertung eingeführt Dabei ist eine<br />

Beispielauswertung eine Beschreibung des Ablaufs eines Programmes. Das Kapitel<br />

beschäftigt sich weiterhin mit der Definition und Analyse äquivalenter Programme, die sich<br />

nicht in ihren Beispielauswertungen unterscheiden. Diese Definition ist von grundlegender<br />

Bedeutung, da zwei äquivalente Programme nach ihrer Auswertung nicht unterschieden<br />

werden können. Jeder auf Beispielauswertungen basierender Synthesealgorithmus wird in der<br />

Regel nicht in der Lage sein, ein bestimmtes Programm einer Äquivalenzklasse zu<br />

rekonstruieren, sondern nur ein zu diesem äquivalenten Programm. Die in diesem Kapitel<br />

aufgeführten Lemmata werden sich bei der Diskussion des Synthesealgorithmus' als nützlich<br />

erweisen.<br />

3.1 Entfaltungen<br />

'HILQLWLRQ<br />

6HL)HLQEHOLHELJHV3URJUDPPIUDJPHQW(LQH=HLFKHQIROJH( ()KHL‰W<br />

(QWIDOWXQJYRQ)ZHQQJLOW<br />

) U') JLOWDXFK( )<br />

(VVHL)HLQZKLOH.RQVWUXNW:GHU*HVWDOW<br />

with<br />

A<br />

while B do C end while<br />

'DEHLVHL$HLQH)ROJHYRQ,QLWLDOLVDWLRQVNRQVWUXNWHQ%HLQ$XVGUXFNXQG&<br />

HLQH$QZHLVXQJVVHTXHQ]'DQQH[LVWLHUWHLQHQDW UOLFKH=DKOQ!XQG<br />

(QWIDOWXQJHQ& & Q YRQ&VRGD‰(KDWHQWZHGHUGLH)RUP<br />

with<br />

A<br />

test B do C' 1 end test<br />

test B do C' 2 end test<br />

...<br />

test B do C' n end test<br />

RGHUGLH)RUP<br />

with<br />

A<br />

test B do C' 1 end test<br />

test B do C' 2 end test<br />

...<br />

test B do C' n end test<br />

test B skip<br />

(VVHL) *+XQG( *+ZREHL*LVW(QWIDOWXQJYRQ*XQG+LVW<br />

(QWIDOWXQJYRQ+<br />

'HILQLWLRQ<br />

6HL3HLQ3URJUDPP'DQQHQWVWHKWHLQH(QWIDOWXQJYRQ3(3GXUFK<br />

(UVHW]HQGHU+DXSWDQZHLVXQJVVHTXHQ]$YRQ3GXUFK($<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

Beispiel 3.1.1:<br />

Sei P gegeben durch<br />

input (x,y)<br />

a<br />

with<br />

while b do<br />

c<br />

with<br />

while d do e end while<br />

f<br />

end while<br />

output x<br />

So ist die folgende Zeichenfolge eine Entfaltungen von P<br />

input (x,y)<br />

a<br />

with<br />

test b do<br />

c<br />

with<br />

test d do e end test<br />

test d do e end test<br />

test d do e end test<br />

test d do e end test<br />

test d do e end test<br />

test d skip<br />

f<br />

end test<br />

test b do<br />

c<br />

test d do e end test<br />

test d do e end test<br />

test d skip<br />

f<br />

end test<br />

test b do<br />

c<br />

test d do e end test<br />

test d do e end test<br />

f<br />

end test<br />

test b skip<br />

output x<br />

'HILQLWLRQ<br />

6HL)HLQ3URJUDPPIUDJPHQW(HLQH(QWIDOWXQJYRQ)XQGYHLQH9DULDEOH<br />

YRQ)'DQQZLUGGLH=DKOGHU9RUNRPPHQGHU9DULDEOHQYLQ(PLW9Y(<br />

EH]HLFKQHW<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

3.2 Strukturäquivalenz<br />

'HILQLWLRQ<br />

6HLHQ)XQG*3URJUDPPIUDJPHQWH)XQG*KHL‰HQVWUXNWXUlTXLYDOHQW<br />

ZHQQ<br />

') XQG'* RGHU<br />

')!'*!:) :*XQGI UMHGHVL∈^:)`VLQGGLH<br />

$QZHLVXQJVVHTXHQ]GHVLWHQZKLOH.RQVWUXNWHVYRQ)XQGGLH<br />

$QZHLVXQJVVHTXHQ]GHVLWHQZKLOH.RQVWUXNWHVYRQ*VWUXNWXUlTXLYDOHQW<br />

'HILQLWLRQ<br />

6HLHQ3XQG43URJUDPPH3XQG4KHL‰HQVWUXNWXUlTXLYDOHQWZHQQLKUH<br />

+DXSWDQZHLVXQJVVHTXHQ]HQVWUXNWXUlTXLYDOHQWVLQG<br />

Beispiel 3.2.1:<br />

Folgende Programme sind strukturäquivalent:<br />

input (x)<br />

set (u := 6)<br />

a<br />

b<br />

with<br />

while c do<br />

x<br />

with<br />

while do<br />

5<br />

end while<br />

f<br />

end while<br />

output u<br />

input (r,s,t)<br />

with<br />

set (x := r)<br />

set (y := s)<br />

while x < y do<br />

with<br />

set (z := 3)<br />

while z do<br />

end while<br />

end while<br />

write "fertig"<br />

output t<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

'HILQLWLRQ<br />

6HLHQ)XQG*VWUXNWXUlTXLYDOHQWH3URJUDPPIUDJPHQWHXQGVHL' ()XQG<br />

( (*'XQG(KHL‰HQVWUXNWXUlTXLYDOHQWZHQQ<br />

') XQG'* <br />

')!XQG'*!XQGI UMHGHVL∈^:)`JLOW<br />

:HQQGDVLWHZKLOH.RQVWUXNW: L) YRQ)GLH(QWIDOWXQJ<br />

with<br />

A F<br />

test B F do C’ F1 end test<br />

test B F do C’ F2 end test<br />

...<br />

test B F do C’ Fn end test<br />

E]ZGLH(QWIDOWXQJ<br />

with<br />

A F<br />

test B F do C’ F1 end test<br />

test B F do C’ F2 end test<br />

...<br />

test B F do C’ Fn end test<br />

test B F skip<br />

EHVLW]WVREHVLW]WGDVLWHZKLOH.RQVWUXNW: L* GLH(QWIDOWXQJ<br />

with<br />

A G<br />

test B G do C’ G1 end test<br />

test B G do C’ G2 end test<br />

...<br />

test B G do C’ Gn end test<br />

E]ZGLH(QWIDOWXQJ<br />

with<br />

A G<br />

test B G do C’ G1 end test<br />

test B G do C’ G2 end test<br />

...<br />

test B G do C’ Gn end test<br />

test B G skip<br />

GDEHLVLQG$ ) XQG$ * GLHORNDOHQ,QLWLDOLVDWLRQVVHTXHQ]HQYRQ: L) XQG: L* % )<br />

XQG% * GLH$XVGU FNHYRQ: L) XQG: L* XQGI UHLQHQDW UOLFKH=DKOQ<br />

& ) & )Q GLH(QWIDOWXQJHQGHU$QZHLVXQJVVHTXHQ]YRQ: L) LQ'XQG<br />

& * & *Q GLH(QWIDOWXQJHQGHU$QZHLVXQJVVHTXHQ]YRQ: L* LQ(ZREHL<br />

]XVlW]OLFKJLOWGD‰I UMHGHVM∈^Q`& )M XQG& *M VWUXNWXUlTXLYDOHQWVLQG<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

'HILQLWLRQ<br />

6HLHQ3XQG43URJUDPPHXQGVHLHQ' (3XQG( (4ZREHL'XQG(<br />

GLH(QWIDOWXQJHQGHU+DXSWDQZHLVXQJVVHTXHQ]HQYRQ3XQG4VLQG'DQQ<br />

KHL‰HQ'XQG(VWUXNWXUlTXLYDOHQWZHQQ'XQG(VWUXNWXUlTXLYDOHQW<br />

Beispiel 3.2.2:<br />

Seien P und Q die Programme aus Beispiel 3.2.1. Dann sind folgende Entfaltungen von P und<br />

Q strukturäquivalent:<br />

input (x)<br />

set (u := 6)<br />

a<br />

b<br />

with<br />

test c do<br />

x<br />

with<br />

test do<br />

5<br />

end test<br />

test do<br />

5<br />

end test<br />

test do<br />

5<br />

end test<br />

test skip<br />

f<br />

end test<br />

test c do<br />

x<br />

with<br />

test do<br />

5<br />

end test<br />

test do<br />

5<br />

end test<br />

f<br />

end test<br />

test c skip<br />

output u<br />

input (r,s,t)<br />

with<br />

set (x := r)<br />

set (y := s)<br />

test x < y do<br />

with<br />

set (z := 3)<br />

test z do<br />

end test<br />

test z do<br />

end test<br />

test z do<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

end test<br />

test z skip<br />

end test<br />

test x < y do<br />

with<br />

set (z := 3)<br />

test z do<br />

end test<br />

test z do<br />

end test<br />

end test<br />

test x < y skip<br />

write "fertig"<br />

output t<br />

/HPPD<br />

6HLHQ)XQG*VWUXNWXUlTXLYDOHQWH3URJUDPPIUDJPHQWH'DQQJLOW')<br />

'*<br />

Beweis:<br />

(vollständige Induktion über D(F))<br />

Induktionsverankerung:<br />

Für D(F) = 0 muß nach Definition auch gelten D(G) = 0.<br />

Induktionsvoraussetzung<br />

Für D(F) = n gilt auch D(G) = n.<br />

Induktionsbehauptung:<br />

Für D(F) = n+1 gilt auch D(G) = n+1.<br />

Induktionsschluß:<br />

Sei A die Hauptanweisungssequenz eines lokalen while-Konstruktes K von F<br />

mit maximaler Tiefe. Dann gilt D(A) = n. Sei j die Nummer von K in der<br />

Reihenfolge der lokalen while-Konstrukte. Da G und F strukturäquivalent,<br />

ist W(G) = W(F) und für jedes i∈{1,...,W(F)} sind die Anweisungssequenzen<br />

des i-ten while-Konstruktes in F und des i-ten while-Konstruktes in G<br />

strukturäquivalent. Insbesondere gilt dies auch für die j-ten while-<br />

Konstrukte. Sei L das j-te while-Konstrukt von G und B seine<br />

Hauptanweisungssequenz. Es sind dann A und B strukturäquivalent. Da<br />

D(A) = n, gilt D(B) = n (Induktionsvoraussetzung). Sei L' ein beliebiges<br />

lokales while-Konstrukt in G und k seine Nummer in der Reihenfolge der<br />

lokalen while-Konstrukte. Sei B' die Hauptanweisungssequenz von L’. Sei K'<br />

das k-te while-Konstrukt in F. Da K ein while-Konstrukt maximaler Tiefe,<br />

muß für die Hauptanweisungssequenz A' von K' gelten D(A') ≤ D(A) = n. Da<br />

A' und B' strukturäquivalent, gilt D(B') ≤ n = D(B). Dann ist L ein lokales<br />

while-Konstrukt maximaler Tiefe. Dann ist D(G) = D(B) + 1 = n+1.<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

/HPPD<br />

6HLHQ)XQG*VWUXNWXUlTXLYDOHQWH3URJUDPPIUDJPHQWH'DQQH[LVWLHUHQ<br />

(QWIDOWXQJHQ'XQG(PLW' ()XQG( (*XQG'XQG(VLQG<br />

VWUXNWXUlTXLYDOHQW<br />

Beweis:<br />

Sei D eine beliebige Entfaltung von F. Die Behauptung folgt durch vollständige<br />

Induktion über D(F) (= D(G) nach Lemma 3.2.1).<br />

Induktionsverankerung:<br />

Für D(F) = 0 gilt auch D(G) = 0, dann sind D und E strukturäquivalent,<br />

wobei E beliebige Entfaltung von G.<br />

Induktionsvoraussetzung:<br />

Für beliebige strukturäquivalente Programmfragmente F' und G' mit D(F') ≤<br />

n existieren für eine Entfaltungen D’ = E(F’) eine Entfaltung E’ = E(G’), wobei<br />

D’ und E’ strukturäquivalent.<br />

Induktionsbehauptung:<br />

Für D(F) = n+1 existiert zu D = E(F) eine Entfaltung E = E(G), so daß D und<br />

E sind strukturäquivalent.<br />

Induktionsschluß:<br />

Wir erhalten eine Entfaltung von E, indem wir jedes lokale while-Konstrukt<br />

L in E durch eine Entfaltung von L ersetzen. Aus der Strukturäquivalenz<br />

folgt W(F) = W(G). Sei für beliebiges i∈{1,..,W(F)} Ki das i-te lokale while-<br />

Konstrukt in F und Li das i-te while-Konstrukt in G. Sei Mi die Entfaltung<br />

von Ki in D.<br />

1. Fall: Mi hat die Form:<br />

with<br />

A F<br />

test B F do C’ F1 end test<br />

test B F do C’ F2 end test<br />

...<br />

test B F do C’ Fm end test<br />

Dabei sei AF die lokale Initialisationssequenz von Ki, BF der Ausdruck von Ki<br />

und C'F1,...,C'Fm für ein m∈© Entfaltungen der Anweisungssequenz CF von Ki.<br />

Es gilt D(CF) ≤ n. Außerdem sind CF und CG strukturäquivalent (nach<br />

Definition der Strukturäquivalenz). Dann existiert aber nach<br />

Induktionsvoraussetzung für jedes j∈{1,..,m} eine Entfaltung C'Gj von CG,<br />

wobei C'Fj und C'Gj strukturäquivalent. Setze Ni gleich<br />

with<br />

A G<br />

test B G do C’ G1 end test<br />

test B G do C’ G2 end test<br />

...<br />

test B G do C’ Gm end test,<br />

so ist Ni eine Entfaltung von Li.<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

2. Fall: Mi habe die Form:<br />

with<br />

A F<br />

test B F do C’ F1 end test<br />

test B F do C’ F2 end test<br />

...<br />

test B F do C’ Fn end test<br />

test B F skip<br />

Wiederum sei AF die lokale Initialisationssequenz von Ki, BF der Ausdruck<br />

von Ki und C’F1,...,C’Fm für ein m∈© Entfaltungen der Anweisungssequenz CF<br />

von Ki. Li habe die Gestalt<br />

with<br />

A G<br />

while B G do C G end while<br />

Dabei sei AG die Initialisationssequenz von Li, BG der Ausdruck von Li und CG<br />

die Anweisungssequenz von Li. Analog zum 1. Fall existiert für jedes<br />

j∈{1,..,m}eine Entfaltung C'Gj von CG, wobei C'Fj und C'Gj strukturäquivalent.<br />

Setze Ni gleich<br />

with<br />

A G<br />

test B G do C’ G1 end test<br />

test B G do C’ G2 end test<br />

...<br />

test B G do C’ Gn end test<br />

test B G skip<br />

Es ist wiederum klar, daß Ni eine Entfaltung von Li ist.<br />

E entstehe aus G durch Ersetzen von Li durch Ni für jedes i∈{1,..,W(F)}. Da<br />

jedes while-Konstrukt entfaltet ist und die Entfaltung eines Fragmentes H,<br />

das kein while-Konstrukt enthält, wiederum H ist, gilt E = E(G). Außerdem<br />

folgt nach Konstruktion, daß D und E strukturäquivalent.<br />

/HPPD<br />

6HLHQ3XQG4VWUXNWXUlTXLYDOHQWH3URJUDPPH'DQQH[LVWLHUHQ<br />

(QWIDOWXQJHQ'XQG(PLW' (3XQG( (4XQG'XQG(VLQG<br />

VWUXNWXUlTXLYDOHQW<br />

Beweis:<br />

folgt aus Lemma 3.2.2 für die Hauptanweisungssequenzen von P und Q.<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

3.3 Werte von Zahlen und Variablen<br />

Bemerkung:<br />

Der Wert einer Zahl n ist diejenige natürliche Zahl, deren Dezimaldarstellung n ist. Wir wollen<br />

deswegen eine Zahl und ihren Wert identifizieren.<br />

'HILQLWLRQ<br />

6HLYHLQH+DXSWYDULDEOH3HLQ3URJUDPP( (3XQG1HLQHJHRUGQHWH<br />

0HQJHQDW UOLFKHU=DKOHQPLWQ _1_ _(93_(LQJDEHPHQJH6HLP<br />

9Y('DQQZLUGGHU:HUWYDOYL(YRQYLQ(EHL(LQJDEH1EHL<br />

9RUNRPPHQLL∈^P`LQGXNWLYGHILQLHUW<br />

) UL JLOW<br />

)DOOYLVW(LQJDEHYDULDEOHXQGNRPPWLP(LQJDEHNRQVWUXNWDOVHWH<br />

9DULDEOHYRUH∈^Q`<br />

'DQQZLUGYDOY( UJHVHW]WZREHLUGDVHWH(OHPHQWYRQ1<br />

LVW<br />

)DOOYLVWNHLQH(LQJDEHYDULDEOHXQG.LVWLKUJOREDOHV<br />

,QLWLDOLVDWLRQVNRQVWUXNW<br />

8QWHUIDOO$XIGHUHQUHFKWHU6HLWHYRQ.VWHKWGLH=DKO]<br />

6HW]HYDOY( ]<br />

8QWHUIDOO$XIGHUHQUHFKWHU6HLWHYRQ.VWHKWGLH9DULDEOHZ<br />

6HLMGLH1XPPHUGHV9RUNRPPHQVYRQZLQ(LP<br />

.RQVWUXNW.6HW]HYDOY( YDOZM(<br />

6HLQXQL!<br />

)DOO,QLKUHPLWHP9RUNRPPHQLQ(OLHJWYLQQHUKDOEHLQHV<br />

,QNUHPHQWHV<br />

'DQQLVWYDOYL( YDOYL(<br />

)DOO,QLKUHPLWHQ9RUNRPPHQOLHJWYLQQHUKDOEHLQHV'HNUHPHQWHV<br />

'DQQLVW<br />

val(v, i, E)<br />

$QVRQVWHQLVWYDOYL( YDOYL(<br />

=<br />

⎧val(v, i - 1, E) - 1, falls val(v, i - 1, E) > 0<br />

⎨<br />

⎩0 sonst<br />

6HL3HLQ3URJUDPPXQG1HLQH(LQJDEHPHQJH6HL( (36HLYHLQH<br />

ORNDOH9DULDEOHHLQHVZKLOH.RQVWUXNWHV:LQ36HL'GLH(QWIDOWXQJYRQ:<br />

LQ(6HLP 9Y''DQQZLUGGHU:HUWYDOYL'YRQYLQ'EHL<br />

9RUNRPPHQLL∈^P`LQGHU(QWIDOWXQJ(YRQ3EHL(LQJDEH1<br />

YHUVFKDFKWHOWLQGXNWLYGHILQLHUW<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

6HL]XHUVW:HLQORNDOHVZKLOH.RQVWUXNWGHU+DXSWDQZHLVXQJVVHTXHQ]YRQ<br />

3<br />

) UL JLOW<br />

6HL.GDVORNDOH,QLWLDOLVDWLRQVNRQVWUXNWYRQYLQ:<br />

8QWHUIDOO$XIGHUHQUHFKWHU6HLWHYRQ.VWHKWGLH=DKO]<br />

6HW]HYDOY' ]<br />

8QWHUIDOO$XIGHUHQUHFKWHU6HLWHYRQ.VWHKWGLH9DULDEOHZ<br />

GLHVNDQQQXUHLQH(LQJDEHYDULDEOHRGHUHLQHJOREDOH<br />

9DULDEOHVHLQ<br />

6HLMGLH1XPPHUGHV9RUNRPPHQVYRQZLQ.LQGHU<br />

(QWIDOWXQJ(6HW]HYDOY' YDOZM(<br />

6HLQXQL!<br />

)DOO,QLKUHPLWHP9RUNRPPHQLQ'OLHJWYLQQHUKDOEHLQHV<br />

,QNUHPHQWHV<br />

'DQQLVWYDOYL' YDOYL'<br />

)DOO,QLKUHPLWHQ9RUNRPPHQOLHJWYLQQHUKDOEHLQHV'HNUHPHQWHV<br />

'DQQLVW<br />

val(v, i, D)<br />

=<br />

⎧val(v, i - 1, D) - 1, falls val(v, i - 1, D) > 0<br />

⎨<br />

⎩0 sonst<br />

$QVRQVWHQLVWYDOYL' YDOYL'<br />

6HLMHW]W:HLQZKLOH.RQVWUXNWYRQ3ZHOFKHVORNDOHVZKLOH.RQVWUXNWHLQHV<br />

]ZHLWHQZKLOH.RQVWUXNWHV:LVW6HL&GLH(QWIDOWXQJYRQ:LQ(<br />

) UL JLOW<br />

6HL.GDVORNDOH,QLWLDOLVDWLRQVNRQVWUXNWYRQYLQ:<br />

8QWHUIDOO$XIGHUUHFKWHQ6HLWHYRQ.VWHKWGLH=DKO]<br />

6HW]HYDOY' ]<br />

8QWHUIDOO$XIGHUUHFKWHQ6HLWHYRQ.VWHKWGLH+DXSWYDULDEOHZ<br />

6HLMGLH1XPPHUGHV9RUNRPPHQVYRQZ,Q.LQGHU<br />

(QWIDOWXQJ(6HW]HYDOY' YDOZM(<br />

8QWHUIDOO $XIGHUUHFKWHQ6HLWHYRQ.VWHKWGLHORNDOH9DULDEOH<br />

Z<br />

6HLMGLH1XPPHUGHV9RUNRPPHQVYRQZLQ.LQGHU<br />

(QWIDOWXQJ&6HW]HYDOY' YDOZM&<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

6HLQXQL!<br />

)DOO,QLKUHPLWHP9RUNRPPHQLQ'OLHJWYLQQHUKDOEHLQHV<br />

,QNUHPHQWHV<br />

'DQQLVWYDOYL' YDOYL'<br />

)DOO,QLKUHPLWHQ9RUNRPPHQOLHJWYLQQHUKDOEHLQHV'HNUHPHQWHV<br />

'DQQLVW<br />

val(v, i, D)<br />

$QVRQVWHQLVWYDOYL' YDOYL'<br />

Beispiel 3.3.1:<br />

Sei P gegeben durch<br />

input (x ,y)<br />

++x<br />

--y<br />

++x<br />

x<br />

with<br />

set (z := x)<br />

while do<br />

z++<br />

with<br />

set (w := z)<br />

while do<br />

w++<br />

end while<br />

end while<br />

output x<br />

und sei E gegeben durch<br />

input (x ,y)<br />

++x<br />

--y<br />

++x<br />

x<br />

with<br />

set (z := x)<br />

test do<br />

++z<br />

// Beginn von D<br />

with<br />

set (w := z)<br />

test do<br />

++w<br />

end test<br />

test do<br />

++w<br />

end test<br />

// Ende von D<br />

=<br />

⎧val(v, i - 1, D) - 1, falls val(v, i - 1, D) > 0<br />

⎨<br />

⎩0 sonst<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

end test<br />

test do<br />

++z<br />

with<br />

set (w := z)<br />

test do<br />

++w<br />

end test<br />

test do<br />

++w<br />

end test<br />

end test<br />

output x<br />

Es sei die Eingabemenge N = (1,2)<br />

So gilt für die Werte der Variablen x in E:<br />

val(x,1,E) = 1<br />

val(x,2,E) = 2<br />

val(x,3,E) = 3<br />

val(x,4,E) = 3<br />

val(x,5,E) = 3<br />

val(x,6,E) = 3<br />

und für die Werte der Variablen w in D:<br />

val(w,1,D) = 4<br />

val(w,2,D) = 5<br />

val(w,3,D) = 6<br />

/HPPD<br />

D6HL3HLQ3URJUDPPXQG(HLQH(QWIDOWXQJYRQ36HLYHLQH<br />

(LQJDEHYDULDEOH'DQQJLOWI UMHGHVL∈^9Y(`LVWYDOYL(GHILQLHUW<br />

E6HL3HLQ3URJUDPPXQG(HLQH(QWIDOWXQJYRQ36HLYHLQHJOREDOH<br />

9DULDEOH'DQQJLOWI UMHGHVL∈^9Y(`LVWYDOYL(GHILQLHUW<br />

F6HL3HLQ3URJUDPPXQG(HLQH(QWIDOWXQJYRQ36HL:HLQZKLOH<br />

.RQVWUXNWYRQ3XQG'GLH(QWIDOWXQJYRQ:LQ(6HLYHLQHORNDOH9DULDEOH<br />

YRQ:'DQQJLOWI UMHGHVL∈^9Y'`LVWYDOYL'GHILQLHUW<br />

Beweis:<br />

a) Sei N die Eingabemenge. Sei v eine Eingabevariable. Wir betrachten jetzt das<br />

erste Auftreten von v.<br />

Da v ist Eingabevariable, liegt das erste Vorkommen von v im<br />

Eingabekonstrukt von E. Dann ist val(v,1,E) über ein Element der<br />

Eingabemenge N definiert.<br />

Für 1 < i ≤ V(v,E) ist val(v,i,E) definiert, wenn val(v,i-1,E) definiert ist. Dann<br />

folgt die Behauptung aber sofort durch Induktion über i.<br />

b) v sei globale Variable. Wir betrachten wiederum das erste Auftreten von v in<br />

E. Nach Lemma 2.3.1 liegt das erste Auftreten von v in P auf der linken Seite<br />

ihres Initialisationskonstruktes K. Da ist dann auch das erste Vorkommen von v<br />

in E.<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

1. Fall: Auf der rechten Seite von K ist die Zahl z. Dann ist val(v,1,E) = z<br />

definiert.<br />

2. Fall: Auf der linken Seite von K ist die Variable w. Dies kann nur eine<br />

Eingabevariable sein, denn globale Variablen dürfen nur einmal in ihrer<br />

Initialisationssequenz vorkommen, nämlich auf der linken Seite ihres<br />

Initialisationskonstruktes. Für Eingabevariablen ist aber die Relation val<br />

definiert für jedes ihrer Vorkommen in E (nach Beweisteil a). Dann ist auch<br />

val(v,1,E) definiert.<br />

Für 1 < i ≤ V(v,E) ist val(v,i,E) definiert, wenn val(v,i-1,E) definiert ist. Dann<br />

folgt die Behauptung aber sofort durch Induktion über i.<br />

c) Sei v eine lokale Variable von W. Nach Lemma 2.3.1 liegt das erste<br />

Vorkommen von v in W auf der linken Seite ihres Initialisationskonstruktes.<br />

Dann ist auch das erste Vorkommen von v in D auf der linken Seite des<br />

Initialisationskonstruktes K von v.<br />

(vollständige Induktion über die Zahl der while-Konstrukte k, in denen W<br />

enthalten ist)<br />

Induktionsverankerung:<br />

Sei k = 0, dann ist W lokales while-Konstrukt der Hauptanweisungssequenz<br />

von P.<br />

1. Fall: auf der rechten Seite von K steht die Zahl z, dann ist val(v,1,D) = z<br />

definiert.<br />

2. Fall: auf der rechten Seite von K steht eine Variable. Dies kann keine<br />

lokale Variable von W sein, da diese nur einmal in der Initialisationssequenz<br />

vorkommen dürfen, nämlich auf der linken Seite ihres<br />

Initialisationskonstruktes. Also muß es eine Hauptvariable sein. Nach den<br />

Beweisteilen a) und b) ist aber die Relation val für diese Variablen für jedes<br />

Vorkommen in E definiert. Dann ist auch val(v,1,D) definiert.<br />

Induktionsvoraussetzung:<br />

Für jedes while-Konstrukt W', das in maximal k while-Konstrukten enthalten<br />

ist, ist die Relation val für jedes Vorkommen jeder lokalen Variablen von W'<br />

in E(W') definiert.<br />

Induktionsbehauptung:<br />

W sei in k+1 while-Konstrukten enthalten. Dann ist val(v,1,D) definiert.<br />

Induktionsschluß:<br />

W sei lokales while-Konstrukt in dem while-Konstrukt W’.<br />

1. Fall: auf der rechten Seite von K steht die Zahl z, dann ist val(v,1,D) = z<br />

definiert.<br />

2. Fall: auf der rechten Seite von K steht die Hauptvariable w. Nach den<br />

Beweisteilen a) und b) ist die Relation val für w definiert. Dann ist auch<br />

val(v,1,D) definiert.<br />

2. Fall: auf der rechten Seite von K steht die lokale Variable w. Dies kann<br />

aber nur eine lokale Variable von W' oder eines while-Konstruktes, in dem W’<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

enthalten ist, sein. Nach Induktionsvoraussetzung ist aber der Wert von w in<br />

der Entfaltung an der Stelle K definiert. Dann ist auch val(v,1,D) definiert.<br />

Für 1 < i ≤ V(v1,E) ist val(v1,i,E) definiert, wenn val(v1,i-1,E) definiert ist. Dann<br />

folgt die Behauptung aber sofort durch Induktion über i.<br />

3.4 Konstruktion von Beispielauswertungen<br />

'HILQLWLRQ<br />

6HL3HLQ3URJUDPPXQG1HLQHJHRUGQHWH0HQJHQDW UOLFKHU=DKOHQPLW<br />

_1_ _(93_'DQQHQWVWHKWHLQH%HLVSLHODXVZHUWXQJYDO31YRQ3EHL<br />

(LQJDEH1GXUFKIROJHQGHV9HUIDKUHQ<br />

%LOGXQJHLQHU(QWIDOWXQJ(YRQ3<br />

ì (UVHW]HQYRQYGXUFKYDOYL(I UMHGHV9RUNRPPHQLHLQHU<br />

+DXSWYDULDEOHQYLQ(<br />

ì (UVHW]HQYRQYGXUFKYDOYL'I UMHGHV9RUNRPPHQLHLQHUORNDOHQ<br />

9DULDEOHQHLQHVZKLOH.RQVWUXNWHV:LQGHU(QWIDOWXQJ' (:<br />

LQQHUKDOEYRQ(<br />

ì /|VFKHQDOOHU,QLWLDOLVDWLRQVNRQVWUXNWHLQ(<br />

ì /|VFKHQMHGHV9RUNRPPHQVGHV6FKO VVHOZRUWHVZLWKLQ(<br />

'LH0HQJHDOOHU%HLVSLHODXVZHUWXQJHQYRQ3XQG1ZLUGDOV%$31<br />

EH]HLFKQHW<br />

Beispiel 3.4.1:<br />

Sei P gegeben durch<br />

input (x,y)<br />

set (z:=4)<br />

y<br />

with<br />

set (c:=0)<br />

set (d:=y)<br />

while d>0 do<br />

++c<br />

--d<br />

end while<br />

output z<br />

und sei die Eingabe N gleich (3,6),<br />

dann ist die folgende Zeichenfolge eine Beispielauswertung von P:<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

input (3,6)<br />

6<br />

test 6 > 0 do<br />

1<br />

5<br />

end test<br />

test 5 > 0 do<br />

2<br />

4<br />

end test<br />

output 4<br />

'HILQLWLRQ<br />

6HL3HLQ3URJUDPP)HLQ)UDJPHQWYRQ3XQG6HLQH%HLVSLHODXVZHUWXQJ<br />

YRQ3(LQH7HLO]HLFKHQIROJH7YRQ6KHL‰W%HLVSLHODXVZHUWXQJVIUDJPHQW]X<br />

)ZHQQ7GLH7HLO]HLFKHQIROJHYRQ6LVWGLHGHU(QWIDOWXQJYRQ)HQWVSULFKW<br />

'HILQLWLRQ<br />

6HL)HLQ3URJUDPPIUDJPHQWXQG7HLQ%HLVSLHODXVZHUWXQJVIUDJPHQW7<br />

KHL‰W%HLVSLHODXVZHUWXQJYRQ)ZHQQHVHLQ3URJUDPP3XQGHLQ<br />

%HLVSLHODXVZHUWXQJ6YRQ3JLEWVRGD‰)LVW3URJUDPPIUDJPHQWYRQ3XQG<br />

7LVW%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ6<br />

3.5 Äquivalente Programme<br />

'HILQLWLRQ<br />

=ZHL3URJUDPPH3XQG4KHL‰HQlTXLYDOHQW3≅4ZHQQ<br />

_(93_ _(94_<br />

I UMHGHJHRUGQHWH0HQJHQDW UOLFKHU=DKOHQ1PLW_1_ _(93_JLOW<br />

%$31 %$41<br />

Beispiel 3.5.1:<br />

Folgende Programme sind äquivalent:<br />

input (a)<br />

with<br />

set (b := a)<br />

set (c := 0)<br />

while b>0 do<br />

--b<br />

++c<br />

--c<br />

++c<br />

end while<br />

output a<br />

input (x)<br />

set (w := 0)<br />

set (u := x)<br />

with<br />

set (y := x)<br />

set (z := w)<br />

set (v := w)<br />

while u>w do<br />

--y<br />

++z<br />

w<br />

++w<br />

end while<br />

output u<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

/HPPD<br />

'LH5HODWLRQ≅LVWHLQHbTXLYDOHQ]UHODWLRQDXIGHU0HQJHGHUZKLOH<br />

3URJUDPPH<br />

Beweis:<br />

Reflexivität, Symmetrie und Transitivität der Relation ≅ folgen direkt aus den<br />

entsprechenden Eigenschaften der Gleichheit der Mengen der<br />

Beispielauswertungen.<br />

'HILQLWLRQ<br />

6HL3HLQ3URJUDPP9 ^Y Y Q`HLQHJHRUGQHWH0HQJHYRQ9DULDEOHQYRQ3<br />

XQG; ^[ [ Q`HLQHJHRUGQHWH0HQJHYRQ%H]HLFKQHUQGLHQLFKWLQ3<br />

YRUNRPPHQ'DQQHQWVWHKWGLHGDV3URJUDPP3σGXUFKGLH<br />

9DULDEOHQVXEVWLWXWLRQσ >Y [ Y Q [ Q @ZREHLMHGHV9RUNRPPHQVYRQY L<br />

GXUFK[ L HUVHW]WZLUGI UMHGHVL∈^Q`<br />

Bemerkung:<br />

a) Die Elemente der Menge X sind Variablen in Pσ.<br />

b) Es ist möglich, Variablen zu tauschen. Zum Beispiel kann eine Substitution [x/y,y/x] durch<br />

die Verkettung der Substitutionen [x/a,x/b] und [a/y,b/x], wobei a und b neue Bezeichner sind,<br />

gemäß obiger Definition ausgeführt werden.<br />

/HPPD<br />

6HLHQ3XQG43URJUDPPHXQGσHLQH9DULDEOHQVXEVWLWXWLRQVRGD‰4 3σ<br />

'DQQJLOW3≅4<br />

Beweis:<br />

Es sei σ = [v1/x1,...,vn/xn], wobei v1,...,vn Variablen in P und x1,...,xn Variablen in<br />

Q. O.B.d.A. seien die Variablen v1,..,vn und x1,...,xn in der Reihenfolge ihres<br />

ersten Auftretens geordnet. P und Q unterscheiden sich nur in diesen Variablen.<br />

Da das erste Vorkommen einer Hauptvariablen vor dem ersten Vorkommen<br />

einer lokalen Variablen liegt, gibt es ein m∈{0,...,n}, so daß v1,..,vm sind<br />

Hauptvariablen und vm+1,...,vn sind lokale Variablen. Es ist klar, daß P und Q<br />

strukturäquivalent sind. Sei D eine beliebige Entfaltung von P. Nach Lemma<br />

3.2.4 existiert eine Entfaltung E von Q, derart daß D und E sind<br />

strukturäquivalent. Die Entfaltungen E und F von P und Q unterscheiden sich<br />

dann ebenfalls nur in den Variablen v1,..,vn und x1,...,xn, die weiterhin in der<br />

Reihenfolge ihres Auftretens geordnet sind. Für jedes i∈{1,...n} gilt außerdem<br />

V(vi,D) = V(xi,E).<br />

Da bei der Konstruktion einer Beispielauswertung alle Variablen durch ihre<br />

Werte ersetzt werden, genügt es zu zeigen, daß für jedes i∈{1,...m} und jedes<br />

j∈{1,...V(vi,D)}gilt val(xi,j,D) = val(vi,j,E)<br />

und für jedes k∈{m+1,...n} und jedes while-Konstrukt Kk von P, in dem vk lokale<br />

Variable ist (Lk sei das entsprechende while-Konstrukt von Q) und jedes<br />

j∈{1,...,V(vk,Dk)} gilt val(vk,j,Dk) = val(xk,j,Ek), wobei Dk<br />

die Entfaltung von Kk in D und Ek die Entfaltung von Lk in E ist.<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

Betrachten wir zuerst die Hauptvariablen:<br />

(vollständige Induktion über die ersten r Variablen (r≤m))<br />

Induktionsverankerung:<br />

Es sei r=1,v1 ist erste substituierte Variable in D, x1 ist erste substituierte<br />

Variable in E.<br />

1. Fall: Wenn v1 Eingabevariable, so ist auch x1 Eingabevariable und v1 und<br />

x1 stehen an derselben Position im Eingabekonstrukt. Dann ist val(x1,1,E) =<br />

val(v1,1,D).<br />

2. Fall: Wenn v1 globale Variable, so ist auch x1 globale Variable, und die<br />

Initialisationskonstrukte von x1 und v1 unterscheiden sich nur in x1 bzw. v1.<br />

Sei "set (v1 := µ)" das Initialisationskonstrukt von v1, Dabei ist µ eine<br />

beliebige Variable (außer v1,..,vn,x1,...,xn) oder eine Zahl. Dann ist "set (x1 :=<br />

µ)" das Initialisationskonstrukt von x1, denn x1 und v1 dürfen auf der rechten<br />

Seite ihres Initialisationskonstruktes nicht vorkommen, ebensowenig wie die<br />

Variablen v2,..,vn und x2,...,xn. (da v1 bzw., x1 die erste dieser Variablen). Also<br />

gilt auch hier val(x1,1,E) = val(v1,1,D).<br />

Da jede Änderung des Wertes von x1 in einem Dekrement oder Inkrement<br />

eine ebensolche Änderung des Wertes von v1 bedeutet, muß auch für jedes<br />

Vorkommen j>1 gelten: val(x1,j,E) = val(v1,j,D).<br />

Induktionsvoraussetzung:<br />

Für r>1 beliebig (aber ≤ m) gilt für jedes i∈{1,...r-1} und jedes j∈{1,...V(vi,E)}<br />

val(xi,j,E) = val(vi,j,D).<br />

Induktionsbehauptung:<br />

Für jedes i∈{1,...r} und jedes j∈{1,...V(vi,E)} gilt val(xi,j,E) = val(vi,j,D).<br />

Induktionsschluß:<br />

Da die Behauptung nach Induktionsvoraussetzung für die ersten r-1<br />

Substitutionsvariablen gilt, müssen wir sie nur noch für das Paar vr und xr<br />

zeigen.<br />

1. Fall: Wenn vr Eingabevariable, so ist auch xr Eingabevariable und vr und<br />

xr stehen an derselben Position im Eingabekonstrukt. Dann ist val(xr,1,E) =<br />

val(vr,1,D).<br />

2. Fall: Wenn vr globale Variable, so ist auch xr globale Variable. Sei "set (vr<br />

:= µ)" das Initialisationskonstrukt von vr, und "set (xr := λ)" das<br />

Initialisationskonstrukt von xr.<br />

Wir wissen, daß µ≠vr und λ≠xr.<br />

Unterfall 1: µ sei entweder eine Zahl oder eine Variable, die nicht in {v1,...,vn}<br />

enthalten ist. Dann ist λ=µ und val(xr,1,E) = val(vr,1,D).<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

Unterfall 2: µ ist eine der Variablen aus der Menge {vr+1,...,vn} (λ ist dann eine<br />

der Variablen aus der Menge {xr+1,...,xn}. Dann würde aber das<br />

erste Vorkommen dieser Variablen vor dem ersten Vorkommen der<br />

Variablen vr liegen im Widerspruch zur Voraussetzung die<br />

Variablen wären nach der Reihenfolge ihres Auftretens geordnet.<br />

Unterfall 3: µ ist vi, wobei i∈{1,...,r-1}. Dann ist λ=xr. Sei j die Nummer des<br />

Vorkommens von vi im Initialisationskonstrukt von vr und von xi im<br />

Initialisationskonstrukt von xr. Nach Induktionsvoraussetzung ist<br />

val(vi, j,D) = val(xi,j,E) und damit auch val(vr,1,D) = val(xr,1,E).<br />

Demnach gilt in jedem möglichen Fall val(vr,1,D) = val(xr,1,E).<br />

Da jede Änderung des Wertes von xr in einem Dekrement oder Inkrement<br />

eine ebensolche Änderung des Wertes von vr bedeutet, muß auch für jedes<br />

Vorkommen j>1 gelten: val(xr,j,E) = val(vr,j,D).<br />

Betrachten wir jetzt die lokalen Variablen:<br />

(vollständige Induktion über die ersten s lokalen Variablen (m1 beliebig gilt für jedes i∈{m+1,...s-1} und jedes j∈{1,...V(vi,Di)}:<br />

val(xi,j,Ei) = val(vi,j,Di), wobei Di die Entfaltung des zu vi gehörigen while-<br />

Konstruktes in D und Ei die entsprechende Entfaltung in E.<br />

Induktionsbehauptung:<br />

Für jedes i∈{m+1,...s} und jedes j∈{1,...V(vi,Di)} gilt val(xi,j,Ei) = val(vi,j,Di).<br />

Induktionsschluß:<br />

Da die Behauptung nach Induktionsvoraussetzung für die ersten s-1 lokalen<br />

Substitutionsvariablen gilt, müssen wir sie nur noch für das Paar vs und xs<br />

zeigen. Sei "set (vs := µ)" das Initialisationskonstrukt von vs, und "set (xs :=<br />

λ)" das Initialisationskonstrukt von xs.<br />

Wir wissen, daß µ≠vs und λ≠xs.<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

Fall 1: µ sei entweder eine Zahl oder eine Variable, die nicht in {v1,...,vn}<br />

enthalten ist. Dann ist λ=µ und val(xs,1,Es) = val(vs,1,Ds).<br />

Fall 2: µ ist eine der Variablen aus der Menge {vs+1,...,vn} (λ ist dann eine der<br />

Variablen aus der Menge {xm+1,...,xn}. Dann würde aber das erste<br />

Vorkommen dieser Variablen vor dem ersten Vorkommen der Variablen<br />

vs liegen im Widerspruch zur Voraussetzung die Variablen wären nach<br />

der Reihenfolge ihres Auftretens geordnet.<br />

Fall 3: µ ist vi, wobei i∈{m+1,...,s-1}. Dann ist λ=xi. vi ist lokale Variable des<br />

while-Konstruktes W von P, dessen Entfaltung innerhalb von D gleich<br />

D’ ist. Dabei ist K in W enthalten. Entsprechendes gilt für die Variable<br />

xi. Sei j die Nummer des Vorkommens von vi im Initialisationskonstrukt<br />

von vs und von xi im Initialisationskonstrukt von xs. Nach<br />

Induktionsvoraussetzung ist val(vi, j,Di) = val(xi,j,Ei) und damit auch<br />

val(vs,1,Ds) = val(xs,1,Es).<br />

Fall 4: µ ist vi, wobei i∈{1,...,m}. Dann ist λ=xi. Damit sind xi und vi<br />

Hauptvariablen. Sei j die Nummer des Vorkommens von vi im<br />

Initialisationskonstrukt von vs und von xi im Initialisationskonstrukt<br />

von xs. Nach obiger Induktion (für Hauptvariablen) ist val(vi, j,D) =<br />

val(xi,j,E) und damit auch val(vs,1,Ds) = val(xs,1,Es).<br />

Demnach gilt in jedem Fall val(vs,1,Ds) = val(xs,1,Es).<br />

Da jede Änderung des Wertes von xm in einem Dekrement oder Inkrement<br />

eine ebensolche Änderung des Wertes von vm bedeutet, muß auch für jedes<br />

Vorkommen j>1 gelten: val(xs,j,Es) = val(vs,j,Ds).<br />

'HILQLWLRQ<br />

6HL3HLQ3URJUDPP'LHNRQVWDQWHQEHUHLQLJWH)RUPYRQ3ZLUG<br />

IROJHQGHUPD‰HQJHELOGHW<br />

) UMHGH.RQVWDQWHFZlKOHHLQHQ%H]HLFKQHUYGHULP3URJUDPPELVKHU<br />

QLFKWYRUNRPPW(UVHW]HMHGHV9RUNRPPHQYRQFGXUFKYXQGI JHGDV<br />

,QLWLDOLVDWLRQVNRQVWUXNWVHWY FLQGLH+DXSWLQLWLDOLVDWLRQVVHTXHQ]HLQ<br />

Beispiel 3.5.2:<br />

Sei P das folgende Programm:<br />

input ()<br />

set (a := 4)<br />

2<br />

with<br />

while 3 do<br />

4<br />

with<br />

set (x := a)<br />

set (y := 5)<br />

while 6 do<br />

7<br />

end while<br />

end while<br />

output a<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

Dann ist der folgende Programmtext eine konstantenbereinigte Form von P:<br />

input ()<br />

set (a := 4)<br />

set (b := 2)<br />

set (c := 3)<br />

set (d := 4)<br />

set (e := 5)<br />

set (f := 6)<br />

set (g := 7)<br />

b<br />

with<br />

while c do<br />

d<br />

with<br />

set (x := a)<br />

set (y := e)<br />

while f do<br />

g<br />

end while<br />

end while<br />

output a<br />

/HPPD<br />

6HL3HLQ3URJUDPPXQG4VHLQHNRQVWDQWHQEHUHLQLJWH)RUP'DQQLVW4HLQ<br />

3URJUDPP<br />

Beweis:<br />

Es ist klar, daß Q ein Programmtext ist. Zu zeigen bleibt demnach nach<br />

Definition 2.3.11, daß jeder Bezeichner im Eingabekonstrukt, im<br />

Ausgabekonstrukt, in einem Initialisationskonstrukt, in einem Dekrement und<br />

in einem Inkrement eine Variable ist.<br />

Wir haben weder das Eingabekonstrukt, noch das Ausgabekonstrukt, noch ein<br />

Dekrement oder ein Inkrement verändert. Wir haben lediglich bestehenden<br />

Initialisationskonstrukte verändert und neue Initialisationskonstrukte<br />

eingeführt. Wir müssen zeigen, daß jeder der neu eingeführten Bezeichner eine<br />

Variable ist.<br />

Betrachten wir zuerst die neu eingeführten Initialisationskonstrukte. Sie liegen<br />

alle in der globalen Initialisationssequenz. Sei K ein solches<br />

Initialisationskonstrukt. Aus der linken Seite von K steht ein neu eingeführter<br />

Bezeichner, etwa v, und auf der rechten Seite steht eine Konstante. v kommt in<br />

genau einem globalen Initialisationskonstrukt vor und zwar nur auf dessen<br />

linken Seite. v kommt nicht im Eingabekonstrukt vor. Also ist v eine Variable.<br />

Betrachten wir jetzt die veränderten Initialisationskonstrukte. Jedes der<br />

veränderten Initialisationskonstrukte hat die Form "set (x := y)", wobei x und y<br />

Bezeichner sind. Dabei ist x schon eine Variable in P und y nach obigen<br />

Bemerkungen ebenfalls eine Variable. Also ist Q ein Programm.<br />

/HPPD<br />

6HL3HLQ3URJUDPPXQG4VHLQHNRQVWDQWHQEHUHLQLJWH)RUP'DQQJLOW4≅3<br />

6HLWH


%HLVSLHODXVZHUWXQJHQ<br />

Beweis:<br />

Sei c eine beliebige Konstante in P.<br />

Bei der Bildung von Q wurde c durch eine globale Variable v ersetzt mit<br />

val(v,i,E) = c für 1 ≤ i ≤ V(v,E), für jede Entfaltung E von Q.<br />

Bei der Bildung einer Beispielauswertung wird v dann durch c ersetzt und alle<br />

Initialisationskonstrukte werden entfernt. Da sich P und Q nur in ihren<br />

Initialisationskonstrukten und in dem Ersatz der Konstanten durch Variablen<br />

mit demselben Wert unterscheiden, sind die Mengen der Beispielauswertungen<br />

für P und Q gleich.<br />

Bemerkung:<br />

Die konstantenbereinigte Form eines Programmes kann weiterhin Konstanten enthalten,<br />

nämlich in der globalen Initialisationssequenz.<br />

/HPPD<br />

6HL3HLQ3URJUDPPXQG. . . L . L . L . M . M . M . Q I UHLQQ∈©HLQH<br />

,QLWLDOLVDWLRQVVHTXHQ]YRQ36HL. . . L . M . L . M . L . M . Q 6HL4GHU<br />

3URJUDPPWH[WGDVDXV3HQWVWHKWGXUFK(UVHW]HQYRQ.GXUFK.'DQQJLOW<br />

D4LVWHLQ3URJUDPP<br />

E4≅3<br />

Beweis:<br />

P und Q unterscheiden sich nur in Ki und Kj. Sei v die Variable auf der linken<br />

Seite von Ki und w die Variable auf der linken Seite von Kj.<br />

a) v und w treten jeweils weiterhin nur einmal in K auf und zwar auf der linken<br />

Seite ihres Initialisationskonstruktes. Da sie im weiteren nicht verändert<br />

wurden, bleiben sie Variablen. Gleiche Überlegung gilt auch für eventuelle<br />

Variablen auf den rechten Seiten von Ki und Kj. Also ist Q ein Programm.<br />

b) P und Q sind strukturäquivalent, also existiert für eine beliebige Entfaltung<br />

D von P nach Lemma 3.2.4 eine Entfaltung E von Q, so daß E und D sind<br />

strukturäquivalent.<br />

1. Fall: K ist globales Initialisationskonstrukt:<br />

Da v und w auf der linken Seiten von Ki und Kj nicht vorkommen dürfen, gilt<br />

val(v,1,D) = val(v,1,E) und val(w,1,D) = val(w,1,E). Demnach werden die<br />

Wert der Variablen v und w durch die Transformation nicht verändert<br />

(ebensowenig wie die Werte anderer Variablen). Da Initialisationskonstrukte<br />

in Beispielauswertungen nicht mehr vorkommen, haben P und Q dieselben<br />

Mengen von Beispielauswertungen.<br />

2. Fall: K ist lokales Initialisationskonstrukt eines while-Konstruktes W:<br />

Sei D' eine Entfaltung von W in D und E' eine Entfaltung von W in E. Da v<br />

und w auf der linken Seiten von Ki und Kj nicht vorkommen dürfen, gilt<br />

val(v,1,D') = val(v,1,E') und val(w,1,D') = val(w,1,E'). Demnach werden die<br />

Wert der Variablen v und w durch die Transformation nicht verändert<br />

(ebensowenig wie die Werte anderer Variablen). Da Initialisationskonstrukte<br />

in Beispielauswertungen nicht mehr vorkommen, haben P und Q dieselben<br />

Mengen von Beispielauswertungen.<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

4 Automatische Generierung von Beispielauswertungen<br />

In diesem Kapitel wird ein Algorithmus zu automatischen Generierung von<br />

Beispielauswertungen aus WHILE-Programmen angeben und seine Korrektheit bewiesen. Es<br />

zeigt sich, daß der Zeitbedarf für die Generierung linear mit der Länge des WHILE-<br />

Programmes ansteigt.<br />

4.1 Variablenlisten<br />

Zur Speicherung der Anfangswerte und der aktuellen Werte unserer Variablen des<br />

Programmes benötigen wir Datenstruktur Variable und Variablenliste:<br />

Die Datenstruktur Variable besteht aus einem String 'lexem' und zweier natürlicher Zahlen<br />

'endwert' und 'anfangswert'. Dabei wird in der Komponente 'lexem' der Name der Variablen<br />

gespeichert und in der Komponente 'endwert' wird der aktuelle Wert der Variablen während<br />

der Bildung einer Beispielauswertung gespeichert, während in der Komponente 'anfangswert'<br />

der erste Wert der Variablen gespeichert wird. Die Datenstruktur Variablenliste besteht dann<br />

aus einer Liste von Variablen und Methoden zur Verwaltung dieser Liste. Auf die Korrektheit<br />

dieser Methoden soll hier nicht eingegangen werden.<br />

4.2 Algorithmus<br />

Die Generierung von Beispielauswertungen ist für jedes WHILE-Programm durchführbar. Es<br />

wird davon ausgegangen, daß die Eingabe in einer geparsten und von Trennzeichen und<br />

Kommentaren bereinigten Form vorliegt. Auch die Ausgabe wird in einer solchen Form<br />

vorliegen.<br />

Algorithmus ComputeProgram(P,N,S)<br />

Eingabe: P : Programm<br />

Ausgabe:<br />

N : Eingabemenge N={n 1 ,...,n m } wobei m = |EV(P)|, n i ∈©<br />

S : Beispielauswertung<br />

Funktion: Das berechnete S ist Beispielauswertung von P für die Eingabe N.<br />

Variablen: V : Variablenliste<br />

T : Beispielauswertungsfragment<br />

i : natürliche Zahl (Zählvariable)<br />

c : natürliche Zahl (für den Wert der Ausgabevariablen)<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Abbildung 4 : Struktur des Algorithmus’ ComputeProgram<br />

Prozeduraufruf<br />

Rekursion<br />

computeProgram(P,N,S)<br />

computeSequence(A,V,T)<br />

Sei P ="input (x 1 ,...,x m ) K 1 ,...,K r A output y", wobei x 1 ,...,x m ,y<br />

Variablen, K 1 ...K r die globalen Initialisationskonstrukte und A eine<br />

Anweisungssequenz ist.<br />

// lösche die Variablenliste und trage Eingabevariablen in V ein<br />

Lösche V<br />

für i = 1 bis m tue<br />

Trage Variable x i mit Anfangs- und Endwert n i am Ende von V ein.<br />

ende für<br />

// Trage die Globalen Variablen in V ein<br />

für i = 1 bis r tue<br />

Sei K i = set (v := α).<br />

wenn α ist Zahl dann<br />

trage Variable v mit Anfangs- und Endwert α am Ende von V ein.<br />

sonst (α ist Eingabevariable)<br />

bestimme Wert c von α aus V<br />

Trage Variable v mit Anfangs- und Endwert c am Ende von V ein.<br />

ende wenn<br />

ende für<br />

// Ermittle Beispielauswertung für die Anweisungssequenz A<br />

Rufe ComputeSequence (A, V, T) auf .<br />

// T ist jetzt das Beispielauswertungsfragment zu A uns V enthält alle Eingabe- und<br />

// globalen Variablen mit ihren Werten am Ende der Ausführung von T<br />

// Bestimme den Wert der Ausgabevariablen<br />

Setze c := Endwert von y in V<br />

// Setze S zusammen<br />

Setze S := "input (n 1 ,...,n m ) T output c"<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Ende Algorithmus ComputeProgram<br />

Prozedur ComputeSequence(A,V,T)<br />

Eingabe: A : Programmfragment<br />

Ein-/Ausgabe:<br />

V : Variablenliste<br />

Ausgabe: T : Beispielauswertungsfragment<br />

Funktion:<br />

T ist Beispielauswertungsfragment von A mit der Variablenbelegung V<br />

am Anfang der Auswertung von A. V beinhaltet am Ende der Prozedur<br />

die Variablenbelegung am Ende von T<br />

Variablen: a : Anweisung<br />

c,i : Natürliche Zahlen<br />

z : Natürliche Zahl (für die Länge der Variablenliste)<br />

// T ist am Anfang leer<br />

T := ""<br />

// Bestimme Länge der Variablenliste<br />

z := Länge von V<br />

// Lese A sequentiell.<br />

wenn A≠"" tue<br />

Setze Lesezeiger vor das ersten Element in A<br />

solange A noch nicht vollständig gelesen tue (d.h. solange der Lesezeiger steht<br />

nicht hinter dem letzten Element in A)<br />

a := lese nächsten Eintrag in A.<br />

Stelle Lesezeiger einen Eintrag vor.<br />

unterscheide<br />

falls a ist Sonderzeichen, Wort oder String:<br />

Füge a am Ende von T an.<br />

falls a ist Zahl:<br />

Füge a am Ende von T an.<br />

falls a ist Variable x:<br />

Füge c am Ende von T an, wobei c der Endwert von x in V ist.<br />

falls a ist Inkrement ++x:<br />

Füge c+1 am Ende von S an, wobei c der Endwert von x in V ist. Setze<br />

Endwert von x in V auf c+1.<br />

falls a ist Dekrement --x:<br />

Sei c der Endwert von x in V. Falls v = 0, füge 0 am Ende von S an,<br />

ansonsten füge c-1 am Ende von S an und setze den Endwert von x in<br />

V auf c-1 .<br />

falls a ist while-Konstrukt der Form "with K 1 ...K r while C do D<br />

end while", wobei K 1 ,...,K r lokale Initialisationskonstrukte (für ein r∈©),<br />

C ein Ausdruck und D eine Anweisungssequenz ist.<br />

// Trage die lokalen Variablen in V ein<br />

für i = 1 bis r tue<br />

Sei K i = set (v := α).<br />

wenn α ist Zahl, dann<br />

trage Variable v mit Anfangs- und Endwert α am Ende von V ein.<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

sonst (α ist Variable in V) bestimme Wert c von α aus V<br />

Trage Variable v mit Anfangs- und Endwert c am Ende von V ein.<br />

ende wenn<br />

ende für<br />

// V enthält jetzt (in den ersten z Komponenten) die übergebenen<br />

// Variablen und (in den letzten Komponenten) die lokalen Variablen<br />

// des while-Konstruktes<br />

// Berechne Beispielauswertungsfragment von a<br />

Variablen : T1,T2,T3,T4 : Beispielauswertungsfragmente<br />

Rufe ComputeSequence(C, V, T1) auf.<br />

Rufe ComputeSequence (D, V, T2) auf.<br />

Füge "test T1 do T2 end test" am Ende von S an.<br />

Rufe ComputeSequence (C, V, T3) auf.<br />

Rufe ComputeSequence (D, V, T4) auf.<br />

Füge "test T3 do T4 end test" am Ende von S an.<br />

// Entferne die lokalen Variablen aus der Variablenliste V<br />

Lösche Rest der Liste V nach Position z<br />

ende unterscheide<br />

ende solange<br />

ende wenn<br />

Ende Prozedur ComputeSequence<br />

4.3 Korrektheit<br />

/HPPD<br />

6HL$GDV3URJUDPPIUDJPHQWLQGHU3UR]HGXU&RPSXWH6HTXHQFH$KDEHGLH<br />

*HVWDOW$ D D V ZREHLD D V $QZHLVXQJHQVLQGXQGV!(VVHL<br />

VLFKHUJHVWHOOWGD‰DOOHUHNXUVLYHQ3UR]HGXUDXIUXIHWHUPLQLHUHQ'DQQ<br />

WHUPLQLHUWGLHVRODQJH6FKOHLIHLQV6FKOHLIHQGXUFKOlXIHQLQ<br />

&RPSXWH6HTXHQFHXQGGLH9DULDEOHDQLPPWQDFKHLQDQGHUGLH:HUWHD D V<br />

DQ<br />

Beweis:<br />

a) Termination der solange-Schleife<br />

Sei i die Nummer, desjenigen Elementes, vor dem der Lesezeiger steht.<br />

Behauptung: Nach (s-1) Schleifendurchläufen gilt i=s.<br />

Beweis durch vollständige Induktion über t (1≤t1:<br />

Es gelte nach (t-1) Schleifendurchläufen i=t.<br />

Induktionsbehauptung:<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Nach t Schleifendurchläufen gilt i=t+1.<br />

Induktionsschluß:<br />

Nach Induktionsvoraussetzung gilt nach (t-1) Schleifendurchläufen i=t. Im t-<br />

ten Schleifendurchlauf wird der Lesezeiger um ein Feld vorgestellt, also gilt<br />

i=t+1.<br />

Nach Induktion gilt ∀t∈{1,...,s}[nach (t-1) Schleifendurchläufen gilt i=t].<br />

Da der Lesezeiger nach (s-1) Schleifendurchläufen vor dem letzten Element in A<br />

steht, und der Lesezeiger im s-ten Schleifendurchlauf um eine Position<br />

vorgestellt wird, steht nach dem s-ten Schleifendurchlauf der Zeiger hinter dem<br />

letzten Element von A und die Schleife terminiert nach s Durchläufen.<br />

b) a nimmt nacheinander die Werte a1,...,as an<br />

In Teil a) wurde bewiesen: ∀t∈{1,...,s}[nach (t-1) Schleifendurchläufen gilt i=t].<br />

Da a immer den Wert desjenigen Elementes übernimmt, auf dem der Lesezeiger<br />

steht, der Lesezeiger anfangs vor dem ersten Element steht und bei jedem<br />

Durchlauf um ein Element vorgestellt wird, und die Schleife nach s Durchläufen<br />

terminiert, nimmt a tatsächlich die Werte a1,...,as an.<br />

Bemerkung:<br />

Die zusätzliche Voraussetzung 'Es sei sichergestellt, daß alle rekursiven Prozeduraufrufe<br />

terminieren.' ist notwendig. Während es klar ist, daß jede Aktion außer den rekursiven<br />

Aufrufen im Körper der Schleife nach endlich vielen Schritten terminiert, würde eine solche<br />

Annahme von den rekursiven Aufrufen aber die Gültigkeit des Lemmas voraussetzen.<br />

/HPPD<br />

6HL3HLQ3URJUDPPXQG$HLQ$XVGUXFNLQ3'LH9DULDEOHQOLVWH9EHLQKDOWH<br />

DOOHLQ$DXIWUHWHQGHQ9DULDEOHQPLWLKUHP:HUWDP$QIDQJGHU$XVI KUXQJ<br />

YRQ$'DQQOLHIHUWHLQ$XIUXIGHU3UR]HGXU&RPSXWH6HTXHQFHPLWGHQ<br />

3DUDPHWHUQ$97HLQ%HLVSLHODXVZHUWXQJVIUDJPHQW7YRQ$9ZLUGQLFKW<br />

YHUlQGHUW<br />

Beweis:<br />

Ausdrücke enthalten nur Sonderzeichen, Wörter, Strings, Zahlen und<br />

Variablen. Bei der Bildung von Beispielauswertungen werden hiervon nur<br />

Variablen betroffen, die nämlich durch ihren letzen Wert ersetzt werden.<br />

1. Fall: A="". Dann ist auch T="" ein Beispielauswertungsfragment von A.<br />

2. Fall: A≠"". Sei A="a1,...,as" für s>0.<br />

Sei W das while-Konstrukt von P, dessen Ausdruck A ist und E eine Entfaltung<br />

von W.<br />

Nach Lemma 4.3.1 terminiert die solange-Schleife in s Durchläufen und a<br />

nimmt nacheinander die Werte a1,...,as an. Da bei jedem Schleifendurchlauf T<br />

(das am Anfang leer war) um ein Element ergänzt wird, hat T nach s<br />

Schleifendurchläufen die Form T="b1,...,bs".<br />

Falls für ein i ai ist Sonderzeichen, Wort, String oder Zahl, gilt ai = bi.<br />

Es bleibt zu zeigen, falls für ein i ai ist das j-te Vorkommen der Variablen v in E,<br />

dann ist bi = val(v,j-1,E).<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Da A weder Inkremente noch Dekremente enthält, ist val(v,j-1,E) aber gleich<br />

dem letzten Wert von ai vor der Auswertung von A. Der ist aber in V<br />

gespeichert. Da bi gleich diesem Wert gesetzt wird, ist das Lemma bewiesen.<br />

V wir in ComputeSequence bei der Bearbeitung von Sonderzeichen, Zahlen,<br />

Strings und Wörtern nicht benutzt, bei der Bearbeitung von Variablen wird nur<br />

lesend auf V zugegriffen. Deswegen wird V bei der Bearbeitung eines Ausdrucks<br />

nicht verändert.<br />

Bemerkung:<br />

Im Beweis von Lemma 4.3.2 wurde keine Aussage über die Entfaltung E gemacht. In der Tat<br />

gibt uns das Führen einer Variablenliste die Möglichkeit, Beispielauswertungen zu berechnen,<br />

ohne die endgültige Struktur der Entfaltung kennen zu müssen.<br />

/HPPD<br />

6HL3HLQ3URJUDPP1HLQH(LQJDEHXQG$HLQH$QZHLVXQJVVHTXHQ]LQ3<br />

'LH9DULDEOHQOLVWH9EHLQKDOWHDOOHLQ$DXIWUHWHQGHQ9DULDEOHQRKQHGLH<br />

ORNDOHQ9DULDEOHQHYHQWXHOOLQ$HQWKDOWHQHQZKLOH.RQVWUXNWHPLWLKUHQ<br />

:HUWHQDP$QIDQJGHU$XVI KUXQJYRQ$LQGHU.RPSRQHQWHHQGZHUW'LH<br />

3UR]HGXU6DPSOH6HTXHQFHZHUGHPLWGHQ3DUDPHWHUQ$97DXIJHUXIHQ<br />

'DQQJLOWQDFKGHP$XIUXI<br />

'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

7LVWHLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ$<br />

9HQWKlOWDOOHLQ$DXIWUHWHQGHQ9DULDEOHQRKQHORNDOH9DULDEOHQ<br />

HQWKDOWHQHUZKLOH.RQVWUXNWHXQGLKUH:HUWHDP(QGHGHU$XVI KUXQJ<br />

YRQ$LQGHU.RPSRQHQWHHQGZHUW<br />

Beweis:<br />

1. Fall: A="". Dann terminiert die Prozedur sofort, T="" ist ein<br />

Beispielauswertungsfragment von A, und V wurde nicht verändert und enthält<br />

immer noch die letzen Werte der Variablen.<br />

2. Fall: A≠"". Sei A="a1,...,as" für s>0.<br />

(vollständige Induktion über D(A))<br />

Induktionsverankerung für D(A)=0:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten<br />

Nach Lemma 4.3.1 terminiert die solange-Schleife in s Durchläufen und a<br />

nimmt nacheinander die Werte a1,...,as an (man beachte, daß wegen D(A) = 0<br />

keine rekursiven Aufrufe erfolgen). Da bei jedem Schleifendurchlauf T (das<br />

am Anfang leer war) um ein Element ergänzt wird, hat T nach s<br />

Schleifendurchläufen die Form T="b1,...,bs".<br />

2. T ist Beispielauswertungsfragment von A<br />

Es sei D(A)=0, dann enthält A keine while-Konstrukte. Demnach entsteht ein<br />

Beispielauswertungsfragment von A durch Ersetzen der Variablen durch ihre<br />

Werte, wobei Variablen aber auch in Inkrementen und Dekrementen<br />

auftreten dürfen.<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Sei ai ein beliebiges Element in A für ein i∈{1,...,s}. ai kann Sonderzeichen,<br />

Wort, String, Zahl, Variable, Inkrement oder Dekrement sein.<br />

Falls ai ist Sonderzeichen, Wort, String oder Zahl, dann ist bi = ai.<br />

Andernfalls muß ai ein Vorkommen einer Variablen sein (eventuell in einem<br />

Inkrement oder Dekrement). Sei E eine Entfaltung von P und N. Falls ai ist<br />

Hauptvariable von P, setze E' := E. Ansonsten sei W das while-Konstrukt,<br />

dessen lokale Variable ai ist. Dann sei E' die Entfaltung von W in E.<br />

Es ist zu zeigen, daß bi = val(v,j,E'), wobei aj das j-tes Auftreten der Variablen<br />

v in E' sei (eventuell in einem Inkrement oder Dekrement).<br />

Behauptung: bi = val(v,j,E') und V enthält nach dem i-ten Schleifendurchlauf<br />

den Wert bi für die Variable v.<br />

Sei g die Nummer des ersten Vorkommens von v in A und h die Nummer des<br />

letzten Vorkommens von v in A.<br />

(vollständige Induktion über die Nummer j des Auftretens von v in A (g≤j≤h))<br />

Induktionsverankerung für das erste Auftreten von v in A:<br />

Vor dem ersten Vorkommen j = g von v enthält V den letzten Wert von v<br />

nach Voraussetzung.<br />

1. Fall: ai ist Variable v (außerhalb eines Inkrementes oder Dekrementes)<br />

dann ist bi = val(v,g-1,E') = val(v,g,E'), da val(v,g-1,E') in V<br />

gespeichert ist.<br />

2. Fall: ai ist Inkrement ++v,<br />

dann ist bi = val(v,g-1,E')+1 = val(v,g,E'), da val(v,g-1,E') in V<br />

gespeichert ist.<br />

3. Fall: ai ist Dekrement --v,<br />

⎧val(v, g - 1, V’ ) - 1, wenn val(v, g - 1, V’ ) > 0<br />

dann gilt bi = ⎨<br />

⎩0 sonst<br />

= val(v,g,E')<br />

In jedem dieser Fälle enthält V nach dem i-ten Schleifendurchlauf den<br />

Wert val(v,g,E') der Variablen v.<br />

Induktionsvoraussetzung für das j-te Vorkommen von v in A:<br />

bi val(v,j,E') und V enthält nach dem i-ten Schleifendurchlauf den Wert bi<br />

für die Variable v.<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Induktionsbehauptung für das (j+1)-te Vorkommen von v in A:<br />

bi = val(v,j+1,E') und V enthält nach dem i-ten Schleifendurchlauf den<br />

Wert bi für die Variable v.<br />

Induktionsschluß:<br />

1. Fall: ai ist Variable v (außerhalb eines Inkrementes oder Dekrementes)<br />

dann ist bi = val(v,j,E') = val(v,j+1,E'), da val(v,j,E') in V<br />

gespeichert ist nach Induktionsvoraussetzung.<br />

2. Fall: ai ist Inkrement ++v,<br />

dann ist bi = val(v,j,E')+1 = val(v,j+1,E'), da val(v,j,E') in V<br />

gespeichert ist nach Induktionsvoraussetzung<br />

3. Fall: ai ist Dekrement --v,<br />

⎧val(v, j, E’ ) - 1, wenn val(v, j, E’ ) > 0<br />

dann gilt bi = ⎨<br />

⎩0 sonst<br />

= val(v,j+1,E')<br />

In jedem dieser Fälle enthält V nach dem ersten Schleifendurchlauf den<br />

Wert val(v,j+1,E') der Variablen v.<br />

Demnach entsteht T aus A durch Ersetzen jedes Vorkommens einer<br />

Variablen (einschließlich Inkremente und Dekremente) durch ihren Wert,<br />

somit ist T Beispielauswertungsfragment zu A.<br />

3. V enthält alle in A auftretenden Variablen (ohne lokale Variablen<br />

enthaltener while-Konstrukte) und ihre Werte am Ende der Ausführung von<br />

A.<br />

Wir haben unter 2. gezeigt, daß für jedes letzte Auftreten h einer Variablen v<br />

von A, val(v,h,E') in V gespeichert wird. Dann enthält V die Werte alle<br />

Variablen von A am Ende von A.<br />

Induktionsvoraussetzung:<br />

Es sei D(A) = d > 0. Dann gelte die Behauptung.<br />

Induktionsbehauptung:<br />

Es sei D(A) = d+1. Dann gelte ebenfalls die Behauptung.<br />

Induktionsschluß:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten<br />

In der Prozedur ComputeSequence kann ein rekursiver Aufruf nur auftreten,<br />

wenn als Programmfragment ein Ausdruck oder eine Anweisungssequenz<br />

eines lokalen while-Konstruktes von A übergeben wird. Für diese<br />

Programmfragmente ist aber die Schachtelungstiefe kleiner gleich d. Nach<br />

Induktionsvoraussetzung ist dann die Termination der Abarbeitung des<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

rekursiven Aufrufs der Prozedur sichergestellt. Dann kann Lemma 4.3.1<br />

angewendet werden. Dies sagt aus, daß die solange-Schleife in s<br />

Durchläufen terminiert und a nacheinander die Werte a1,...,as annimmt. Da<br />

bei jedem Schleifendurchlauf T (das am Anfang leer war) um ein Element<br />

ergänzt wird, hat T nach s Schleifendurchläufen die Form T="b1,...,bs".<br />

2. T ist Beispielauswertungsfragment von A<br />

Wir zeigen: Nach dem i-ten Schleifendurchlauf ist b1,...,bi ein<br />

Beispielauswertungsfragment von a1,...,ai und V enthält die Endwerte aller<br />

Variablen nach Auswertung des Elementes ai (1≤i≤s).<br />

(vollständige Induktion über die Nummer i des Auftretens einer Anweisung<br />

in A (1≤i≤s))<br />

Induktionsverankerung:<br />

a1 kann Sonderzeichen, Wort, String, Zahl, Variable, Inkrement,<br />

Dekrement oder ein while-Konstrukt sein. Dabei werden bei der<br />

Erstellung von Beispielauswertungen nur Variablen, Dekremente,<br />

Inkremente und while-Konstrukte verändert.<br />

Falls a1 ist Sonderzeichen, Wort, String oder Zahl, dann ist b1 = a1.<br />

Sei a1 jetzt eine Variable v (eventuell in einem Inkrement oder<br />

Dekrement).<br />

Sei E eine Entfaltung von P. Falls a1 Hauptvariable, setze E' := E.<br />

Ansonsten sei W dasjenige while-Konstrukt von P, dessen lokale Variable<br />

v ist und E' ist die Entfaltung von W in E. Sei a1 das j-te Auftreten der<br />

Variablen v in E'.<br />

Es ist zu zeigen, daß b1 = val(v,j,E').<br />

v ist nach Voraussetzung in V enthalten, somit ist auch der Wert von v vor<br />

der Bearbeitung der Anweisung (val(v,j-1,E')) bekannt.<br />

1. Fall: a1 ist Variable v (außerhalb eines Inkrementes oder<br />

Dekrementes),<br />

dann ist b1 = val (v,j-1,E') = val(v,j,E').<br />

2. Fall: a1 ist Inkrement ++v,<br />

dann ist b1 = val(v,j-1,E')+1 = val(v,j,E')<br />

3. Fall: a1 ist Dekrement --v,<br />

⎧val(v, j - 1, E’ ) - 1, wenn val(v, j - 1, E’ ) > 0<br />

dann gilt b1 = ⎨<br />

⎩0 sonst<br />

= val(v,j,E')<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

In jedem dieser Fälle enthält V nach dem ersten Schleifendurchlauf den<br />

Wert val(v,j,E') der Variablen v.<br />

Sei a1 jetzt ein while-Konstrukt der Form "with K 1 ,...,K t while C do<br />

D end while", wobei für ein t K1,...,Kt die lokalen<br />

Initialisationskonstrukte von a1 , C der Ausdruck von a1 und D die<br />

Anweisungssequenz von a1. Man beachte, daß V vor dem ersten rekursiven<br />

Aufruf alle in C und D vorkommenden Variablen enthält mit ihren<br />

Anfangswerte bei der Bearbeitung von C.<br />

Es erfolgen vier rekursive Aufrufe:<br />

a) ComputeSequence(C, V, T1)<br />

b) ComputeSequence(D, V, T2)<br />

c) ComputeSequence(C, V, T3)<br />

d) ComputeSequence(D, V, T4)<br />

Nach Lemma 4.3.2 enthält T1 nach der Ausführung von a) ein<br />

Beispielauswertungsfragment von C und V wird nicht verändert. Demnach<br />

enthält V die Wert der Variablen am Anfang der Auswertung von D.<br />

Nach der Induktionsvoraussetzung (äußere Induktion) enthält T2 nach<br />

Ausführung der Anweisung b) ein Beispielauswertungsfragment von D<br />

und V enthält die Werte der in D vorkommenden Variablen am Ende der<br />

Abarbeitung.<br />

Deswegen kann wieder Lemma 4.3.2 für die Anweisung c) verwendet<br />

werden, wonach T3 ein Beispielauswertungsfragment von C für die<br />

Variablenliste V ist. V wird nicht verändert.<br />

V enthält damit die Werte der Variablen vor der Ausführung von D. Nach<br />

Induktionsvoraussetzung erhält T4 nach der Ausführung des Aufrufs d)<br />

ein Beispielauswertungsfragment von D und V enthält die Werte der<br />

Variablen nach der Bearbeitung von D (*).<br />

Bei der Bildung einer Beispielauswertung muß a1 in vier Stufen verändert<br />

werden:<br />

I. Überführen von a1 zu E(a1) als Teil von E<br />

II. Ersetzen jedes Vorkommen einer Variablen in a1 durch ihren Wert.<br />

III. Löschen jeder Initialisationssequenz in a1.<br />

IV. Löschen aller Schlüsselworte "with" in a1.<br />

Beweis der einzelnen Stufen der Bildung der Beispielauswertung:<br />

I. Überführen von W in eine Entfaltung E''.<br />

Nach obigen Ausführungen werden bei der Bearbeitung von a1 zwei<br />

Beispielauswertungsfragmente T2 und T4 der Anweisungssequenz D von<br />

a1 berechnet. Bei der Berechnung dieser Beispielauswertungen müssen<br />

Entfaltungen E1 und E2 von D zugrunde gelegen haben. Dann ist das<br />

folgende Konstrukt E'' eine Entfaltung von a1:<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

with<br />

K 1 ,...,K t<br />

test C do E 1 end test<br />

test C do E 2 end test<br />

Dann hat jede Beispielauswertung von E’’ die Gestalt:<br />

test C* do E* 1 end test<br />

test C* do E* 2 end test<br />

Dabei seien C*, E*1 und E*2 Beispielauswertungsfragmente. Genau dieses<br />

Konstrukt wird aber bei der Bearbeitung von a1 erzeugt. Demnach wird<br />

bei der Konstruktion der Beispielauswertung von a1 tatsächlich eine<br />

Entfaltung E'' von a1 angewendet.<br />

II. Ersetzen jedes Vorkommen einer Variablen in W durch ihren Wert.<br />

T1,T2,T3,T4 sind Beispielauswertungen, enthalten damit keine Variablen,<br />

dann enthält auch<br />

test T1 do T2 end test<br />

test T3 do T4 end test<br />

keine Variablen. Dieses Konstrukt ist aber gerade b1.<br />

III. Löschen jeder Initialisationssequenz in W.<br />

Es wird an keiner Stelle in der Prozedur ComputeSequence ein<br />

Initialisationskonstrukt in das Beispielauswertungsfragment T eingefügt.<br />

IV. Löschen aller Schlüsselworte "with" in W.<br />

Es wird an keiner Stelle in der Prozedur ComputeSequence das<br />

Schlüsselwort "with" in T eingefügt.<br />

Bei der Bearbeitung von a1 wird das Konstrukt<br />

test T1 do T2 end test<br />

test T3 do T4 end test<br />

am Ende von T angefügt. Es handelt sich dabei tatsächlich um eine<br />

Beispielauswertungsfragment von a1.<br />

Es bleibt zu zeigen, daß V die Endwerte aller Variablen in A nach<br />

Auswertung von a1 enthält:<br />

Nach Voraussetzung enthielt V die Endwerte aller Variablen vor der<br />

Auswertung von a1.<br />

Als erstes stellen wir fest, daß V nur in einem der drei folgenden Fälle<br />

verändert wird:<br />

(1) a1 ist Inkrement,<br />

(2) a1 ist Dekrement,<br />

(3) a1 ist while-Konstrukt.<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

In den Fällen (1) und (2) wird aber nur der Wert einer Variablen<br />

überschrieben, und zwar mit dem korrektem neuen Wert dieser Variablen.<br />

Also enthält V die Werte aller Variablen nach der Ausführung von a1.<br />

Den Fall (3) haben wir bereits mit (*) abgehandelt.<br />

Induktionsvoraussetzung:<br />

Die Behauptung gilt für alle Anweisungen a1,..,ai (1≤i≤s).<br />

Induktionsbehauptung:<br />

Die Behauptung gelte für ai+1.<br />

Induktionsschluß:<br />

ai+1 kann Sonderzeichen, Wort, String, Zahl, Variable, Inkrement,<br />

Dekrement oder ein while-Konstrukt sein. Dabei werden bei der<br />

Erstellung von Beispielauswertungen nur Variablen, Dekremente,<br />

Inkremente und while-Konstrukte verändert.<br />

Falls ai+1 ist Sonderzeichen, Wort, String oder Zahl, dann ist bi+1 = ai+1.<br />

Sei ai+1 jetzt eine Variable v (eventuell in einem Inkrement oder<br />

Dekrement).<br />

Wiederum sei E eine Entfaltung von P. Falls ai+1 Hauptvariable, setze E'<br />

:= E. Ansonsten sei W dasjenige while-Konstrukt von P, dessen lokale<br />

Variable v ist und E' ist die Entfaltung von W in E.<br />

Es sei für ein j ai+1 das j-te Auftreten von v in E'. Es ist zu zeigen, daß bi+1<br />

= val(v,j,E').<br />

Hilfsbehauptung:<br />

Beweis:<br />

Nach dem i-tem Schleifendurchlauf enthält V den Wert<br />

val(v,j-1,E') als Endwert für die Variable v.<br />

Nach Induktionsvoraussetzung enthält V den Wert die<br />

aktuellen Werte aller Variablen des Programmes.<br />

Dann enthält V den Wert der Variablen v bei deren<br />

letzem Auftreten, also val(v,j-1,E'). (Hilfsbehauptung)<br />

Diese Hilfsbehauptung ermöglicht uns die folgenden Aussagen:<br />

1. Fall: ai+1 ist Variable v (außerhalb eines Inkrementes oder<br />

Dekrementes),<br />

dann ist bi+1 = val (v,j-1,E') = val(v,j,E').<br />

2. Fall: ai+1 ist Inkrement ++v,<br />

dann ist bi+1 = val(v,j-1,E')+1 = val(v,j,E').<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

3. Fall: ai+1 ist Dekrement --v,<br />

⎧val(v, j - 1, E’ ) - 1, wenn val(v, j - 1, E’ ) > 0<br />

dann gilt bi+1 = ⎨<br />

⎩0 sonst<br />

= val(v,j,E’)<br />

In jedem dieser Fälle enthält V nach dem (i+1)-ten Schleifendurchlauf den<br />

Wert val(v,j,E') der Variablen v.<br />

Sei ai+1 jetzt ein while-Konstrukt der Form "with K 1 ,...,K t while C<br />

do D end while", wobei für ein t K1,...,Kt die lokalen<br />

Initialisationskonstrukte von ai , C der Ausdruck von a1 und D die<br />

Anweisungssequenz von ai+1.<br />

Es erfolgen vier rekursive Aufrufe:<br />

a) ComputeSequence(C, V, T1)<br />

b) ComputeSequence(D, V, T2)<br />

c) ComputeSequence(C, V, T3)<br />

d) ComputeSequence(D, V, T4)<br />

Nach der Induktionsbehauptung der inneren Induktion beinhaltet V die<br />

Werte aller Variablen des Programmes vor der Auswertung von ai+1, somit<br />

auch vor der ersten Ausführung von C. Dann kann Lemma 4.3.2<br />

angewandt werden. und T1 enthält nach der Ausführung von a) ein<br />

Beispielauswertungsfragment von C und V wird nicht verändert. Demnach<br />

enthält V die Wert der Variablen am Anfang der Auswertung von D.<br />

Nach der Induktionsvoraussetzung der äußeren Induktion enthält T2 nach<br />

Ausführung der Anweisung b) ein Beispielauswertungsfragment von D<br />

und V enthält die Werte der in D vorkommenden Variablen am Ende der<br />

Abarbeitung. Damit enthält V auch die Werte der Variablen vor der<br />

zweiten Ausführung von C.<br />

Deswegen kann wieder Lemma 4.3.2 für die Anweisung c) verwendet<br />

werden, wonach T3 ein Beispielauswertungsfragment von C für die<br />

Variablenliste V ist. V wird dabei nicht verändert.<br />

V enthält damit die Werte der Variablen vor der Ausführung von D. Nach<br />

Induktionsvoraussetzung erhält T4 nach der Ausführung des Aufrufs d)<br />

ein Beispielauswertungsfragment von D und V enthält die Werte der<br />

Variablen nach der Bearbeitung von D (*).<br />

Bei der Bildung einer Beispielauswertung muß ai+1 in vier Stufen<br />

verändert werden:<br />

I. Überführen von ai+1 zu E(ai+1) als Teil von E<br />

II. Ersetzen jedes Vorkommen einer Variablen in ai+1 durch ihren Wert.<br />

III. Löschen jeder Initialisationssequenz in ai+1.<br />

IV. Löschen aller Schlüsselworte "with" in ai+1.<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Der Beweis, daß bi+1 diesen vier Schritte genügt, ist vollkommen analog zu<br />

dem Beweis in der Induktionsverankerung der inneren Induktion.<br />

Demnach ist beweisen, daß bi+1 ein Beispielauswertungsfragment von ai+1<br />

ist.<br />

Wir müssen nun zeigen, daß V die Werte aller Variablen des Programmes<br />

nach der Ausführung von ai+1 enthält. V wird in der Prozedur nur bei der<br />

Abarbeitung eines Inkrementes, eines Dekrementes und eines while-<br />

Konstruktes verändert.<br />

Im Falle eines Inkrementes oder Dekrementes wird jeweils nur der<br />

Endwert einer Variablen verändert. Dieser wird aber auf den neuen Wert<br />

der Variablen gesetzt. Alle anderen Variablen in V werden nicht<br />

verändert. Also enthält die Werte aller Variablen nach der Ausführung<br />

von ai+1.<br />

Für den Fall, daß ai+1 ein while-Konstrukt ist, ist die Behauptung durch (*)<br />

bewiesen.<br />

Nach Induktion folgt die Behauptung: Für alle i (1≤i≤s) ist b1....bi ein<br />

Beispielauswertungsfragment von a1...ai. Damit ist für i = s Schritt 2<br />

bewiesen: T ist Beispielauswertungsfragment für A.<br />

3. V enthält alle in A auftretenden Variablen (ohne lokale Variablen<br />

enthaltener while-Konstrukte) und ihre Werte am Ende der Ausführung von<br />

A.<br />

Mit der inneren Induktion in Schritt 2 haben wir bewiesen, daß für alle i<br />

(1≤i≤s) V nach dem i-ten Schritt die Werte der Variablen nach der<br />

Auswertung von ai enthält. Damit folgt die Behauptung 3 für den Fall i = s.<br />

Damit ist auch die äußere Induktion abgeschlossen und das Lemma bewiesen.<br />

Bemerkung:<br />

Für die Berechnung der Beispielauswertungsfragmente der Anweisungssequenzen eines<br />

Programmes P muß die Entfaltung E = E(P) nicht im voraus bekannt sein, da zur Ermittlung<br />

der Variablenwerte das Führen von Variablenlisten ausreichend ist.<br />

6DW]<br />

6HL3HLQEHOLHELJHV3URJUDPPXQG1HLQHEHOLHELJHJHRUGQHWH0HQJH<br />

QDW UOLFKHU=DKOHQPLW_1_ _(93_'DQQEHUHFKQHWGHU$OJRULWKPXV<br />

&RPSXWH3URJUDPÃEHL(LQJDEHYRQ3XQG1HLQH%HLVSLHODXVZHUWXQJ6YRQ3<br />

Beweis:<br />

Sei P ="input (x 1 ,...,x m ) A output y", wobei x1,...,xm,y Variablen und A<br />

eine Anweisungssequenz ist.<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Hilfsbehauptung:<br />

Die Variablenliste V enthält beim Aufruf von ComputeSequence alle Variablen<br />

von A, die nicht lokale Variable eines while-Konstruktes sind, mit ihrem letzten<br />

Wert vor der ersten Anweisung von A.<br />

Beweis:<br />

Die Variablen in A, die nicht lokale Variable eines while-Konstruktes sind, sind<br />

die Hauptvariablen von P. Sei v eine solche Hauptvariable.<br />

1. Fall: v ist Eingabevariable. Dann muß v im Eingabekonstrukt vorkommen<br />

und der Anfangswert von v ergibt sich unabhängig von E(P) aus N, und zwar ist<br />

dies der i-te Eintrag in N, wenn v die i-te Variable im Eingabekonstrukt ist<br />

(1≤i≤|EV(P)|) Dieser Wert wird aber zusammen mit v in V eingetragen. Da der<br />

Wert von v sich nicht im globalen Initialisationskonstrukt verändert werden<br />

kann, ist dieser Wert der letzte Wert von v vor der ersten Anweisung von A.<br />

2. Fall: v ist globale Variable. Dann muß v in der globalen<br />

Initialisationssequenz vorkommen. Sei K das Initialisationskonstrukt von v. K<br />

habe die Gestalt "set (v := µ)".<br />

1. Unterfall: µ ist sie Zahl c. Dann ist c der Anfangswert von v für jede<br />

Entfaltung E(P) und wird zusammen mit v in V eingetragen. v kann ihren Wert<br />

in der globalen Initialisationssequenz nicht mehr ändern. Also ist c der Wert<br />

von v vor der ersten Anweisung von A.<br />

2. Unterfall: µ ist die Variable w. w kann keine globale Variable sein, da globale<br />

Variablen nur einmal in der globalen Initialisationssequenz vorkommen dürfen,<br />

nämlich auf der rechten Seite ihres Initialisationskonstruktes. Also kann w nur<br />

eine Eingabevariable sein. Deren Wert steht aber in V. Dann wird auch v mit<br />

ihrem korrekten Anfangswert in V eingetragen. Da dieser sich nicht in der<br />

globalen Initialisationssequenz ändern kann, enthält V auch in diesem Fall den<br />

Wert von v vor der ersten Anweisung von A. (Hilfsbehauptung)<br />

Nach der Hilfsbehauptung kann Lemma 4.3.3 angewendet werden. Danach gilt<br />

für den Aufruf ComputeSequence (A,V,T), daß<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

2. T ist ein Beispielauswertungsfragment von A.<br />

3. V enthält alle in A auftretenden Variablen (ohne lokale Variablen<br />

enthaltener while-Konstrukte) und ihre Werte am Ende der Ausführung von<br />

A.<br />

Wegen 3. muß auch der letzte Wert c der Variablen y in V enthalten sein. Sei N<br />

= {n1,...,nm}. Damit ist "input (n 1 ,...,n m ) T output c" eine<br />

Beispielauswertung für P.<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

4.4 Komplexität<br />

/HPPD<br />

6HL9HLQH9DULDEOHQOLVWHGHU/lQJHP'DQQEHWUlJWGHUK|FKVWH6FKULWW]DKO<br />

I U<br />

ì GDV(LQI JHQHLQHU9DULDEOHQDP(QGHGHU/LVWH<br />

ì GDV/HVHQHLQHU9DULDEOHQ<br />

ì GDVbQGHUQGHV:HUWHVHLQHU9DULDEOHQ<br />

ì GDV6XFKHQHLQHU9DULDEOHQLQGHU/LVWH<br />

ì GDV/|VFKHQGHU9DULDEOHQOLVWH<br />

MHZHLOV2P<br />

Beweis:<br />

Da eine Variablenliste als lineare Liste implementiert werden kann, folgt die<br />

Behauptung aus den entsprechenden Abschätzungen für die lineare Liste.<br />

/HPPD<br />

6HL3HLQ3URJUDPP6HL$HLQH$QZHLVXQJVVHTXHQ]LQ3XQG9HLQH<br />

9DULDEOHQOLVWHGLHDOOH9DULDEOHQLQ$PLWLKUHP:HUWYRUGHUHUVWHQ<br />

$QZHLVXQJYRQ$HQWKlOWI UHLQH(QWIDOWXQJ(36HLQGLH=DKOGHU<br />

$QZHLVXQJHQYRQ$HLQVFKOLH‰OLFKGHU$QZHLVXQJHQLQGHQ$XVGU FNHQXQG<br />

$QZHLVXQJVVHTXHQ]HQLQ$HQWKDOWHQHUZKLOH.RQVWUXNWHXQGPGLH<br />

*HVDPW]DKOYRQ9DULDEOHQLQ3HLQVFKOLH‰OLFKORNDOHU9DULDEOHQLQ$<br />

HQWKDOWHQHUZKLOH.RQVWUXNWH'DQQWHUPLQLHUWGLH3UR]HGXU<br />

&RPSXWH6HTXHQFHEHLGHP$XIUXI&RPSXWH6HTXHQFH$97QDFKK|FKVWHQV<br />

2PòQ6FKULWWHQ<br />

Beweis:<br />

Sei A = "", so terminiert die Prozedur in konstanter Zeit.<br />

Sei A ≠ "".<br />

Nach Lemma 4.3.1 terminiert die solange-Schleife in s Schleifendurchläufen in<br />

ComputeSequence und die Variable a nimmt nacheinander die Werte a1,...,as an.<br />

(vollständige Induktion über D(A))<br />

Induktionsverankerung:<br />

Für D(A) = 0 erfolgt kein rekursiver Aufruf der Prozedur ComputeSequence.<br />

Demnach ist n = s. Für die Bearbeitung von Variablen, Inkrementen und<br />

Dekrementen ist nach Lemma 4.4.1 eine Komplexität O(m) anzusetzen,<br />

während alle anderen Aktionen in einem Schleifendurchlauf nur konstanten<br />

Zeitbedarf besitzen.<br />

Induktionsvoraussetzung:<br />

Es sei d > 0 und d' < d. Für D(A') = d' terminiere der Aufruf der Prozedur<br />

ComputeSequence nach höchstens O(m'²n') Schritten, wobei A' eine<br />

Anweisungssequenz, n' die Zahl der Anweisungen von A' und m die Zahl der<br />

Variablen von A' ist.<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Induktionsbehauptung:<br />

Für D(A) = d terminiere der Aufruf der Prozedur ComputeSequence nach<br />

höchstens O(m²n) Schritten.<br />

Induktionsschluß:<br />

Seien W1,...,Wk für ein k∈© die lokalen while-Konstrukte von A und sei p die<br />

Zahl der Variablen in A, die innerhalb von A vorkommen, aber nicht lokale<br />

Variable eines in A enthaltenen while-Konstruktes sind. Sei für i∈{1,..,k} ni<br />

die Zahl der Anweisungen von Wi und mi die Zahl der lokalen Variablen von<br />

Wi.<br />

k<br />

Dann gilt m = p + ∑ m und n = s + n i<br />

∑ i .<br />

i=1<br />

Wir wollen jetzt den Zeitbedarf für einen Schleifendurchlauf in Abhängigkeit<br />

von der Art der im Schleifendurchlauf gelesenen Anweisung angeben.<br />

Sei für ein i∈{1,..,s} ai eine Anweisung:<br />

Sei ai eine Zahl, eine Wort, eine Zeichenkette oder ein Trennzeichen, so<br />

erfolgt der Schleifendurchlauf in konstanter Zeit.<br />

Sei ai eine Variable, eine Inkrement oder ein Dekrement, so ist ein<br />

maximaler Zeitbedarf O(p) notwendig, da Zugriffe auf die Variablenliste<br />

notwendig sind.<br />

Sei ai eine while-Konstrukt, etwa Wj, für ein j∈{1,..,k},so rührt der Zeitbedarf<br />

für den Schleifendurchlauf vor allem aus drei Aktionen:<br />

Das Eintragen der lokalen Variablen in V, den vierfachen rekursiven Aufruf<br />

und das Löschen der lokalen Variablen aus V.<br />

Das Eintragen der lokalen Variablen in die Variablenliste V benötigt eine<br />

maximale Komplexität O(p+mj)², da während des Einfügens der Variablen in<br />

der Liste gesucht werden müssen.<br />

Sei C der Ausdruck von Wj und D die Anweisungssequenz von Wj. Da D(C) =<br />

1 und D(D) < d folgt nach Induktionsvoraussetzung für die rekursiven<br />

Aufrufe ein maximaler Zeitbedarf O((p+mi)²ni).<br />

Das Entfernen der lokalen Variablen aus V kann mit einem Aufwand von<br />

O(p) geschehen.<br />

k<br />

i=1<br />

Dann läßt sich der maximale Zeitbedarf für die Prozedur abschätzen durch:<br />

k<br />

∑<br />

O((s - k)p) + (O(p + m ) + O((p + m ) n ) + O(p))<br />

i=1<br />

i<br />

2<br />

Wir können sehen, daß wir innerhalb der Summe nur den Term O((p+mi)²ni<br />

beibehalten müssen.<br />

Umformung ergibt:<br />

k<br />

∑<br />

O((s - k)p) + O((p + m ) n )<br />

i=1<br />

i<br />

2<br />

i<br />

i<br />

2<br />

i<br />

6HLWH


$XWRPDWLVFKH*HQHULHUXQJYRQ%HLVSLHODXVZHUWXQJHQ<br />

Es gilt nun sicherlich<br />

k<br />

∑<br />

O((s - k)p) + O((p + m ) n ) ≤ O(sp) + O((p + m ) (s + n ))<br />

i=1<br />

i<br />

2<br />

i<br />

und hieraus folgt für den maximalen Zeitbedarf h der Prozedur:<br />

h = O(sp) + O(m²n) = O(m²n).<br />

6DW]<br />

6HL3HLQ3URJUDPPXQG1HLQH(LQJDEHPHQJHPLW_1_ _(93_6HLQGLH<br />

=DKOGHU$QZHLVXQJHQYRQ3HLQVFKOLH‰OLFKGHU$QZHLVXQJHQLQGHQ<br />

$XVGU FNHQXQG$QZHLVXQJVVHTXHQ]HQLQ3HQWKDOWHQHUZKLOH.RQVWUXNWH<br />

XQGPGLH*HVDPW]DKOYRQ9DULDEOHQLQ3HLQVFKOLH‰OLFKORNDOHU9DULDEOHQLQ<br />

3HQWKDOWHQHUZKLOH.RQVWUXNWH'DQQWHUPLQLHUWGHU$OJRULWKPXV<br />

&RPSXWH3URJUDPQDFKK|FKVWHQV2PòQ6FKULWWHQ<br />

Beweis:<br />

Sei p die Zahl der Hauptvariablen von P. Nach Lemma 4.4.1 ist der Zeitbedarf<br />

für den Zugriff auf eine Variablenliste durch O(q) beschränkt, wobei q die Länge<br />

der Variablenliste ist. Der Zeitbedarf für das Eintragen der Eingabevariablen<br />

beträgt höchstens O(p), während der Zeitbedarf für das Eintragen der globalen<br />

Variablen durch O(p²) abgeschätzt werden darf. Nach dem Beweis von Satz<br />

4.3.1 wissen wir, daß in der Variablenliste V die Hauptvariablen mit ihrem<br />

Wert vor der ersten Anweisung von P eingetragen sind. Nach Lemma 4.4.2<br />

terminiert der Aufruf der Prozedur ComputeSequence nach höchstens O(m²n)<br />

Schritten. Für das Finden des Wertes der Ausgabevariablen ist nur ein<br />

Zeitbedarf von maximal O(p) notwendig. Wir sehen also, daß in dem<br />

Algorithmus das Zeitverhalten durch den Prozeduraufruf bestimmt wird. Auch<br />

das vorherige Parsen des Programmes fällt nicht ins Gewicht. Deswegen gilt<br />

auch für den Algorithmus ein maximaler Zeitbedarf O(m²n).<br />

k<br />

∑<br />

i=1<br />

i<br />

2<br />

k<br />

∑<br />

i=1<br />

i<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

5 Automatische Synthese von Klasse-I-Programmen<br />

In diesem Kapitel wird ein Algorithmus zur automatischen Synthese von WHILE-<br />

Programmen aus Beispielauswertungen angegeben und seine Korrektheit bewiesen. Dabei<br />

schränken wir unsere Klasse der zu synthetisierenden Algorithmen ein auf die Klasse-I-<br />

Programme, für die sowohl die Synthese als auch der Korrektheitsbeweis einfach zu<br />

bewerkstelligen sind. Für diese Klasse erhalten wir bemerkenswerte Resultate:<br />

ì<br />

ì<br />

Bei Eingabe einer Beispielauswertung eines Programmes P liefert der Synthesealgorithmus<br />

ein Programm Q, das sich von P nur in den Namen der Variablen und der Reihenfolge der<br />

Initialisierungen unterscheidet.<br />

Die Laufzeit des Synthesealgorithmus ist linear zur Größe der Eingabe.<br />

5.1 Idee<br />

Bei der (automatischen und manuellen) Generierung von Beispielauswertungen werden im<br />

wesentlichen zwei Operationen vorgenommen:<br />

1. Die Ersetzung von Variablen, Inkrementen und Dekrementen durch Zahlen.<br />

2. Die Ersetzung von while-Konstrukten durch Entfaltungen.<br />

Wir haben bereits bei der automatischen Generierung von Beispielauswertungen die<br />

Bedeutung von Variablenlisten kennengelernt. Dabei wurden sie benutzt, um den Wert einer<br />

Variablen ohne genaue Kenntnis der Entfaltungen zu bestimmen. Dabei war der letzte Wert<br />

der Variablen in der Variablenliste gespeichert. Da der Name der Variablen, deren Wert zu<br />

bestimmen war, bekannt ist, kann der gesuchte Wert durch einen lesenden Zugriff auf die<br />

Variablenliste bestimmt werden. In Umkehrung dieses Verfahren wollen wir jetzt aus der<br />

Kenntnis einer Variablenliste und dem aktuellen Wert einer Variablen an einer Position den<br />

Namen einer Variablen bestimmen. Es ist sofort einsichtig, daß diese Aufgabe im allgemeinen<br />

nicht eindeutig lösbar ist. Wir müssen deswegen die Klasse der Programme beschränken auf<br />

eine Teilklasse, bei denen die Aufgabe eindeutig lösbar ist.<br />

Jedes while-Konstrukt wird bei der Entfaltung in eine Folge von mindestens zwei Konstrukten<br />

der Form "test ... do ... end test" (im folgenden test-Konstrukt genannt)<br />

umgewandelt. Wir können deswegen aus dem Vorkommen zweier dieser Konstrukte<br />

hintereinander auf ein while-Konstrukt schließen. Sich anschließende test-Konstrukte können<br />

als Teil der Entfaltung des while-Konstruktes interpretiert werden oder als Beginn einer<br />

Entfaltung eines anderen while-Konstruktes. Auch hierbei sind Einschränkungen in der Klasse<br />

der lernbaren Programme notwendig.<br />

Wir können wieder unsere Variablenliste verwenden, die wir allerdings um eine Komponente<br />

'neues-lexem' erweitern müssen. Neben den Methoden zur Manipulation des Anfangswertes<br />

und des Endwertes benötigen wird eine Methode zur Generierung neuer Variablen. Eine solche<br />

Variable muß aber verschieden sein von allen anderen Variablen des bereits generierten<br />

Programmfragmentes. Eine Möglichkeit dies zu bewerkstelligen besteht darin, jede neue<br />

Variable zu indizieren, wobei der Index bei jeder Generierung um eins erhöht wird.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

5.2 Klasse-I-Programme<br />

'HILQLWLRQ<br />

(LQ:+,/(3URJUDPP3KHL‰W.ODVVH,3URJUDPPZHQQIROJHQGH<br />

%HGLQJXQJHQHUI OOWVLQG<br />

(VG UIHQNHLQH]ZHLZKLOH.RQVWUXNWHGLUHNWDXIHLQDQGHUIROJHQ<br />

(VNRPPHQNHLQHORNDOHQ9DULDEOHQYRU<br />

'DVHUVWH9RUNRPPHQHLQHU9DULDEOHQLQGHU+DXSWDQZHLVXQJVVHTXHQ]<br />

YRQ3GDUIQLFKWLQQHUKDOEHLQHV,QNUHPHQWHVRGHU'HNUHPHQWHVVHLQ<br />

'DVHUVWH9RUNRPPHQHLQHU9DULDEOHQLQHLQHPZKLOH.RQVWUXNWGDUI<br />

QLFKWLQQHUKDOEHLQHV,QNUHPHQWHVRGHU'HNUHPHQWHVVHLQ<br />

) UMH]ZHL9DULDEOHQLQHLQHPZKLOH.RQVWUXNWPX‰GLH'LIIHUHQ]<br />

]ZLVFKHQLKUHQ:HUWHLQGHUHUVWHQ(QWIDOWXQJLQGHU]ZHLWHQ(QWIDOWXQJ<br />

YHUVFKLHGHQVHLQ<br />

'HILQLWLRQ<br />

(LQH%HLVSLHODXVZHUWXQJHLQHV.ODVVH,3URJUDPPHVKHL‰W.ODVVH,<br />

%HLVSLHODXVZHUWXQJZHQQIROJHQGH%HGLQJXQJHQHUI OOWVLQG<br />

'LH9DULDEOHLQHLQHP'HNUHPHQWGDUILQGHU$QZHLVXQJYRUGHP<br />

'HNUHPHQWQLFKWGHQ:HUWKDEHQ<br />

,QMHGHU$QZHLVXQJDX‰HUKDOEHLQHVZKLOH.RQVWUXNWHVPX‰GLH'LIIHUHQ]<br />

GHU:HUWH]ZHLHU9DULDEOHQPLQGHVWHQVEHWUDJHQ<br />

5.3 Algorithmus<br />

Wir schränken die Klasse der zulässigen Beispielauswertungen auf Klasse-I-<br />

Beispielauswertungen ein. Wir gehen davon aus, daß die Eingabe in einer geparsten und von<br />

Trennzeichen und Kommentaren bereinigter Form vorliegt. Auch die Ausgabe wird in dieser<br />

Form vorliegen.<br />

Algorithmus SampleProgram(S,P)<br />

Eingabe: S : Klasse-I-Beispielauswertung<br />

Ausgabe: P : Programm<br />

Funktion:<br />

Der Algorithmus berechnet ein Programm P aus S<br />

Variablen: V : Variablenliste<br />

A : Anweisungssequenz<br />

i,j : natürliche Zahlen (Zählvariablen)<br />

S habe die Form "input(c 1 ,...,c m ) T output d". Dabei sind m,c 1 ,...,c m ,d<br />

natürliche Zahlen und T ein Beispielauswertungsfragment.<br />

// lösche die Variablenliste und generiere die Eingabevariablen<br />

Lösche V<br />

für i = 1 bis m tue<br />

Generiere neue Variable v i<br />

Trage Variable v i mit Anfangs- und Endwert c i in V ein.<br />

ende für<br />

// Ermittle Anweisungssequenz A aus Beispielauswertungsfragment T und<br />

// bestimme globale Variablen in der Variablenliste V<br />

Rufe SampleSequence (T,V,A) auf.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

// Konstruiere globale Initialisationssequenz<br />

für i = m+1 bis Länge(V) tue<br />

Sei v i die i-te Variable in V und c i ihr Anfangswert.<br />

für j = 1 bis m tue<br />

Sei v j die j-te Variable in V und c j ihr Anfangswert<br />

wenn c j = c i dann Setze K i := "set (v i := v j )".<br />

verlasse für<br />

Abbildung 5 : Struktur des Algorithmus’ SampleProgram<br />

Prozeduraufruf<br />

Rekursion<br />

sampleProgram(S,P)<br />

sampleSequence(T,V,A)<br />

sampleWHILE<br />

(C,D,C’,D’,V,G,H)<br />

testWHILE(B,C,G,H,V,result)<br />

sampleWExpression<br />

(C,C’,V,X,G)<br />

testWExpression<br />

(B,G,V,result)<br />

sampleWStatementSequence<br />

(C,H,V,result)<br />

testWStatementSequence<br />

(C,H,V,result)<br />

matchWHILE<br />

(M,M’,N,N’,V,Y,X,result)<br />

ende für<br />

Wenn K i nicht gesetzt, setze K i := "set (v i := c i )".<br />

ende für<br />

// Bestimme Ausgabevariable<br />

Suche erste Variable y in V mit Endwert d.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

wenn gefunden, dann ist<br />

P = "input(v 1 ,...,v m ) K m+1 ... K Länge(V) A output y",<br />

sonst beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

Ende Algorithmus sampleProgram<br />

Prozedur sampleSequence(T,V,A)<br />

Eingabe: T : Beispielauswertungsfragment<br />

Ein-/Ausgabe:<br />

V : Variablenliste<br />

Ausgaben: A : Anweisungssequenz<br />

Funktion:<br />

A ist eine Anweisungssequenz zu T und V enthält alle Hauptvariablen<br />

am Ende von T mit ihren Anfangs- und Endwerten<br />

Variablen: t : Auswertung einer Anweisung<br />

// A ist am Anfang leer<br />

A := ""<br />

// Lese T sequentiell<br />

wenn T≠"" tue<br />

Setze Lesezeiger vor das ersten Element in T<br />

solange T noch nicht vollständig gelesen tue (d.h. solange der Lesezeiger steht<br />

nicht hinter dem letzten Element in T)<br />

t := lese nächstes Element in T.<br />

Stelle Lesezeiger einen Eintrag vor.<br />

unterscheide<br />

falls t ist String, Wort oder Sonderzeichen:<br />

füge t am Ende von A an.<br />

falls t ist Zahl:<br />

Suche erste Variable v in V mit Endwert t.<br />

wenn gefunden, dann<br />

füge v am Ende von A an.<br />

sonst<br />

Suche erste Variable v in V mit Endwert t - 1.<br />

wenn gefunden, dann<br />

füge ++v am Ende von A an.<br />

Setze Endwert von v in V auf t.<br />

sonst<br />

Suche erste Variable v in V mit Endwert t + 1.<br />

wenn gefunden, dann<br />

füge --v am Ende von A an.<br />

Setze Endwert von v in V auf t.<br />

sonst<br />

Sei v neue Variable. Füge v am Ende von A an. Trage v in V<br />

ein mit Anfangs- und Endwert t.<br />

ende wenn<br />

ende wenn<br />

ende wenn<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

falls t ist test-Konstrukt der Form "test C do D end test", wobei C<br />

und D Beispielauswertungsfragmente:<br />

wenn Lesezeiger steht nicht hinter dem letzten Element von T und<br />

wenn das nächste Element von T ist test-Konstrukt der Form "test C’<br />

do D’ end test", wobei C' und D' Beispielauswertungsfragmente,<br />

dann<br />

Variablen: u,u' : Auswertung einer Anweisung<br />

result : logischer Wert<br />

G : Ausdruck<br />

H : Anweisungssequenz<br />

u := Lese nächstes Element in T.<br />

Setze Lesemarke ein Element vor.<br />

// Generiere while-Konstrukt aus t und u<br />

Rufe SampleWHILE(C,D,C’,D’,V,G,H) auf, wobei G ein Ausdruck<br />

und H eine Anweisungssequenz ist.<br />

// Füge while-Konstrukt am Ende von A an<br />

Füge "with while G do H end while"<br />

// folgen weitere Entfaltungen des while-Konstruktes?<br />

solange Lesezeiger steht nicht hinter dem letzten Element von T<br />

und solange das nächste Element von T ist test-Konstrukt der<br />

Form "test C’’ do D’’ end test", wobei C'' und D''<br />

Beispielauswertungsfragmente, tue<br />

u' := Lese nächstes Element in T.<br />

Setze Lesemarke ein Element vor.<br />

// Test durchführen<br />

Rufe TestWHILE(C’’,D’’,G,H,V,result) auf.<br />

wenn result = FALSCH, dann<br />

beende Algorithmus mit Fehlermeldung.<br />

ende wenn<br />

ende solange<br />

wenn Lesezeiger steht nicht hinter dem letzten Element von T und<br />

wenn das nächste Element von T ist test-Konstrukt der Form<br />

"test C’’ skip’", wobei C'' ein Beispielauswertungsfragment<br />

ist, dann<br />

u' := Lese nächstes Element in T.<br />

Setze Lesemarke ein Element vor.<br />

Rufe TestWExpression(C’’,G,V,result) auf.<br />

wenn result = FALSCH, dann<br />

beende Algorithmus mit Fehlermeldung.<br />

ende wenn<br />

ende wenn<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

sonst<br />

// test-Konstrukt am Ende der Anweisungssequenz<br />

beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

andernfalls<br />

// es kann kein weiterer Fall auftreten<br />

beende Algorithmus mit Fehlermeldung<br />

ende unterscheide<br />

ende solange<br />

ende wenn<br />

Ende Prozedur sampleSequence<br />

Prozedur SampleWHILE(C,D,C’,D’,V,G,H)<br />

Eingabe: C,C’,D,D’ : Beispielauswertungsfragmente<br />

Ein-/Ausgabe: V : Variablenliste<br />

Ausgaben: G : Ausdruck<br />

H : Anweisungssequenz<br />

Funktion:<br />

werden<br />

am<br />

Variablen:<br />

G und H sind Ausdruck und Anweisungssequenz<br />

eines while-Konstruktes,<br />

dessen Beispielauswertungsfragment die Folge<br />

test C do D end test<br />

test C’ do D’ end test<br />

ist.<br />

V enthält alle Variablen des Programmes mit ihren Endwerten<br />

am Ende der Auswertung von D'. Neu eingeführte Variablen<br />

in V mit ihrem Anfangswert zu Beginn von C und ihrem Endwert<br />

Ende von D' eingetragen.<br />

X : Variablenliste<br />

// die Variablenliste X dient zur Aufnahme aller in der<br />

// Beispielauswertung verwendeten Variablen<br />

// X ist am Anfang leer<br />

Lösche X.<br />

// Generierung von G. In die Variablenliste V werden nur noch nicht<br />

// vorher verwendete Variablen neu eingetragen, die bisherigen Inhalte werden<br />

// nicht verändert. Jede in G benutzte Variable wird in V aufgenommen mit<br />

// Anfangs- und Endwert gleich dem Wert in der Auswertung C'.<br />

Rufe SampleWExpression(C,C',V,X,G) auf.<br />

// Generierung von H. Neue Variablen werden in V mit ihrem Anfangswert<br />

// in C aufgenommen.<br />

// Die Endwerte der Variablen in V entsprechen den Werten am Ende der<br />

// Auswertung C. Jede in G und H vorkommende Variable steht in X mit Anfangs-<br />

// und Endwert in C'.<br />

Rufe SampleWStatementSequence(D,D',V,X,H) auf.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

// Der Anfangswert jeder Variablen in X muß dem Endwert der<br />

// Variablen in V entsprechen<br />

für jedes v in X tue<br />

Sei a der Anfangswert von v in X.<br />

Sei e der Endwert von v in V.<br />

Wenn e ≠ a, dann<br />

beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

ende für<br />

// Trage die Endwerte der Variablen in X als Endwerte der Variablen in V ein.<br />

für jedes v in X tue<br />

Sei c der Endwert von v in X.<br />

Setze Endwert von v in V auf c.<br />

ende für<br />

Ende Prozedur SampleWHILE<br />

Prozedur SampleWExpression(C,C’,V,X,G)<br />

Eingabe: C,C’ : Beispielauswertungsfragmente<br />

Ein-/Ausgaben: X,V : Variablenliste<br />

Ausgabe: G : Ausdruck<br />

Funktion:<br />

Variablen:<br />

G ist Ausdruck eines while-Konstruktes, dessen<br />

Beispielauswertungsfragmente in der ersten und zweiten Entfaltung<br />

C und C’ sind. Wird eine Variable in G verwendet, die in V noch nicht<br />

vorkommt, so wird sie in V eingetragen mit dem Anfangswert des<br />

ersten Vorkommens in der Auswertung C. Jede in G verwendete<br />

Variable wird in X eingetragen mit Anfangs- und Endwert aus C’.<br />

t,u : Entfaltungen von Anweisungen<br />

// G ist am Anfang leer<br />

G := "".<br />

// Lese C und C’ parallel<br />

wenn C≠"" und wenn C’≠"" dann<br />

Setze Lesezeiger L vor das erste Element in C. Setze Lesezeiger L’ vor das<br />

erste Element in C’.<br />

solange weder C noch C' vollständig gelesen tue (d.h. weder L steht hinter dem<br />

letzen Element in C noch L' steht hinter dem letzten Element in C')<br />

t := lese nächstes Element in C<br />

u := lese nächstes Element in C'<br />

Stelle L einen Eintrag vor. Stelle L' einen Eintrag vor.<br />

unterscheide<br />

falls t ist String, Wort oder Sonderzeichen:<br />

wenn t = u, dann füge t am Ende von G an.<br />

sonst beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

falls t ist Zahl c:<br />

wenn u ist Zahl, etwa c'. dann<br />

Suche erste Variable v in V und X mit Endwerte c und c'.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

wenn gefunden, dann<br />

// wiederholtes Vorkommen einer Variablen<br />

Füge v am Ende von G an.<br />

sonst<br />

Suche erste Variable v in V mit Endwert c.<br />

wenn gefunden, dann<br />

// erstes Vorkommen einer bereits bekannten Variablen in<br />

// G.<br />

Trage v in X ein mit Anfangs- und Endwert c'.<br />

Füge v am Ende von G an.<br />

ende wenn<br />

sonst<br />

// vorkommende Variable ist nicht in V enthalten<br />

Sei x eine neue Variable.<br />

Trage x mit Anfangs- und Endwert c in V ein.<br />

Trage x mit Anfangs- und Endwert c' in X ein.<br />

Füge x am Ende von G an.<br />

ende wenn<br />

ende wenn<br />

sonst<br />

// t ist Zahl, aber nicht u<br />

beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

andernfalls<br />

beende Algorithmus mit Fehlermeldung<br />

ende unterscheide<br />

ende solange<br />

wenn entweder C oder C' nicht vollständig gelesen, dann<br />

beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

ende wenn<br />

Ende Prozedur SampleWExpression<br />

Prozedur SampleWStatementSequence(D,D’,V,X,H)<br />

Eingabe: D,D' : Beispielauswertungsfragmente<br />

Ein-/Ausgabe:V,X : Variablenlisten<br />

Ausgabe: H : Anweisungssequenz<br />

Funktion:<br />

Variablen:<br />

H ist Anweisungssequenz eines while-Konstruktes, deren<br />

Beispielauswertungsfragmente in der ersten und zweiten Entfaltung<br />

D und D' sind.<br />

Noch nicht bisher in V vorkommende Variablen werden mit ihrem<br />

Anfangswert am zur Beginn der Auswertung D eingetragen. Für jede<br />

in H vorkommende Variable enthält V als Endwert den letzten Wert<br />

in D. Jede bisher noch nicht in X vorkommende Variable wird mit<br />

ihrem Anfangswert zu Beginn von D' in X eingetragen. Als Endwert<br />

jeder in H verwendete Variablen wird der letzte Wert von D' in X<br />

eingetragen.<br />

t,u : Entfaltungen von Anweisungen<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

// H ist am Anfang leer<br />

H := "".<br />

// Lese D und D’ parallel<br />

wenn D≠"" und wenn D’≠"" dann<br />

Setze Lesezeiger L vor das erste Element in D.<br />

Setze Lesezeiger L’ vor das erste Element in D’.<br />

solange weder D noch D' vollständig gelesen tue (d.h. weder L steht hinter dem<br />

letzen Element in D noch L' steht hinter dem letzten Element in D')<br />

t := lese nächstes Element in D<br />

u := lese nächstes Element in D'<br />

Stelle L einen Eintrag vor. Stelle L' einen Eintrag vor.<br />

unterscheide<br />

falls t ist String, Wort oder Sonderzeichen:<br />

wenn t = u, dann füge t am Ende von H an.<br />

sonst beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

falls t ist Zahl c:<br />

wenn u ist Zahl, etwa c'. dann<br />

Suche erste Variable v mit Endwert c in V und Endwert c' in X.<br />

wenn gefunden, dann<br />

Füge v am Ende von H an.<br />

sonst wenn c = 0, dann<br />

Suche erste Variable v mit Endwert c in V und Endwert c'+1 in<br />

X.<br />

wenn gefunden, dann<br />

Füge --v am Ende von H an.<br />

Ändere Endwert von v in X auf c'.<br />

sonst<br />

Suche erste Variable v mit Endwert c - 1 in V und Endwert c'<br />

- 1 in X.<br />

wenn gefunden, dann<br />

Füge ++v am Ende von H an.<br />

Ändere Endwert von v in V auf c und von v in X auf c'.<br />

sonst<br />

Suche erste Variable v mit Endwert c + 1 in V und<br />

Endwert c' +1 in X.<br />

wenn gefunden, dann<br />

Füge --v am Ende von H an.<br />

Ändere Endwert von v in V auf c und von v in X auf c'.<br />

sonst wenn c' = 0, dann<br />

Suche erste Variable v mit Endwert c + 1 in V und<br />

Endwert c' in X.<br />

wenn gefunden, dann<br />

Füge --v am Ende von H an.<br />

Ändere Endwert von v auf c.<br />

sonst<br />

// erstes Vorkommen einer Variablen, nicht in<br />

// Inkrement oder Dekrement erlaubt<br />

Suche erste Variable v mit Endwert c in V.<br />

wenn gefunden, dann<br />

Füge v am Ende von H an.<br />

Trage v in X ein mit Anfangs- und Endwert c'.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

sonst<br />

// ganz neue Variable<br />

Sei v eine neue Variable.<br />

Füge v am Ende von H an.<br />

Trage v mit Anfangs- und Endwert c in V ein.<br />

Trage v mit Anfangs- und Endwert c' in X ein.<br />

ende wenn<br />

ende wenn<br />

ende wenn<br />

ende wenn<br />

ende wenn<br />

ende wenn<br />

sonst<br />

// t ist Zahl, aber nicht u<br />

Beende Algorithmus mit Fehlermeldung.<br />

ende wenn<br />

falls t ist test-Konstrukt der Form "test A 1 do B 1 end test", wobei<br />

A 1 und B 1 Beispielauswertungsfragmente:<br />

wenn u ist test-Konstrukt der Form "test A’ 1 do B’ 1 end<br />

test", wobei A' 1 und B' 1 Beispielauswertungsfragmente, dann<br />

wenn L steht nicht hinter dem letzten Element von D und wenn L'<br />

steht nicht hinter dem letztem Element von D' und wenn das<br />

nächste Element von D ist test-Konstrukt der Form "test A 2 do<br />

B 2 end test", wobei A 2 und D 2 Beispielauswertungsfragmente,<br />

und wenn das nächste Element von D' ist test-Konstrukt der<br />

Form "test A’ 2 do B’ 2 end test", wobei A' 2 und D' 2<br />

Beispielauswertungsfragmente, dann<br />

Variablen: t',u' : Auswertungen von Anweisungen<br />

i : natürliche Zahlen (Laufvariablen)<br />

result : logischer Wert<br />

M,M': Ausdrücke<br />

N,N': Anweisungssequenzen<br />

Y : Variablenliste<br />

t' := Lese nächstes Element in D.<br />

u' := Lese nächstes Element in D'.<br />

Setze Lesemarken L und L' je ein Element vor.<br />

// Generiere while-Konstrukte aus t und t' und u und u'<br />

Lösche Y.<br />

Rufe SampleWHILE(A 1 ,B 1 ,A 2 ,B 2 , V,M,N) auf.<br />

Rufe SampleWHILE(A 1 ',B 1 ',A 2 ',B 2 ',Y,M',N') auf.<br />

// stimmen die generierten while-Konstrukte in D und D'<br />

überein?<br />

// Außerdem müssen die Variablen aus Y in X eingetragen<br />

// werden<br />

Rufe MatchWHILE(M,M',N,N',V,Y,X,result) auf.<br />

// eigentlich sollten die Konstrukte schon passen<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

wenn result = FALSCH, dann<br />

beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

// Damit steht die Form des while-Konstruktes fest<br />

Füge "with while M do N end while" am Ende von H<br />

an.<br />

// folgen weitere Entfaltungen des while-Konstruktes in D?<br />

solange L steht nicht hinter dem letzten Element von D und<br />

solange das nächste Element von D ist test-Konstrukt der<br />

Form "test A 3 do B 3 end test", wobei A 3 und B 3<br />

Beispielauswertungsfragmente sind, tue<br />

t' := Lese nächstes Element in D.<br />

Setze L ein Element vor.<br />

// Test durchführen<br />

Rufe TestWHILE(A 3 ,B 3 ,M,N,V,result) auf.<br />

wenn result = FALSCH, dann<br />

beende Algorithmus mit Fehlermeldung.<br />

ende wenn<br />

ende solange<br />

wenn L steht nicht hinter dem letzten Element von D und<br />

wenn das nächste Element von D ist test-Konstrukt der<br />

Form "test B 3 skip’", wobei B 3 ein<br />

Beispielauswertungsfragment ist, dann<br />

t' := Lese nächstes Element in D.<br />

Setze Lesemarke L ein Element vor.<br />

Rufe TestWExpression(A 3 ,M,V,result) auf.<br />

wenn result = FALSCH, dann<br />

beende Algorithmus mit Fehlermeldung.<br />

ende wenn<br />

ende wenn<br />

// folgen weitere Entfaltungen des while-Konstruktes in D'<br />

solange L' steht nicht hinter dem letzten Element von D' und<br />

solange das nächste Element von D' ist test-Konstrukt der<br />

Form "test A’ 3 do B’ 3 end test", wobei A' 3 und B' 3<br />

Beispielauswertungsfragmente sind, tue<br />

u' := Lese nächstes Element in D.<br />

Setze L' ein Element vor.<br />

// Test durchführen<br />

Rufe TestWHILE(A' 3 ,B' 3 ,M,N,X,result) auf.<br />

wenn result = FALSCH, dann<br />

beende Algorithmus mit Fehlermeldung.<br />

ende wenn<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

ende solange<br />

wenn L’ steht nicht hinter dem letzten Element von D’ und<br />

wenn das nächste Element von D' ist test-Konstrukt der<br />

Form "test B’ 3 skip’", wobei B' 3 ein<br />

Beispielauswertungsfragment ist, dann<br />

u' := Lese nächstes Element in D'.<br />

Setze Lesemarke L' ein Element vor.<br />

Rufe TestWExpression(A' 3 ,M,X,result) auf.<br />

wenn result = FALSCH, dann<br />

beende Algorithmus mit Fehlermeldung.<br />

ende wenn<br />

ende wenn<br />

sonst<br />

// test-Konstrukt am Ende der Anweisungssequenz<br />

beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

sonst<br />

// t ist test-Konstrukt, aber nicht u<br />

beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

andernfalls<br />

// kein weiterer Fall möglich<br />

beende Algorithmus mit Fehlermeldung<br />

ende unterscheide<br />

ende solange<br />

wenn entweder D oder D' nicht vollständig gelesen, dann<br />

beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

ende wenn<br />

Ende Prozedur SampleWStatementSequence<br />

Prozedur MatchWHILE(M,M’,N,N’,V,Y,X,result)<br />

Eingabe: M,M' : Ausdrücke<br />

N,N' : Anweisungssequenzen<br />

V : Variablenliste (Variablen aus M und N)<br />

Y : Variablenliste (Variablen aus M' und N', keine der Variablen<br />

erhält einen Eintrag 'neues Lexem')<br />

Ein-/Ausgabe:<br />

X : Variablenliste<br />

Ausgabe: result : logischer Wert<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Funktion:<br />

result = WAHR ⇔<br />

M und M’ sowie N und N’ stimmen bis auf die Namen der Variablen<br />

überein.<br />

Für jede Variable y (in Y). die in M' oder N' vorkommt, deren<br />

entsprechende Variable in M und N x ist (in V), wird x mit Anfangs- und<br />

Endwert von y in X eingetragen, wenn x beim Aufruf der Prozedur in X<br />

nicht enthalten ist.<br />

Für jede Variable y (in Y), die in M' oder N' vorkommt, deren<br />

entsprechende Variablen in M und N x ist (in V), wird der Endwert von x<br />

in V auf den Endwert von y in Y gesetzt, sofern beim Aufruf der<br />

Prozedur x in X enthalten ist.<br />

Variablen: i : natürliche Zahl (Schleifenvariable)<br />

t,u : Anweisungen<br />

// optimistisch<br />

result := WAHR<br />

// Überprüfe Ausdrücke<br />

wenn M = "" oder M' = "" tue<br />

wenn M ≠ "" oder M' ≠ "" tue<br />

result := FALSCH<br />

ende wenn<br />

sonst<br />

// beide Ausdrücke sind nicht leer<br />

Setze Lesezeiger L vor das erste Element in M und Lesezeiger L' vor das erste<br />

Element in M'.<br />

solange weder M noch M' zu ende gelesen (d.h. weder L noch L' steht hinter<br />

dem letzten Element von M bzw. M') und solange result = WAHR tue<br />

// lese beide Ausdrücke simultan<br />

t := lese nächste Anweisung in M<br />

u := lese nächste Anweisung in M'<br />

Setze L ein Element vor.<br />

Setze L' ein Element vor.<br />

unterscheide<br />

falls t ist Zeichenkette, Wort oder Sonderzeichen:<br />

wenn t≠u, dann<br />

result := FALSCH<br />

ende wenn<br />

falls t ist Variable, etwa v (kein Inkrement oder Dekrement):<br />

wenn u ist Variable, etwa x dann<br />

wenn neuer Wert von x in Y ist vorhanden, etwa y dann<br />

wenn v≠y, dann<br />

result := FALSCH<br />

ende wenn<br />

sonst wenn v in X enthalten. dann<br />

Sei a der Anfangswert von x in Y.<br />

Sei e der Endwert von v in X.<br />

wenn a = e, dann<br />

Sei e' der Endwert von x in Y.<br />

Trage e' als Endwert von v in X ein.<br />

Trage v als neuen Wert von x in Y ein.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

sonst<br />

Beende Algorithmus mit Fehlermeldung<br />

ende wenn<br />

sonst<br />

Sei a der Anfangswert von x in Y und e der Endwert von x in Y.<br />

Trage v mit Anfangswert a und Endwert e in X ein.<br />

Trage v als neuen Wert von x in Y ein.<br />

ende wenn<br />

sonst<br />

result := FALSCH<br />

ende wenn<br />

andernfalls:<br />

Beende Algorithmus mit Fehlermeldung<br />

ende unterscheide<br />

ende solange<br />

wenn entweder M oder M’ nicht zu ende gelesen tue<br />

result = FALSCH<br />

ende wenn<br />

ende wenn<br />

wenn result = WAHR, dann<br />

// Überprüfe Anweisungssequenzen<br />

wenn N = "" oder N' = "" tue<br />

wenn N ≠ "" oder N' ≠ "" tue<br />

result := FALSCH<br />

ende wenn<br />

sonst<br />

// beide Ausdrücke sind nicht leer<br />

Setze Lesezeiger L vor das erste Element in N und Lesezeiger L' vor das<br />

erste Element in N'.<br />

solange weder N noch N' zu ende gelesen tue (d.h. weder L noch L' steht<br />

hinter dem letzten Element von N bzw. N')<br />

// Lese Anweisungssequenzen simultan<br />

t := lese nächste Anweisung in N<br />

u := lese nächste Anweisung in N'<br />

Setze L ein Element vor.<br />

Setze L' ein Element vor.<br />

unterscheide<br />

falls t ist Zeichenkette, Wort oder Sonderzeichen:<br />

wenn t≠u, dann<br />

result := FALSCH<br />

ende wenn<br />

falls t ist Variable, etwa v (kein Inkrement oder Dekrement):<br />

wenn u ist Variable, etwa x dann<br />

wenn u besitzt neuen Name, etwa y dann<br />

wenn v ≠ y, dann<br />

result := FALSCH<br />

ende wenn<br />

sonst wenn v in X enthalten, dann<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Sei e der Endwert von x in Y. Setze den Endwert von v in X<br />

auf e.<br />

Trage v als neuen Namen von x in Y ein.<br />

sonst<br />

Sei a der Anfangswert von x in Y und e der Endwert von x in Y.<br />

Trage v mit Anfangswert a und Endwert e in X ein.<br />

Trage v als neuen Namen von x in Y ein.<br />

ende wenn<br />

sonst<br />

result := FALSCH<br />

ende wenn<br />

falls t ist Inkrement ++v, wobei v Variable aus V:<br />

// v muß als neuer Name von der entsprechenden Variablen in<br />

// x bekannt sein und in X enthalten sein, da v nicht erstes<br />

Vorkommen<br />

// der Variablen in M und N sein darf<br />

wenn t ist Inkrement, etwa ++x, wobei x Variable aus Y:<br />

wenn nicht neuer Name von x existiert und ist gleich v, dann<br />

result := FALSCH<br />

ende wenn<br />

sonst<br />

result := FALSCH<br />

ende wenn<br />

falls t ist Dekrement --v:<br />

// v muß als neuer Name der entsprechenden Variablen in x bekannt<br />

// sein und in X enthalten sein, da v nicht erstes Vorkommen der<br />

// Variablen in M und N sein darf.<br />

wenn t ist Inkrement, etwa ++x, wobei x Variable aus Y:<br />

wenn nicht neuer Name von x existiert und ist gleich v, dann<br />

result := FALSCH<br />

ende wenn<br />

sonst<br />

result := FALSCH<br />

ende wenn<br />

falls t ist while-Konstrukt:<br />

wenn u ist while-Konstrukt, dann<br />

Variablen: result' : logischer Wert<br />

// Form der while-Konstrukte<br />

t habe die folgende Form: t = "with while B do C end<br />

while"<br />

u habe die folgende Form: u = "with while B’ do C’ end<br />

while".<br />

Dabei seien B und B' Ausdrücke und C und C'<br />

Anweisungssequenzen.<br />

// Stimmen die while-Konstrukte überein ?<br />

Rufe MatchWHILE (B,C,B',C',V,Y,X,result')<br />

wenn result' = FALSCH, dann<br />

result := FALSCH<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

ende wenn<br />

sonst<br />

result := FALSCH<br />

ende wenn<br />

andernfalls:<br />

Beende Algorithmus mit Fehlermeldung<br />

ende unterscheide<br />

ende solange<br />

wenn entweder N oder N’ nicht zu ende gelesen tue<br />

result = FALSCH<br />

ende wenn<br />

ende wenn<br />

Ende Prozedur MatchWHILE<br />

Prozedur TestWHILE (B,C,G,H,V,result)<br />

Eingabe: B : Beispielauswertung eines Ausdrucks<br />

C : Beispielauswertung einer Anweisungssequenz<br />

G : Ausdruck<br />

H : Anweisungssequenz<br />

Ein-/Ausgabe:<br />

V : Variablenliste<br />

Ausgabe: result : logischer Wert<br />

Funktion:<br />

Variable:<br />

result = WAHR ⇔ "test A do B end test" ist Teil eines<br />

Beispielauswertungsfragmentes eines while-Konstruktes, dessen<br />

Ausdruck G und dessen Anweisungssequenz H ist. Die Variablenliste V<br />

enthält vor dem Aufruf alle lokalen Variablen des while-Konstruktes mit<br />

ihren Werten vor der Auswertung von B. Nach Beendigung der<br />

Prozedur enthält X die Werte der lokalen Variablen nach der<br />

Auswertung von C, sofern result = WAHR gilt.<br />

result' : logischer Wert<br />

// optimistisch<br />

result := WAHR<br />

// Ausdruck testen<br />

Rufe TestWExpression (B,G,V,result') auf.<br />

wenn result' = FALSCH dann<br />

result := FALSCH<br />

sonst<br />

// Anweisungssequenz testen<br />

Rufe TestWStatementSequence (C,H,V,result') auf.<br />

result := result'<br />

ende wenn<br />

Ende Prozedur TestWHILE<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Prozedur TestWExpression (B,G,V,result)<br />

Eingabe: B : Beispielauswertung eines Ausdrucks<br />

G : Ausdruck<br />

V : Variablenliste<br />

Ausgabe: result : logischer Wert<br />

Funktion:<br />

result = WAHR ⇔ "test B skip" oder "test B do C end test"<br />

(C Beispielauswertung) ist Teil eines Beispielauswertungsfragmentes<br />

eines while-Konstruktes, dessen Ausdruck G ist. Die Variablenliste V<br />

enthält vor dem Aufruf alle lokalen Variablen des while-Konstruktes mit<br />

ihren Werten vor der Auswertung von B.<br />

Variablen: t : Beispielauswertung einer Anweisung<br />

u : Anweisung<br />

// optimistisch<br />

result := WAHR<br />

// Lese B und G sequentiell<br />

wenn B = "", dann<br />

wenn G ≠ "" dann<br />

result := FALSCH<br />

ende wenn<br />

sonst<br />

wenn G = "", dann<br />

result := FALSCH<br />

sonst<br />

// weder G noch B sind leer<br />

Setze Lesezeiger L vor das erste Element von A. Setze Lesezeiger L' vor das<br />

erste Element von G.<br />

solange weder A noch G zu ende gelesen (d.h. weder L noch L' steht hinter<br />

dem letzen Element in A bzw. G) und solange result = WAHR tue<br />

t := lese nächstes Element in G<br />

u := lese nächstes Element in B<br />

Stelle L ein Element vor<br />

Stelle L' ein Element vor.<br />

unterscheide<br />

falls t ist Zeichenkette, Wort oder Sonderzeichen:<br />

wenn t≠u, dann<br />

result := FALSCH<br />

ende wenn<br />

falls t ist Variable v:<br />

Sei c der Endwert von v in V.<br />

wenn u≠c, dann<br />

result := FALSCH<br />

ende wenn<br />

andernfalls:<br />

Beende Algorithmus mit Fehlermeldung<br />

ende unterscheide<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

ende solange<br />

wenn B oder G nicht zu ende gelesen, tue<br />

result := FALSCH<br />

ende wenn<br />

ende wenn<br />

ende wenn<br />

Ende Prozedur TestWExpression<br />

Prozedur TestWStatementSequence (C,H,V,result)<br />

Eingabe: C : Beispielauswertung eines Anweisungssequenz<br />

H : Anweisungssequenz<br />

Ein-/Ausgabe:<br />

V : Variablenliste<br />

Ausgabe: result : logischer Wert<br />

Funktion: result = WAHR ⇔ "test B do C end test" (B<br />

Beispielauswertungsfragment) ist Teil eines<br />

Beispielauswertungsfragmentes eines while-Konstruktes, dessen<br />

Anweisungssequenz H ist. Die Variablenliste V enthält vor dem Aufruf<br />

alle lokalen Variablen des while-Konstruktes mit ihren Werten vor der<br />

Auswertung der ersten Anweisung von C. Für den Fall result = WAHR<br />

enthält V am Ende der Prozedur die Endwerte der Variablen nach der<br />

Auswertung von C.<br />

Variablen: t : Beispielauswertung einer Anweisung<br />

u : Anweisung<br />

// optimistisch<br />

result := WAHR<br />

// Lese C und H sequentiell<br />

wenn C = "", dann<br />

wenn H ≠ "", dann<br />

result := FALSCH<br />

ende wenn<br />

sonst<br />

wenn H = "", dann<br />

result := FALSCH<br />

sonst<br />

// weder C noch H sind leer<br />

Setze Lesezeiger L vor das erste Element von C.<br />

Setze Lesezeiger L' vor das erste Element von H.<br />

solange weder C noch H zu ende gelesen (d.h. weder L noch L' steht hinter<br />

dem letzen Element in C bzw. H) und solange result = WAHR tue<br />

t := lese nächstes Element in H<br />

u := lese nächstes Element in C<br />

Stelle L ein Element vor.<br />

Stelle L' ein Element vor.<br />

unterscheide<br />

falls t ist Zeichenkette, Wort oder Sonderzeichen:<br />

wenn t≠u, dann<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

result := FALSCH<br />

ende wenn<br />

falls t ist Variable v:<br />

Sei c der Endwert von v in V.<br />

wenn u≠c, dann<br />

result := FALSCH<br />

ende wenn<br />

falls t ist Inkrement ++v:<br />

Sei c der Endwert von v in V.<br />

wenn u ist Zahl c+1, dann<br />

setze Endwert von v in V auf c+1.<br />

sonst<br />

result := FALSCH<br />

ende wenn<br />

falls t ist Dekrement --v:<br />

Sei c der Endwert von v in V.<br />

wenn c > 0 oder u > 0, dann<br />

wenn u ist Zahl c-1, dann<br />

Setze Endwert von v in V auf c-1.<br />

sonst<br />

result := FALSCH<br />

ende wenn<br />

ende wenn<br />

falls t ist while-Konstrukt der Form "with while D do E end<br />

while", wobei D ein Ausdruck und E eine Anweisungssequenz ist:<br />

Variablen: i : natürliche Zahl (Schleifenvariable)<br />

result' : logischer Wert<br />

u' : Beispielauswertungsfragment einer Anweisung<br />

// u muß test-Konstrukt sein und zwar Teil des<br />

// Beispielauswertungsfragmentes von t<br />

wenn u ist test-Konstrukt der Form "test B’ do C’ end test",<br />

wobei B' Beispielauswertungsfragment eines Ausdrucks und C'<br />

Beispielauswertungsfragment einer Anweisungssequenz ist, dann<br />

Rufe TestWHILE (A',B',D,E,V,result') auf.<br />

wenn result' = FALSCH, dann<br />

result := FALSCH<br />

sonst<br />

// es muß mindestens noch eine weitere Entfaltung von t<br />

// kommen<br />

wenn C zu ende gelesen (d.h. L' steht hinter dem letzen<br />

Element von C), dann<br />

result := FALSCH<br />

sonst<br />

u' := lese nächstes Element in C.<br />

Setze L' ein Element vor.<br />

wenn u' ist test-Konstrukt der Form "test B’’ do C’’<br />

end test", wobei B'' Beispielauswertungsfragment eines<br />

Ausdrucks und C'' Beispielauswertungsfragment einer<br />

Anweisungssequenz ist, dann<br />

Rufe TestWHILE (B'',C'',D,E,V,result') auf.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

wenn result’ = FALSCH, dann<br />

result := FALSCH<br />

sonst<br />

// es können nun noch weitere Entfaltungen von t<br />

// folgen<br />

solange C nicht zu ende gelesen und solange<br />

nächstes Element in C ist test-Konstrukt der Form<br />

"test B’’’ do C’’’ end test", wobei B'''<br />

Beispielauswertungsfragment eines Ausdrucks und<br />

C''' Beispielauswertungsfragment einer Anweisung,<br />

tue<br />

u' := Lese nächstes Element in C.<br />

Setze L' ein Element vor.<br />

Rufe TestWHILE (B''',C''',D,E,V,result') auf.<br />

wenn result' = FALSCH, dann<br />

result := FALSCH<br />

ende wenn<br />

wenn C nicht zu ende gelesen und wenn nächstes<br />

Element in C ist test-Konstrukt der Form "test B’’’<br />

skip", wobei B''' Beispielauswertungsfragment, dann<br />

u' := Lese nächstes Element in C.<br />

Setze L' ein Element vor.<br />

Rufe TestWExpression (B''',D,V,result') auf.<br />

wenn result' = FALSCH, dann<br />

result := FALSCH<br />

ende wenn<br />

ende wenn<br />

ende wenn // result' = FALSCH<br />

sonst<br />

// u' ist nicht test-Konstrukt<br />

result' = FALSCH<br />

ende wenn<br />

ende wenn // C zu ende gelesen<br />

ende wenn<br />

sonst<br />

// u ist nicht test-Konstrukt<br />

result := FALSCH<br />

ende wenn<br />

andernfalls:<br />

Beende Algorithmus mit Fehlermeldung<br />

ende unterscheide<br />

ende solange<br />

wenn C oder H nicht zu ende gelesen, tue<br />

result := FALSCH<br />

ende wenn<br />

ende wenn<br />

ende wenn<br />

Ende Prozedur TestWStatementSequence<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

5.4 Korrektheit<br />

Das erste Lemma gilt der Prozedur TestWExpression.<br />

/HPPD<br />

6HL3HLQ3URJUDPPXQG:HLQZKLOH.RQVWUXNWLQ3:HQWKDOWHNHLQH<br />

=DKONRQVWDQWH6HL6HLQH%HLVSLHODXVZHUWXQJYRQ3XQG7GDV<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ66HL*GHU$XVGUXFNYRQ:XQG%<br />

HLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ*LQQHUKDOEYRQ7'LH9DULDEOHQOLVWH<br />

9HQWKDOWHPLQGHVWHQVDOOH9DULDEOHQYRQ*PLWLKUHQ:HUWHQDP$QIDQJ<br />

GHU$XVZHUWXQJ%'DQQJLOWI UGLH3UR]HGXU7HVW:([SUHVVLRQDXIJHUXIHQ<br />

PLWGHQ3DUDPHWHUQ%*9UZREHLUHLQHORJLVFKH9DULDEOHLVWLQGLHGLH<br />

$XVJDEHGHU3UR]HGXUJHVFKULHEHQZLUG<br />

'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

1DFK%HHQGLJXQJGHU3UR]HGXUJLOWU :$+5.<br />

Beweis:<br />

1. Termination<br />

Die Prozedur enthält keine eigenen (expliziten) Prozeduraufrufe und nur eine<br />

einzige Schleife. Die Schleife kann nur betreten werden, wenn beide Lesezeiger<br />

vor dem ersten Element von B bzw. G stehen und wird (spätestens) verlassen,<br />

sobald einer der beiden Lesezeiger hinter dem letzen Element von A bzw. G<br />

steht. Bei jedem Schleifendurchlauf werden aber beide Lesezeiger um ein<br />

Element vorgestellt. Dann muß jeder der Lesezeiger nach endlich vielen<br />

Schleifendurchläufen hinter dem letzem Element von A bzw. G stehen, es sei<br />

denn, die Schleife wird vor diesem Stand beendet. Also wird die Schleife in<br />

jedem Fall nach endlich vielen Rechenschritten verlassen und die Prozedur<br />

terminiert im Endlichen.<br />

2. am Ende der Prozedur hat r den Wert WAHR<br />

r erhält am Ende der Prozedur den Wert der Ausgabevariablen result der<br />

Prozedur. Dieser Variable wird an einer Stelle (nämlich am Anfang der<br />

Prozedur) der Wert WAHR und an fünf Stellen der Wert FALSCH zugewiesen,<br />

nämlich<br />

a) wenn B = "" und G ≠ "",<br />

b) wenn B ≠ "" und G = "",<br />

c) wenn in einem Schleifendurchlauf t Zeichenkette, Wort oder Sonderzeichen<br />

ist und u ≠ t gilt.<br />

d) wenn in einem Schleifendurchlauf t eine Variable v ist und t ungleich dem<br />

Endwert von v in V ist.<br />

e) nach dem Ende der solange-Schleife einer der Lesezeiger nicht hinter dem<br />

letzten Element von A bzw. G steht.<br />

Sonst erfolgt kein schreibender Zugriff auf result. Da result am Anfang der<br />

Prozedur den Wert WAHR erhält, kann ein Wert ungleich WAHR für result nur<br />

eintreten, wenn einer der Fälle a) bis e) auftritt. Wir müssen demnach diese<br />

Fälle widerlegen.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

ÃAbbildung 6 : Struktur des Beweises von Satz 5.4.1<br />

SampleProgram<br />

Satz 5.4.1<br />

SampleSequence<br />

Lemma 5.4.15<br />

benötigt für<br />

Lemma 3.5.1<br />

Lemma 3.5.2<br />

Lemma 3.5.3<br />

TestWHILE<br />

Lemma 5.4.4<br />

TestWExpression<br />

Lemma 5.4.1<br />

SampleWHILE<br />

Lemma 5.4.14<br />

Lemma 3.5.4<br />

TestWSequence<br />

Lemma 5.4.3<br />

SampleWSequence<br />

Lemma 5.4.13<br />

SampleWExpression<br />

Lemma 5.4.7<br />

MatchWHILE<br />

Lemma 5.4.2 Lemma 5.4.5<br />

Lemma 5.4.12<br />

Lemma 5.4.6<br />

Lemma 5.4.11<br />

Lemma 5.4.10<br />

Lemma 5.4.9<br />

Lemma 5.4.8<br />

.<br />

G ist ein Ausdruck. Nach Voraussetzung enthält G keine Zahlkonstanten. Also<br />

kann G nur Zeichenketten, Sonderzeichen, Wörter und Variablen (außerhalb<br />

eines Inkrementes und Dekrementes) enthalten. Zeichenketten, Sonderzeichen<br />

und Wörter werden bei der Bildung von Beispielauswertungen nicht verändert,<br />

Variablen werden durch Zahlen ersetzt. Also wird jedes Element eines<br />

Ausdruckes durch ein Element des Beispielauswertungsfragmentes dieses<br />

Ausdrucks ersetzt. Also muß gelten Länge(B) = Länge(G). Dies schließt die Fälle<br />

a) und b) sofort aus.<br />

Es sei A = "a1...aLänge(G)" und G = "g1...gLänge(G)". Dann gilt für i∈{1,...,Länge(G)}: gi<br />

wird bei der Bildung der Beispielauswertung in genau ein Element von A<br />

umgewandelt, nämlich in ai. Sei j∈{1,...,Länge(G)} beliebig. Beim j-ten<br />

Schleifendurchlauf wird genau ein Element t von G und u von A gelesen. Aus<br />

obiger Überlegung folgt, daß t = gj und u = aj.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Falls t ist Zeichenkette, Wort und Sonderzeichen, so muß gelten t = u nach<br />

Konstruktion der Beispielauswertungen. Damit ist Fall c) widerlegt.<br />

Verbleibt der Fall, daß t eine Variable ist, etwa die Variable v. Nach<br />

Voraussetzung enthält die Variablenliste V die Werte der Variablen, die im<br />

Ausdruck vorkommen. Da V innerhalb der Prozedur nicht verändert wird,<br />

enthält V den Wert von v an jeder Stelle des Ausdrucks. Nach Konstruktion der<br />

Beispielauswertung muß u gleich diesem Wert sein. Damit ist Fall d) widerlegt.<br />

Sei jetzt m die Nummer des letzten Schleifendurchlaufs. Da nach obigen<br />

Überlegungen innerhalb der Schleife immer result = WAHR gilt, muß gelten m<br />

= Länge(A) = Länge(G). Damit ist auch der Fall e) ausgeschlossen.<br />

Als nächstes wenden wir uns den Prozeduren TestWStatementSequence und TestWHILE. Die<br />

Analyse dieser Prozeduren wird erheblich erschwert dadurch, daß die beiden Prozeduren sich<br />

gegenseitig aufrufen. Damit sind beide Prozeduren indirekt rekursiv. Beginnen wir mit der<br />

Prozedur TestWStatementSequence für den Fall, daß keine indirekte Rekursion auftritt.<br />

/HPPD<br />

6HL3HLQ3URJUDPPXQG:HLQZKLOH.RQVWUXNWLQ3:HQWKDOWHNHLQH<br />

=DKONRQVWDQWHQXQGNHLQHORNDOHQZKLOH.RQVWUXNWH6HL6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ3XQG7GDV%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ<br />

66HL+GLH$QZHLVXQJVVHTXHQ]YRQ:XQG&HLQ<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ+LQQHUKDOEYRQ7'LH9DULDEOHQOLVWH9<br />

HQWKDOWHPLQGHVWHQVDOOH9DULDEOHQYRQ+PLWLKUHQ:HUWHQDP$QIDQJYRQ<br />

&'DQQJLOWI UGLH3UR]HGXU7HVW:6WDWHPHQW6HTXHQFHDXIJHUXIHQPLWGHQ<br />

3DUDPHWHUQ&+9UZREHLUHLQHORJLVFKH9DULDEOHLVWLQGLHGLH$XVJDEH<br />

GHU3UR]HGXUJHVFKULHEHQZLUG<br />

'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

1DFK%HHQGLJXQJGHU3UR]HGXUJLOWU :$+5<br />

9HQWKlOWPLQGHVWHQVDOOH9DULDEOHQGLHLQ+YRUNRPPHQPLWLKUHQ<br />

:HUWHQDP(QGHYRQ&<br />

Beweis:<br />

1. Termination<br />

Da nach Voraussetzung W keine lokalen while-Konstrukte enthält, gilt dies<br />

auch für H. Explizite Prozeduraufrufe treten in der Prozedur aber nur auf, wenn<br />

H mindestens ein while-Konstrukt enthält, was aber nicht der Fall ist. Es wird<br />

dann auch nur eine einzige Schleife durchlaufen, nämlich die äußere solange-<br />

Schleife. Diese kann nur betreten werden, wenn beide Lesezeiger vor dem<br />

ersten Element von C bzw. H stehen (C und H sind nicht leer) und wird<br />

(spätestens) verlassen, sobald einer der beiden Lesezeiger hinter dem letzten<br />

Element von C bzw. H steht. Da der Fall "t ist while-Konstrukt" nicht auftreten<br />

kann, ist sichergestellt, daß beide Lesezeiger bei jedem Schleifendurchlauf um<br />

genau ein Element vorgestellt werden. Dann muß jeder der Lesezeiger nach<br />

endlich vielen Schleifendurchläufen hinter dem letzem Element von C bzw. H<br />

stehen, es sei denn, die Schleife wird vor diesem Stand beendet. Also wird die<br />

Schleife in jedem Fall nach endlich vielen Rechenschritten verlassen und die<br />

Prozedur terminiert.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

2. am Ende der Prozedur hat r den Wert WAHR<br />

r erhält am Ende der Prozedur den Wert der Ausgabevariablen result der<br />

Prozedur. Dieser Variable wird an einer Stelle (nämlich am Anfang der<br />

Prozedur) der Wert WAHR und an sieben Stellen der Wert FALSCH zugewiesen<br />

(man beachte, daß der Fall "t ist while-Konstrukt" nicht auftreten kann),<br />

nämlich<br />

a) wenn C = "" und H ≠ "",<br />

b) wenn C ≠ "" und H = "",<br />

c) wenn in einem Schleifendurchlauf t Zeichenkette, Wort oder Sonderzeichen<br />

ist und u ≠ t gilt.<br />

d) wenn in einem Schleifendurchlauf t eine Variable v ist und u ungleich dem<br />

Endwert von v in V ist.<br />

e) wenn in einem Schleifendurchlauf t ein Inkrement ++v ist und u ungleich<br />

dem Wert c + 1, wobei c der Endwert von v in V ist.<br />

f) wenn in einem Schleifendurchlauf t ein Dekrement --v ist, wobei für den<br />

Endwert c von v in V gilt c > 0, und u ist ungleich der Zahl c - 1.<br />

g) nach dem Ende der solange-Schleife einer der Lesezeiger nicht hinter dem<br />

letzten Element von C bzw. H steht.<br />

Sonst erfolgt kein schreibender Zugriff auf result, da der Fall "t ist while-<br />

Konstrukt" niemals eintreten kann. Demnach kann ein Wert ungleich WAHR<br />

für result nur eintreten, wenn einer der Fälle a) bis g) auftritt. Wir müssen<br />

demnach diese Fälle widerlegen.<br />

Nach Voraussetzung enthält H keine Zahlkonstanten und keine while-<br />

Konstrukte sondern nur Zeichenketten, Sonderzeichen, Wörter, Variablen,<br />

Inkremente und Dekremente. Zeichenketten, Sonderzeichen und Wörter werden<br />

bei der Bildung von Beispielauswertungen nicht verändert, Variablen,<br />

Inkremente und Dekremente werden durch Zahlen ersetzt. Also wird bei der<br />

Bildung der Beispielauswertung jedes Element von H durch genau ein Element<br />

des Beispielauswertungsfragmentes von H ersetzt. Insbesondere folgt daraus:<br />

Länge(C) = Länge(H). Dies schließt die Fälle a) und b) sofort aus.<br />

Wir wollen nun zuerst zeigen, daß vor dem ersten Schleifendurchlauf und nach<br />

jedem Schleifendurchlauf die Variablenliste V die aktuellen Werte aller<br />

Variablen von H an der Position des Lesezeigers in C enthält (sofern die Schleife<br />

nicht vorzeitig verlassen wurde).<br />

Beweis durch vollständige Induktion über die Zahl der Schleifendurchläufe<br />

Induktionsverankerung (0 Schleifendurchläufe):<br />

Vor dem ersten Schleifendurchlauf gilt obige Behauptung nach<br />

Voraussetzung.<br />

Induktionsvoraussetzung:<br />

Sei j∈{0,..,Länge(H)-1}, Nach dem j-ten Schleifendurchlauf enthält V die<br />

Endwerte aller Variablen von H an der Position des Lesezeigers.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Induktionsbehauptung:<br />

V enthält auch nach dem (j+1)-ten Schleifendurchlauf die Endwerte aller<br />

Variablen von H an der Position des Lesezeigers.<br />

Induktionsschluß:<br />

Es wird pro Schleifendurchlauf ein Element von H gelesen und zwar<br />

sequentiell. Demnach wird im (j+1)-ten Schleifendurchlauf das (j+1)-te<br />

Element von H gelesen. Sei t dieses Element.<br />

1. Fall: t ist Zeichenkette, Wort, Sonderzeichen oder Variable. Dann ist der<br />

Wert jeder Variablen nach dem (j+1)-ten Schleifendurchlauf gleich ihrem<br />

Wert nach dem j-ten Schleifendurchlauf. Nach Induktionsvoraussetzung ist<br />

dieser Wert aber bereits in V enthalten.<br />

2. Fall: t ist Inkrement ++v, wobei v eine Variable ist. Nach<br />

Induktionsvoraussetzung enthält V den Wert von v nach dem j-ten<br />

Schleifendurchlauf c. Der Endwert von v in V wird auf den Wert c+1 gesetzt,<br />

welcher in der Tat der Wert der Variablen v nach Ausführung des<br />

Inkrementes ist. Da der Endwert aller Variablen ungleich v nicht verändert<br />

wurde, enthält V ihre Endwerte nach Induktionsvoraussetzung.<br />

3. Fall: t ist Dekrement --v, wobei v eine Variable ist, und v hat im j-ten<br />

Schleifendurchlauf den Wert 0. Nach Induktionsvoraussetzung enthält V den<br />

Wert von v nach dem j-ten Schleifendurchlauf, nämlich 0. V wird nicht<br />

verändert. Damit enthält V den Wert von v nach dem (j+1)-ten<br />

Schleifendurchlauf, ebenfalls 0. Es wurde keine Variable ungleich v<br />

verändert, deshalb enthält V die Endwerte dieser lokalen Variablen nach<br />

Induktionsvoraussetzung.<br />

4. Fall: t ist Dekrement --v, wobei v eine lokale Variable ist, und v hat im j-<br />

ten Schleifendurchlauf den Wert c > 0. Nach Induktionsvoraussetzung<br />

enthält V den Endwert c von v. Der Endwert von v in V wird dann auf den<br />

Wert c-1 erniedrigt, was der Wert von v nach dem (j+1)-ten<br />

Schleifendurchlauf entspricht. Es wird der Wert keiner Variablen außer v<br />

verändert. Also enthält V nach Induktionsvoraussetzung die Endwerte dieser<br />

Variable nach j+1 Schleifendurchläufen.<br />

Es können keine weiteren Fälle auftreten.<br />

Sei jetzt C = "c1...cLänge(H)" und H = "h1...hLänge(H)". Dann gilt für i∈{1,...,Länge(H)}<br />

hi wird bei der Bildung der Beispielauswertung in genau ein Element von C<br />

umgewandelt, nämlich in ci. Sei j∈{1,...,Länge(H)} beliebig. Beim j-ten<br />

Schleifendurchlauf wird genau ein Element t von H und u von C gelesen. Aus<br />

obiger Überlegung folgt, daß t = hj und u = cj.<br />

Falls t ist Zeichenkette, Wort und Sonderzeichen, so muß gelten t = u nach<br />

Konstruktion der Beispielauswertungen. Damit ist Fall c) widerlegt.<br />

Falls t ist Variable, etwa v, so wird v bei der Bildung der Beispielauswertung<br />

durch den Wert von v ersetzt. Nach obiger Induktion enthält V den Wert c von v<br />

nach dem j-ten Schleifendurchlauf, welcher mit dem Wert nach dem (j+1)-ten<br />

Schleifendurchlauf übereinstimmt. Es muß also gelten: u = c. Damit ist Fall d)<br />

widerlegt.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Sei nun t da Inkrement ++v, wobei v eine Variable ist. Nach obiger Induktion<br />

enthält V den Wert von v nach dem j-ten Schleifendurchlauf c. Der Wert von v<br />

nach dem (j+1)-ten Schleifendurchlauf ist folglich c+1. Also muß gelten u = c+1.<br />

Dies widerlegt Fall e).<br />

Es gelte jetzt t ist Dekrement --v, wobei für den Wert c von v nach dem j-ten<br />

Schleifendurchlauf gilt: c > 0. Nach obiger Induktion enthält V den Wert c als<br />

Endwert von v. Nach Konstruktion der Beispielauswertung ist der neue Wert<br />

von v (nach dem (j+1)-ten Schleifendurchlauf) gleich c - 1. Also muß gelten u = c<br />

-1. Dies widerlegt den Fall f).<br />

Sei jetzt m die Nummer des letzten Schleifendurchlaufes. Da nach obigen<br />

Überlegungen innerhalb der Schleife immer result = WAHR gilt, muß gelten m<br />

= Länge(V) = Länge(H). Damit ist auch der Fall g) ausgeschlossen.<br />

3. V enthält nach Beendigung der Prozedur (mindestens) alle Variablen von H<br />

mit ihren Werten am Ende von C.<br />

V enthält (mindestens) alle Variablen von H nach Voraussetzung. Weiterhin<br />

wurde bewiesen, daß V die Werte alle auftretenden Variablen vor dem ersten<br />

Schleifendurchlauf und am Ende jedes Schleifendurchlaufs enthält. Also enthält<br />

V auch die Endwerte nach dem letzten Schleifendurchlauf. Da der Lesezeiger<br />

am Ende der Prozedur hinter dem letzten Element von C steht (da die Schleife<br />

nicht vorzeitig verlassen wird), enthält V die Endwerte der Variablen am Ende<br />

von C.<br />

Wir wollen jetzt die Korrektheit der Prozedur TestWStatementSequence für den Fall einer<br />

Schachtelungstiefe d > 0 zeigen. Dazu müssen wir aber die Korrektheit der Prozedur<br />

TestWHILE voraussetzen. Der Clou liegt dabei darin, daß wir die Korrektheit der Prozedur<br />

TestWHILE nur für Anweisungssequenzen mit einer Schachtelungstiefe kleiner d fordern.<br />

/HPPD<br />

6HL3HLQ3URJUDPPXQG:HLQZKLOH.RQVWUXNWLQ3:HQWKDOWHNHLQH<br />

=DKONRQVWDQWHQ6HL6HLQH%HLVSLHODXVZHUWXQJYRQ3XQG7GDV<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ66HL+GLH$QZHLVXQJVVHTXHQ]YRQ<br />

:XQG&HLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ+LQQHUKDOEYRQ76HLG<br />

'+!(VJHOWHQIROJHQGH9RUDXVVHW]XQJI UGLH3UR]HGXU7HVW:+,/(<br />

6HL:HLQZKLOH.RQVWUXNWLQ3GDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG7GDV<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ66HL*GHU$XVGUXFNYRQ:XQG+<br />

GLH$QZHLVXQJVVHTXHQ]YRQ:ZREHL'+G6HLtest B’ do C’ end<br />

testHLQWHVW.RQVWUXNWLQ7ZHOFKHVGXUFK(QWIDOWXQJYRQ:HQWVWDQGHQ<br />

LVW'LH9DULDEOHQOLVWH9HQWKDOWHGLH:HUWHDOOHU9DULDEOHQYRQ:PLWLKUHQ<br />

(QGZHUWHQYRU*'DQQJLOWI UGLH3UR]HGXUWHVW:+,/(EHLP$XIUXI<br />

%&*+9UHVXOW<br />

'LH$XVI KUXQJGHU3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

1DFK%HHQGLJXQJGHU3UR]HGXUJLOWI UGHQ$XVJDEHSDUDPHWHUUHVXOW<br />

:$+5<br />

9HQWKlOWQDFK%HHQGLJXQJGHU3UR]HGXUGLH(QGZHUWHDOOHUORNDOHQ<br />

9DULDEOHQYRQ:DP(QGHYRQ&<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

:HLWHUKLQJLOW'LH9DULDEOHQOLVWH9HQWKDOWHPLQGHVWHQVDOOH9DULDEOHQYRQ<br />

+PLWLKUHQ:HUWHQDP$QIDQJYRQ&'DQQJLOWI UGLH3UR]HGXU<br />

7HVW:6WDWHPHQW6HTXHQFHDXIJHUXIHQPLWGHQ3DUDPHWHUQ&+9UZREHLU<br />

HLQHORJLVFKH9DULDEOHLVWLQGLHGLH$XVJDEHGHU3UR]HGXUJHVFKULHEHQZLUG<br />

, 'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

,, 1DFK%HHQGLJXQJGHU3UR]HGXUJLOWU :$+5<br />

,,,9HQWKlOWPLQGHVWHQVDOOH9DULDEOHQGLHLQ+YRUNRPPHQPLWLKUHQ<br />

:HUWHQDP(QGHYRQ&<br />

Beweis:<br />

1. Termination<br />

Hilfsbehauptung 1: Sei m = Länge (H). Dann wird die äußere solange-Schleife<br />

maximal m-mal durchlaufen.<br />

Beweis:<br />

Wegen D(H) > 0 folgt m > 0. Wir nehmen an, die Schleife werde mindestens<br />

einmal betreten (wird die Schleife nicht betreten, ist Hilfsbehauptung 1 sofort<br />

bewiesen, da die Schleife nullmal durchlaufen wird). Des weiteren nehmen wir<br />

an, jeder der ersten m Schleifendurchläufe terminiere (falls der i-te<br />

Schleifendurchlauf (1≤i≤m) nicht terminiert, kann der (i+1)-te<br />

Schleifendurchlauf nicht betreten werden), sofern die Schleife nicht vorzeitig<br />

beendet wird.<br />

Die äußere solange-Schleife wird verlassen, wenn eine der folgenden<br />

Bedingungen nach einem Schleifendurchlauf wahr wird:<br />

- result = FALSCH<br />

- L steht hinter dem letzten Element von C.<br />

- L' steht hinter dem letzten Element von H.<br />

Es genügt zu zeigen: Falls die Schleife nicht vorzeitig terminiert, steht L' nach<br />

m Schleifendurchläufen hinter dem letzten Element von H.<br />

Vor dem ersten Schleifendurchlauf steht L' vor dem ersten Element von H. Da<br />

bei jedem Schleifendurchlauf L' um genau ein Element vorgestellt wird, folgt die<br />

Hilfsbehauptung nach Induktion. (Hilfsbehauptung 1)<br />

Hilfsbehauptung 2: Sei j∈{0,..,m}. Die Schleife werde nicht vor dem j-ten<br />

Schleifendurchlauf beendet, noch terminiere einer der ersten j<br />

Schleifendurchläufe nicht. V enthalte vor dem j-ten Schleifendurchlauf die<br />

Werte aller Variablen an der Position des Lesezeigers L in C'. Im j-ten<br />

Schleifendurchlauf wird t als while-Konstrukt "with while D do E end<br />

while" gelesen, wobei D ein Ausdruck und E eine Anweisungssequenz ist (man<br />

beachte, daß Klasse-I-Programme keine lokalen Variablen besitzen). Der<br />

Lesezeiger L stehe vor dem Anfang einer Folge F von test-Konstrukten, die das<br />

Beispielauswertungsfragment von t sind. Dann gilt:<br />

(i) Der Schleifendurchlauf ist nach endlich vielen Rechenschritten beendet.<br />

(ii) L steht am Ende hinter dem letztem Element der Folge F.<br />

(iii)<br />

V enthält die Werte aller Variablen nach der Auswertung der letzten<br />

Anweisung von F.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Beweis:<br />

Das erste gelesene Element der Folge F habe die Form u = "test B’ do C’<br />

end test", wobei B’ ein Beispielauswertungsfragment von D und C’ ein<br />

Beispielauswertungsfragment von E ist. Man beachte, daß V die Werte aller<br />

Variablen von u am Anfang von B' enthält und D(C') < d ist. Dann gilt nach den<br />

Voraussetzungen des Lemma für den Aufruf der Prozedur TestWHILE:<br />

I. Die Ausführung der Prozedur terminiert nach endlich vielen Schritten.<br />

II. Nach Beendigung der Prozedur gilt für den Ausgabeparameter result' =<br />

WAHR.<br />

III. V enthält nach Beendigung der Prozedur die Endwerte aller Variablen von<br />

u am Ende von C'.<br />

Der Lesezeiger L steht jetzt vor dem zweiten Element der Liste F. Dieses habe<br />

die Form u = "test B’’ do C’’ end test", wobei B'' ein<br />

Beispielauswertungsfragment von D und C'' ein Beispielauswertungsfragment<br />

von E ist. Wiederum gelten für den Aufruf der Prozedur TestWHILE die<br />

Voraussetzungen des Lemma und es gilt für den Aufruf:<br />

I. Die Ausführung der Prozedur terminiert nach endlich vielen Schritten.<br />

II. Nach Beendigung der Prozedur gilt für den Ausgabeparameter result' =<br />

WAHR.<br />

III. V enthält nach Beendigung der Prozedur die Endwerte aller Variablen von<br />

u am Ende von C''.<br />

Der Lesezeiger L steht wieder hinter dem test-Konstrukt u'.<br />

Dieselbe Argumentation läßt sich anwenden, wenn weitere test-Konstrukte<br />

innerhalb der Folge F anstehen. Falls das letzte Element der Folge der test-<br />

Konstrukte ein test-Konstrukt der Form = "test B’’’ skip", wobei B''' ein<br />

Beispielauswertungsfragment von D ist, so liefert das Lemma 5.4.1 das<br />

gewünschte Ergebnis. (Hilfsbehauptung 2)<br />

Hilfsbehauptung 3: Sei j∈{0,..,m}. Die Schleife werde nicht vor dem j-ten<br />

Schleifendurchlauf beendet, noch terminiere einer der ersten j<br />

Schleifendurchläufe nicht. Dann wird im j-ten Schleifendurchlauf genau ein<br />

Element von H gelesen.<br />

Beweis:<br />

Die Anweisungssequenz H und der Lesezeiger L' werden bei keinem<br />

Prozeduraufruf übergeben. Also kann kein Element von H während eines<br />

Prozeduraufrufs gelesen werden. Außerhalb von Prozeduraufrufen wird der<br />

Lesezeiger nur einmal während eines Schleifendurchlaufs vorgestellt. Also kann<br />

pro Schleifendurchlauf nur ein Element der Anweisungssequenz H gelesen<br />

werden. (Hilfsbehauptung 3)<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Hilfsbehauptung 4: Sei j∈{0,..,m}. Die Schleife werde nicht vor dem j-ten<br />

Schleifendurchlauf beendet, noch terminiere einer der ersten j<br />

Schleifendurchläufe nicht. Dann ist der j-te Schleifendurchlauf nach endlich<br />

vielen Schritten beendet, der Lesezeiger L' steht hinter dem j-ten Element von<br />

H, und der Lesezeiger L steht hinter dem Beispielauswertungsfragment des j-<br />

ten Elementes von C. Außerdem enthält V nach dem j-ten Schleifendurchlauf<br />

die Endwerte aller vorkommenden Variablen an der Position des Lesezeigers L<br />

in C (für j=0 enthält V die Werte vor dem ersten Schleifendurchlauf, d.h. vor der<br />

Ausführung von C).<br />

Beweis durch vollständige Induktion über die Zahl der Schleifendurchläufe:<br />

Induktionsverankerung (0 Schleifendurchläufe):<br />

Vor dem ersten Schleifendurchlauf gilt obige Behauptung nach<br />

Voraussetzung.<br />

Induktionsvoraussetzung:<br />

Sei j∈{0,..,Länge(H)-1}. Der j-te Schleifendurchlauf terminiert, der Lesezeiger<br />

L' steht hinter dem j-ten Element von H, und der Lesezeiger L (in C) stehe<br />

hinter dem Beispielauswertungsfragment des j-ten Elementes von H. Nach<br />

dem j-ten Schleifendurchlauf enthält V die Endwerte aller Variablen von H<br />

an der Position des Lesezeigers.<br />

Induktionsbehauptung:<br />

Der (j+1)-te Schleifendurchlauf ist nach endlich vielen Schritten beendet, der<br />

Lesezeiger L' steht hinter dem (j+1)-ten Element, der Lesezeiger L' steht<br />

hinter dem Beispielauswertungsfragment des (j+1)-ten Elementes von H, und<br />

V enthält auch nach dem (j+1)-ten Schleifendurchlauf die Endwerte aller<br />

Variablen von H an der Position des Lesezeigers.<br />

Induktionsschluß:<br />

Nach Hilfsbehauptung 3 wird pro Schleifendurchlauf ein Element von H<br />

gelesen und zwar sequentiell. Demnach wird im (j+1)-ten Schleifendurchlauf<br />

das (j+1)-te Element von H gelesen. Sei t dieses Element.<br />

Wir müssen vier Behauptungen zeigen:<br />

a) der (j+1)-te Schleifendurchlauf terminiert.<br />

b) nach dem Schleifendurchlauf steht der Lesezeiger L' hinter t.<br />

c) nach dem Schleifendurchlauf steht der Lesezeiger L hinter dem<br />

Beispielauswertungsfragment von t in C.<br />

d) die Variablenliste V enthält (mindestens) die Werte aller vorkommenden<br />

Variablen an der Position des Lesezeigers L.<br />

Falls t ein while-Konstrukt ist, liefert und die Induktionsvoraussetzung die<br />

Voraussetzung für die Anwendung der Hilfsbehauptung 2. Demnach gilt:<br />

(i) Der Schleifendurchlauf ist nach endlich vielen Rechenschritten beendet.<br />

(ii) L steht am Ende hinter dem letztem Element des<br />

Beispielauswertungsfragmentes von t.<br />

(iii)<br />

V enthält die Werte aller Variablen nach der Auswertung des<br />

Beispielauswertungsfragmentes von t.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Wenden wird uns jetzt den vier Behauptungen der Hilfsbehauptung 4 zu:<br />

a) der (j+1)-te Schleifendurchlauf terminiert.<br />

Falls t kein while-Konstrukt ist, ist diese Behauptung sofort einsichtig, und<br />

für den Fall, daß t ein while-Konstrukt ist, liefert uns die Aussage (i) von<br />

Hilfsbehauptung 2 das gewünschte Ergebnis.<br />

b) nach dem Schleifendurchlauf steht der Lesezeiger L' hinter t.<br />

Dies folgt direkt aus Hilfsbehauptung 3.<br />

c) nach dem Schleifendurchlauf steht der Lesezeiger L hinter dem<br />

Beispielauswertungsfragment von t in C.<br />

Für den Fall, daß t kein while-Konstrukt ist, wird nur ein Element von C<br />

gelesen, nämlich das Beispielauswertungsfragment von t (dies muß gelten, da<br />

nach Induktionsvoraussetzung der Lesezeiger hinter dem<br />

Beispielauswertungsfragment des j-ten Elementes von H gestanden hat). Das<br />

Beispielauswertungsfragment besteht nur aus einem Element. Da der<br />

Lesezeiger L auch nur um ein Element vorgestellt wird, steht er folglich<br />

hinter dem Beispielauswertungsfragment.<br />

d) die Variablenliste V enthält (mindestens) die Werte aller vorkommenden<br />

Variablen an der Position des Lesezeigers L.<br />

1. Fall: t ist Zeichenkette, Wort, Sonderzeichen oder Variable. Dann ist der<br />

Wert jeder Variablen nach dem (j+1)-ten Schleifendurchlauf gleich ihrem<br />

Wert nach dem j-ten Schleifendurchlauf. Nach Induktionsvoraussetzung ist<br />

dieser Wert aber bereits in V enthalten.<br />

2. Fall: t ist Inkrement ++v, wobei v eine lokale Variable ist. Nach<br />

Induktionsvoraussetzung enthält V den Wert von v nach dem j-ten<br />

Schleifendurchlauf c. Der Endwert von v in V wird auf den Wert c+1 gesetzt,<br />

welcher in der Tat der Wert der Variablen v nach Ausführung des<br />

Inkrementes ist. Da der Endwert aller Variablen ungleich v nicht verändert<br />

wurde, enthält V ihre Endwerte nach Induktionsvoraussetzung.<br />

3. Fall: t ist Dekrement --v, wobei v eine Variable ist, und v hat im j-ten<br />

Schleifendurchlauf den Wert 0. Nach Induktionsvoraussetzung enthält V den<br />

Wert von v nach dem j-ten Schleifendurchlauf, nämlich 0. V wird nicht<br />

verändert. Damit enthält V den Wert von v nach dem (j+1)-ten<br />

Schleifendurchlauf, ebenfalls 0. Es wurde keine Variable ungleich v<br />

verändert, deshalb enthält V die Endwerte dieser Variablen nach<br />

Induktionsvoraussetzung.<br />

4. Fall: t ist Dekrement --v, wobei v eine Variable ist, und v hat im j-ten<br />

Schleifendurchlauf den Wert c > 0. Nach Induktionsvoraussetzung enthält V<br />

den Endwert c von v. Der Endwert von v in V wird dann auf den Wert c-1<br />

erniedrigt, was der Wert von v nach dem (j+1)-ten Schleifendurchlauf<br />

entspricht. Es wird der Wert keiner Variablen außer v verändert. Also<br />

enthält V nach Induktionsvoraussetzung die Endwerte dieser Variable nach<br />

j+1 Schleifendurchläufen.<br />

5. Fall: t ist while-Konstrukt.<br />

Dann folgt die Behauptung aus Aussage (iii) der Hilfsbehauptung 2.<br />

Weitere Fälle können nicht auftreten. (Hilfsbehauptung 4)<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Durch Induktion folgt aus Hilfsbehauptung 4: Für jedes j∈{1,..,m} terminiert der<br />

j-te Schleifendurchlauf, sofern die Schleife nicht vorzeitig abgebrochen wird.<br />

Nach Hilfsbehauptung 1 werden aber maximal m Schleifendurchläufe<br />

ausgeführt. Also muß die Schleife nach endlicher Zeit verlassen werden.<br />

2. am Ende der Prozedur hat r den Wert WAHR<br />

r erhält am Ende der Prozedur den Wert der Ausgabevariablen result der<br />

Prozedur. Dieser Variable wird an einer Stelle (nämlich am Anfang der<br />

Prozedur) der Wert WAHR und an zwölf Stellen der Wert FALSCH zugewiesen,<br />

nämlich<br />

a) wenn C = "" und H ≠ "",<br />

b) wenn C ≠ "" und H = "",<br />

c) wenn in einem Schleifendurchlauf t Zeichenkette, Wort oder Sonderzeichen<br />

ist und u ≠ t gilt.<br />

d) wenn in einem Schleifendurchlauf t eine Variable v ist und u ungleich dem<br />

Endwert von v in V ist.<br />

e) wenn in einem Schleifendurchlauf t ein Inkrement ++v ist und u ungleich<br />

dem Wert c + 1, wobei c der Endwert von v in V ist.<br />

f) wenn in einem Schleifendurchlauf t ein Dekrement --v ist, wobei für den<br />

Endwert c von v in V gilt c > 0, und u ist ungleich der Zahl c - 1.<br />

g) wenn nach einem Aufruf von TestWHILE der Wert result' = FALSCH<br />

zurückgeliefert wird.<br />

h) wenn nach einem Aufruf von TestWExpression der Wert result' = FALSCH<br />

zurückgeliefert wird.<br />

i) wenn bei der Behandlung eines while-Konstruktes für u ein anderes Element<br />

als ein test-Konstrukt gelesen wird.<br />

j) wenn bei der Behandlung eines while-Konstruktes für u' ein anderes Element<br />

als ein test-Konstrukt gelesen wird.<br />

k) wenn bei der Behandlung eines while-Konstruktes nach dem Einlesen des<br />

ersten test-Konstruktes des Beispielauswertungsfragmentes von t das Ende<br />

von C erreicht wird.<br />

l) nach dem Ende der solange-Schleife einer der Lesezeiger nicht hinter dem<br />

letzten Element von C bzw. H steht.<br />

Demnach kann ein Wert ungleich WAHR für result nur eintreten, wenn einer<br />

der Fälle a) bis l) auftritt. Wir müssen demnach diese Fälle widerlegen.<br />

Die Anweisungssequenz einer leeren Anweisungsfolge ist wieder ein leeres<br />

Beispielauswertungsfragment. Demnach kann der Fall a) nie eintreten. Falls<br />

aber C ≠ "", d.h. C enthält eine Anweisung a, so muß H ein<br />

Beispielauswertungsfragment von a enthalten, dann kann aber nicht gelten H =<br />

"", womit auch der Fall b) nicht eintreten kann.<br />

Für den Fall C = "" und H = "" wird r als WAHR zurückgegeben, also können wir<br />

annehmen, daß die Schleife betreten wird. Sei t die im j-ten Schleifendurchlauf<br />

(j beliebig) gelesene Anweisung. Da in H keine Zahlkonstanten vorkommen,<br />

kann t nur Wort, Zeichenkette, Sonderzeichen, Variable, Inkrement, Dekrement<br />

oder while-Konstrukt sein.<br />

Nach Hilfsbehauptung 4 des ersten Teils des Beweises steht der Lesezeiger L<br />

vor dem Beispielauswertungsfragment von t in C. Im Falle, daß t Zeichenkette,<br />

Wort oder Sonderzeichen ist, muß für das gelesene Element u gelten: t = u, was<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

den Fall c) verbietet. Falls t ist Variable, Inkrement oder Dekrement, so muß<br />

das gelesene Element u eine Zahl sein, nämlich den Wert von v. Der letzte Wert<br />

von v ist in der Variablenliste V gespeichert (nach Hilfsbehauptung 4 vom<br />

ersten Teil des Beweises). Sei c dieser Wert. Dann ist der Wert von v nach dem<br />

Schleifendurchlauf im Fall, daß t eine Variable ist, gleich c, im Fall, daß t ein<br />

Inkrement ist, gleich c+1, und im Fall, daß t ein Dekrement ist, gleich c-1,<br />

sofern c>0 gilt. Damit sind auch die Fälle d), e) und f) widerlegt.<br />

Wenden wir uns jetzt den Fall g) bis k) zu. Die Prozedur TestWHILE wird<br />

innerhalb der Prozedur TestWStatementSequence an genau drei Stellen<br />

aufgerufen, und zwar nur im Fall, daß t ein while-Konstrukt ist. Sei also t ein<br />

while-Konstrukt, etwa "with while D do E end while", wobei D ein<br />

Ausdruck und E eine Anweisungssequenz ist (man beachte, daß Klasse-I-<br />

Programme keine lokalen Initialisationen besitzen). Nach Hilfsbehauptung 4<br />

des ersten Teile des Beweises steht der Lesezeiger L in C vor dem<br />

Beispielauswertungsfragment von t. Dieses habe für ein k∈© (k>1) die Form<br />

test F 1 do G 1 end test<br />

test F 2 do G 2 end test<br />

...<br />

test F k do G k end test<br />

oder die Form<br />

test F 1 do G 1 end test<br />

test F 2 do G 2 end test<br />

...<br />

test F k do G k end test<br />

test F k+1 skip<br />

Dabei sind F1,..,Fk+1 Beispielauswertungsfragmente von D und G1,..,Gk<br />

Beispielauswertungsfragmente von E. Da k > 1 müssen zum<br />

Beispielauswertungsfragment von t mindestens zwei test-Konstrukte gehören.<br />

Dann kann aber die Liste C nicht nach dem Einlesen des ersten test-<br />

Konstruktes zu Ende sein. Also kann der Fall k) nicht eintreten.<br />

Das erste bei der Bearbeitung des while-Konstruktes von C gelesene Element<br />

(u) ist also auf jedem Fall<br />

test F 1 do G 1 end test<br />

also ein test-Konstrukt, weswegen der Fall i) nicht eintreten kann.<br />

Für den anschließenden Aufruf der Prozedur testWHILE gilt aber:<br />

ì u ist Teil des Beispielauswertungsfragment von t, wobei D(D) < d.<br />

ì V enthält (mindestens) alle Variablen von t mit ihren Anfangswerten zu<br />

Beginn der Auswertung u, da keine lokalen Variablen auftreten können.<br />

Somit gilt für den Rückgabewert result' der Prozedur testWHILE nach<br />

Voraussetzung (Punkt II): result' = WAHR.<br />

Das zweite gelesene Element von C (u') ist<br />

test F 2 do G 2 end test<br />

wiederum ein test-Konstrukt, womit auch der Fall j) widerlegt ist<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Für den zweiten Aufruf der Prozedur testWHILE gilt wieder:<br />

ì u' ist Teil des Beispielauswertungsfragment von t, und D(D) < d.<br />

ì V enthält (mindestens) alle Variablen von t mit ihren Anfangswerten zu<br />

Beginn von u' (nach Punkt III) der Voraussetzung).<br />

Dann kann wieder aus Punkt II der Voraussetzung für die Prozedur TestWHILE<br />

geschlossen werden: der Ergebniswert result' = WAHR.<br />

Die analoge Beweisführung läßt sich auch auf die restlichen k-2 test-Konstrukte<br />

des Beispielauswertungsfragmentes von t anwenden, womit wir zu den Schluß<br />

kommen:<br />

ì<br />

ì<br />

Nach dem Einlesen des k-ten test-Konstruktes des<br />

Beispielauswertungsfragmentes von t steht der Lesezeiger L hinter diesem<br />

Element.<br />

Nach dem Einlesen des k-ten test-Konstruktes des<br />

Beispielauswertungsfragmentes von t enthält die Variablenliste V<br />

(mindestens) alle vorkommenden Variablen mit ihren Werten am Ende der<br />

Auswertung des k-ten test-Konstruktes.<br />

ì Jeder der Aufrufe der Prozedur TestWHILE liefert das Ergebnis result' =<br />

WAHR (womit der Fall g) widerlegt ist).<br />

Falls kein (k+1)-tes test-Konstrukt folgt, wird die Prozedur TestWExpression<br />

nicht aufgerufen, und der Fall h) kann nicht eintreten. Nehmen wir deswegen<br />

an, an der Position des Lesezeigers stehe ein (k+1)-tes test-Konstrukt, nämlich<br />

test F k+1 skip<br />

Somit wird die Prozedur SampleWExpression aufgerufen. Wir können aber das<br />

Lemma 5.4.1 benutzen, wonach allerdings nach dem Aufruf der Wert result' =<br />

WAHR ist, weswegen auch der Fall h) widerlegt ist.<br />

Da innerhalb der äußeren solange-Schleife immer result = WAHR gilt, kann die<br />

Schleife nur verlassen werden, wenn entweder C oder H zu ende gelesen.<br />

Nach Hilfsbehauptung 4 des ersten Teils des Beweises wissen wir, daß am Ende<br />

der Schleife, in der eine Anweisung t aus H gelesen wurde, der Lesezeiger in der<br />

Liste C hinter dem Beispielauswertungsfragment zu t steht. Nehmen wir jetzt<br />

an, H wäre nicht zu ende gelesen, aber die Schleife terminiere. Also muß C zu<br />

ende gelesen sein. Dann existiert aber eine Anweisung a von H, dessen<br />

Beispielauswertungsfragment nicht in C enthalten ist. Also ist C kein<br />

Beispielauswertungsfragment von H im Widerspruch zur Voraussetzung des<br />

Lemmas.<br />

Nehmen wir umgekehrt an, H wäre zu ende gelesen, aber nicht C, beim<br />

Terminieren der Schleife. Dann enthält C aber Elemente, die nicht<br />

Beispielauswertungsfragment einer Anweisung aus H sein können, womit C<br />

selbst kein Beispielauswertungsfragment von H sein kann, wiederum im<br />

Widerspruch zur Voraussetzung.<br />

Also muß nach Beendigung der Schleife gelten, daß sowohl H als auch C zu ende<br />

gelesen sind, womit der Fall k) ausgeschlossen ist.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Damit ist beweisen, daß am Ende der Prozedur, die Ausgabevariable result den<br />

Wert WAHR besitzt.<br />

3. V enthält (mindestens) alle Variablen, die in H vorkommen mit ihren Werten<br />

am Ende von C.<br />

Diese Aussage folgt durch Induktion aus der Hilfsbehauptung 4 des ersten Teils<br />

des Beweises.<br />

Wir wollen jetzt die Korrektheit der Prozedur TestWHILE beweisen. Das Problem dabei liegt,<br />

daß wir dazu das Lemma 5.4.3 benutzen müssen, zu dessen Beweis aber Aussagen über die<br />

Korrektheit von TestWHILE gemacht wurden.<br />

/HPPD<br />

6HL3HLQ3URJUDPPXQG:HLQZKLOH.RQVWUXNWLQ3:HQWKDOWHNHLQH<br />

=DKONRQVWDQWHQ6HL6HLQH%HLVSLHODXVZHUWXQJYRQ3XQG7GDV<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6:KDEHGLH*HVWDOWwith while<br />

G do H end whileXQG7KDEHGLH*HVWDOWtest B do C end test'LH<br />

9DULDEOHQOLVWH9HQWKDOWHPLQGHVWHQVDOOH9DULDEOHQYRQ:PLWLKUHQ<br />

:HUWHQDP$QIDQJYRQ7'DQQJLOWI UGLH3UR]HGXU7HVW:+,/(DXIJHUXIHQ<br />

PLWGHQ3DUDPHWHUQ%&*+9UZREHLUHLQHORJLVFKH9DULDEOHLVWLQGLH<br />

GLH$XVJDEHGHU3UR]HGXUJHVFKULHEHQZLUG<br />

'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

1DFK%HHQGLJXQJGHU3UR]HGXUJLOWU :$+5<br />

9HQWKlOWPLQGHVWHQVDOOH9DULDEOHQGLHLQ:YRUNRPPHQPLWLKUHQ<br />

:HUWHQDP(QGHYRQ7<br />

Beweis:<br />

(vollständige Induktion über die Schachtelungstiefe D(W))<br />

Induktionsverankerung für D(W) = 1:<br />

Für den Aufruf der Prozedur TestWExpression kann das Lemma 5.4.1<br />

angewendet werden, wonach die Prozedur nach endlicher Zeit terminiert und<br />

der Rückgabewert result' = WAHR zurückgegeben wird. Da die Prozedur<br />

TestWExpression die Variablenliste V nicht verändert, enthält V die Werte<br />

aller Variablen von W zu Beginn der Auswertung H.<br />

Da result' = WAHR wird die Prozedur TestWStatementSequence aufgerufen.<br />

Wegen D(W) = 1 gilt D(H) = 0, somit enthält H weder Zahlkonstanten noch<br />

lokale while-Konstrukte. Somit kann das Lemma 5.4.2 angewendet werden,<br />

wonach für den Aufruf gilt:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

2. Nach Beendigung der Prozedur gilt für den Rückgabewert result' = WAHR.<br />

3. V enthält (mindestens) nach Beendigung der Prozedur alle Variablen, die<br />

in H vorkommen mit ihren Werten am Ende der Auswertung von C.<br />

Da der Ausgabeparameter r den Wert von result' erhält, sind alle<br />

Behauptungen des Lemma beweisen.<br />

Induktionsvoraussetzung:<br />

Sei d∈© + beliebig. Die Behauptungen des Lemma gelten für alle W mit D(W)<br />

≤ d.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Induktionsbehauptung:<br />

Die Behauptungen des Lemma gelten für alle W mit D(W) = d+1.<br />

Induktionsschluß:<br />

Für den Aufruf der Prozedur TestWExpression kann das Lemma 5.4.1<br />

angewendet werden, wonach die Prozedur nach endlicher Zeit terminiert und<br />

der Rückgabewert result' = WAHR zurückgegeben wird. Da die Prozedur<br />

TestWExpression die Variablenliste V nicht verändert, enthält V die Werte<br />

aller Variablen von W zu Beginn der Auswertung H.<br />

Da result' = WAHR, wird die Prozedur TestWStatementSequence aufgerufen.<br />

Für diesen Aufruf kann aber das Lemma 5.4.3 angewendet werden, da die<br />

darin gemachten Aussagen über die Prozedur TestWHILE für while-<br />

Konstrukte mit Schachtelungstiefe d' ≤ d nach der Induktionsvoraussetzung<br />

gelten. Somit gilt:<br />

1. Die Prozedur TestWStatementSequence terminiert nach endlich vielen<br />

Schritten.<br />

2. Nach Beendigung der Prozedur gilt result' = WAHR.<br />

2. V enthält (mindestens) alle Variablen, die in H vorkommen mit ihren<br />

Werten am Ende von C.<br />

Da die Ausgabevariable r den Wert von result' erhält, sind alle<br />

Behauptungen des Lemmas erfüllt.<br />

Das nächste Lemma analysiert das Verhalten der Prozedur MatchWHILE:<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOW6HLHQ:XQG<br />

:]ZHLZKLOH.RQVWUXNWHPLW: with while M do N end whileXQG<br />

: with while M’ do N’ end while'DEHLVHLQHQ0XQG0<br />

$XVGU FNHXQG1XQG1$QZHLVXQJVVHTXHQ]HQ'LH9DULDEOHQYRQ:VWHKHQ<br />

LQGHU9DULDEOHQOLVWH9GLH9DULDEOHQYRQ:VWHKHQLQGHU9DULDEOHQOLVWHQ<<br />

'HU(LQWUDJQHXHU:HUWMHGHU9DULDEOHQDXV


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Beweis:<br />

Zeigen wir zuerst zwei Hilfsbehauptungen:<br />

Hilfsbehauptung 1:<br />

Die erste solange-Schleife wird maximal |M| = |M’| Mal durchlaufen.<br />

Beweis:<br />

Es ist klar, daß |M| = |M'|, da sich M und M' nur in den Namen der<br />

vorkommenden Variablen unterscheiden. Der Lesezeiger L, der über M läuft<br />

steht am Anfang der ersten solange-Schleife (sofern diese überhaupt betreten<br />

wird) vor dem ersten Element von M und wird bei jedem Schleifendurchlauf um<br />

genau ein Element vorgestellt. Dann steht L (sofern die Schleife nicht vorher<br />

beendet wird) nach |M| Schleifendurchläufen hinter dem letztem Element von<br />

M und die Schleife wird beendet. (Hilfsbehauptung 1)<br />

Hilfsbehauptung 2:<br />

Die zweite solange-Schleife wird maximal |N| = |N'| Mal durchlaufen.<br />

Beweis:<br />

Es ist wiederum klar, daß |N| = |N'|. Der Lesezeiger L steht vor dem ersten<br />

Schleifendurchlauf der zweiten solange-Schleife (sofern die Schleife überhaupt<br />

betreten wird) vor dem ersten Element von N und wird bei jedem<br />

Schleifendurchlauf um ein Element vorgestellt. Deshalb steht L nach genau<br />

|M| Schleifendurchläufen hinter dem letzten Element von M, falls jeder<br />

Schleifendurchlauf terminiert und die Schleife nicht vorher beendet wird.<br />

(Hilfsbehauptung 2)<br />

Wenden wir uns jetzt dem Beweis des Lemmas zu:<br />

(vollständige Induktion über die Schachtelungstiefe D(W) = D(W'))<br />

Induktionsverankerung für D(W) = D(W') = 1:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

Wegen D(W) = D(W’) = 1 ist D(N) = D(N’) = 0 und die W und W’ enthalten<br />

keine lokalen while-Konstrukte, also kann der Fall, daß ein while-Konstrukt<br />

als Anweisung gefunden worden ist, nicht auftreten und es finden keine<br />

rekursiven Aufrufe statt. Damit ist klar, daß jeder Schleifendurchlauf nach<br />

einer endlichen Anzahl von Schritten beendet wird. Da nach Hilfsbehauptung<br />

1 und 2 nur endlich viele Schleifendurchläufe auftreten können, ist die<br />

Termination der Prozedur MatchWHILE gesichert.<br />

2. Nach dem Aufruf der Prozedur MatchWHILE hat result den Wert WAHR.<br />

result erhält zu Anfang der Auswertung den Wert WAHR und es existieren<br />

14 Stellen innerhalb der Prozedur, an denen die Variable result den Wert<br />

FALSCH zugewiesen bekommt:<br />

a) falls |M| ≠ |M‘|<br />

b) falls in einem Schleifendurchlauf der ersten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Zeichenkette, Wort oder<br />

Sonderzeichen und t ≠ u.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

c) falls in einem Schleifendurchlauf der ersten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Variable und u ist keine<br />

Variable<br />

d) falls in einem Schleifendurchlauf der ersten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t und u sind Variablen, t ∈ X<br />

und neuer Name von u in Y ist nicht t.<br />

e) falls |N| ≠ |N'|<br />

f) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Zeichenkette, Wort oder<br />

Sonderzeichen und t ≠ u.<br />

g) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Variable und u ist keine<br />

Variable<br />

h) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t und u sind Variablen, neuer<br />

Wert von u ist vorhanden und neuer Name von u in Y ist nicht t.<br />

i) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Inkrement, aber nicht u.<br />

j) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Inkrement einer Variablen<br />

v und u ist Inkrement einer Variablen x und der neue Name von x in Y<br />

ist nicht v.<br />

k) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Dekrement, aber nicht u.<br />

l) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Dekrement einer Variablen<br />

v und u ist Dekrement einer Variablen x und der neue Name von x in Y<br />

ist nicht v.<br />

m)falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist while-Konstrukt, aber<br />

nicht u.<br />

n) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t und u sind while-Konstrukte<br />

und der rekursive Aufruf der Prozedur MatchWHILE liefert als<br />

Ergebnis result' = FALSCH.<br />

Ansonsten wird die Variable result nicht verändert. Wir müssen also jeden<br />

der Fälle a) bis n) widerlegen, um zu beweisen, daß am Ende der Prozedur<br />

die Variable result den Wert WAHR besitzt.<br />

Der Beweis der Hilfsbehauptungen 1 und 2 schließt die Fällt a) und e) aus.<br />

Ebenso können die Fälle m) und n) nicht auftreten, da D(N) = 0.<br />

Widerlegen wir jetzt die Fälle b), c) und d) und formulieren dies als<br />

Hilfsbehauptung.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Hilfsbehauptung 3:<br />

Die Fälle b), c) und d) können nicht eintreten.<br />

Beweis:<br />

Falls M = M' = "" wird die erste solange-Schleife nicht betreten, und keiner<br />

der Fälle b), c) oder d) kann eintreten. Nehmen wir deswegen an, weder M<br />

noch M' seien leer und die Schleife wird betreten.<br />

Da in P keine Zahlkonstanten vorkommen, kann eine Anweisung in M (oder<br />

M') nur eine Zeichenkette, ein Wort, ein Sonderzeichen oder eine Variable<br />

(außerhalb eines Dekrementes oder Inkrementes) sein. Außerdem wissen wir,<br />

daß sich M und M' nur in den Namen der Variablen unterscheiden. Dann<br />

muß auch die i-te Anweisung in M der i-ten Anweisung in M' bis auf die<br />

Namen von Variablen entsprechen (i∈{1,...,|M|}). Da aber in jedem<br />

Schleifendurchlauf genau ein Element t von M und genau ein Element u von<br />

M' gelesen wird, ist klar, daß es ein i gibt, so daß t ist das i-te Element von M<br />

und u ist das i-te Element von M'. Also müssen sich t und u bis aus den<br />

Namen von Variablen entsprechen. Falls also u keine Variable ist, d.h. u ist<br />

Zeichenkette, Wort oder Sonderzeichen, muß gelten t = u, womit der Fall b)<br />

widerlegt ist.<br />

Sei nun t eine Variable, etwa v, so muß auch u eine Variable sein, etwa x (in<br />

Widerspruch zu Fall c)). Es kann aber sein v ≠ x. Dennoch muß für jedes<br />

Vorkommen der Variablen v in M dieselbe Variable x in M' gegenüberstehen.<br />

1. Fall: die Variable v tritt zum ersten Mal in M auf.<br />

Dann gelten die folgenden drei Aussagen:<br />

(1) x hat keinen neuen Wert in Y nach Voraussetzung.<br />

(2) x tritt in M' zum ersten Mal auf.<br />

(3) in jedem bisherigem Vorkommen stand die Variable v der Variablen x<br />

gegenüber.<br />

Folglich stimmen t und u bis auf den Namen der Variablen überein. Man<br />

beachte, daß das Lexem v als neuer Name von x in die Variablenliste Y<br />

eingetragen wird und die Variable v mit dem Anfangs- und Endwert der<br />

Variablen x aus Y in die Variablenliste X eingetragen wird, sofern v nicht in<br />

X enthalten ist. Falls v in X enthalten ist, wird der Endwert von v in X<br />

überschrieben durch den Endwert von x in Y.<br />

2. Fall: die Variable v tritt nicht zum ersten Mal in M auf:<br />

Nach dem 1. Fall muß gelten: x hat in Y einen neuen Namen, etwa v'. Es<br />

muß demnach gelten v' = v und der Fall d) kann nie eintreten.<br />

(Hilfsbehauptung 3)<br />

Wir wissen damit, daß nach Beendigung der ersten solange-Schleife gilt:<br />

result = WAHR. Zu widerlegen bleiben die Fälle f), g), h), i), j), k) und l).<br />

Falls N = "" und damit N' = "", kann keiner dieser Fälle auftreten. Deswegen<br />

nehmen wird an: N ≠ "" und N' ≠ "" und die zweite solange-Schleife wird<br />

betreten.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Da in N und N’ weder Zahlkonstanten noch while-Konstrukte vorkommen,<br />

sind als Anweisungen nur Zeichenketten, Wörter, Sonderzeichen, Variablen,<br />

Inkremente und Dekremente erlaubt. Sei jetzt für einen Schleifendurchlauf t<br />

eine Anweisung aus N und u die Anweisung aus N'. u muß jetzt bis auf den<br />

Namen von Variablen mit t übereinstimmen.<br />

Falls t Zeichenkette, Wort oder Sonderzeichen, so muß gelten t = u, denn<br />

dann enthalten weder u noch t Variablen, wodurch der Fall f) widerlegt ist.<br />

Falls t eine Variable ist, so muß auch u eine Variable sein, in Widerlegung zu<br />

Fall g). Sei etwa t = v und u = x, wobei v ∈V und x ∈Y.<br />

1. Fall: die Variable v kommt nicht in M vor und tritt zum ersten Mal in N<br />

auf.<br />

Dann gelten die folgenden drei Aussagen:<br />

(1) x hat in Y keinen neuen Namen.<br />

(2) x tritt nicht in M' auf und tritt in N' zum ersten Mal auf.<br />

(3) in jedem bisherigem Vorkommen in den while-Konstrukten stand die<br />

Variable v der Variablen x gegenüber.<br />

Folglich stimmen t und u bis auf den Namen der Variablen überein. Man<br />

beachte, daß das Lexem v als neuer Name von x in die Variablenliste Y<br />

eingetragen wird und die Variable v mit dem Anfangs- und Endwert der<br />

Variablen x aus Y in die Variablenliste X eingetragen wird, falls v ∉ X. Falls<br />

v ∈ X, so wird der Endwert von v in X auf den Endwert von x in Y gesetzt.<br />

2. Fall: die Variable v tritt nicht zum ersten Mal in N oder M auf:<br />

Nach dem 1. Fall muß gelten, daß x in Y einen neuen Namen hat, etwa v'. Es<br />

muß demnach gelten v' = v und der Fall h) kann nie eintreten.<br />

Sei nun t ein Inkrement, etwa ++v. Dann muß auch u ein Inkrement sein,<br />

etwa ++x. Dies widerlegt den Fall i). Da in Klasse-I-Programmen das erste<br />

Vorkommen einer Variablen in einem while-Konstrukt innerhalb eines<br />

Inkrementes nicht erlaubt ist, muß die Variable v in M oder N bereits<br />

außerhalb eines Inkrementes oder Dekrementes vorgekommen sein. Dann ist<br />

v in X enthalten und der neue Name von x in Y ist v, womit der Fall j)<br />

widerlegt ist.<br />

Falls t ein Dekrement ist, etwa --v, muß u ebenfalls ein Dekrement sein, etwa<br />

--x. Deswegen kann der Fall k) nicht eintreten. Da in Klasse-I-Programmen<br />

das erste Vorkommen einer Variablen in einem while-Konstrukt innerhalb<br />

eines Dekrementes nicht erlaubt ist, muß die Variable v in M oder N bereits<br />

außerhalb eines Inkrementes oder Dekrementes vorgekommen sein. Also ist<br />

v ∈ X und v ist der neue Name von x in Y in Widerspruch zum Auftreten des<br />

Falles l).<br />

Dadurch ist bewiesen, daß in keinem Fall die Ausgabevariable result den<br />

Wert FALSCH zugewiesen werden kann. Also hat am Ende der Prozedur<br />

result den Wert WAHR.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

3. Jede Variable aus W, die nicht beim Aufruf der Prozedur in X enthalten<br />

ist, wird in X angefügt mit Anfangs- und Endwert der entsprechenden<br />

Variablen aus Y.<br />

Im Beweis von Punkt 2 haben wir gezeigt, daß für jedes erste Vorkommen<br />

einer Variablen v in W, v mit Anfangs- und Endwert der entsprechenden<br />

Variablen x aus Y in die Variablenliste X eingetragen wird, sofern v nicht<br />

bereits in X enthalten gewesen ist. V wird aber nur beim ersten Vorkommen<br />

einer Variablen in W verändert, und zwar wird nur deren Eintrag verändert.<br />

Also wird die Variable v nur eingetragen, wenn v am Anfang der Prozedur<br />

nicht in X enthalten war. Da außerdem jede Variable aus W zum ersten Mal<br />

in W vorkommt, folgt die Behauptung.<br />

4. Der Endwert in X jeder Variable aus W, die in X enthalten ist, wird mit<br />

dem Endwert der entsprechenden Variablen in Y überschrieben.<br />

Unter Punkt 2 sahen wir, daß falls eine Variable v bei ihrem ersten<br />

Vorkommen in W in X bereits enthalten gewesen ist, ihr Endwert mit dem<br />

Endwert der entsprechenden Variablen aus x (in der Variablenliste Y)<br />

überschrieben wird. Außerhalb des Vorkommens der Variablen v wird die<br />

Variable v in V nicht verändert. da jede Variable in W einmal zum ersten Mal<br />

in W vorkommen muß, folgt die Behauptung.<br />

Induktionsvoraussetzung:<br />

Sei nun d ∈© + beliebig und es gelte für den Aufruf der Prozedur<br />

MatchWHILE, wobei D(W) ≤ d:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

2. Nach dem Aufruf hat result den Wert WAHR.<br />

3. Jede Variable aus W, die nicht beim Aufruf der Prozedur in X enthalten<br />

ist, wird in X angefügt mit Anfangs- und Endwert der entsprechenden<br />

Variablen aus Y.<br />

4. Der Endwert in X jeder Variable aus W, die in X enthalten ist, wird mit<br />

dem Endwert der entsprechenden Variablen in Y überschrieben, sofern die<br />

Endwerte nicht bereits übereinstimmen.<br />

Induktionsbehauptung:<br />

Die Behauptungen gelten auch für D(W) = d+1.<br />

Induktionsschluß:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

Betrachten wird zunächst die erste solange-Schleife. Wir stellen als erstes<br />

fest, daß jeder Schleifendurchlauf terminiert. Nach Hilfsbehauptung 1 ist die<br />

Zahl der Schleifendurchläufe durch die Länge von M beschränkt. Also<br />

terminiert die Schleife nach endlicher Schrittzahl, sofern sie überhaupt<br />

betreten wird.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

In der zweiten Schleife ist der endliche Schleifendurchlauf garantiert, falls<br />

die gelesenen Anweisungen Worte, Sonderzeichen, Zeichenketten, Variablen,<br />

Inkremente oder Dekremente sind, da dann kein Prozeduraufruf erfolgt.<br />

Falls die gelesenen Anweisungen t und u while-Konstrukte sind, stellen wir<br />

fest, daß D(t) = D(u) ≤ d. Also kann für den rekursiven Aufruf der Prozedur<br />

matchWHILE die Induktionsvoraussetzung angewandt werde, womit auch in<br />

diesem Fall die Termination des Schleifendurchlaufs gesichert ist. Nach<br />

Hilfsbehauptung 2 werden für die zweite solange-Schleife nur endlich viele<br />

Schleifendurchläufe benötigt, falls die Schleife überhaupt betreten wird, so<br />

daß die Prozedur in jedem Fall nach endlich vielen Schritten beendet ist.<br />

2. Nach dem Aufruf der Prozedur MatchWHILE hat result den Wert WAHR.<br />

result erhält zu Anfang der Auswertung den Wert WAHR und es existieren<br />

14 Stellen innerhalb der Prozedur, an denen die Variable result den Wert<br />

FALSCH zugewiesen bekommt:<br />

a) falls |M| ≠ |M‘|<br />

b) falls in einem Schleifendurchlauf der ersten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Zeichenkette, Wort oder<br />

Sonderzeichen und t ≠ u.<br />

c) falls in einem Schleifendurchlauf der ersten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Variable und u ist keine<br />

Variable<br />

d) falls in einem Schleifendurchlauf der ersten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t und u sind Variablen, t ∈ X<br />

und neuer Name von u in Y ist nicht t.<br />

e) falls |N| ≠ |N'|<br />

f) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Zeichenkette, Wort oder<br />

Sonderzeichen und t ≠ u.<br />

g) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Variable und u ist keine<br />

Variable<br />

h) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t und u sind Variablen, neuer<br />

Wert von u ist vorhanden und neuer Name von u in Y ist nicht t.<br />

i) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Inkrement, aber nicht u.<br />

j) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Inkrement einer Variablen<br />

v und u ist Inkrement einer Variablen x und der neue Name von x in Y<br />

ist nicht v.<br />

k) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Dekrement, aber nicht u.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

l) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist Dekrement einer Variablen<br />

v und u ist Dekrement einer Variablen x und der neue Name von x in Y<br />

ist nicht v.<br />

m)falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t ist while-Konstrukt, aber<br />

nicht u.<br />

n) falls in einem Schleifendurchlauf der zweiten solange-Schleife für die<br />

eingelesenen Anweisungen t und u gilt: t und u sind while-Konstrukte<br />

und der rekursive Aufruf der Prozedur MatchWHILE liefert als<br />

Ergebnis result' = FALSCH.<br />

Ansonsten wird die Variable result nicht verändert. Wir müssen also jeden<br />

der Fälle a) bis n) widerlegen, um zu beweisen, daß am Ende der Prozedur<br />

die Variable result den Wert WAHR besitzt.<br />

Den Fall a) haben wir bereits im Beweis der Hilfsbehauptung 1<br />

ausgeschlossen. Die Fälle b), c) und d) widerlegen wir mit Hilfsbehauptung 3<br />

(der Beweis ist vollkommen analog), und die Widerlegung von Fall e) folgt<br />

aus dem Beweis der Hilfsbehauptung 2.<br />

Wir wissen damit, daß nach Beendigung der ersten solange-Schleife gilt:<br />

result = WAHR. Zu widerlegen bleiben die Fälle f), g), h), i), j), k) und l).<br />

Falls N = "" und damit N' = "", kann keiner dieser Fälle auftreten. Deswegen<br />

nehmen wird an: N ≠ "" und N' ≠ "" und die zweite solange-Schleife wird<br />

betreten. Da in N und N' keine Zahlkonstanten vorkommen, sind als<br />

Anweisungen nur Zeichenketten, Wörter, Sonderzeichen, Variablen,<br />

Inkremente, Dekremente und while-Konstrukte erlaubt.<br />

Sei jetzt für einen Schleifendurchlauf t eine Anweisung aus N und u die<br />

Anweisung aus N'. u muß jetzt bis auf den Name von Variablen mit t<br />

übereinstimmen.<br />

Falls t Zeichenkette, Wort oder Sonderzeichen, so muß gelten t = u, denn<br />

dann enthalten weder u noch t Variablen, wodurch der Fall f) widerlegt ist.<br />

Falls t eine Variable ist, so muß auch u eine Variable sein, in Widerlegung zu<br />

Fall g). Sei etwa t = v und u = x, wobei v ∈V und x ∈Y.<br />

1. Fall: die Variable v kommt nicht in M vor und tritt zum ersten Mal in N<br />

auf.<br />

Dann gelten die folgenden Aussagen:<br />

(1) x hat in Y keinen neuen Namen.<br />

(2) x tritt nicht in M' auf und tritt in N' zum ersten Mal auf.<br />

Diese Aussagen sind jetzt nicht trivial, müssen also bewiesen werden:<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Beweis der Aussage 2:<br />

Annahme: x wäre bereits einmal vorgekommen, etwa in der Anweisung a'.<br />

Dann muß es eine Anweisung a in W geben, die sich von a' nur in dem<br />

Namen der Variablen unterscheidet. Der Name der Variablen kann aber<br />

nicht v sein, da v in der Anweisung t zum ersten Mal vorkommt. Sei also<br />

etwa w die Variable in a. Also sind x und w bis auf den Namen dieselbe<br />

Variable, da u = x ist, müßte demnach t = w sein. Also kann x nicht bereits<br />

vorgekommen sein. (Aussage 1)<br />

Beweis der Aussage 1:<br />

Man beachte bitte, daß bei einem rekursiven Aufruf der Prozedur<br />

MatchWHILE die Variablenliste Y als Eingabeparameter übergeben wird. Y<br />

kann also bei einem rekursiven Aufruf nicht verändert werden. Y wird also<br />

nur an einer Stelle im Programm verändert, nämlich, wenn bei der<br />

Bearbeitung einer Variable y, und zwar wenn ein neuer Name der Variablen<br />

y eingetragen wird. Da aber die Variable v zum ersten Mal in W auftritt,<br />

muß auch die Variable x zum ersten Mal in W' auftreten (nach Aussage 2).<br />

Dann kann kein neuer Name für x eingetragen worden sein. (Aussage 1)<br />

Folglich stimmen t und u bis auf den Namen der Variablen überein. Man<br />

beachte, daß das Lexem v als neuer Name von x in die Variablenliste Y<br />

eingetragen wird und die Variable v mit dem Anfangs- und Endwert der<br />

Variablen x aus Y in die Variablenliste X eingetragen wird, falls v ∉ X. Falls<br />

v ∈ X, so wird der Endwert von v in X auf den Endwert von x in Y gesetzt.<br />

2. Fall: die Variable v tritt nicht zum ersten Mal in N oder M auf:<br />

Dann müssen wir wieder drei Fälle unterscheiden:<br />

(i) die Variable v tritt zum ersten Mal in M auf.<br />

(ii) die Variable v tritt zum ersten Mal in M auf, jedoch nicht innerhalb eines<br />

lokalen while-Konstruktes.<br />

(iii) die Variable v tritt zum ersten Mal in M innerhalb eines lokalen while-<br />

Konstruktes auf.<br />

Im Unterfall (i) haben wir bereits bewiesen, daß die x zugeordnete Variable<br />

in V als neue Name von x in die Variablenliste Y eingetragen ist. Außerdem<br />

wird v in X eingetragen mit Anfangs- und Endwert von x aus Y. Die x<br />

zugeordnete Variable ist aber v, sonst stimmen t und u nicht bis auf den<br />

Namen der Variablen überein. Also kann der Fall h) nicht eintreten.<br />

Für den Unterfall (ii) haben wir im 1. Fall gesehen, daß dann die x<br />

zugeordnete Variable als neuer Name in Y eingetragen wurde. Da v die x<br />

zugeordnete Variable ist, muß v der neue Name von x in Y sein, wodurch der<br />

Fall h) widerlegt ist. Außerdem ist v mit Anfangs- und Endwert von x in Y in<br />

X eingetragen.<br />

Im Unterfall (iii) wissen wir aus der Induktionsvoraussetzung (da<br />

Schachtelungstiefe einer lokalen while-Konstruktes kleiner als D(W) sein<br />

muß, daß die x zugeordnete Variable als neuer Name von x in Y eingetragen<br />

wurde und diese zugeordnete Variable mit Anfangs- und Endwert von x in X<br />

eingefügt wurde. Die x zugeordnete Variable ist aber v, also kann der Fall h)<br />

auch in diesem Unterfall nicht eintreten.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Sei nun t ein Inkrement, etwa ++v. Dann muß auch u ein Inkrement sein,<br />

etwa ++x. Dies widerlegt den Fall i). Da in Klasse-I-Programmen das erste<br />

Vorkommen einer Variablen in einem while-Konstrukt innerhalb eines<br />

Inkrementes nicht erlaubt ist, muß die Variable v in M oder N bereits<br />

außerhalb eines Inkrementes oder Dekrementes vorgekommen sein. Analog<br />

zum 2. Fall bei der Behandlung einer Variablen kann man sich vergewissern,<br />

daß v in X enthalten ist (mit Anfangs- und Endwert von x in Y) und der neue<br />

Name von x in Y v ist, womit der Fall j) widerlegt ist. Dieselbe<br />

Argumentation widerlegt die Fälle k) und l) beim Auftreten von<br />

Dekrementen.<br />

Verbleibt die Möglichkeit, daß t ein while-Konstrukt ist. Dann muß auch u<br />

ein while-Konstrukt sein, denn sonst könnten u und v nicht übereinstimmen.<br />

Also ist der Fall m) ausgeschlossen. Es gelte jetzt für die while-Konstrukte t<br />

und u:<br />

t = with while B do C end while<br />

u = with while B’ do C’ end while<br />

Dabei beachte man, daß Klasse-I-Programme keine lokalen Variablen<br />

besitzen. B und B' sind Ausdrücke und C und C' sind Anweisungssequenzen.<br />

Man beachte, daß D(C) = D(C') < d. Folglich gilt nach<br />

Induktionsvoraussetzung für den rekursiven Aufruf der Prozedur<br />

MatchWHILE.: Die Ausgabevariable result' hat nach Beendigung des<br />

rekursiven Aufrufs dem Wert WAHR, womit auch der Fall n) widerlegt ist.<br />

Dadurch ist bewiesen, daß in keinem Fall die Ausgabevariable result den<br />

Wert FALSCH zugewiesen werden kann. Also hat am Ende der Prozedur<br />

result den Wert WAHR.<br />

3. Jede Variable aus W, die nicht beim Aufruf der Prozedur in X enthalten<br />

ist, wird in X angefügt mit Anfangs- und Endwert der entsprechenden<br />

Variablen aus Y.<br />

Nach Induktionsvoraussetzung wird jede Variable aus einem lokalen while-<br />

Konstrukt von W mit Anfangs- und Endwert der entsprechenden Variablen<br />

aus Y in die Variablenliste X aufgenommen, sofern diese nicht bereits beim<br />

rekursiven Prozeduraufruf in X enthalten gewesen ist. Unter Punkt 2 haben<br />

wir gesehen, daß beim Auftritt einer Variablen v in W außerhalb eines<br />

lokalen while-Konstruktes diese mit Anfangs- und Endwert der<br />

entsprechenden Variablen x aus Y in die Variablenliste Y eingetragen wird,<br />

sofern für die Variable x in Y kein neuer Name eingetragen ist. Dies ist aber<br />

genau beim ersten Vorkommen einer Variablen in W bzw. W' der Fall. Also<br />

wird beim ersten Vorkommen einer Variablen in W, die nicht bereits in V<br />

enthalten ist, diese in die Variablenliste V aufgenommen. Da jede<br />

vorkommende Variable zum ersten Mal vorkommt, ist die Behauptung<br />

bewiesen.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

4. Der Endwert in X jeder Variable aus W, die in X enthalten ist, wird mit<br />

dem Endwert der entsprechenden Variablen in Y überschrieben, sofern die<br />

Endwerte nicht bereits übereinstimmen.<br />

Auch diese Behauptung folgt für den Fall des ersten Vorkommens der<br />

Variablen innerhalb eines lokalen while-Konstruktes von W aus der<br />

Induktionsvoraussetzung. Im Beweis der Behauptung 2 haben wird gesehen,<br />

daß der Endwert einer bereits in X enthalten Variablen v auf den Endwert<br />

der entsprechenden Variablen x aus Y gesetzt wird, wenn für die Variable x<br />

aus Y kein neuer Wert angegeben ist. Dies ist aber dann der Fall, wenn die<br />

Variablen v und x in W und W' erstmalig vorkommen. Da jede vorkommen<br />

Variable einmal zum ersten Mal vorkommen muß, wird der Endwert jeder<br />

beim Aufruf der Prozedur in X enthalte Variable aus W mit dem Endwert der<br />

entsprechenden Variablen in W' überschrieben. Dabei kann es<br />

selbstverständlich vorkommen, daß der Endwert einer Variablen aus X mit<br />

demselben Endwert überschrieben wird, was aber kein Widerspruch zur<br />

Behauptung ist. Auch diese Behauptung ist jetzt bewiesen.<br />

Nach Induktion folgt jetzt die Gültigkeit des Lemmas.<br />

Als nächstes beweisen wir die Korrektheit der Prozedur SampleSequence.<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ66HL:HLQZKLOH.RQVWUXNWLQ:XQG7HLQ<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6'LHHUVWHQEHLGHQWHVW.RQVWUXNWH<br />

YRQ7VHLHQ<br />

WHVWÃ&ÃGRÃ'ÃHQGÃWHVW<br />

WHVWÃ&ÃGRÃ'ÃHQGÃWHVW<br />

'DEHLVHLHQ&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWHGHV$XVGUXFNHVYRQ:<br />

XQG'XQG'%HLVSLHODXVZHUWXQJVIUDJPHQWHGHU$QZHLVXQJVVHTXHQ]YRQ:<br />

6HLHQ9XQG;9DULDEOHQOLVWHQZREHL;OHHULVW'DQQJLOWI UGHQ$XIUXIGHU<br />

3UR]HGXU6DPSOH:([SUHVVLRQPLWGHQ3DUDPHWHUQ&&9;*<br />

'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

&XQG&VLQG%HLVSLHODXVZHUWXQJHQYRQ*<br />

-HGH9DULDEOHLQ*GLHEHLP$XIUXIGHU3UR]HGXUQLFKWLQ9HQWKDOWHQLVW<br />

ZLUGLQ9HLQJHWUDJHQ,KU$QIDQJVZHUWLVWGHU:HUWLKUHVHUVWHQ<br />

$XIWUHWHQVLQ&<br />

$P(QGHGHU3UR]HGXULVWMHGH9DULDEOHYRQ*LQ9HLQJHWUDJHQ,KU<br />

(QGZHUWLVWGHU:HUWLKUHV$XIWUHWHQVLQ&<br />

-HGH9DULDEOHLQ*ZLUGLQ;HLQJHWUDJHQ,KU$QIDQJVZHUWXQGLKU<br />

(QGZHUWLVWGHU:HUWLKUHV$XIWUHWHQVLQ&<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Beweis:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

Klar ist, daß |C| = |C'|. Falls C = "", wird die Prozedur sofort beendet. Nehmen<br />

wir also an m = |C| = |C'| > 0. In diesem Fall wird die solange-Schleife<br />

betreten und spätestens dann verlassen, wenn die Lesezeiger am Ende von C<br />

und C' stehen. Da vor dem ersten Schleifendurchlauf diese vor der ersten<br />

Anweisung des Ausdrucks stehen und beide Lesezeiger um je ein Element<br />

vorgezogen werden, terminiert die Schleife nach m Schleifendurchläufen. Da<br />

außerdem jeder Schleifendurchlauf in endlicher Zeit beendet ist, ist auch die<br />

Prozedur nach endlich vielen Schritten beendet.<br />

2. C und C' sind Beispielauswertungen von G<br />

C und C' dürfen nur Zeichenketten, Wörter, Sonderzeichen und Zahlen<br />

enthalten. Unter Punkt 1 haben wir gesehen, daß in der solange-Schleife in<br />

jedem Schleifendurchlauf je ein Element von C und C' gelesen wird, und zwar<br />

vom ersten Element bis zum letzten Element. Außerdem ist sofort zu sehen, daß<br />

in jedem Schleifendurchlauf G um ein Element ergänzt wird. Da G vor dem<br />

ersten Schleifendurchlauf kein Element enthält, wissen wir, daß |G| = |C| =<br />

|C'|, sofern die Prozedur nicht infolge eines Fehlers verlassen wird. Deswegen<br />

wollen wir als nächstes zeigen, daß der Fehlerfall nicht auftreten kann.<br />

Es gibt in der Prozedur SampleWExpression vier Stellen, an denen der<br />

Algorithmus abgebrochen werden kann.<br />

a) wenn in einem Schleifendurchlauf das von C eingelesene Element t ein Wort,<br />

eine Zeichenkette oder ein Sonderzeichen ist und ungleich dem von C'<br />

eingelesenem Element u.<br />

b) wenn in einem Schleifendurchlauf das von C eingelesene Element t eine Zahl<br />

ist und das von C' eingelesen Element u nicht.<br />

c) wenn C ein Element ungleich einem Sonderzeichen, einer Zeichenkette,<br />

einem Wort oder einer Zahl enthält.<br />

d) wenn |C| ≠ |C'|.<br />

Nach unseren Vorbemerkungen können wir die Fälle c) und d) sofort<br />

ausschließen. Sei jetzt ai für ein i ∈ {1,..,|C|} die i-te Anweisung im Ausdruck<br />

von W. Dann werden im i-ten Schleifendurchlauf die<br />

Beispielauswertungsfragmente t und u von ai gelesen. ai kann jetzt<br />

Sonderzeichen, Zeichenkette, Wort oder Variable sein, da P keine<br />

Zahlkonstanten enthält. Falls ai ist Sonderzeichen, Zeichenkette oder Wort,<br />

muß gelten t = ai und u = ai. Also ist der Fall a) widerlegt. Falls ai eine Variable,<br />

so müssen sowohl t als auch u Zahlen sein, womit auch der Fall b) nicht<br />

zutreffen kann.<br />

G enthält nur Zeichenketten, Sonderzeichen, Wörter und Variablen. Wir müssen<br />

nun zeigen, daß für jedes i ∈ {1,..,|G|} die i-ten Elemente ci und ci' von C und C'<br />

Beispielauswertungsfragmente des i-ten Elementes von G sind.<br />

Sei also i beliebig und gi ist Sonderzeichen, Wort oder Zeichenkette. Dann muß<br />

gelten: ci = ci' = gi. Aus obigen Überlegungen wissen wir bereits daß ci und ci' im<br />

i-ten Schleifendurchlauf gelesen werden, und daß gilt ci = ci'. Dann wird aber ci<br />

als i-tes Element von G angefügt. Also gilt gi = ci = ci'.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Falls gi ist eine Variable, so müssen ci und ci' Zahlen sein, und es muß gelten ci =<br />

val(gi,j,E) und ci' = val(gi,k,E). Dabei sei E eine Entfaltung und j und k die<br />

Nummern des Auftretens von gi an der Stelle ci und ci'. Da P keine<br />

Zahlkonstanten enthält, müssen aber ci und ci' Werte einer Variablen von P<br />

sein, etwa der Variablen x. Als i-tes Element von G wird aber gerade eine<br />

Variable angefügt, deren Wert gerade dem von x entspricht. Also sind ci und ci'<br />

Beispielauswertungsfragmente von gi.<br />

Sei P jetzt das Programm, dessen Hauptanweisungsteil G ist und in dessen<br />

Hauptinitialisationssequenz die Variablen von G mit ihren Anfangswerten zu<br />

Beginn der Auswertung von G initialisiert werden. Die Ein- und Ausgaben von<br />

P sind unerheblich. Es ist klar, daß G ein Programmfragment von P ist und daß<br />

C ein Beispielauswertungsfragment einer Auswertung von P ist. Also ist C eine<br />

Beispielauswertung von G. Die analoge Argumentation gilt auch für C'.<br />

3. Jede Variable in G, die beim Aufruf der Prozedur nicht in V enthalten ist,<br />

wird in V eingetragen. Ihr Anfangswert ist der Wert ihres ersten Auftretens<br />

in C.<br />

Sei v eine Variable in G und i die Nummer des ersten Vorkommens von v in G.<br />

Also wurde v im i-ten Schleifendurchlauf an G angefügt. Sei c ihr Wert in C.<br />

Das i-te Element von C muß also c sein. Falls v beim Aufruf der Prozedur in V<br />

enthalten ist, so muß eine Variable in V existieren mit Endwert c, nämlich v.<br />

Falls also keine solche Variable existiert, so kann v nicht in V enthalten sein. In<br />

diesem Fall wird aber v in V eingetragen. Ihr Anfangswert ist der Wert c.<br />

4. Am Ende der Prozedur ist jede Variable von G in V eingetragen. Ihr Endwert<br />

ist der Wert ihres Auftretens in C.<br />

Im Punkt 3 haben wir gezeigt, daß jede Variable v ∈ G, die zu Beginn der<br />

Prozedur nicht in V eingetragen ist, in V eingetragen wird. Bei diesem Eintrag<br />

wird der Wert von v in der Auswertung C als Endwert eingetragen. Sei nun v ∈<br />

G, wobei v bereits zu Beginn der Prozedur in V enthalten ist. In diesem Fall<br />

muß aber der Endwert von v in v mit dem Wert von v in C übereinstimmen, da<br />

dieser sich innerhalb eines Ausdrucks nicht ändern kann.<br />

5. Jede Variable in G wird in X eingetragen. Ihr Anfangswert und ihr Endwert<br />

ist der Wert ihres Auftretens in C'.<br />

Sei v eine Variable in G. Da X am Anfang der Prozedur leer, gilt zu Beginn der<br />

Prozedur: v ∉ X. Sei i die Nummer des ersten Vorkommens von v in G. Dann<br />

wurde v im i-ten Schleifendurchlauf an G angefügt. Sei c der Wert von v in C<br />

und c' der Wert von v in C', so ist das i-te Element von C gleich c und das i-te<br />

Element von C' gleich c'.<br />

1. Fall: v ist zu Beginn der Prozedur in V enthalten.<br />

Da v ∉ X (v wurde nicht in den ersten (i-1) Programmläufen in X eingetragen),<br />

wird jetzt v mit Anfangs- und Endwert c' in X eingetragen.<br />

2. Fall: v ist zu Beginn der Prozedur nicht in V enthalten.<br />

Auch in diesem Fall wird v mit Anfangs- und Endwert c' in X eingetragen.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ36HL:HLQZKLOH.RQVWUXNWHLQ3GHU)RUP<br />

ZLWKÃZKLOHÃ$ÃGRÃ%ÃHQGÃZKLOHÃ$$XVGUXFNXQG%$QZHLVXQJVVHTXHQ]<br />

XQGVHL7HLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6'LHHUVWHQEHLGHQ<br />

WHVW.RQVWUXNWHYRQ7VHLHQ<br />

WHVWÃ&ÃGRÃ'ÃHQGÃWHVW<br />

WHVWÃ&ÃGRÃ'ÃHQGÃWHVW<br />

'DEHLVLQG&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ$XQG'XQG'<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ%'LH9DULDEOHQOLVWH9HQWKDOWHDOOHLQ3<br />

YRUGHU$XVZHUWXQJ7DXIJHWUHWHQHQ9DULDEOHQPLWLKUHQ$QIDQJVXQG<br />

(QGZHUWHQYRUGHU$XVZHUWXQJGHVHUVWHQ(OHPHQWHVYRQ&'LH<br />

9DULDEOHQOLVWH;VHLOHHU'HU$XIUXIGHU3UR]HGXUVDPSOH:([SUHVVLRQPLW<br />

GHQ3DUDPHWHUQ&&9;*WHUPLQLHUHQDFKHQGOLFKYLHOHQ6FKULWWHQXQG<br />

OLHIHUHDOV$XVJDEHHLQHQ$XVGUXFN*'DQQH[LVWLHUWHLQH<br />

9DULDEOHQXPEHQHQQXQJσVRGD‰$ *σ<br />

Beweis:<br />

Nach Lemma 5.4.6 wissen wir, daß der Aufruf der Prozedur sampleWExpression<br />

nach endlich vielen Schritten terminiert und einen Ausdruck G liefert. Dabei<br />

sind C und C' Beispielauswertungsfragmente von A und von G. Weder A noch G<br />

enthalten Zahlkonstanten, somit können beide nur Sonderzeichen, Wörter,<br />

Zeichenketten oder Variable enthalten. Es ist klar, daß |G| = |A|. Sei für ein i<br />

∈ {1,..,|A|} gi das i-te Element von G, ai das i-te Element von A ci das i-te<br />

Element von C und c'i das i-te Element von C'. Falls gi Zeichenkette,<br />

Sonderzeichen oder Wort, muß gelten ci = c'i = gi. Somit muß auch gelten ai = gi,<br />

sonst könnten ci und c'i nicht Beispielauswertungsfragmente von ai sein<br />

(dieselbe Überlegung gilt auch umgekehrt). Sei also gi eine Variable, so muß<br />

auch ai eine Variable sein. Sei j die Position des ersten Auftretens von gi in G<br />

und k die Position des ersten Auftretens von ai in A. Wir müssen als erstes<br />

zeigen, daß k = j.<br />

Sei c der Wert von gi in C und c' der Wert von gi in C'. Sei e der Wert von ai in C<br />

und e' der Wert von ai in C'. Es ist klar, daß c = e = ci und c' = e' = c'i. Es gilt<br />

demnach cj = c = e = ck. Sei aj die Variable an der j-ten Position von A und gk die<br />

Variable an der k-ten Position von G. Dann wissen wir, daß aj, gk, ai und gi in C<br />

den Wert c = e und in C' den Wert c' = e' haben. Da in Klasse-I-Programmen in<br />

einem while-Konstrukt keine zwei verschiedenen Variablen vorkommen dürfen,<br />

deren Wert in den ersten beiden Entfaltungen identisch ist, muß gelten aj = ai.<br />

Da k die Position des ersten Vorkommens von ai in A ist, muß gelten j ≥ k.<br />

Nehmen wir jetzt an, es gelte j > k. Dann gilt gk ≠ gi, denn das erste Vorkommen<br />

von gi ist an der Position j. Wir wissen, daß in der Prozedur sampleWExpression<br />

nach dem k-ten Schleifendurchlauf die Variable gk in V und X eingetragen ist<br />

mit den Endwerten c und c'. Dann wird aber im j-ten Schleifendurchlauf eine<br />

Variable in V mit dem Wert c = ci und in X mit dem Wert c' = c'i gefunden,<br />

nämlich die Variable gk und wird als j-tes Element von G angefügt. Also kann gi<br />

nicht j-tes Element von G sein im Widerspruch zur Annahme, daß j die Position<br />

des ersten Vorkommens der Variablen gi sei. Also muß die Annahme j > k falsch<br />

sein und es ist bewiesen, daß j = k.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Dann ist das j-te Element von C gleich c und das j-te Element von C’ gleich c’.<br />

Falls gi zu Beginn der Prozedur in V enthalten ist, gilt gi = ai, da V alle in P<br />

vorkommenden Variablen vor der Stelle der Auswertung T enthält. Sei also gi<br />

eine Variable, die zu Beginn der Prozedur nicht in V enthalten ist. Dann gilt im<br />

allgemeinen gi ≠ ai, allerdings stimmen die Werte der Variablen in C und C'<br />

überein. Sei nun m eine weitere Position eines Vorkommens von gi in G. Dann<br />

muß das m-te Element von C der Wert c sein und das i-te Element von C' der<br />

Wert c' sein. Da in Klasse-I-Programmen keine zwei Variablen in einem<br />

Ausdruck erlaubt sind, die in den ersten beiden Entfaltungen in ihren Werten<br />

übereinstimmen, muß ai das m-te Element von A sein. Umgekehrt, falls n die<br />

Position eines weiteren Vorkommens von ai in A ist, wissen wir, daß die n-ten<br />

Elemente in C und C' gerade c und c' sind. Es ist aber eine Variable in den<br />

Variablenlisten V und X zu Beginn des n-ten Schleifendurchlaufs in der<br />

Prozedur enthalten, nämlich die Variable gi. Also wird gi das m-te Element von<br />

G. Damit wissen wir, daß für jedes n∈ {1,..,|A|} gilt: Das n-te Element von A ist<br />

die Variable ai genau dann, wenn das n-te Element von g ist die Variable gi für<br />

jede Variable in A und G.<br />

Definieren wir nun σ so, daß jede Variable gi zu der zugehörigen Variablen ai<br />

zugeordnet wird, folgt die Behauptung.<br />

Wenden wir uns nun der Prozedur SampleWSequence zu. Zunächst betrachten wir den<br />

vereinfachten Fall, daß die Anweisungssequenz keine lokalen while-Konstrukte enthält.<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ66HL:HLQZKLOH.RQVWUXNWLQ:PLWG: XQG<br />

7HLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6'LHHUVWHQEHLGHQWHVW<br />

.RQVWUXNWHYRQ7VHLHQ<br />

test C do D end test<br />

test C’ do D’ end test<br />

'DEHLVHLHQ&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWHGHV$XVGUXFNHVYRQ:<br />

XQG'XQG'%HLVSLHODXVZHUWXQJVIUDJPHQWHGHU$QZHLVXQJVVHTXHQ]YRQ:<br />

6HLHQ9XQG;9DULDEOHQOLVWHQ) UMHGH9DULDEOHYLP$XVGUXFNYRQ:<br />

H[LVWLHUWHLQH9DULDEOH[LQ9XQG;VRGD‰GHU(QGZHUWYRQ[LQ9LVWGHU<br />

:HUWYRQYLQ&XQGGHU(QGZHUWYRQ[LQ;LVWGHU:HUWYRQYLQ&'DQQ<br />

JLOWI UGHQ$XIUXIGHU3UR]HGXU6DPSOH:6WDWHPHQW6HTXHQFHPLWGHQ<br />

3DUDPHWHUQ''9;+<br />

'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

'XQG'VLQG%HLVSLHODXVZHUWXQJHQYRQ+<br />

-HGH9DULDEOHLQ+GLHEHLP$XIUXIGHU3UR]HGXUQLFKWLQ9HQWKDOWHQLVW<br />

ZLUGLQ9HLQJHWUDJHQ,KU$QIDQJVZHUWLVWGHU:HUWLKUHVHUVWHQ<br />

$XIWUHWHQVLQ'<br />

$P(QGHGHU3UR]HGXULVWMHGH9DULDEOHYRQ+LQ9HLQJHWUDJHQ,KU<br />

(QGZHUWLVWGHU:HUWLKUHVOHW]WHQ$XIWUHWHQVLQ'<br />

-HGH9DULDEOHLQ+GLHEHLP$XIUXIGHU3UR]HGXUQLFKWLQ;HQWKDOWHQLVW<br />

ZLUGLQ;HLQJHWUDJHQ,KU$QIDQJVZHUWLVWGHU:HUWLKUHVHUVWHQ<br />

$XIWUHWHQVLQ'<br />

$P(QGHGHU3UR]HGXULVWMHGH9DULDEOHYRQ+LQ;HLQJHWUDJHQ,KU<br />

(QGZHUWLVWGHU:HUWLKUHVOHW]WHQ$XIWUHWHQVLQ'<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Beweis:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

W enthält keine lokalen while-Konstrukte. Daraus folgt, daß |D| = |D'|, da<br />

jede Anweisung der Anweisungssequenz in genau eine Anweisung des<br />

Beispielauswertungsfragmentes überführt wird. Falls D = "", wird die Prozedur<br />

sofort beendet. Nehmen wir also an m = |D| = |D'| > 0. In diesem Fall wird die<br />

solange-Schleife betreten und spätestens dann verlassen, wenn die Lesezeiger<br />

am Ende von D und D' stehen. Da vor dem ersten Schleifendurchlauf diese vor<br />

der ersten Anweisung der Anweisungssequenz stehen und beide Lesezeiger um<br />

je ein Element vorgezogen werden, terminiert die Schleife nach m<br />

Schleifendurchläufen. Da außerdem jeder Schleifendurchlauf in endlicher Zeit<br />

beendet ist, ist auch die Prozedur nach endlich vielen Schritten beendet.<br />

2. D und D' sind Beispielauswertungen von H.<br />

D und D' dürfen nur Zeichenketten, Wörter, Sonderzeichen und Zahlen<br />

enthalten. Unter Punkt 1 haben wir gesehen, daß in der solange-Schleife in<br />

jedem Schleifendurchlauf je ein Element von D und D' gelesen wird, und zwar<br />

vom ersten Element bis zum letzten Element. Außerdem ist sofort zu sehen, daß<br />

in jedem Schleifendurchlauf H um genau ein Element ergänzt wird. Da H vor<br />

dem ersten Schleifendurchlauf kein Element enthält, wissen wir, daß |H| =<br />

|D| = |D'|, sofern die Prozedur nicht infolge eines Fehlers verlassen wird.<br />

Deswegen wollen wir als nächstes zeigen, daß der Fehlerfall nicht auftreten<br />

kann.<br />

Es gibt in der Prozedur SampleWExpression vier Stellen, an denen der<br />

Algorithmus abgebrochen werden kann.<br />

a) wenn in einem Schleifendurchlauf das von D eingelesene Element t ein Wort,<br />

eine Zeichenkette oder ein Sonderzeichen ist und ungleich dem von D'<br />

eingelesenem Element u.<br />

b) wenn in einem Schleifendurchlauf das von D eingelesene Element t eine Zahl<br />

ist und das von D' eingelesen Element u nicht.<br />

c) wenn D ein Element ungleich einem Sonderzeichen, einer Zeichenkette,<br />

einem Wort oder einer Zahl enthält.<br />

d) wenn |D| ≠ |D'|.<br />

Nach unseren Vorbemerkungen können wir die Fälle c) und d) sofort<br />

ausschließen. Sei jetzt ai für ein i ∈ {1,..,|D|} die i-te Anweisung im Ausdruck<br />

von W. Dann werden im i-ten Schleifendurchlauf die<br />

Beispielauswertungsfragmente t und u von ai gelesen. ai kann jetzt<br />

Sonderzeichen, Zeichenkette, Wort oder Variable sein, da P keine<br />

Zahlkonstanten enthält. Falls ai ist Sonderzeichen, Zeichenkette oder Wort,<br />

muß gelten t = ai und u = ai. Also ist der Fall a) widerlegt. Falls ai eine Variable,<br />

so müssen sowohl t als auch u Zahlen sein, womit auch der Fall b) nicht<br />

zutreffen kann.<br />

H enthält nur Zeichenketten, Sonderzeichen, Wörter, Variablen, Inkremente<br />

und Dekremente. Wir müssen nun zeigen, daß für jedes i ∈ {1,..,|H|} die i-ten<br />

Elemente di und di' von D und D' Beispielauswertungsfragmente des i-ten<br />

Elementes hi von H sind. Sei also i beliebig.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

1. Fall: hi ist Sonderzeichen, Wort oder Zeichenfolge:<br />

Aus obigen Überlegungen wissen wir bereits daß di und di' im i-ten<br />

Schleifendurchlauf gelesen werden, und daß gilt di = di'. Dann wird aber di als i-<br />

tes Element von H angefügt. Also gilt hi = di = di'. Also sind di und d'i<br />

Beispielauswertungsfragmente von hi.<br />

2. Fall: hi ist Variable:<br />

Da im i-ten Schritt eine Variable in H angefügt worden ist, müssen sowohl di als<br />

auch d'i Zahlen sein. Da P keine Zahlkonstanten enthält, müssen aber di und di'<br />

Werte einer Variablen von P sein, etwa der Variablen x, die aber auch in einem<br />

Inkrement oder einem Dekrement vorkommen kann. Schauen wir uns diese<br />

Möglichkeiten an:<br />

a) x steht nicht innerhalb eines Inkrementes oder Dekrementes und x kommt<br />

nicht zum erstenmal in W vor.<br />

b) x steht nicht innerhalb eines Inkrementes oder Dekrementes und x kommt<br />

zum erstenmal in W vor.<br />

c) x steht innerhalb eines Inkrementes (dann muß x schon einmal in W<br />

vorgekommen sein)<br />

d) x steht innerhalb eines Dekrementes (dann muß x schon einmal in W<br />

vorgekommen sein)<br />

Wenden wir uns zuerst dem Punkt b) zu. In diesem Fall kann es keine Variable<br />

v∈V, v∈X geben, so daß der Endwert von v in V im i-ten Schleifendurchlauf<br />

entspricht di und der Endwert von v in X entspricht di'.<br />

Beweis: (indirekt)<br />

Annahme, es gebe eine solche Variable v in den Variablenlisten. Dann muß es<br />

aber eine Variable y in W geben, deren Beispielauswertungen an einer Stelle in<br />

C/C' oder D/D' gleich di oder di' sind, denn sonst würden die Werte di und di'<br />

nicht als Endwerte einer Variablen in V und X aufgenommen . Es kann aber<br />

keine zwei Variablen in einem Klasse-I-Programm geben, deren Differenz der<br />

Werte in zwei Entfaltungen desselben while-Konstruktes gleich sind. Also muß<br />

gelten y = x im Widerspruch zur Annahme, x käme an der Stelle i zum<br />

erstenmal in W vor.<br />

Die analoge Argumentation verbietet auch das Vorkommen einer Variablen<br />

v∈V, v∈X geben, so daß der Endwert von v in V im i-ten Schleifendurchlauf<br />

entspricht di-1 und der Endwert von v in X entspricht di'-1, bzw. der Endwert<br />

von v in V im i-ten Schleifendurchlauf entspricht di+1 und der Endwert von v in<br />

X entspricht di'+1.<br />

Es kann jetzt sein, daß eine Variable v in V existiert, deren Endwert di ist. Dann<br />

wird die Variable v auch in X eingetragen mit Anfangs- und Endwert v.<br />

Ansonsten wird eine neue Variable generiert (etwa v) und mit Anfangs- und<br />

Endwert di und di' in V und X eingetragen. Es gilt dann hi = v. Damit sind aber<br />

di und di' Beispielauswertungsfragmente von hi (falls V und X tatsächlich die<br />

Werte der Variablen in H repräsentieren).<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Damit die Fälle a), c) oder d) auftreten können, muß x wie in Fall b) in W<br />

vorgekommen sein. Annahme: Das erste Vorkommen von x geschieht im<br />

Ausdruck von W. Dann wissen wir nach Voraussetzung des Lemmas, daß in den<br />

Variablenlisten V und X eine Variable, etwa v, enthalten ist, deren Wert im<br />

Ausdruck dem Wert von x entspricht. Wenn aber das erste Vorkommen von x in<br />

der Anweisungssequenz von W liegt, wissen wir aus der Behandlung von b), daß<br />

es eine Variable, etwa v, in V und X gibt, deren Wert an der Stelle des ersten<br />

Vorkommens von x mit dem Wert von x übereinstimmt.<br />

Wir zeigen jetzt induktiv, daß der Wert von v auch an den Stellen des weiteren<br />

Vorkommens der Variablen x übereinstimmt.<br />

Annahme: Die Endwerte der Variablen v in V und X beim m-ten Vorkommen<br />

der Variablen x in W entsprechen den Werten der Variablen x bei ihrem m-ten<br />

Vorkommen in den Auswertungen D und D'.<br />

Betrachten wir jetzt das (m+1)-te Vorkommen der Variablen x. Es ist klar, daß<br />

zwischen zwei Vorkommen die Endwerte der Variablen v in V und X nicht<br />

verändert werden konnten. Falls dies geschehen wäre, müßte es eine Variable y<br />

≠ x geben, deren Differenz der Werte in D und D' gleich der Differenz der Werte<br />

von x in D und D' entspricht, was aber in Klasse-I-Programmen nicht der Fall<br />

ist.<br />

Das (m+1)-te Vorkommen von x sei (wie in Fall a) außerhalb eines Inkrementes<br />

oder Dekrementes. Dann wird der Wert von v (ebenso wie der Wert von x) nicht<br />

verändert.<br />

Wenn das (m+1)-te Vorkommen von x innerhalb eines Inkrementes liegt, so<br />

wird der Wert von x um 1 erhöht. Sei e der Wert von x in D und e' der Wert von<br />

x in D'. Wir wissen, es existiert eine Variable v in V und X mit den Endwerten e-<br />

1 und e'-1. Gleichzeitig wissen wir, daß es keine Variable in V und X mit den<br />

Endwerten e und e' gibt, denn wenn dies der Fall wäre, müßte es eine Variablen<br />

in W ungleich x geben, Differenz der Werte in D und D' gleich der Differenz der<br />

Werte von x ist. Dies ist aber in P nicht möglich. Also wird gi gesetzt auf ++v<br />

und der Wert von v wird in V und X auf e und e' gesetzt.<br />

Die letzte Möglichkeit ist das Vorkommen von x in einem Dekrement. Seien e<br />

und e' die Werte von x in D und D' vor dem Dekrement und f und f' die Werte<br />

von c in D und D' beim Auftreten des Dekrementes. Dann wissen wir, daß in<br />

Klasse-I-Programmen immer gilt: f < e und f' < e'. Gleichzeitig wissen wir aus<br />

der Induktionsvoraussetzung, daß die Variablen v in V und X die Werte e und e'<br />

besitzt. Es kann keine zweite Variable in W vorkommen, deren Differenz ihres<br />

Wertes in D und D' gleich der Differenz des Wertes von x sein kann. Also wissen<br />

wir auch, daß V und X keine Variable enthalten mit den Werten f und f', sowie f-<br />

1 und f'-1. Also wird in H das Dekrement --v eingetragen und die Werte von v in<br />

V und X auf f und f' erniedrigt.<br />

Aus obiger Überlegung sehen wir, daß für den Fall a) hi = v ist, wobei der Wert<br />

von v in V gleich di und der Wert von v in X gleich di' ist. Somit sind di und di'<br />

Beispielauswertungsfragmente von hi.<br />

Die Fälle c) und d) können nicht eintreten, da dann der Wert von v nicht mit<br />

dem Wert von x übereinstimmt.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

3. Fall : hi ist Inkrement:<br />

Dann müssen di und d'i Zahlen sein, nämlich die Werte einer Variablen<br />

(eventuell in einem Dekrement oder Inkrement). Sei x diese Variable. Dann<br />

liefert uns die Überlegungen aus dem 2. Fall die Aussage, daß eine Variable<br />

(etwa v) in V und X existiert, deren Wert an der Stelle i gleich dem Wert von x<br />

an der Stelle i ist, also ist der Wert von v in D gleich di und in D' gleich di'. Also<br />

sind di und di' Beispielauswertungsfragmente von hi. Da v in einen Inkrement<br />

vorkommt, muß auch x in einem Inkrement vorkommen.<br />

4. Fall: hi ist Dekrement:<br />

Dann müssen di und d'i Zahlen sein, nämlich die Werte einer Variablen<br />

(eventuell in einem Dekrement oder Inkrement). Sei x diese Variable. Dann<br />

liefert uns die Überlegungen aus dem 2. Fall die Aussage, daß eine Variable<br />

(etwa v) in V und X existiert, deren Wert an der Stelle i gleich dem Wert von x<br />

an der Stelle i ist, also ist der Wert von v in D gleich di und in D' gleich di'. Also<br />

sind di und di' Beispielauswertungsfragmente von hi. Da v in einem Dekrement<br />

vorkommt, muß auch x in einem Dekrement vorkommen.<br />

Wir haben jetzt gezeigt, daß in jedem Fall di und di'<br />

Beispielauswertungsfragmente von hi sind. Sei P jetzt das Programm, dessen<br />

Hauptanweisungsteil H ist und in dessen Hauptinitialisationssequenz die<br />

Variablen von H mit ihren Anfangswerten zu Beginn der Auswertung von H<br />

initialisiert werden. Die Ein- und Ausgaben von P sind unerheblich. Es ist klar,<br />

daß H ein Programmfragment von P ist und daß D ein<br />

Beispielauswertungsfragment einer Auswertung von P ist. Also ist D eine<br />

Beispielauswertung von H. Die analoge Argumentation gilt auch für D'.<br />

3. Jede Variable in H, die beim Aufruf der Prozedur nicht in V enthalten ist,<br />

wird in V eingetragen. Ihr Anfangswert ist der Wert ihres ersten Auftretens<br />

in D.<br />

Sei v eine Variable in H und i die Nummer des ersten Vorkommens von v in H.<br />

Dieses erste Vorkommen darf nicht innerhalb eines Inkrementes oder<br />

Dekrementes sein. v wurde im i-ten Schleifendurchlauf an H angefügt. Sei d ihr<br />

Wert in D. Das i-te Element von D muß also d sein. Falls v beim Aufruf der<br />

Prozedur in V enthalten ist, so muß eine Variable in V existieren mit Endwert d,<br />

nämlich v. Falls also keine solche Variable existiert, so kann v nicht in V<br />

enthalten sein. In diesem Fall wird aber v in V eingetragen. Ihr Anfangswert ist<br />

der Wert d.<br />

4. Am Ende der Prozedur ist jede Variable von H in V eingetragen. Ihr Endwert<br />

ist der Wert ihres letzten Auftretens in D.<br />

Im Punkt 3 haben wir gezeigt, daß jede Variable v ∈ H, die zu Beginn der<br />

Prozedur nicht in V eingetragen ist, in V eingetragen wird. Bei diesem Eintrag<br />

wird der Wert von v in der Auswertung D als Endwert eingetragen. Es ist damit<br />

klar, daß am Ende der Prozedur jede Variablen von H in V eingetragen ist.<br />

Wir zeigen jetzt, daß der Wert von v in der Auswertung D mit dem Endwert von<br />

v in der Variablenliste V übereinstimmt. Der Wert von v bei der Auswertung<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

kann nur aus zwei Gründen geändert werden: a) v kommt in einem Inkrement<br />

vor. b) v kommt in einem Dekrement vor. Immer aber, wenn ++v oder --v in h<br />

eingetragen wird, wird der Wert von v in V auf den neuen Wert der Variablen<br />

gesetzt. Da der Wert von v in V ansonsten nicht verändert wird, gilt die<br />

Behauptung auch für den letzten Wert von v in D.<br />

5. Jede Variable in H, die beim Aufruf der Prozedur nicht in X enthalten ist,<br />

wird in X eingetragen. Ihr Anfangswert ist der Wert ihres ersten Auftretens<br />

in D'.<br />

und<br />

6. Am Ende der Prozedur ist jede Variable von H in X eingetragen. Ihr Endwert<br />

ist der Wert ihres letzten Auftretens in D'.<br />

Der Beweis dieser Aussagen verläuft vollkommen analog zum Beweis der<br />

Punkte 3 und 4.<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ36HL:HLQZKLOH.RQVWUXNWHLQ3GHU)RUP<br />

with while A do B end while ($$XVGUXFNXQG%<br />

$QZHLVXQJVVHTXHQ]<br />

'DEHLHQWKDOWH%NHLQHORNDOHQZKLOH.RQVWUXNWH<br />

(VVHL7HLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6'LHHUVWHQEHLGHQWHVW<br />

.RQVWUXNWHYRQ7VHLHQ<br />

test C do D end test<br />

test C’ do D’ end test<br />

'DEHLVLQG&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ$XQG'XQG'<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ%'LH9DULDEOHQOLVWH9HQWKDOWHDOOHLQ3<br />

YRUGHU$XVZHUWXQJ7DXIJHWUHWHQHQ9DULDEOHQPLWLKUHQ$QIDQJVXQG<br />

(QGZHUWHQYRUGHU$XVZHUWXQJGHVHUVWHQ(OHPHQWHVYRQ') UMHGH<br />

9DULDEOHYLP$XVGUXFNYRQ:H[LVWLHUWHLQH9DULDEOH[LQ9XQG;VRGD‰<br />

GHU(QGZHUWYRQ[LQ9LVWGHU:HUWYRQYLQ&XQGGHU(QGZHUWYRQ[LQ;LVW<br />

GHU:HUWYRQYLQ&'HU$XIUXIGHU3UR]HGXUVDPSOH:6WDWHPHQW6HTXHQFH<br />

PLWGHQ3DUDPHWHUQ''9;+WHUPLQLHUHQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

XQGOLHIHUHDOV$XVJDEHHLQHQ$XVGUXFN+'DQQH[LVWLHUWHLQH<br />

9DULDEOHQXPEHQHQQXQJσVRGD‰% +σ<br />

Beweis:<br />

Nach Lemma 5.4.8 wissen wir, daß der Aufruf der Prozedur<br />

sampleWStatementSequence nach endlich vielen Schritten terminiert und eine<br />

Anweisungssequenz H liefert. Dabei sind D und D'<br />

Beispielauswertungsfragmente von B und von H.<br />

Klar ist, daß |B| = |H| und daß weder B noch H while-Konstrukte und<br />

Zahlkonstanten enthalten können. Sei für ein beliebiges i∈{1,..,|B|} bi die i-te<br />

Anweisung von B und hi die i-te Anweisung von H. Falls bi ist Sonderzeichen,<br />

Wort oder Zeichenkette, so gilt bi = hi. Es sind also nur die Fälle interessant, daß<br />

bi Variable, Inkrement oder Dekrement ist.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

In Teil 2 des Beweises von Lemma 5.4.9 haben wir gezeigt, daß es für jede in B<br />

vorkommende Variable v eine in H vorkommende Variable x gibt, deren<br />

Endwert in der Variablenliste V an der Stelle des Vorkommens eines<br />

Beispielauswertungsfragmentes der Variablen v in D gleich dem Wert von v ist,<br />

und deren Endwert in der Variablenliste X an der Stelle des Vorkommens eines<br />

Beispielauswertungsfragmentes der Variablen v in D' gleich dem Wert von v ist.<br />

Bei der Bildung von H wurde aber gerade jedes Vorkommen von v in B durch x<br />

ersetzt. Zur Vervollständigung des Beweises müssen wir nun noch zeigen, daß<br />

es kein Vorkommen von x in H gibt, so daß (für ein i) x ist in hi enthalten, und v<br />

ist nicht in bi enthalten.<br />

Nehmen wir an, ein solches i existiere. Sei x die in hi vorkommende Variable. Es<br />

ist klar, daß bi nur eine Variable, ein Inkrement oder ein Dekrement sein kann,<br />

denn sonst wäre bi = hi und hi könnte eine Variable enthalten. Sei w die in bi<br />

vorkommende Variable. Wir wissen nun, daß es ein in H vorkommendes y gibt,<br />

so daß beim Übergang von B nach H jedes Vorkommen von w durch y ersetzt<br />

wurde. Also muß gelten x = y. Dann gilt aber auch v = w.<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ36HL:HLQZKLOH.RQVWUXNWHLQ3GHU)RUP<br />

with while A do B end while $$XVGUXFNXQG%<br />

$QZHLVXQJVVHTXHQ]<br />

'DEHLHQWKDOWH%NHLQHORNDOHQZKLOH.RQVWUXNWH<br />

(VVHL7HLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6'LHHUVWHQEHLGHQWHVW<br />

.RQVWUXNWHYRQ7VHLHQ<br />

test C do D end test<br />

test C’ do D’ end test<br />

'DEHLVLQG&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ$XQG'XQG'<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ%'LH9DULDEOHQOLVWH9HQWKDOWHDOOHLQ3<br />

YRUGHU$XVZHUWXQJ7DXIJHWUHWHQHQ9DULDEOHQPLWLKUHQ$QIDQJVXQG<br />

(QGZHUWHQYRUGHU$XVZHUWXQJGHVHUVWHQ(OHPHQWHVYRQ') UMHGH<br />

9DULDEOHYLP$XVGUXFNYRQ:H[LVWLHUWHLQH9DULDEOH[LQ9XQG;VRGD‰<br />

GHU(QGZHUWYRQ[LQ9LVWGHU:HUWYRQYLQ&XQGGHU(QGZHUWYRQ[LQ;LVW<br />

GHU:HUWYRQYLQ&'LH3UR]HGXUVDPSOH:6WDWHPHQW6HTXHQFHZHUGHPLW<br />

GHQ3DUDPHWHUQ''9;+DXIJHUXIHQ6HLσGLH9DULDEOHQXPEHQHQQXQJ<br />

DXV/HPPD4HQWVWHKHDXV3GXUFKHUVHW]HQYRQ%GXUFK+σ'DQQ<br />

VWLPPHQGLH:HUWHEHLGHU$XVZHUWXQJYRQ3QDFKMHGHU$XVZHUWXQJYRQ%<br />

PLWGHQ:HUWHQGHU$XVZHUWXQJYRQ4QDFKMHGHU$XVZHUWXQJYRQ+σ<br />

EHUHLQ<br />

Beweis:<br />

Nach Lemma 5.4.9 ist P = Q. Damit stimmen die Auswertungen von P und Q<br />

überein.<br />

Wir wollen nun die Prozedur SampleWSequence untersuchen für den Fall, daß die<br />

Anweisungssequenz lokale while-Konstrukte enthalten dürfen. Dazu müssen wir wieder<br />

Aussagen über die Korrektheit der Prozedur SampleWHILE machen.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ3<br />

6HL:HLQZKLOH.RQVWUXNWLQ3PLW': G∈©XQG7HLQ<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6<br />

) UGLH3UR]HGXU6DPSOH:+,/(JHOWHQGLHIROJHQGHQ9RUDXVVHW]XQJHQ<br />

6HL:HLQZKLOH.RQVWUXNWYRQ3PLW':G:KDEHGLHIROJHQGH)RUP<br />

with while A’ do B’ end while<br />

'DEHLVHL$HLQ$XVGUXFNXQG%HLQH$QZHLVXQJVVHTXHQ]6HL7HLQ<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ6'LHHUVWHQEHLGHQWHVW.RQVWUXNWHYRQ7<br />

ODXWHQ<br />

test E do F end test<br />

test E’ do F’ end test<br />

'DEHLVHLHQ(XQG(%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ$XQG'XQG'<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ%6HL9HLQH9DULDEOHQOLVWH'DQQJLOW<br />

I UGHQ$XIUXIGHU3UR]HGXU6DPSOH:+,/(PLWGHQ3DUDPHWHUQ()()9*<br />

XQG+ZREHLGLH$XVJDEHYDULDEOH*HLQ$XVGUXFNXQGGLH$XVJDEHYDULDEOH<br />

+HLQH$QZHLVXQJVVHTXHQ]LVW<br />

, 'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

,, 6HL8 with while G’ do H’ end while 'DQQLVW7HLQH<br />

%HLVSLHODXVZHUWXQJYRQ8<br />

,,,(VJLEWHLQH9DULDEOHQXPEHQHQQXQJσVRGD‰*σ $XQG+σ %<br />

,9:LUGLQ*RGHU+HLQH9DULDEOHYHUZHQGHWGLHQLFKWEHUHLWVEHLP$XIUXI<br />

GHU3UR]HGXULQ9HQWKDOWHQLVWVRZLUGVLHPLWLKUHP$QIDQJVZHUWLQ9<br />

HLQJHWUDJHQ<br />

9 9HQWKlOWDP(QGHGHU3UR]HGXUGLH:HUWHDOOHULQ*XQG+<br />

YRUNRPPHQGHQ9DULDEOHQDP(QGHGHU$XVZHUWXQJ)<br />

'LHHUVWHQEHLGHQWHVW.RQVWUXNWHYRQ7VHLHQ<br />

test C do D end test<br />

test C’ do D’ end test<br />

'DEHLVHLHQ&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWHGHV$XVGUXFNHVYRQ:<br />

XQG'XQG'%HLVSLHODXVZHUWXQJVIUDJPHQWHGHU$QZHLVXQJVVHTXHQ]YRQ:<br />

6HLHQ9XQG;9DULDEOHQOLVWHQ) UMHGH9DULDEOHYLP$XVGUXFNYRQ:<br />

H[LVWLHUWHLQH9DULDEOH[LQ9XQG;VRGD‰GHU(QGZHUWYRQ[LQ9LVWGHU<br />

:HUWYRQYLQ&XQGGHU(QGZHUWYRQ[LQ;LVWGHU:HUWYRQYLQ&;<br />

HQWKlOWVRQVWNHLQH9DULDEOH'DQQJLOWI UGHQ$XIUXIGHU3UR]HGXU<br />

6DPSOH:6WDWHPHQW6HTXHQFHPLWGHQ3DUDPHWHUQ''9;+<br />

'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

'XQG'VLQG%HLVSLHODXVZHUWXQJHQYRQ+<br />

-HGH9DULDEOHLQ+GLHEHLP$XIUXIGHU3UR]HGXUQLFKWLQ9HQWKDOWHQLVW<br />

ZLUGLQ9HLQJHWUDJHQ,KU$QIDQJVZHUWLVWGHU:HUWLKUHVHUVWHQ<br />

$XIWUHWHQVLQ'<br />

P(QGHGHU3UR]HGXULVWMHGH9DULDEOHYRQ+LQ9HLQJHWUDJHQ,KU<br />

(QGZHUWLVWGHU:HUWLKUHVOHW]WHQ$XIWUHWHQVLQ'<br />

-HGH9DULDEOHLQ+GLHEHLP$XIUXIGHU3UR]HGXUQLFKWLQ;HQWKDOWHQLVW<br />

ZLUGLQ;HLQJHWUDJHQ,KU$QIDQJVZHUWLVWGHU:HUWLKUHVHUVWHQ<br />

$XIWUHWHQVLQ'<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

$P(QGHGHU3UR]HGXULVWMHGH9DULDEOHYRQ+LQ;HLQJHWUDJHQ,KU<br />

(QGZHUWLVWGHU:HUWLKUHVOHW]WHQ$XIWUHWHQVLQ'<br />

Beweis:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

Falls die äußere solange-Schleife nicht betreten wird, ist die Termination der<br />

Prozedur gesichert. Nehmen wir also an, die Schleife werde mindestens einmal<br />

durchlaufen.<br />

Man beachte, daß bei jedem Schleifendurchlauf der äußeren solange-Schleife<br />

mindestens ein Element t von D und mindestens ein Element u von D‘ gelesen<br />

wird. Dann werden die Lesezeiger beider Sequenzen um (mindestens) ein<br />

Element vorgestellt. Da vor dem ersten Schleifendurchlauf beide Zeiger am<br />

Anfang der Sequenzen stehen, ist sichergestellt, daß nach maximal<br />

min(|D|,|D'|) Schleifendurchläufen einer der Zeiger hinter dem letzten<br />

Element seiner Sequenz steht, sofern die Schleife nicht vorzeitig beendet wird.<br />

Wir zeigen nun, daß jeder Schleifendurchlauf der äußeren solange-Schleife<br />

terminiert. In einem beliebigen Schleifendurchlauf werde das Element t von D<br />

gelesen. Falls t ist Wort, Sonderzeichen, Zeichenkette oder Zahl ist der<br />

Schleifendurchlauf in endlicher Zeit abgearbeitet. Sei nun t ein test-Konstrukt.<br />

Falls auch das von D' gelesene Element u ein test-Konstrukt ist, erfolgen bis zu<br />

fünf Prozeduraufrufe und es können zwei solange-Schleifen betreten werden.<br />

Bei den ersten beiden Prozeduraufrufen wird die Prozedur SampleWHILE<br />

aufgerufen. Für diesen Aufruf gilt aber die Voraussetzung, wonach die Prozedur<br />

nach endlicher Zeit terminiert. Die Termination des dritten Aufrufs, in dem die<br />

Prozedur MatchWHILE benötigt wird, folgt aus Lemma 5.4.5. Die Termination<br />

der Aufrufe der Prozedur TestWExpression folgt nach Lemma 5.4.1. Die<br />

folgenden solange-Schleifen werden beendet, wenn ein Lesezeiger hinter de<br />

letzten Element seiner Sequenz steht. Da dieser Zeiger aber in der inneren<br />

solange-Schleife um ein Element vorgestellt wird, ist die Termination gesichert.<br />

In den inneren solange-Schleifen wird die Prozedur TestWHILE aufgerufen,<br />

deren Termination nach endlich vielen Schritten aber bereits in Lemma 5.4.4<br />

bewiesen worden ist. Dann terminiert auch in diesem Fall der<br />

Schleifendurchlauf der äußeren solange-Schleife, und die Termination der<br />

Prozedur SampleWSequence ist gesichert.<br />

2. D und D' sind Beispielauswertungen von H.<br />

Sei B die Anweisungssequenz von W. Wir beweisen den folgenden Hilfssatz<br />

durch Induktion über die Länge eines Anfangsstückes von B.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Hilfssatz:<br />

a) Für jedes i ∈ {0,..,|B|} wird die äußere solange-Schleife mindestens i-mal<br />

durchlaufen.<br />

b) H hat nach dem Ende des i-ten Schleifendurchlaufs genau i Elemente.<br />

c) Die Lesezeiger in D und D' stehen hinter der Auswertung des i-ten Elementes<br />

von B.<br />

d) Die Anfangsstücke von D und D', die durch Auswertung der ersten i Elemente<br />

von B entstehen, sind Beispielauswertungen von H nach dem i-ten<br />

Schleifendurchlauf.<br />

e) Die Variablenliste V enthält (mindestens) alle in den ersten i<br />

Schleifendurchläufe in H verwendeten Variablen mit ihrem Endwerten an der<br />

Stelle des i-ten Schleifendurchlaufs in D.<br />

f) Die Variablenliste X enthält (mindestens) alle in den ersten i<br />

Schleifendurchläufen in H verwendeten Variablen mit ihren Endwerten an der<br />

Stelle des i-ten Schleifendurchlaufs in D'.<br />

g) Zu jeder im Anfangsstück von B vorkommenden Variablen x existiert eine<br />

Variable v in H, deren Werte in D und D' mit den Werten von x<br />

übereinstimmen.<br />

Beweis des Hilfssatzes:<br />

Die Induktionsverankerung gilt trivialerweise. Die Behauptung gelte jetzt für<br />

alle i ≤ n ∈ © (n < |B|).<br />

Sei b das (n+1)-te Element von B. b kann keine Zahlkonstante sein. Nach<br />

Induktionsvoraussetzung wird die Schleife n-mal durchlaufen. Die Lesezeiger<br />

stehen hinter der Auswertung des n-ten Element von B. Dies kann nicht hinter<br />

dem letzten Element von D und D' sein, da ansonsten D und D' keine<br />

Auswertung von b enthielten. Also wird die Schleife wiederum betreten (es muß<br />

allerdings bewiesen werden, daß der Schleifendurchlauf nicht vorzeitig beendet<br />

wird).<br />

Sei t das von D gelesene Element und u das von D' gelesene Element. Man<br />

beachte, daß beide Lesezeiger um ein Element vorgestellt werden. Wir<br />

unterscheiden jetzt nach b:<br />

1. Fall: b ist Sonderzeichen, Wort oder Zeichenfolge:<br />

In diesem Fall gilt t = u = b, da t und u Beispielauswertungen von b sind. Das<br />

(n+1)-te Element von H ist aber dann ebenfalls b. Nach<br />

Induktionsvoraussetzung sind die Anfangsstücke von D und D', die durch<br />

Auswertung der ersten n Elemente von b entstanden sind,<br />

Beispielauswertungen für die ersten n Elemente von H. Dann sind aber die<br />

Anfangsstücke von D und D' bis einschließlich der Elemente t und u<br />

Beispielauswertungen der ersten n+1 Elementen von H. Da die Auswertung von<br />

b nur aus einem Element besteht, stehen die Lesezeiger hinter der Auswertung<br />

des (n+1)-ten Elementes von B. Die Aussagen über V und X gelten nach wie vor<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

nach Induktionsvoraussetzung, da weder V noch X, noch der Wert einer<br />

Variablen verändert wurde.<br />

2. Fall: b ist Variable, etwa x, und x kommt in den ersten n Anweisungen von B<br />

und in A nicht vor:<br />

Sei d der Wert von b in D und d' der Wert von b in D' (jeweils an der Stelle n+1).<br />

Es kann nun keine Variable in V und X existieren, deren Differenz ihrer Werte<br />

in V und X gleich d' - d ist.<br />

Beweis (indirekt):<br />

Annahme, eine solche Variable existiere, sie heiße w. Nehmen wir zuerst an, die<br />

Variable wäre bereits beim Aufruf der Prozedur in den Variablenlisten<br />

enthalten. Da w in X vorkommt, muß es nach Voraussetzung ein Variable y in A<br />

geben, deren Werte in den Auswertungen C und C' mit den Endwerten von w in<br />

V und X übereinstimmen. Also stimmen der Differenzen der Werte in der ersten<br />

und zweiten Entfaltung überein. Dies ist aber in Klasse-I-Programmen nur<br />

zulässig, wenn x = y. Dies steht aber im Widerspruch zur Aussage, x käme nicht<br />

in A vor.<br />

w sei jetzt beim Aufruf der Prozedur nicht in V und X enthalten. Also muß w in<br />

den ersten n Schleifendurchläufen in V und X eingetragen worden sein, etwa im<br />

j-ten Schleifendurchlauf. w könnte bei einem Aufruf der Prozedur<br />

SampleWHILE aufgenommen worden sein. Nach den Voraussetzungen über<br />

diese Prozedur müßte dann aber w auch in G' oder H' vorkommen. A' und G',<br />

bzw. B' und H' unterscheiden sich aber nur in den Namen der Variablen. D.h. es<br />

muß eine Variable in A' oder B' vorkommen, deren Werte mit w<br />

übereinstimmen. Sei etwa y diese Variable. Dann stimmt aber die Differenz der<br />

Werte von y in der ersten und zweiten Entfaltung von W mit den Werten in der<br />

ersten und zweiten Entfaltung von x überein. Dann muß aber gelten x = y im<br />

Widerspruch zur Voraussetzung, in der (n+1)-ten Anweisung von B käme x<br />

erstmalig vor.<br />

Die letzte Möglichkeit für den Eintrag von w ist, daß w im j-ten<br />

Schleifendurchlauf eingetragen worden ist, in dem aber kein while-Konstrukt<br />

gelesen wurde. Dazu müssen aber die im j-ten Schleifendurchlauf von D und D'<br />

eingelesenen Beispielauswertungen, etwa e und e' Zahlen sein. Da in P<br />

Zahlkonstanten nicht vorkommen, müssen e und e' Werte einer Variablen im<br />

Anfangsstück von B sein, etwa Werte der Variablen y. Also stimmen die<br />

Differenzen der Werte der Variablen x und y in ihrer ersten und zweiten<br />

Entfaltung überein. Dies ist aber nur erlaubt, wenn x = y. Dies widerspricht der<br />

Voraussetzung, x trete im i-ten Schleifendurchlauf erstmalig auf.<br />

Dann wird aber im i-ten Schleifendurchlauf eine Variable, etwa v, in H<br />

angefügt, deren Wert aber mit dem Wert von x übereinstimmt. Diese Variable<br />

ist dann in V und X enthalten. Die Beispielauswertungen von v sind aber gerade<br />

d und d'. Nach Induktionsvoraussetzung sind die Anfangsstücke von D und D'<br />

für die ersten n Anweisungen von B aber Beispielauswertungen der ersten n<br />

Anweisungen von H. Nun gilt dies auch für die Beispielauswertungen des (n+1)-<br />

ten Elementes von B. Also gilt die Teilaussage d) des Hilfssatzes.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Die Schleife wird beendet, also mindestens (n+1)-mal durchlaufen (Teilaussage<br />

a)). Die Beispielauswertungen von b bestehen nur aus einem Element,<br />

deswegen stehen die Lesezeiger bereits hinter den Beispielauswertungen von b<br />

(Teilaussage b)). H wurde um ein Element ergänzt, hat also n+1 Elemente, da<br />

es vor dem Schleifendurchlauf nach Induktionsvoraussetzung n Elemente hatte<br />

(Teilaussage c)). Die Variablenlisten V und X wurden nur dahingehend<br />

verändert, daß eine neue Variable aufgenommen wurde. Die Werte der anderen<br />

Variablen wurden nicht verändert. Ebenso wurden in den i-ten Anweisungen<br />

von B und H die Werte irgendwelcher Variablen verändert. Der Wert der in H<br />

eingetragenen Variablen ist als Endwert in V und X aufgenommen, womit die<br />

Teilbehauptungen e) und f) bestätigt sind. Die Teilaussage g) folgt direkt aus<br />

der Induktionsvoraussetzung für alle im Anfangsstück von B vorkommenden<br />

Variablen außer x. Daß die Bedingung für x gilt, haben wir aber oben gezeigt.<br />

3. Fall: b ist Variable, etwa x, und x kommt in den ersten n Anweisungen von B<br />

oder in A vor:<br />

Sei d der Wert von b in D und d' der Wert von b in D' (jeweils an der Stelle n+1).<br />

Nach Induktionvoraussetzung wissen wir, daß es eine Variable, etwa v, im<br />

Anfangsstück von H (die ersten n Anweisungen) gibt, deren Werte bei der<br />

Auswertung von H mit den Werten von x bei der Auswertung von B<br />

übereinstimmen. Die Werte am Ende der Auswertung der n-ten Anweisung von<br />

H sind in den Variablenlisten V und X gespeichert. Also muß der Endwert von v<br />

in V gleich d sein, und der Endwert von v in X muß gleich d' sein. Es kann nun<br />

keine zweite Variable in V und X geben, deren Differenz der Endwerte gleich d' -<br />

d ist. Denn dann müßte es eine zweite Variable in A oder im Anfangsstück von<br />

B geben, deren Differenz der Werte in der ersten und zweiten Entfaltung gleich<br />

d' - d ist. Das (n+1)-te Element von H kann damit nur die Variable v sein. d und<br />

d' sind damit Beispielauswertungen von v. Nach Induktionsvoraussetzung sind<br />

die Anfangsstücke von D und D' für die ersten n Anweisungen von B aber<br />

Beispielauswertungen der ersten n Anweisungen von H. Nun gilt dies auch für<br />

die Beispielauswertungen des (n+1)-ten Elementes von B. Also gilt die<br />

Teilaussage d) des Hilfssatzes.<br />

Die Schleife wird beendet, also mindestens (n+1)-mal durchlaufen (Teilaussage<br />

a)). Die Beispielauswertungen von b bestehen nur aus einem Element,<br />

deswegen stehen die Lesezeiger bereits hinter den Beispielauswertungen von b<br />

(Teilaussage b)). H wurde um ein Element ergänzt, hat also n+1 Elemente, da<br />

es vor dem Schleifendurchlauf nach Induktionsvoraussetzung n Elemente hatte<br />

(Teilaussage c)).<br />

V und X werden nicht verändert, also gelten die Teilaussagen e) und f) nach<br />

Induktionsvoraussetzung. Die Gültigkeit der Teilbehauptung g) folgt für die<br />

ersten n Element von H aus der Induktionsvoraussetzung. Sie gilt aber<br />

ebenfalls für das (n+1)-te Element von H. Denn v hat im (n+1)-ten<br />

Schleifendurchlauf gerade bei der Auswertung von H gerade die Werte d und d'.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

4. Fall : b ist Inkrement:<br />

Sei d der Wert von b in D und d’ der Wert von b in D’ (jeweils an der Stelle n+1).<br />

Sei x die Variable in b, d.h. b = "++x". x muß bereits in A oder in den ersten n<br />

Anweisungen von B vorgekommen sein. Nach Induktionvoraussetzung wissen<br />

wir, daß es eine Variable, etwa v, im Anfangsstück von H (die ersten n<br />

Anweisungen) gibt, deren Werte bei der Auswertung von H mit den Werten von<br />

x bei der Auswertung von B übereinstimmen. Die Werte am Ende der<br />

Auswertung der n-ten Anweisung von H sind in den Variablenlisten V und X<br />

gespeichert. Also muß der Endwert von v in V gleich d-1 sein, und der Endwert<br />

von v in X muß gleich d'-1 sein. Es kann nun keine zweite Variable in V und X<br />

geben, deren Differenz der Endwerte gleich d' - d ist (selbe Argumentation wie<br />

im 3. Fall). Insbesondere enthalten V und X keine Variable mit den Endwerten<br />

d und d'. Dann muß das (n+1)-te Element von H das Inkrement der Variablen v<br />

sein.<br />

d und d' sind damit Beispielauswertungen des (n+1)-ten Elementes von H. Nach<br />

Induktionsvoraussetzung sind die Anfangsstücke von D und D' für die ersten n<br />

Anweisungen von B aber Beispielauswertungen der ersten n Anweisungen von<br />

H. Damit gilt die Teilaussage d) des Hilfssatzes.<br />

Die Schleife wird beendet, also mindestens (n+1)-mal durchlaufen (Teilaussage<br />

a)). Die Beispielauswertungen von b bestehen nur aus einem Element,<br />

deswegen stehen die Lesezeiger bereits hinter den Beispielauswertungen von b<br />

(Teilaussage b)). H wurde um ein Element ergänzt, hat also n+1 Elemente, da<br />

es vor dem Schleifendurchlauf nach Induktionsvoraussetzung n Elemente hatte<br />

(Teilaussage c)).<br />

Die Variablenlisten V und X werden dahingehend verändert, daß für die<br />

Endwerte der Variablen v die Werte d und d' eingetragen werden. Diese Werte<br />

stimmen aber tatsächlich mit den Werten von v nach Auswertung der (n+1)-ten<br />

Anweisung überein. Nach Induktionsvoraussetzung stimmen die Einträge der<br />

übrigen bisher in H vorgekommenen Variablen mit ihren Werten nach<br />

Auswertung der n-ten Anweisung überein. Dann stimmen sie aber auch mit den<br />

Werten nach Auswertung der (n+1)-ten Anweisung überein. Damit sind die<br />

Teilbehauptungen e) und f) bewiesen. Die Gültigkeit der Teilbehauptung g) folgt<br />

für die ersten n Element von H aus der Induktionsvoraussetzung. Sie gilt aber<br />

ebenfalls für das (n+1)-te Element von H, denn der Wert der Variablen v stimmt<br />

mit dem Wert der Variablen v überein.<br />

5. Fall: b ist Dekrement:<br />

Sei d der Wert von b in D und d' der Wert von b in D' (jeweils an der Stelle n+1).<br />

Sei x die Variable in b, d.h. b = "--x". x muß bereits in A oder in den ersten n<br />

Anweisungen von B vorgekommen sein. Man beachte, daß in Klasse-I-<br />

Beispielauswertungen keine Variable dekrementiert werden darf, die bereits<br />

den Wert 0 hat. Nach Induktionvoraussetzung wissen wir, daß es eine Variable,<br />

etwa v, im Anfangsstück von H (die ersten n Anweisungen) gibt, deren Werte<br />

bei der Auswertung von H mit den Werten von x bei der Auswertung von B<br />

übereinstimmen. Die Werte am Ende der Auswertung der n-ten Anweisung von<br />

H sind in den Variablenlisten V und X gespeichert. Also muß der Endwert von v<br />

in V gleich d+1 sein, und der Endwert von v in X muß gleich d'+1 sein, wobei wir<br />

auch an dieser Stelle verwenden, daß der Wert einer zu dekrementierenden<br />

Variablen größer Null sein muß. Es kann nun keine zweite Variable in V und X<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

geben, deren Differenz der Endwerte gleich d’ - d ist (selbe Argumentation wie<br />

im 3. Fall). Insbesondere enthalten V und X keine Variable mit den Endwerten<br />

d und d' und auch keine Variable mit den Endwerten d-1 und d'-1. Dann muß<br />

das (n+1)-te Element von H das Dekrement der Variablen v sein.<br />

Vollkommen analog wie im 4. Fall kann man die Gültigkeit des Hilfssatzes<br />

zeigen.<br />

6. Fall: b ist while-Konstrukt:<br />

b habe die Form<br />

with while A’ do B’ end while<br />

Dabei sei A' ein Ausdruck und B' eine Anweisungssequenz. Dann existieren<br />

natürliche Zahlen m, m' > 1, do daß d die Form<br />

test C 1 do D 1 end test<br />

test C 2 do D 2 end test<br />

...<br />

test C m do D m end test<br />

oder die Form<br />

test C 1 do D 1 end test<br />

test C 2 do D 2 end test<br />

...<br />

test C m do D m end test<br />

test C m+1 skip<br />

hat. Entsprechend hat d' die Form<br />

test C’ 1 do D’ 1 end test<br />

test C’ 2 do D’ 2 end test<br />

...<br />

test C’ m’ do D’ m end test<br />

oder die Form<br />

test C’ 1 do D’ 1 end test<br />

test C’ 2 do D’ 2 end test<br />

...<br />

test C’ m’ do D’ m’ end test<br />

test C’ m+1 skip<br />

hat. Dabei sind C1,..,Cm,Cm+1,C'1,...,C'm,C'm+1 Beispielauswertungsfragmente von<br />

A' und D1,..,Dm,D'1,..,D'm Beispielauswertungsfragmente von B'.<br />

Dann ist das von D eingelesene Fragment t das test-Konstrukt<br />

test C 1 do D 1 end test<br />

und das von D' eingelesene Fragment u ist das test-Konstrukt<br />

test C’ 1 do D’ 1 end test<br />

Der Lesezeiger L in D steht jetzt vor dem zweiten test-Konstrukt von d und der<br />

Lesezeiger L' in D' steht vor dem zweiten test-Konstrukt von d'. Folglich gilt für<br />

die beiden jetzt eingelesenen Fragmente t' und u':<br />

t' hat die Form<br />

test C 2 do D 2 end test<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

und u’ hat die Form<br />

test C’ 2 do D’ 2 end test<br />

Der Lesezeiger L steht nun hinter dem zweiten test-Konstrukt von d und der<br />

Lesezeiger L’ in D’ steht hinter dem zweiten test-Konstrukt von d’. Man beachte,<br />

daß hinter der Position von L und L' weitere test-Konstrukte von d und d' folgen<br />

können.<br />

Im (n+1)-ten Schleifendurchlauf wird jetzt die Prozedur SampleWHILE zweimal<br />

und die Prozedur MatchWHILE einmal aufgerufen.<br />

Für die Aufrufe der Prozedur SampleWHILE dürfen wir die Voraussetzungen<br />

für unser Lemma verwenden, da D(b) < D(W). Dann gilt nach dem ersten Aufruf<br />

der Prozedur SampleWHILE mit den Parametern (C1,D1,C2,D2,V,M,N)<br />

aufgerufen, dabei sind der Ausdruck M und die Anweisungssequenz N<br />

Ausgabeparameter. Nach Voraussetzung gilt nach dem Aufruf:<br />

I. Die Prozedur terminiert nach endlich vielen Schritten.<br />

II. Sei U = " with while M do N end while ". Dann ist d eine<br />

Beispielauswertung von U.<br />

III.Es gibt eine Variablenumbenennung σ, so daß Mσ = A' und Nσ = B'.<br />

IV.Wird in M oder N eine Variable verwendet, die nicht bereits beim Aufruf der<br />

Prozedur in V enthalten ist, so wird sie mit ihrem Anfangswert in V<br />

eingetragen.<br />

V. V enthält am Ende der Prozedur die Werte aller in Mund N vorkommenden<br />

Variablen am Ende der Auswertung D2.<br />

Für den zweiten Aufruf der Prozedur SampleWHILE mit den Parametern<br />

(C'1,D'1,C'2,D'2',Y,M',N'), wobei Y eine beim Aufruf leere Variablenliste, M' ein<br />

Ausdruck und N' eine Anweisungssequenz ist, gilt entsprechend:<br />

I.‘ Die Prozedur terminiert nach endlich vielen Schritten.<br />

II.‘ Sei U' = " with while M’ do N’ end while ". Dann ist d' eine<br />

Beispielauswertung von U.<br />

III.‘ Es gibt eine Variablenumbenennung τ, so daß M'τ = A' und N'τ = B'.<br />

IV.‘ Jede in M' oder N' verwendete Variablen wird mit ihrem Anfangswert in Y<br />

eingetragen.<br />

V.‘ Y enthält am Ende der Prozedur die Werte aller in M' und N'<br />

vorkommenden Variablen am Ende der Auswertung D'2.<br />

Anschließend wird die Prozedur MatchWHILE mit den Parametern<br />

(M,M',N,N',V,Y,X,result) aufgerufen, wobei result eine Ausgabevariable ist.<br />

Nach Lemma 5.4.5 gilt dann:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

2. Nach dem Aufruf hat result den Wert WAHR.<br />

3. Jede Variable aus M und N, die nicht beim Aufruf der Prozedur in X<br />

enthalten ist, wird in X angefügt mit Anfangs- und Endwert der<br />

entsprechenden Variablen aus Y.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

4. Der Endwert in X jeder Variable aus M und N, die in X enthalten ist, wird<br />

mit dem Endwert der entsprechenden Variablen in Y überschrieben, sofern<br />

die Endwerte nicht bereits übereinstimmen.<br />

Nach II. ist d eine Beispielauswertung von U unter Berücksichtigung der<br />

Variablenliste V. Wir wollen nun zeigen, daß d' ebenfalls eine<br />

Beispielauswertung von U ist, nämlich für die Variablenliste X.<br />

Nach II' ist d' eine Beispielauswertung von U' (mit Variablenliste Y). Es gilt<br />

ebenfalls U'τ = b = Uσ. U und U' unterscheiden sich also nur in den Namen der<br />

Variablen. Da d' Beispielauswertung von U', gibt es ein Programm P' und eine<br />

Beispielauswertung S' von P', so daß d' ist eine Beispielauswertungsfragment<br />

von S' und U' ist ein Programmfragment von P'. Das Programm Q sei jetzt<br />

definiert als Q = Pστ -1 . Dann ist U Programmfragment von Q. Nach Lemma<br />

3.5.2 sind P' und Q ähnlich. Dann ist aber S' Beispielauswertung von Q und d'<br />

Beispielauswertung von U. Da result den Wert FALSCH besitzt, wird U an H<br />

angefügt. H wird im (n+1)-ten Schleifendurchlauf nicht mehr verändert. Nach<br />

Induktionsvoraussetzung hat H vor dem (n+1)-ten Schleifendurchlauf n<br />

Element, somit hat H nach dem Anfügen von U n+1 Elemente. Somit ist die<br />

Teilaussage b) es Hilfssatzes bewiesen. Nach Induktionsvoraussetzung sind die<br />

Anfangsstücke von D und D', die durch Auswertung der ersten n Elemente von<br />

B entstehen, Beispielauswertungen der ersten n Anweisungen von H. da auch<br />

die Auswertung des (n+1)-ten Elementes von B Beispielauwertungen des (n+1)-<br />

ten Elementes von h sind, gilt auch die Teilbehauptung d).<br />

Der Lesezeiger L in D steht nun vor m-2 weiteren test-Konstrukten der Form<br />

test C i do D i end test<br />

wobei i ∈{3,..,m}, Dann wird die erste innere solange-Schleife m-2 mal<br />

durchlaufen (sofern der Algorithmus nicht vorzeitig abgebrochen wird). Für<br />

jeden Aufruf der Prozedur TestWHILE gilt Lemma 5.4.4, denn jeder dieser test-<br />

Konstrukte ist eine Beispielauswertung von b und damit auch von U, und wir<br />

wissen<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

2. Nach Beendigung der Prozedur gilt für die Ausgabevariable result = WAHR.<br />

3. V enthält alle Variablen, die in U vorkommen mit ihren Werten am Ende von<br />

des gelesenen test-Konstruktes.<br />

Daraus folgt, daß die Schleife tatsächlich m-2 mal durchlaufen wird. L steht<br />

dann hinter dem m-ten test-Konstrukt von d und V enthält alle Variablen aus U<br />

mit ihren Werten am Ende von Dm.<br />

Es kann nun noch ein test-Konstrukt von d folgen. Falls kein weiteres test-<br />

Konstrukt folgt, steht der Lesezeiger L hinter der Beispielauswertung von b und<br />

die Variablenliste V enthält (mindestens) alle in den ersten n+1<br />

Schleifendurchläufe in H verwendeten Variablen mit ihrem Endwerten nach<br />

dem (n+1)-ten Schleifendurchlauf.<br />

Nehmen wir jetzt an, es folge ein weiteres test-Konstrukt. Dieses muß dann die<br />

Form haben<br />

test C m+1 skip<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Für den folgenden Aufruf der Prozedur TestWExpression gelten die Aussagen<br />

des Lemma 5.4.1:<br />

1. Die Prozedur terminiert nach endlich vielen Schritten.<br />

2. Nach Beendigung der Prozedur gilt für die Rückgabevariable result = WAHR.<br />

Die Variablenliste V wird nicht verändert, sie enthält damit alle in den ersten<br />

n+1 Schleifendurchläufe in H verwendeten Variablen mit ihrem Endwerten<br />

nach dem (n+1)-ten Schleifendurchlauf. Damit ist auf jedem Fall die<br />

Teilaussage e) bewiesen. Der Lesezeiger L steht hinter dem letzten Element der<br />

Beispielauswertung von b.<br />

Vor der zweiten inneren solange-Schleife enthält die Variablenliste X alle in den<br />

ersten n+1 Anweisungen von H vorkommenden Variablen mit ihren Endwerten<br />

nach Auswertung der zweiten Entfaltung von U in der Beispielauswertung D',<br />

d.h. sie besitzen die Werte der Variablen am Ende von D'2’ (denn X enthält alle<br />

Variablen von V mit den Endwerten der entsprechenden Variablen von Y (aus<br />

der Variablenumbenennung) am Ende von D'2).<br />

Der Lesezeiger L' in D' steht nun vor dem 3. test-Konstrukt von d', es folgen also<br />

mindestens m'-2 weitere test-Konstrukte. Analog wie bei der Behandlung der<br />

test-Konstrukte von d, wird die zweite innere solange Schleife genau m'-2 mal<br />

durchlaufen und die Variablenliste X enthält die Endwerte der Variablen am<br />

Ende der Auswertung D'm’. Der Lesezeiger L' steht dann hinter dem m'-ten<br />

Element von d'. Falls ein (m'+1)-tes Element von d‘ folgt, so hat dies die Form<br />

test C’ m’+1 skip<br />

und es kann analog wie bei der Behandlung des entsprechenden Elementes von<br />

d die Prozedur TestWExpression verwendet werden. Auf jedem Fall beinhaltet<br />

die Variablenliste X (mindestens) alle in den ersten n+1 Schleifendurchläufen in<br />

H verwendeten Variablen mit ihren Endwerten an der Stelle des (n+1)-ten<br />

Schleifendurchlaufs in D' (Teilaussage f)). Beide Lesezeiger stehen hinter der<br />

Auswertung des (n+1)-ten Elementes von B (Teilbehauptung c)). Da die Schleife<br />

nach Induktionsvoraussetzung mindestens n mal durchlaufen wird, und der<br />

(n+1)-te Schleifendurchlauf beendet wird, wird die äußere solange-Schleife also<br />

mindestens (n+1)-mal durchlaufen (Teilbehauptung a)).<br />

Verbleibt zu zeigen die Teilbehauptung g). Nach Induktionsvoraussetzung<br />

wissen wir, daß es für jede der im Anfangsstück von B vorkommenden<br />

Variablen, etwa x, eine Variable v in H gibt, deren Werte in D und D' mit den<br />

Werten von x übereinstimmen.<br />

Nehmen wir hierzu an, die Teilbehauptung gelte nicht. Sei x eine in den ersten<br />

n+1 Anweisungen von B vorkommende Variable, zu der es keinen Variable in<br />

den ersten n+1 Anweisungen von H gibt, deren Werte in D und D' mit den<br />

Werten von x übereinstimmen. Wegen der Induktionsvoraussetzung kann die<br />

Nichtübereinstimmung nicht in den ersten n Anweisungen der beiden<br />

Anweisungssequenzen auftreten. Also muß die Nichtübereinstimmung zwischen<br />

b und U auftreten. b und U unterscheiden sich aber nur in den Namen der<br />

Variablen. Sei a eine Anweisung, in der x vorkommt. Dann muß es eine<br />

entsprechende Anweisung a' in U geben, die sich von a nur im Namen der<br />

Variablen unterscheidet. Sei v die in a' vorkommende Variable. x und v haben<br />

jetzt an der Stelle der Anweisungen a und a' bei der Auswertung verschiedene<br />

Werte, dann sind aber ihre Auswertungen verschieden, d.h. die<br />

Beispielauswertungen von b und U unterscheiden sich an mindestens einer<br />

Stelle. Dies steht aber im Widerspruch zu Punkt II. unserer Voraussetzung für<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

die Korrektheit der Prozedur SampleWHILE. Also kann es keine im<br />

Anfangsstück von B vorkommende Variable geben, zu der es keine<br />

entsprechende Variable im Anfangsstück von H gibt, die in ihren Werten bei der<br />

Auswertung übereinstimmen.<br />

Damit ist der Hilfssatz nach Induktion bewiesen. (Hilfssatz)<br />

Die 2. Aussage des Lemmas folgt direkt aus Teilaussage d) des Hilfssatzes für<br />

den Fall n = |B|.<br />

3. Jede Variable in H, die beim Aufruf der Prozedur nicht in V enthalten ist,<br />

wird in V eingetragen. Ihr Anfangswert ist der Wert ihres ersten Auftretens in<br />

D.<br />

Nach Punkt e) des Hilfssatzes im Beweis der 2. Aussage, wissen wir, daß jede in<br />

H vorkommende Variable, in V enthalten ist. Dann muß aber eine Variable, die<br />

vorher nicht in V enthalten ist, in V eingetragen worden sein. Es stellt sich nun<br />

die Frage, was der Anfangswert einer solchen Variablen ist. Betrachten wir<br />

dazu das erste Vorkommen der Variablen. Falls das erste Vorkommen der<br />

Variablen innerhalb eines lokalen while-Konstruktes von H liegt, so wissen wir<br />

nach unseren Voraussetzungen für die Korrektheit der Prozedur<br />

SampleWHILE, daß ihr der entsprechende Anfangswert in V eingetragen<br />

worden ist. Da der Anfangswert einer Variablen, die bereits in V enthalten ist,<br />

niemals verändert wird, so mu gilt die Aussage.<br />

Falls das erste Vorkommen der Variablen, etwa v, nicht in einem lokalen while-<br />

Konstrukt liegt, so muß es eine Anweisung h in H geben, so daß h gerade die<br />

Variable v ist. Es gibt also ein Schleifendurchlauf, in dem eine Variable in H<br />

aufgenommen wurde, die an dieser Stelle noch nicht in V enthalten ist. Dann<br />

kann V keine Variable enthalten, deren Werte mit denen von v übereinstimmen,<br />

da in Klasse-I-Programmen keine zwei Variablen in einem while-Konstrukt<br />

erlaubt sind, die in der Differenz ihrer Werte bei der Auswertung der ersten und<br />

zweiten Entfaltung übereinstimmen. Dann wird aber in diesem<br />

Schleifendurchlauf v mit ihrem Wert bei der Auswertung D als Anfangswert in<br />

V eingetragen.<br />

4. Am Ende der Prozedur ist jede Variable von H in V eingetragen. Ihr Endwert<br />

ist der Wert ihres letzten Auftretens in D.<br />

Folgt direkt aus Teilaussage e) des Hilfssatzes im Beweis der 2. Aussage.<br />

5. Jede Variable in H, die beim Aufruf der Prozedur nicht in X enthalten ist,<br />

wird in X eingetragen. Ihr Anfangswert ist der Wert ihres ersten Auftretens in<br />

D'.<br />

Nach Punkt f) des Hilfssatzes im Beweis der 2. Aussage, wissen wir, daß jede in<br />

H vorkommende Variable in X enthalten ist. Dann muß aber eine Variable, die<br />

vorher nicht in X enthalten ist, in X eingetragen worden sein. Es stellt sich nun<br />

die Frage, was der Anfangswert einer solchen Variablen ist. Betrachten wir<br />

dazu das erste Vorkommen der Variablen.<br />

Falls das erste Vorkommen der Variablen, etwa v, innerhalb eines lokalen<br />

while-Konstruktes von H liegt, so wissen nach unseren Voraussetzungen für die<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Prozedur SampleWHILE, daß diese Variable mit ihrem Anfangswert bei der<br />

Auswertung D in die Variablenliste V eingetragen worden ist. Die Variablenliste<br />

Y enthält dann eine Variable, etwa y, die in ihren Werten mit den Werten von v<br />

bei der Auswertung D' übereinstimmt. Der Anfangswert von y in Y ist dann<br />

gleich dem ersten Wert von v bei der Auswertung D'. Nach Lemma 5.4.5 wird<br />

dann aber beim Aufruf der Prozedur MatchWHILE die Variable v in X<br />

eingetragen. Ihr Anfangswert wird auf den Anfangswert der Variablen y in Y<br />

gesetzt.<br />

Falls das erste Vorkommen der Variablen, etwa v, nicht in einem lokalen while-<br />

Konstrukt liegt, so muß es eine Anweisung h in H geben, so daß h gerade die<br />

Variable v ist. Es gibt also ein Schleifendurchlauf, in dem eine Variable in H<br />

aufgenommen wurde, die an dieser Stelle noch nicht in X enthalten ist. Dann<br />

kann X keine Variable enthalten, deren Werte mit denen von v übereinstimmen,<br />

da in Klasse-I-Programmen keine zwei Variablen in einem while-Konstrukt<br />

erlaubt sind, die in der Differenz ihrer Werte bei der Auswertung der ersten und<br />

zweiten Entfaltung übereinstimmen. Dann wird aber in diesem<br />

Schleifendurchlauf v mit ihrem Wert bei der Auswertung D' als Anfangswert in<br />

X eingetragen.<br />

6. Am Ende der Prozedur ist jede Variable von H in X eingetragen. Ihr Endwert<br />

ist der Wert ihres letzten Auftretens in D'.<br />

Folgt direkt aus Teilaussage f) des Hilfssatzes im Beweis der 2. Aussage.<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ3<br />

6HL:HLQZKLOH.RQVWUXNWLQ3PLW': G∈©XQG7HLQ<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6<br />

) UGLH3UR]HGXU6DPSOH:+,/(JHOWHQGLHIROJHQGHQ9RUDXVVHW]XQJHQ<br />

6HL:HLQZKLOH.RQVWUXNWYRQ3PLW':G:KDEHGLHIROJHQGH)RUP<br />

with while A’ do B’ end while<br />

'DEHLVHL$HLQ$XVGUXFNXQG%HLQH$QZHLVXQJVVHTXHQ]6HL7HLQ<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ6'LHHUVWHQEHLGHQWHVW.RQVWUXNWHYRQ7<br />

ODXWHQ<br />

test E do F end test<br />

test E’ do F’ end test<br />

'DEHLVHLHQ(XQG(%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ$XQG'XQG'<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ%6HL9HLQH9DULDEOHQOLVWH'DQQJLOW<br />

I UGHQ$XIUXIGHU3UR]HGXU6DPSOH:+,/(PLWGHQ3DUDPHWHUQ()()9*<br />

XQG+ZREHLGLH$XVJDEHYDULDEOH*HLQ$XVGUXFNXQGGLH$XVJDEHYDULDEOH<br />

+HLQH$QZHLVXQJVVHTXHQ]LVW<br />

, 'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

,, 6HL8 Ãwith while G’ do H’ end while'DQQLVW7HLQH<br />

%HLVSLHODXVZHUWXQJYRQ8<br />

,,,(VJLEWHLQH9DULDEOHQXPEHQHQQXQJσVRGD‰*σ $XQG+σ %<br />

,9:LUGLQ*RGHU+HLQH9DULDEOHYHUZHQGHWGLHQLFKWEHUHLWVEHLP$XIUXI<br />

GHU3UR]HGXULQ9HQWKDOWHQLVWVRZLUGVLHPLWLKUHP$QIDQJVZHUWLQ9<br />

HLQJHWUDJHQ<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

9 9HQWKlOWDP(QGHGHU3UR]HGXUGLH:HUWHDOOHULQ*XQG+<br />

YRUNRPPHQGHQ9DULDEOHQDP(QGHGHU$XVZHUWXQJ)<br />

:KDEHGLH)RUP<br />

with while A do B end whileÃ$$XVGUXFNXQG%<br />

$QZHLVXQJVVHTXHQ]<br />

(VVHL7HLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6'LHHUVWHQEHLGHQWHVW<br />

.RQVWUXNWHYRQ7VHLHQ<br />

test C do D end test<br />

test C’ do D’ end test<br />

'DEHLVLQG&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ$XQG'XQG'<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ%'LH9DULDEOHQOLVWH9HQWKDOWHDOOHLQ3<br />

YRUGHU$XVZHUWXQJ7DXIJHWUHWHQHQ9DULDEOHQPLWLKUHQ$QIDQJVXQG<br />

(QGZHUWHQYRUGHU$XVZHUWXQJGHVHUVWHQ(OHPHQWHVYRQ') UMHGH<br />

9DULDEOHYLP$XVGUXFNYRQ:H[LVWLHUWHLQH9DULDEOH[LQ9XQG;VRGD‰<br />

GHU(QGZHUWYRQ[LQ9LVWGHU:HUWYRQYLQ&XQGGHU(QGZHUWYRQ[LQ;LVW<br />

GHU:HUWYRQYLQ&'HU$XIUXIGHU3UR]HGXUVDPSOH:6WDWHPHQW6HTXHQFH<br />

PLWGHQ3DUDPHWHUQ''9;+WHUPLQLHUHQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

XQGOLHIHUHDOV$XVJDEHHLQHQ$XVGUXFN+'DQQH[LVWLHUWHLQH<br />

9DULDEOHQXPEHQHQQXQJσVRGD‰% +σ<br />

Beweis:<br />

Nach Lemma 5.4.11 wissen wir, daß der Aufruf der Prozedur<br />

sampleWStatementSequence nach endlich vielen Schritten terminiert und eine<br />

Anweisungssequenz H liefert. Dabei sind D und D'<br />

Beispielauswertungsfragmente von B und von H.<br />

Wir haben im Beweis der 2. Aussage des Lemma 5.4.11 folgende Aussage<br />

bewiesen:<br />

Zu jeder in B vorkommenden Variablen x existiert eine Variable v in H, deren<br />

Werte in D und D' mit den Werten von x übereinstimmen.<br />

Die Variablenumbenennung σ entstehe jetzt dadurch, daß jede Variable v in H<br />

durch die entsprechende Variable x in B ersetzt wird. Wir müssen nun zeigen,<br />

daß B = Hσ.<br />

Wir wissen, daß |B| = |H| = |Hσ|. Wenn also B ≠ Hσ, so muß es ein<br />

i∈{1,..,|B|} geben, so daß die i-te Anweisung von B ungleich der i-ten<br />

Anweisung von Hσ ist. Sei nun b die entsprechende Anweisung in B und h die<br />

entsprechende Anweisung in H, sei s die entsprechende Anweisung in Hσ. Wir<br />

unterscheiden jetzt nach b, wobei wir wissen, daß b keine Zahlkonstante sein<br />

kann.<br />

1. Fall: b ist Wort, Sonderzeichen oder Zeichenkette:<br />

Dann muß gelten, b = h = s, denn sonst könnte D nicht Beispielauswertung für<br />

B und für H sein.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

2. Fall: b ist Variable, Inkrement oder Dekrement:<br />

Es ist klar, daß sowohl h als auch s ebenfalls Variable, Inkrement oder<br />

Dekrement sind. Sei x die in b vorkommende Variable und y die in s<br />

vorkommende Variable. Es existiert nun eine Variable v in H, deren Werte mit<br />

den Werten von x übereinstimmen.<br />

Nehmen wir jetzt an, x ≠ y. Da die bei der Bildung von Hσ aus H jedes<br />

Vorkommen von v durch x ersetzt wurde, kann v nicht die in h vorkommende<br />

Variable sein. Sei nun w die in h vorkommende Variable. Die Differenz der<br />

Werte von w und v bei den Auswertungen in der ersten und zweiten Entfaltung<br />

des umgebenen while-Konstruktes müssen sich unterscheiden. Dann können D<br />

und D' aber nicht zugleich Beispielauswertungen von H und von B sein.<br />

Also muß gelten x = y. Wir wissen, daß sowohl vor und nach der Auswertung<br />

von b und h die Werte von x und v übereinstimmen. Also müssen auch die<br />

Werte von x vor und nach der Auswertung von b und s übereinstimmen. Also<br />

muß gelten b = s.<br />

3. Fall: b ist while-Konstrukt:<br />

Es ist klar, daß sowohl h als auch s while-Konstrukte sein müssen. Für die<br />

Bildung von h wurde aber die Prozedur SampleWHILE verwendet, für deren<br />

Aufruf die Voraussetzungen für ihre Korrektheit gelten. Demnach gibt es eine<br />

Variablenumbenennung σ', so daß b = hσ'. Verbleibt zu zeigen, daß hσ' = s = hσ.<br />

Annahme hσ' ≠ s. Bei der Bildung von s wurde aber jede Variable v in h durch<br />

die entsprechende Variable x in b ersetzt, mit deren Werten sie übereinstimmt.<br />

Also muß es eine Variable v in h geben, so daß σ'(v) ≠ x. Dann kann aber nicht<br />

gelten b = hσ', denn es gibt eine Variable, die in b enthalten ist, aber nicht in<br />

hσ'. Also muß gelten hσ' = s. Damit gilt auch b = s.<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ3<br />

6HL:HLQZKLOH.RQVWUXNWLQ3PLW': G∈©XQG7HLQ<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6<br />

) UGLH3UR]HGXU6DPSOH:+,/(JHOWHQGLHIROJHQGHQ9RUDXVVHW]XQJHQ<br />

6HL:HLQZKLOH.RQVWUXNWYRQ3PLW':G:KDEHGLHIROJHQGH)RUP<br />

with while A’ do B’ end while<br />

'DEHLVHL$HLQ$XVGUXFNXQG%HLQH$QZHLVXQJVVHTXHQ]6HL7HLQ<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ6'LHHUVWHQEHLGHQWHVW.RQVWUXNWHYRQ7<br />

ODXWHQ<br />

test E do F end test<br />

test E’ do F’ end test<br />

'DEHLVHLHQ(XQG(%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ$XQG'XQG'<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ%6HL9HLQH9DULDEOHQOLVWH'DQQJLOW<br />

I UGHQ$XIUXIGHU3UR]HGXU6DPSOH:+,/(PLWGHQ3DUDPHWHUQ()()9*<br />

XQG+ZREHLGLH$XVJDEHYDULDEOH*HLQ$XVGUXFNXQGGLH$XVJDEHYDULDEOH<br />

+HLQH$QZHLVXQJVVHTXHQ]LVW<br />

, 'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

,, 6HL8 Ãwith while G’ do H’ end while'DQQLVW7HLQH<br />

%HLVSLHODXVZHUWXQJYRQ8<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

,,,(VJLEWHLQH9DULDEOHQXPEHQHQQXQJσVRGD‰*σ $XQG+σ %<br />

,9:LUGLQ*RGHU+HLQH9DULDEOHYHUZHQGHWGLHQLFKWEHUHLWVEHLP$XIUXI<br />

GHU3UR]HGXULQ9HQWKDOWHQLVWVRZLUGVLHPLWLKUHP$QIDQJVZHUWLQ9<br />

HLQJHWUDJHQ<br />

9 9HQWKlOWDP(QGHGHU3UR]HGXUGLH:HUWHDOOHULQ*XQG+<br />

YRUNRPPHQGHQ9DULDEOHQDP(QGHGHU$XVZHUWXQJ)<br />

:KDEHGLH)RUP<br />

with while A do B end while ($$XVGUXFNXQG%<br />

$QZHLVXQJVVHTXHQ]<br />

(VVHL7HLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6'LHHUVWHQEHLGHQWHVW<br />

.RQVWUXNWHYRQ7VHLHQ<br />

test C do D end test<br />

test C’ do D’ end test<br />

'DEHLVLQG&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ$XQG'XQG'<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ%'LH9DULDEOHQOLVWH9HQWKDOWHDOOHLQ3<br />

YRUGHU$XVZHUWXQJ7DXIJHWUHWHQHQ9DULDEOHQPLWLKUHQ$QIDQJVXQG<br />

(QGZHUWHQYRUGHU$XVZHUWXQJGHVHUVWHQ(OHPHQWHVYRQ') UMHGH<br />

9DULDEOHYLP$XVGUXFNYRQ:H[LVWLHUWHLQH9DULDEOH[LQ9XQG;VRGD‰<br />

GHU(QGZHUWYRQ[LQ9LVWGHU:HUWYRQYLQ&XQGGHU(QGZHUWYRQ[LQ;LVW<br />

GHU:HUWYRQYLQ&'LH3UR]HGXUVDPSOH:6WDWHPHQW6HTXHQFHZHUGHPLW<br />

GHQ3DUDPHWHUQ''9;+DXIJHUXIHQ6HLσGLH9DULDEOHQXPEHQHQQXQJ<br />

DXV/HPPD4HQWVWHKHDXV3GXUFKHUVHW]HQYRQ%GXUFK+σ'DQQ<br />

VWLPPHQGLH:HUWHEHLGHU$XVZHUWXQJYRQ3QDFKMHGHU$XVZHUWXQJYRQ%<br />

PLWGHQ:HUWHQGHU$XVZHUWXQJYRQ4QDFKMHGHU$XVZHUWXQJYRQ+σ<br />

EHUHLQ<br />

Beweis:<br />

Nach Lemma 5.4.12 ist P = Q. Damit stimmen die Auswertungen von P und Q<br />

überein.<br />

Als nächstes müssen wir die Korrektheit der Prozedur SampleWHILE beweisen. Dabei<br />

müssen wir darauf achten, daß wir bei der Benutzung der Lemmata 5.4.11, 5.4.12 und 5.4.13<br />

die Voraussetzungen für SampleWHILE erfüllen.<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ3<br />

6HL:HLQZKLOH.RQVWUXNWLQ3XQG7HLQ%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ<br />

:LQ6:KDEHGLHIROJHQGH)RUP<br />

with while A do B end while<br />

'DEHLVHL$HLQ$XVGUXFNXQG%HLQH$QZHLVXQJVVHTXHQ]6HL7HLQ<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWYRQ:LQ6'LHHUVWHQEHLGHQWHVW.RQVWUXNWH<br />

YRQ7ODXWHQ<br />

test C do D end test<br />

test C’ do D’ end test<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

'DEHLVHLHQ&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ$XQG'XQG'<br />

%HLVSLHODXVZHUWXQJVIUDJPHQWHYRQ%6HL9HLQH9DULDEOHQOLVWH'DQQJLOWI U<br />

GHQ$XIUXIGHU3UR]HGXU6DPSOH:+,/(PLWGHQ3DUDPHWHUQ&'&'9*<br />

XQG+ZREHLGLH$XVJDEHYDULDEOH*HLQ$XVGUXFNXQGGLH$XVJDEHYDULDEOH<br />

+HLQH$QZHLVXQJVVHTXHQ]LVW<br />

, 'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

,, 6HL8 Ãwith while G do H end while'DQQLVW7HLQH<br />

%HLVSLHODXVZHUWXQJYRQ8<br />

,,,(VJLEWHLQH9DULDEOHQXPEHQHQQXQJσVRGD‰*σ $XQG+σ %<br />

,9:LUGLQ*RGHU+HLQH9DULDEOHYHUZHQGHWGLHQLFKWEHUHLWVEHLP$XIUXI<br />

GHU3UR]HGXULQ9HQWKDOWHQLVWVRZLUGVLHPLWLKUHP$QIDQJVZHUWLQ9<br />

HLQJHWUDJHQ<br />

9 9HQWKlOWDP(QGHGHU3UR]HGXUGLH:HUWHDOOHULQ*XQG+<br />

YRUNRPPHQGHQ9DULDEOHQDP(QGHGHU$XVZHUWXQJ'<br />

Beweis:<br />

Wir führen den Beweis durch vollständige Induktion nach der<br />

Schachtelungstiefe D(W).<br />

Induktionsverankerung für D(W) = 0:<br />

I. Die Prozedur terminiert nach endlich vielen Schritten<br />

Die einzigen Prozeduraufrufe in SampleWHILE sind Aufrufe der Prozeduren<br />

SampleWStatementSequence und SampleWExpression. Der Aufruf der<br />

Prozedur SampleWExpression terminiert nach endlich vielen Schritten, wie<br />

wir in Lemma 5.4.6 gezeigt haben. Für den Aufruf der Prozedur<br />

SampleWStatementSequence können wir das Lemma 5.4.8 anwenden,<br />

wodurch ebenfalls die Termination im Endlichen gewährleistet ist. Da die<br />

beiden für-Schleifen innerhalb von SampleWHILE sicher terminieren, ist<br />

auch die Termination nach endlich vielen Schritten der Prozedur<br />

SampleWHILE gewährleistet.<br />

II. Sei U = " with while G do H end while ". Dann ist T eine<br />

Beispielauswertung von U.<br />

Wir wollen zuerst zeigen, daß die Prozedur nicht mit Fehlermeldung<br />

abgebrochen wird. Da dies innerhalb eines Prozeduraufrufes nicht geschehen<br />

kann, kann der Abbruch nur auftreten, wenn innerhalb der ersten für-<br />

Schleife in der Prozedur SampleWHILE für eine Variable v der Endwert in V<br />

und der Anfangswert in X nicht übereinstimmen.<br />

Nach Lemma 5.4.6 gilt aber:<br />

Jede Variable in G wird in X eingetragen. Ihr Anfangswert und ihr<br />

Endwert ist der Wert ihres Auftretens in C'.<br />

Am Ende der Prozedur ist jede Variable von G in V eingetragen. Ihr<br />

Endwert ist der Wert ihres Auftretens in C.<br />

Nach Lemma 5.4.8 gilt:<br />

Am Ende der Prozedur ist jede Variable von H in V eingetragen. Ihr<br />

Endwert ist der Wert ihres letzten Auftretens in D.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Jede Variable in H, die beim Aufruf der Prozedur nicht in X enthalten ist,<br />

wird in X eingetragen. Ihr Anfangswert ist der Wert ihres ersten<br />

Auftretens in D’.<br />

Am Ende der Prozedur ist jede Variable von H in X eingetragen. Ihr<br />

Endwert ist der Wert ihres letzten Auftretens in D’.<br />

Hieraus läßt sich folgern:<br />

Jede Variable in U ist in sowohl in V als auch in X enthalten. Endwert jeder<br />

Variablen aus U in V ist der Wert ihres letzten Auftretens in der Auswertung<br />

der ersten Entfaltung von U. Anfangswert jeder Variablen aus U in X ist der<br />

Wert ihres ersten Auftretens in der Auswertung der zweiten Entfaltung von<br />

U. Das erste Auftreten einer Variablen in einem while-Konstrukt eines<br />

Klasse-I-Programmes darf nicht innerhalb eines Inkrementes oder eines<br />

Dekrementes sein. Also muß der erste Wert einer Variablen in der zweiten<br />

Entfaltung eines while-Konstruktes mit dem letzten Wert in der ersten<br />

Entfaltung übereinstimmen. Also muß auch der Anfangswert einer Variablen<br />

in X mit dem Endwert derselben Variablen in V übereinstimmen.<br />

Der Ausdruck G ist Ausgabe der Prozedur SampleWExpression. Nach Lemma<br />

5.4.6 gilt aber dann:<br />

C und C' sind Beispielauswertungen von G (für die Variablenlisten V und<br />

X).<br />

Analog kann für die Prozedur SampleWStatementSequence nach Lemma<br />

5.4.8 ausgesagt werden:<br />

D und D' sind Beispielauswertungen von H (für die Variablenlisten V und<br />

X)<br />

Dann ist vollkommen klar, daß das Beispielauswertungsfragment<br />

test C do D end test<br />

test C’ do D’ end test<br />

Beispielauswertung von U ist. Verbleibt die Frage, ob T Beispielauswertung<br />

von U ist. Die Auswertung jeder weiteren Entfaltung von W unterscheidet<br />

sich aber nur in den Werten der in U vorkommenden Variablen. Nach Punkt<br />

III (noch zu beweisen) unterscheiden sich U und W aber nur durch eine<br />

Variablenumbenennung. Wir zeigen jetzt, daß es zu jeder Variablen x in W<br />

eine Variable v in U gibt, so daß der Wert von x und der Wert von v sich<br />

entsprechen für jede Anweisung der Beispielauswertung für W und U.<br />

Als erstes stellen wir fest, daß die Bedingung am Ende jedes weiteren test-<br />

Konstruktes der Beispielauswertungen von U und W erfüllt ist (wir nehmen<br />

an, die Beispielauswertung bestehe aus genügend vielen Entfaltungen). Dies<br />

folgt direkt aus Lemma 5.4.10. Sei x eine beliebige Variable in W und v die<br />

entsprechende Variable in U. Da die Werte von x und v zu Beginn und am<br />

Ende der i-ten Auswertung (i > 2) von U und W übereinstimmen, muß es ein<br />

Vorkommen der Variablen in der i-ten Auswertung von W und U geben, in<br />

denen sich die Werte unterscheiden, wenn das i-te test-Konstrukt von T<br />

keine Beispielauswertung von U ist. Dann können sich die beiden<br />

Anweisungen aber nicht nur in den Namen der Variablen unterscheiden.<br />

Dann können sich aber auch W und U nicht nur in den Namen der Variablen<br />

unterscheiden.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Also können sich die Auswertungen der i-ten Entfaltung von W und der i-ten<br />

Entfaltung von U nicht unterscheiden für jedes i > 0. Dann ist aber T eine<br />

Beispielauswertung von U (man erhöhe einfach die Zahl der Entfaltungen<br />

von U auf die Zahl der test-Konstrukte in T).<br />

III. Es gibt eine Variablenumbenennung σ, so daß Gσ = A und Hσ = B.<br />

Nach Lemma 5.4.7 gibt es eine Variablenumbenennung σ1, so daß A = Gσ1,<br />

nach Lemma 5.4.9 gibt es eine Variablenumbenennung σ2, so daß B = Hσ2.<br />

Die Variablenumbenennung σ entsteht dann einfach durch<br />

Zusammenfassung von σ1 und σ2.<br />

IV.Wird in G oder H eine Variable verwendet, die nicht bereits beim Aufruf<br />

der Prozedur in V enthalten ist, so wird sie mit ihrem Anfangswert in V<br />

eingetragen.<br />

Diese Aussage folgt direkt aus Lemma 5.4.6 und Lemma 5.4.8.<br />

V.V enthält am Ende der Prozedur die Werte aller in G und H<br />

vorkommenden Variablen am Ende der Auswertung D'.<br />

Nach dem Aufruf der Prozedur SampleWExpression in der Prozedur<br />

SampleWHILE gilt nach Lemma 5.4.6:<br />

Am Ende der Prozedur ist jede Variable von G in V eingetragen. Ihr<br />

Endwert ist der Wert ihres Auftretens in C.<br />

Jede Variable in G wird in X eingetragen. Ihr Anfangswert und ihr<br />

Endwert ist der Wert ihres Auftretens in C'.<br />

Nach dem Aufruf der Prozedur SampleWStatementSequence in der Prozedur<br />

SampleWHILE gilt nach Lemma 5.4.8:<br />

Am Ende der Prozedur ist jede Variable von H in V eingetragen. Ihr<br />

Endwert ist der Wert ihres letzten Auftretens in D.<br />

Am Ende der Prozedur ist jede Variable von H in X eingetragen. Ihr<br />

Endwert ist der Wert ihres letzten Auftretens in D'.<br />

Dann enthält die Variablenliste X die Werte aller in G und H vorkommenden<br />

Variablen am Ende der Auswertung D'. Da in der zweiten für-Schleife der<br />

Prozedur SampleWHILE der Endwert jeder Variablen von V, die auch in X<br />

enthalten ist (damit in U vorkommt), auf den Endwert derselben Variablen in<br />

der Variablenliste X gesetzt wird, enthält V damit die Endwerte jeder in G<br />

und H vorkommenden Variablen am Ende der Auswertung D'.<br />

Induktionsvoraussetzung:<br />

Sei n∈© beliebig. Für while-Konstrukte aus P mit D(W) ≤ n gelte für den<br />

Aufruf der Prozedur SampleWHILE:<br />

I. Die Prozedur terminiert nach endlich vielen Schritten.<br />

II. Sei U = " with while G do H end while ". Dann ist T eine<br />

Beispielauswertung von U.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

III.Es gibt eine Variablenumbenennung σ, so daß Gσ = A und Hσ = B.<br />

IV.Wird in G oder H eine Variable verwendet, die nicht bereits beim Aufruf<br />

der Prozedur in V enthalten ist, so wird sie mit ihrem Anfangswert in V<br />

eingetragen.<br />

V. V enthält am Ende der Prozedur die Werte aller in G und H<br />

vorkommenden Variablen am Ende der Auswertung D'.<br />

Induktionsbehauptung:<br />

W sei ein while-Konstrukt mit D(W) = n+1. Dann gilt für den Aufruf der<br />

Prozedur SampleWHILE:<br />

I. Die Prozedur terminiert nach endlich vielen Schritten.<br />

II. Sei U = " with while G do H end while ". Dann ist T eine<br />

Beispielauswertung von U.<br />

III.Es gibt eine Variablenumbenennung σ, so daß Gσ = A und Hσ = B.<br />

IV.Wird in G oder H eine Variable verwendet, die nicht bereits beim Aufruf<br />

der Prozedur in V enthalten ist, so wird sie mit ihrem Anfangswert in V<br />

eingetragen.<br />

V. V enthält am Ende der Prozedur die Werte aller in G und H<br />

vorkommenden Variablen am Ende der Auswertung D'.<br />

Induktionsschluß:<br />

Die Induktionsvoraussetzung erfüllt genau die Voraussetzungen für die<br />

Korrektheit der Prozedur SampleWHILE, die in den Lemmata 5.4.11, 5.4.12<br />

und 5.4.13 verlangt wurde. Der Induktionsschluß ist dann vollkommen<br />

analog wie die Induktionsverankerung zu beweisen, wobei anstelle der<br />

Lemmata 5.4.8, 5.4.9 und 5.4.10 die Lemmata 5.4.11, 5.4.12 und 5.4.13<br />

treten.<br />

Wenden wir uns jetzt der nicht-rekursiven Prozedur SampleSequence zu:<br />

/HPPD<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

%HLVSLHODXVZHUWXQJYRQ36HL7GLH%HLVSLHODXVZHUWXQJGHU<br />

+DXSWDQZHLVXQJVVHTXHQ]YRQ3'LH9DULDEOHQOLVWH9HQWKDOWHDOOH<br />

(LQJDEHYDULDEOHQYRQ3PLWLKUHQ:HUWHQLP(LQJDEHNRQVWUXNWYRQ3'DQQ<br />

JLOWI UGHQ$XIUXIGHU3UR]HGXU6DPSOH6HTXHQFHPLWGHQ3DUDPHWHUQ<br />

79$ZREHLGHU$XVJDEHSDUDPHWHUHLQH$QZHLVXQJVVHTXHQ]LVW<br />

, 'LH3UR]HGXUWHUPLQLHUWQDFKHQGOLFKYLHOHQ6FKULWWHQ<br />

,, 7LVWHLQH%HLVSLHODXVZHUWXQJYRQ$<br />

,,,(VJLEWHLQH9DULDEOHQXPEHQHQQXQJσVRGD‰$σ %ZREHL%GLH<br />

+DXSWDQZHLVXQJVVHTXHQ]YRQ3LVW<br />

,9:LUGLQ$HLQH9DULDEOHYHUZHQGHWGLHQLFKWEHUHLWVEHLP$XIUXIGHU<br />

3UR]HGXULQ9HQWKDOWHQLVWVRZLUGVLHPLWLKUHP$QIDQJVZHUWLQ9<br />

HLQJHWUDJHQ<br />

9 9HQWKlOWDP(QGHGHU3UR]HGXUGLH:HUWHDOOHULQ$YRUNRPPHQGHQ<br />

9DULDEOHQDP(QGHGHU$XVZHUWXQJ7<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Beweis:<br />

I. Die Prozedur terminiert nach endlich vielen Schritten.<br />

Wenn T = "", wird die Prozedur sofort abgebrochen. Gehen wir also davon aus,<br />

daß T ≠ "" und die äußere solange-Schleife wird betreten. Zeigen wir zuerst, daß<br />

die äußere solange-Schleife maximal |T| mal durchlaufen wird. Die äußere<br />

solange-Schleife wird spätestens verlassen, wenn der Lesezeiger in T hinter dem<br />

letzten Element von T steht. Da der Lesezeiger vor dem ersten<br />

Schleifendurchlauf vor dem ersten Element von T steht und bei jedem<br />

Schleifendurchlauf um wenigstens ein Element vorgestellt wird, terminiert die<br />

äußere solange-Schleife nach höchstens |T| Durchläufen, falls jeder<br />

Schleifendurchlauf in endlicher Zeit beendet wird.<br />

Prüfen wir jetzt dies nach. Falls das von T gelesene Element t ungleich einem<br />

test-Konstrukt ist, ist die Termination des Schleifendurchlaufs gewährleistet.<br />

Nehmen wir deswegen an, t wäre ein test-Konstrukt.<br />

Der Aufruf der Prozedur SampleWHILE terminiert nach Lemma 5.4.14, ebenso<br />

die innere solange-Schleife, da die Prozedur TestWHILE nach Lemma 5.4.4<br />

terminiert, und die Schleife nur endlich oft durchlaufen wird. Denn die innere<br />

solange-Schleife wird abgebrochen, wenn der Lesezeiger L nicht vor einem<br />

weiteren test-Konstrukt steht, und der Lesezeiger L wird in der Schleife um ein<br />

Element vorgestellt. Da T nur endlich viele test-Konstrukte enthalten kann, ist<br />

die Termination der inneren solange-Schleife garantiert. Da der Aufruf der<br />

Prozedur TestWExpression gemäß Lemma 5.4.1 terminiert, ist die Laufzeit für<br />

jeden Schleifendurchlauf der äußeren solange-Schleife endlich.<br />

II. T ist eine Beispielauswertung von A.<br />

Wir zeigen zuerst, daß die Prozedur nicht mit einem Fehler abbricht. Es gibt in<br />

der Prozedur genau fünf Stellen, an denen die Prozedur abgebrochen wird (sie<br />

wird nicht in einem der aufgerufenen Prozeduren abgebrochen):<br />

a) wenn die Prozedur TestWHILE den Wert result = FALSCH zurückliefert.<br />

b) wenn die Prozedur TestWExpression den Wert result = FALSCH<br />

zurückliefert.<br />

c) wenn das von T gelesene Element t ein test-Konstrukt ist, und der Lesezeiger<br />

in T hinter dem letzten Element von T steht.<br />

d) wenn das von T gelesene Element t ein test-Konstrukt ist, das auf t folgende<br />

Element aber nicht.<br />

e) wenn T ein Element ungleich einem Wort, einer Zeichenkette, einem<br />

Sonderzeichen, einer Zahl oder einem test-Konstrukt ist.<br />

Fall e) können wir sofort ausschließen. Die Fälle a) und b) werden durch die<br />

Lemmata 5.4.1 und 5.4.4 widerlegt.<br />

Als nächstes beobachten wir, daß sobald mit t ein test-Konstrukt eingelesen<br />

wird, in diesem Schleifendurchlauf der Lesezeiger soweit vorgestellt wird, daß er<br />

hinter dem letzten Element von T steht, oder vor einem Element von T ungleich<br />

einem test-Konstrukt steht. D.h. falls T eine Folge von test-Konstrukten<br />

enthält, so wird nur das erste test-Konstrukt in t eingelesen. Da jedes<br />

Beispielauswertungsfragment eines while-Konstruktes aus mindestens zwei<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

test-Konstrukten besteht, muß t ein weiteres test-Konstrukt folgen. Dies<br />

schließt die Fälle c) und d) aus.<br />

In jedem Schleifendurchlauf wird A um ein Element ergänzt. Die äußere<br />

Schleife wird also |A| mal durchlaufen. Sei B die Hauptanweisungssequenz von<br />

P. Wir zeigen nun den folgenden Hilfssatz:<br />

Hilfssatz:<br />

1) Für jedes i∈{0,..,|A|} ist das Anfangsstück der<br />

Beispielauswertungsfragmente der ersten i Anweisungen von B<br />

Beispielauswertung der ersten i Anweisungen von A.<br />

2) Die Variablenliste V enthält nach i Schleifendurchläufen die Wert aller in den<br />

ersten i Anweisungen von A vorgekommenen Variablen am Ende nach der i-ten<br />

Anweisung von A.<br />

3) Der Lesezeiger L steht nach dem i-ten Schleifendurchlauf hinter der<br />

Beispielauswertung der i-ten Anweisung von B.<br />

Beweis (induktiv):<br />

Für i = 0 ist der Hilfssatz trivial. Wir nehmen nun an, die Behauptung gelte für<br />

alle i ≤ n und zeigen den Hilfssatz für i = n+1.<br />

Nach Induktionsvoraussetzung steht der Lesezeiger L vor dem<br />

Beispielauswertung des (n+1)-ten Elementes von B. Das erste Element dieser<br />

Beispielauswertung wird in t eingelesen und der Lesezeiger um ein Element<br />

vorgestellt. Sei a das (n+1)-te Element von A. Wir unterscheiden nach t:<br />

1. Fall: t ist Sonderzeichen, Wort oder Zeichenkette:<br />

Dann ist t = a eine Beispielauswertung von a. Nach Induktionsvoraussetzung<br />

ist das Anfangsstück der Auswertungen der ersten n Elemente von B eine<br />

Beispielauswertung der ersten n Elemente von A. Somit ist das Anfangsstück<br />

von T für die ersten n+1 Elemente von B eine Beispielauswertung der ersten<br />

n+1 Elemente von A und die Teilaussage 1) ist bewiesen. Da weder V noch eine<br />

Variable in A verändert wurde, gilt Teilaussage 2) nach<br />

Induktionsvoraussetzung. Da die Beispielauswertung des (n+1)-ten Elementes<br />

von B nur ein Element in T ist, gilt auch die Teilaussage 3).<br />

2. Fall: t ist Zahl, etwa c:<br />

t muß Wert einer Variablen sein, da in P keine Zahlkonstanten vorkommen. Da<br />

wir nicht innerhalb eines while-Konstruktes sind, darf es in Klasse-I-<br />

Programmen genau eine Variable geben, deren Wert zwischen c-1 und c+1 liegt<br />

Nach Induktionsvoraussetzung enthält V die Werte aller Variablen in A nach<br />

Auswertung des n-ten Elementes.<br />

1. Unterfall: es gibt eine Variable v in V mit Endwert c.<br />

Es gibt keine andere Variable in A, deren Wert c ist. Dann ist a gerade die<br />

Variable v und t ist Beispielauswertung von a. An dieser Stelle ist auch wichtig,<br />

daß das Dekrement von Variablen mit Wert 0 in Klasse-I-Programmen nicht<br />

erlaubt ist.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

2. Unterfall: es gibt eine Variable v in V mit Endwert c - 1:<br />

Dann gibt es keine andere Variable in A, deren Wert c sein kann. Dann ist a<br />

gleich ++v und t ist Beispielauswertung von a.<br />

3. Unterfall: es gibt eine Variable v in V mit Endwert c + 1:<br />

Dann gibt es keine andere Variable in A, deren Wert c sein kann. Dann ist a<br />

gleich --v und t ist Beispielauswertung von a.<br />

4. Unterfall: es gibt keine Variable in V, für deren Endwert d gilt: c-1 ≤ d ≤ c+1:<br />

Dann muß c der Wert einer Variablen, etwa v, sein, die noch nicht<br />

vorgekommen ist, da nach Induktionsvoraussetzung V die Werte aller<br />

vorgekommenen Variablen beinhaltet. Das erste Vorkommen einer Variablen<br />

darf aber nicht in einem Inkrement oder Dekrement erfolgen, also ist a nur die<br />

Variable v. Die Variable hat dann den Anfangswert c, der als Anfangs- und als<br />

Endwert zusammen mit v in V eingetragen wird. c ist dann Beispielauswertung<br />

von v.<br />

Mithilfe der Induktionsvoaussetzung sieht man nun, daß das Anfangsstück von<br />

T der Auswertungen der ersten n+1 Anweisungen von B eine<br />

Beispielauswertung der ersten n+1 Elemente von A ist, womit wir Teilaussage<br />

1) bewiesen haben. Ebenfalls wissen wir, daß das Beispielauswertungsfragment<br />

des (n+1)-ten Elementes von b nur aus t besteht. Da nach<br />

Induktionsvoraussetzung der Lesezeiger vor dem (n+1)-ten Schleifendurchlauf<br />

hinter dem Beispielauswertungsfragment der n-ten Anweisung von B steht,<br />

wissen wir, daß der Lesezeiger jetzt hinter dem Beispielauswertungsfragment<br />

der (n+1)-ten Anweisung on B steht (Teilaussage 3)).<br />

Falls a kein Inkrement oder Dekrement ist, ändert sich weder der Wert einer<br />

Variablen im Anfangsstück von B noch der Wert einer Variablen in V. Falls a<br />

ein Inkrement ist, etwa der Variablen v, so wird der Wert der Variablen v<br />

sowohl bei der Auswertung von A als auch in V um 1 erhöht. Falls a eine<br />

Dekrement ist, etwa der Variablen v (dann ist der Wert von v nicht 0), so wird<br />

sowohl der Wert von v bei der Auswertung T als auch in der Variablenliste V<br />

um 1 erniedrigt. Die Werte aller Variablen ungleich v werden nicht berührt. V<br />

beinhaltet nach Induktionsvoraussetzung die Werte aller Variablen des<br />

Anfangsstückes der ersten n Anweisungen von A nach der Auswertung der n-<br />

ten Anweisung. Nach dem (n+1)-ten Schleifendurchlauf beinhaltet V die Werte<br />

aller im Anfangsstück der ersten n+1 Anweisungen von A nach der Auswertung<br />

von a, womit wir Teilaussage 2) bewiesen haben.<br />

3. Fall: t ist test-Konstrukt:<br />

Wir wissen, daß der Lesezeiger vor einem weiteren test-Konstrukt stehen muß.<br />

Dieses zweite test-Konstrukt wird als u gelesen, und der Lesezeiger wird um ein<br />

Element vorgestellt.<br />

t und u sind jetzt die Auswertung der ersten und zweiten Entfaltung eines<br />

while-Konstruktes. D.h. t hat die Form<br />

test C do D end test<br />

und u hat die Form<br />

test C’ do D’ end test<br />

Dabei sind C und C' Beispielauswertungsfragmente eines Ausdrucks und D und<br />

D' Beispielauswertungsfragmente einer Anweisungssequenz.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Für den Aufruf der Prozedur SampleWHILE mit den Parametern<br />

(C,D,C',D',V,G,H), wobei der Ausdruck G und die Anweisungssequenz H<br />

Ausgabeparameter sind, wissen wir dann nach Lemma 5.4.14, daß die<br />

Beispielauswertung der (n+1)-ten Anweisung von B eine Beispielauswertung für<br />

a ist. Zusammen mit der Induktionsvoraussetzung wissen wir dann aber, daß<br />

das Anfangsstück von T der ersten n+1 Anweisungen von B eine<br />

Beispielauswertung der ersten n+1 Anweisungen von A ist (Teilaussage 1)).<br />

Außerdem sagt uns Lemma 5.4.14, daß jede in der in a erstmalig<br />

vorgekommenen mit ihrem Anfangswert in V eingetragen worden ist. Ebenso<br />

besagt das Lemma, daß die Endwerte jeder Variablen im Anfangsstück von A<br />

mit den Endwerten in der Variablenliste V nach dem Aufruf übereinstimmen.<br />

Dann beinhaltet die Variablenliste V die Werte aller bereits vorgekommen<br />

Variablen nach Auswertung von u.<br />

Wir wissen bereits, daß am Ende des (n+1)-ten Schleifendurchlaufs der<br />

Lesezeiger L hinter der Auswertung des (n+1)-ten Elementes von B steht<br />

(Teilaussage 3)). Lemma 5.4.4 sagt uns, daß nach jedem Aufruf der Prozedur<br />

TestWHILE für eines weiteres test-Konstrukt der Beispielauswertung des (n+1)-<br />

ten Elementes von B die Werte von V die Werte der Variablen von a am Ende<br />

dieses test-Konstruktes sind. Falls nach Beendigung der inneren solange-<br />

Schleife die Prozedur SampleWExpresion aufgerufen wird, so folgt nach Lemma<br />

5.4.1, daß die Werte der Variablen am Ende der Auswertung des letzten test-<br />

Konstruktes die Endwerte dieser Variablen in V sind. Dann wissen wir, daß die<br />

Variablenliste V die Endwerte aller Variablen am Ende der Auswertung von a<br />

(wie in T) beinhaltet (Teilaussage 2)).<br />

Damit ist der Hilfssatz bewiesen. (Hilfssatz)<br />

Die 2. Behauptung des Lemmas folgt aus der 1. Teilaussage des Hilfssatzes.<br />

III. Es gibt eine Variablenumbenennung σ, so daß Aσ = B, wobei B die<br />

Hauptanweisungssequenz von P ist.<br />

Wir wissen aus dem Beweis von II, daß T Beispielauswertung sowohl für A als<br />

auch für B ist. Daraus folgt, daß |A| = |B|. Wir zeigen, daß sich A und B nur<br />

im Namen der Variablen unterscheiden. Sei i ∈ {1,..,|A|} beliebig. Sei ai die i-te<br />

Anweisung von A und bi die i-te Anweisung von B.<br />

1. Fall: bi ist Sonderzeichen, Zahl oder Zeichenkette.<br />

Dann muß gelten ai = bi, denn sonst könnten T nicht Beispielauswertung von A<br />

und von B sein.<br />

2. Fall: bi ist while-Konstrukt:<br />

ai ist dann ebenfalls while-Konstrukt und wurde durch die Prozedur<br />

SampleWHILE gebildet. Für diese Prozedur gilt das Lemma 5.4.14, nach dem ai<br />

und bi bis auf die Namen der Variablen übereinstimmen. Man beachte, daß für<br />

jede erstmalig in bi auftretende Variable, eine neue Variable in ai eingeführt<br />

wurde, die denselben Wert wie die ursprüngliche Variable besitzt.<br />

3. Fall: bi ist Variable x, die erstmalig in B auftaucht.<br />

Sei c der Wert von x an der Stelle der Auswertung von bi. V kann keine Variable<br />

mit einem Wert zwischen c-1 und c+1 enthalten, denn sonst müßte es eine<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

zweite Variable in B geben, deren Wert sich vom Wert von x um weniger als 2<br />

unterscheidet. Also wird a gleich einer neuen Variablen, etwa v, gesetzt, deren<br />

Wert mit dem von x übereinstimmt.<br />

4. Fall: bi ist Variable x, die nicht erstmalig in B auftaucht.<br />

x muß erstmalig im 2. Fall oder im 3. Fall vorgekommen sein. Dann gibt es eine<br />

Variable v in A, deren Wert mit dem Wert von x übereinstimmt. Nach dem<br />

Hilfssatz im Beweis des 2. Teils des Lemmas ist der Wert der Variablen v in V<br />

enthalten. Dann wird aber ai auf die Variable gesetzt. ai und bi unterscheiden<br />

sich nur im Namen der Variablen.<br />

5. Fall: bi ist Inkrement einer Variablen, etwa der Variablen x.<br />

x kann nicht erstmalig in bi vorkommen, sondern muß gemäß dem 2. Fall oder<br />

dem 3. Fall eingeführt worden sein. Auf jeden Fall gibt es eine Variable v in A<br />

und V, deren Wert mit dem Wert von x übereinstimmt. Sei c der Wert von x vor<br />

dem Inkrement. Dann beinhaltet V eine Variable mit dem Wert c-1, aber keine<br />

Variablen mit dem Wert c, also wird ai auf das Inkrement der Variablen v<br />

gesetzt und der Endwert von v in v um eins erhöht. ai und bi stimmen wieder<br />

nur im Namen der Variablen überein.<br />

6. Fall: bi ist Inkrement einer Variablen, etwa der Variablen x.<br />

Die Argumentation verläuft völlig analog zum 5. Fall.<br />

Wie sehen also, daß A und B sich nur in den Namen der Variablen<br />

unterscheiden. Für jede Variable x in B existiert eine Variable v in A, deren<br />

Werte mit den Werten von x übereinstimmen. Die Variablenumbenennung σ<br />

entsteht dann einfach durch Ersetzen jeder Variablen v durch die entsprechende<br />

Variablen x.<br />

Wird in A eine Variable verwendet, die nicht bereits beim Aufruf der Prozedur<br />

in V enthalten ist, so wird sie mit ihrem Anfangswert in V eingetragen.<br />

Haben wir bereits im Beweis des Hilfssatzes im Beweis des 2. Teil des Lemmas<br />

gesehen.<br />

V enthält am Ende der Prozedur die Werte aller in A vorkommenden Variablen<br />

am Ende der Auswertung T.<br />

Folgt direkt aus der 2. Teilaussage des Hilfssatzes im Beweis des 2. Teils des<br />

Lemmas.<br />

Endlich können wir unseren Satz formulieren:<br />

6DW]<br />

6HL3HLQ.ODVVH,3URJUDPPXQG6HLQH.ODVVH,%HLVSLHODXVZHUWXQJYRQ3<br />

'DQQJLOWI UGHQ$XIUXIGHV$OJRULWKPXV6DPSOH3URJUDPPLWGHQ<br />

3DUDPHWHUQ65ZREHLGHU$XVJDEHSDUDPHWHU5HLQ3URJUDPPLVW<br />

'HU$OJRULWKPXVWHUPLQLHUWQDFKHQGOLFKYLHOHQ5HFKHQVFKULWWHQ<br />

3≅5<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Beweis:<br />

1. Der Algorithmus terminiert nach endlich vielen Rechenschritten.<br />

Die einzige Prozedur, die aufgerufen wird, ist die Prozedur SampleSequence.<br />

Deren Termination wird aber in Lemma 5.4.15 bestätigt. Die für-Schleifen im<br />

Algorithmus SampleProgram werden nach endlicher Zeit verlassen. Dann<br />

benötigt der Algorithmus insgesamt nur endliche Rechenzeit.<br />

2. P ≅ R.<br />

Sei Q die konstantenbereinigte Form von P. In der ersten für-Schleife des<br />

Algorithmus' wird für jede Eingabevariable von Q eine Variable mit Anfangsund<br />

Endwert des Wertes der Eingabevariablen im Eingabekonstrukt in die<br />

Variablenliste V eingetragen, die anfänglich leer war. Für den folgenden Aufruf<br />

der Prozedur SampleSequence mit den Parametern (T,V,A), wobei T die<br />

Beispielauswertung der Hauptanweisungssequenz von Q und der<br />

Ausgabeparameter A eine Anweisungssequenz ist, gilt das Lemma 5.4.15:<br />

I. Die Prozedur terminiert nach endlich vielen Schritten.<br />

II. T ist eine Beispielauswertung von A.<br />

III.Es gibt eine Variablenumbenennung σ, so daß Aσ = B, wobei B die<br />

Hauptanweisungssequenz von P ist.<br />

IV.Wird in A eine Variable verwendet, die nicht bereits beim Aufruf der<br />

Prozedur in V enthalten ist, so wird sie mit ihrem Anfangswert in V<br />

eingetragen.<br />

V. V enthält am Ende der Prozedur die Werte aller in A vorkommenden<br />

Variablen am Ende der Auswertung T.<br />

Man beachte, daß es nur eine Variable in V geben kann, etwa y, deren Wert mit<br />

dem Wert der Ausgabevariablen in Q übereinstimmt. R erhält den Wert<br />

input (v 1 ,..,v m ) K m+1 ... K Länge(V) A output y<br />

Dabei v1,...,vm die Variablen, die den Eingabevariablen von Q entsprechen und<br />

Km+1,...,KLänge(V) die Hauptinitialisationssequenz (man beachte, daß V die Werte<br />

des ersten Vorkommens aller Variablen von A enthält, diese Werte müssen mit<br />

den Initialisationswerten übereinstimmen).<br />

R' entstehe durch R durch Ersetzen der Variablen von R durch die<br />

entsprechenden Variablen in Q. Nach Lemma 3.5.2 gilt R' ≅ R.<br />

R' und Q unterscheiden sich jetzt nur noch in der Reihenfolge der Initialisation<br />

in der Hauptinitialisationssequenz. Nach Lemma 3.5.4 gilt dennoch Q ≅ R' ≅ R.<br />

Nach Lemma 3.5.1 gilt dann Q ≅ R. Nach Lemma 3.5.3 gilt P ≅ Q ≅ R. Dann<br />

folgt wieder mit Lemma 3.5.1: P ≅ R.<br />

Satz 5.4.1 verschenkt aber einiges der Aussage der Lemmata.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

6DW]<br />

6HL3HLQ.ODVVH,3URJUDPPGDVNHLQH=DKONRQVWDQWHQHQWKlOWXQG6HLQH<br />

.ODVVH,%HLVSLHODXVZHUWXQJYRQ3'DQQJLOWI UGHQ$XIUXIGHV$OJRULWKPXV<br />

6DPSOH3URJUDPPLWGHQ3DUDPHWHUQ65ZREHLGHU$XVJDEHSDUDPHWHU5<br />

HLQ3URJUDPPLVW<br />

'HU$OJRULWKPXVWHUPLQLHUWQDFKHQGOLFKYLHOHQ5HFKHQVFKULWWHQ<br />

3XQWHUVFKHLGHWVLFKYRQ5QXULQGHQ1DPHQGHU9DULDEOHQXQGLQGHU<br />

5HLKHQIROJHGHU,QLWLDOLVLHUXQJHQLP+DXSWLQLWLDOLVDWLRQVNRQVWXNW<br />

Beweis:<br />

folgt direkt aus dem Beweis des Lemma 5.4.1.<br />

5.5 Komplexität<br />

Wie wollen hier einen Ausdruck für eine obere Schranke der Rechenzeit des Algorithmus im<br />

schlechtesten Fall herleiten. Dabei wollen annehmen, daß wir für jede Operation nur eine<br />

Zeiteinheit benötigen.<br />

Wir beginnen unsere Komplexitätsanalyse mit der Aufwandsberechnung für die Prozedur<br />

TestWExpression.<br />

/HPPD<br />

'LH3UR]HGXU7HVW:([SUHVVLRQZHUGHPLWGHQ3DUDPHWHU%*9UHVXOW<br />

DXIJHUXIHQZREHL*HLQH$XVGUXFN%HLQH%HLVSLHODXVZHUWXQJYRQ*9HLQH<br />

9DULDEOHQOLVWHXQGUHVXOWHLQHORJLVFKH$XVJDEHYDULDEOHLVW'DQQEHQ|WLJW<br />

GLH3UR]HGXULPVFKOHFKWHVWHQ)DOO2_%__9_6FKULWWH<br />

Beweis:<br />

In Lemma 5.4.1 haben wir gezeigt, daß die äußere solange-Schleife in der<br />

Prozedur |B| = |G| mal durchlaufen wird. Jedes Element von G kann<br />

entweder Zeichenkette, Wort, Sonderzeichen oder Variable sein. In den ersten<br />

drei Fällen kann der Schleifendurchlauf sofort (in konstanter Zeit)<br />

abgeschlossen werden. Fall das vom Ausdruck G gelesene Element aber eine<br />

Variable ist, so muß der Wert der Variablen in der Variablenliste V ermittelt<br />

werden Dazu sind maximal |V| Vergleiche notwendig. Damit ergibt sich der<br />

Zeitbedarf im schlechtesten Fall zu O(|B||V|).<br />

Für die Berechnung der Komplexität der Prozedur TestWStatementSequence benötigen wir<br />

eine Voraussetzung für die Komplexität der Prozedur TestWHILE. Deswegen betrachten wir<br />

zunächst die Komplexität für den Fall, daß die Prozedur TestWHILE nicht aufgerufen wird.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Abbildung 7 : Struktur des Beweises von Satz 5.5.1<br />

benötigt für<br />

SampleProgram<br />

Satz 5.5.1<br />

SampleSequence<br />

Lemma 5.5.10<br />

Lemma 5.4.15<br />

TestWHILE<br />

SampleWHILE<br />

Lemma 5.5.4<br />

Lemma 5.5.9<br />

SampleWSequence<br />

Lemma 5.4.3<br />

TestWSequence<br />

Lemma 5.5.3<br />

Lemma 5.5.8<br />

Lemma 5.4.11<br />

Lemma 5.4.2<br />

Lemma 5.5.2<br />

Lemma 5.5.7<br />

Lemma 5.4.8<br />

TestWExpression<br />

SampleWExpression<br />

Lemma 5.4.1<br />

Lemma 5.5.1<br />

Lemma 5.5.6<br />

Lemma 5.4.6<br />

MatchWHILE<br />

Lemma 5.4.5<br />

Lemma 5.5.5<br />

/HPPD<br />

'LH3UR]HGXU7HVW:6WDWHPHQW6HTXHQFHZHUGHPLWGHQ3DUDPHWHU<br />

&+9UHVXOWDXIJHUXIHQZREHL+HLQH$QZHLVXQJVVHTXHQ]LVW&HLQH<br />

%HLVSLHODXVZHUWXQJYRQ+9HLQH9DULDEOHQOLVWHXQGUHVXOWHLQHORJLVFKH<br />

$XVJDEHYDULDEOHLVW(VJHOWH'+ 'DQQEHQ|WLJWGLH3UR]HGXULP<br />

VFKOHFKWHVWHQ)DOO2_&__9_6FKULWWH<br />

Beweis:<br />

In Lemma 5.4.2 haben wir gezeigt, daß die äußere solange-Schleife in der<br />

Prozedur |C| = |H| mal durchlaufen wird. Jedes Element von H muß entweder<br />

Zeichenkette, Wort, Sonderzeichen, Variablen, Dekrement oder Inkrement sein.<br />

Im Falle einer Zeichenkette, eines Sonderzeichens oder eines Wortes wird der<br />

Schleifendurchlauf nach konstanter Zeit beendet. Falls aber die gelesene<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Anweisung eine Variable, ein Inkrement oder ein Dekrement ist, so muß zuerst<br />

der Wert dieser Variablen (und die Speicherstelle dieses Wertes) aus der<br />

Variablenliste V entnommen werden. Hierzu sind im schlechtesten Fall |V|<br />

Operationen notwendig. Der Gesamtzeitbedarf im schlechtesten Fall für die<br />

Prozedur ist also von der Größenordnung O(|C||V|).<br />

/HPPD<br />

'LH3UR]HGXU7HVW:6WDWHPHQW6HTXHQFHZHUGHPLWGHQ3DUDPHWHU<br />

&+9UHVXOWDXIJHUXIHQZREHL+HLQH$QZHLVXQJVVHTXHQ]LVW&HLQH<br />

%HLVSLHODXVZHUWXQJYRQ+9HLQH9DULDEOHQOLVWHXQGUHVXOWHLQHORJLVFKH<br />

$XVJDEHYDULDEOHLVW(VVHLG '+<br />

) UGLH3UR]HGXU7HVW:+,/(JHOWHGLHIROJHQGH9RUDXVVHW]XQJ<br />

'LH3UR]HGXU7HVW:+,/(ZHUGHPLWGHQ3DUDPHWHUQ%&*+9UHVXOW<br />

DXIJHUXIHQZREHL*HLQ$XVGUXFN+HLQH$QZHLVXQJVVHTXHQ]%HLQH<br />

%HLVSLHODXVZHUWXQJYRQ*XQG&HLQH%HLVSLHODXVZHUWXQJYRQ+LVWUHVXOW<br />

VHLHLQHORJLVFKH$XVJDEHYDULDEOHXQG9HLQH9DULDEOHQOLVWH(VJHOWH'+<br />

G(VVHLQGLH6XPPHGHU=DKOGHU=HLFKHQLQ%XQG&XQGP _9_'DQQ<br />

LVWGLH.RPSOH[LWlWLPVFKOHFKWHVWHQ)DOOJHJHEHQGXUFK2QP<br />

(VVHLQGLH=DKOGHU=HLFKHQLQ&XQGP _9_'DQQEHQ|WLJWGLH3UR]HGXU<br />

7HVW:6WDWHPHQW6HTXHQFHLPVFKOHFKWHVWHQ)DOO2QP5HFKHQVFKULWWH<br />

Beweis:<br />

Wir wissen nach Lemma 5.4.3, daß die äußere solange-Schleife |H| mal<br />

durchlaufen wird. Man beachte, daß im allgemeinen |H| ≠ |C|. Sei Ri für<br />

i∈{1,..,|H|} die Rechenzeit im i-ten Schleifendurchlauf. Dann wird die<br />

Gesamtrechenzeit der Prozedur im wesentlichen bestimmt durch<br />

der Zeitbedarf für alle übrigen Operationen ist konstant.<br />

|H|<br />

∑ R i<br />

i=1<br />

, denn<br />

Berechnen wir zuerst die Rechenzeit im Fall, daß das von H eingelesene<br />

Element t ein while-Konstrukt sein. Sei j die Nummer des Schleifendurchlaufs,<br />

in dem t eingelesen wird. Sei G' der Ausdruck von t und H' die<br />

Anweisungssequenz von t. Sei T die Beispielauswertung von t in C. T sei ist<br />

dann entweder eine Folge:<br />

test B1 do C1 end test<br />

test B 2 do C 2 end test<br />

...<br />

test B r do C r end test<br />

oder eine Folge<br />

test B 1 do C 1 end test<br />

test B 2 do C 2 end test<br />

...<br />

test B r do C r end test<br />

test B r+1 skip<br />

für ein r > 1. Dabei sind B1,..,Br+1 Beispielauswertungen von G' und C1,..,Cr<br />

Beispielauswertungen von H'. Die Rechenzeit Rj ist damit im wesentlichen<br />

durch die Aufrufe der Prozedur TestWHILE mit den Parametern<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

(B1,C1,G,H,V,result)<br />

(B2,C2,G,H,V,result)<br />

...<br />

(Br,Cr,G,H,V,result)<br />

bestimmt, sowie durch den eventuell folgenden Aufruf der Prozedur<br />

TestWExpression. Für jeden der Aufrufe der Prozedur TestWHILE gilt die<br />

Voraussetzung in unserem Lemma. Sei ni die Summe der Zahl der Zeichen in Bi<br />

und Ci. Dann ist die Komplexität im schlechtesten Fall für das i-te test-<br />

Konstrukt gegeben durch O(nim).<br />

Die Komplexität für den eventuellen Aufruf der Prozedur TestWExpression mit<br />

den Parametern (Br+1, G,V,result) ist nach Lemma 5.5.1 aber gerade<br />

O(|Br+1|m). Da jede Anweisung aus mindestens einem Zeichen besteht, läßt<br />

sich die Komplexität für den Aufruf der Prozedur TestWExpression abgrenzen<br />

durch O(nr+1m), wobei nr+1 die Zahl der Zeichen von Br+1 ist.<br />

Dann läßt sich die Komplexität im schlechtesten Fall für den j-ten<br />

Schleifendurchlauf begrenzen durch O(nTm), wobei nT die Zahl der Zeichen von<br />

T ist.<br />

Falls das von H eingelesene Element t eine Variable, ein Inkrement oder ein<br />

Dekrement ist, so ist die Länge der Beispielauswertung von t gleich 1. Die<br />

Rechenzeit ist hier vor allem abhängig von der Zeit für das Suchen des Wertes<br />

und des Speicherplatzes für die Änderung desselben einer Variablen in V. D.h.<br />

Rj = O(1 m). Falls das von H eingelesene Element t eine Zeichenkette, ein<br />

Sonderzeichen oder ein Wort ist, so ist die Länge der Beispielauswertung von t<br />

gleich der Länge von t. Die Rechenzeit ist in diesem Fall konstant.<br />

Bezeichne nCi die Länge der Beispielauswertung der i-ten Anweisung von H, so<br />

gilt für die Gesamtrechenzeit der Prozedur:<br />

R = R =<br />

ges<br />

|H|<br />

∑<br />

i=1<br />

i<br />

|H|<br />

∑<br />

i=1<br />

Im schlimmsten Fall gilt also Rges = O(nm).<br />

⎧O(1)<br />

falls i - te Anweisung ist Sonderzeichen,<br />

⎪<br />

Wort oder Zeichenkette<br />

⎪<br />

⎨O(nCim) falls i - te Anweisung ist Variable,<br />

⎪<br />

Inkrement oder Dekrement<br />

⎪<br />

⎩⎪<br />

O(nCim) sonst<br />

Nun zur Prozedur TestWHILE. Die im Lemma 5.5.3 benutzte Voraussetzung über die<br />

Komplexität der Prozedur TestWHILE wird sich jetzt durch die Induktionsvoraussetzung<br />

ergeben.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

/HPPD<br />

'LH3UR]HGXU7HVW:+,/(ZHUGHPLWGHQ3DUDPHWHUQ%&*+9UHVXOW<br />

DXIJHUXIHQZREHL*HLQ$XVGUXFN+HLQH$QZHLVXQJVVHTXHQ]%HLQH<br />

%HLVSLHODXVZHUWXQJYRQ*XQG&HLQH%HLVSLHODXVZHUWXQJYRQ+LVWUHVXOWVHL<br />

HLQHORJLVFKH$XVJDEHYDULDEOHXQG9HLQH9DULDEOHQOLVWH(VVHLQGLH6XPPH<br />

GHU=DKOGHU=HLFKHQLQ%XQG&XQGP _9_'DQQLVWGLH.RPSOH[LWlWLP<br />

VFKOHFKWHVWHQ)DOOJHJHEHQGXUFK2QP<br />

Beweis:<br />

Sofort einsichtig ist, daß die Rechenzeit für die Prozedur TestWHILE im<br />

wesentlichen gleich der Summe der Rechenzeiten der beiden Prozeduraufrufen<br />

ist. Sei nB die Zahl der Zeichen in B und nC die Zahl der Zeichen in C.<br />

(vollständige Induktion)<br />

Induktionsverankerung für D(H) = 0:<br />

Die Rechenzeit für die Prozedur TestWExpression ist O(|B||V|) ≤ O(nBm)<br />

nach Lemma 5.5.1. Die Rechenzeit für die Prozedur TestWStatementSequence<br />

ist gegeben durch O(nCm) nach Lemma 5.5.2. Also ergibt sich die<br />

Gesamtrechenzeit für die Prozedur zu O(nm).<br />

Induktionsvoraussetzung:<br />

Sei d∈©. Für D(H) ≤ d sei die Komplexität der Prozedur TestWHILE gleich<br />

O(nm).<br />

Induktionsbehauptung:<br />

Für D(H) = d+1 sei die Komplexität der Prozedur TestWHILE gleich O(nm).<br />

Induktionsschluß:<br />

Nach Lemma 5.5.1 ist die Komplexität der Prozedur TestWExpression gleich<br />

O(|B||V|) ≤ O(nBm). Nach Induktionsvoraussetzung können wir für den<br />

Aufruf der Prozedur TestWStatementSequence da Lemma 5.5.3 verwenden,<br />

wonach sich die Komplexität im schlechtesten Fall ergibt zu O(nCm). Folglich<br />

wird die Gesamtkomplexität beschrieben durch O(nm).<br />

Als nächstes analysieren wir das Zeitverhalten der Prozedur MatchWHILE.<br />

/HPPD<br />

'LH3UR]HGXU0DWFK:+,/(ZHUGHPLWGHQ3DUDPHWHUQ<br />

00119


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Wir berechnen zuerst die Rechenzeit für den ersten Teil der Prozedur, in dem<br />

die Ausdrücke M und M' miteinander verglichen werden.<br />

Die erste solange-Schleife wird nach dem Beweis von Lemma 5.4.5 |M|-mal<br />

durchlaufen. Falls das von M gelesene Element eine Zeichenkette, ein Wort oder<br />

ein Sonderzeichen ist, so ist der Zeitbedarf für einen Schleifendurchlauf<br />

konstante, falls das gelesene Element eine Variable, ein Inkrement oder ein<br />

Dekrement ist, so ergibt sich der Aufwand im wesentlichen durch das Auffinden<br />

der Endwerte der Variablen in den Variablenlisten V und Y und das Eintragen<br />

einer Variablen in die Variablenliste X. Dieser Aufwand kann also durch<br />

O(|V|)+O(|X|)+O(|Y|) = O(m) beschrieben werden. Für die erste solange-<br />

Schleife läßt sich dann ein Gesamtaufwand von O(|M|m) ≤ O(nMm) angeben.<br />

Der zweite Teil der Prozedur MatchWHILE, in dem die Anweisungssequenzen<br />

miteinander verglichen werden, ist rekursiv, wir benötigen also zum Beweis des<br />

Lemmas vollständige Induktion.<br />

Induktionsverankerung für D(N) = 0:<br />

In diesem Fall ist die Ausführung der Prozedur nicht rekursiv. Nach Lemma<br />

5.4.5 wird die zweite äußere solange-Schleife |N|-mal durchlaufen. Die<br />

einzigen Elemente, die N und N' enthalten können sind (nach dem Beweis<br />

von Lemma 5.4.5) Sonderzeichen, Zeichenketten, Worte, Variablen,<br />

Inkremente und Dekremente.<br />

Im Falle eines Wortes, eines Sonderzeichens oder einer Zeichenkette wird der<br />

Schleifendurchlauf in konstanter Zeit abgeschlossen. Der Zeitbedarf für die<br />

Behandlung eines Inkrementes, eines Dekrementes oder einer Variablen wird<br />

im wesentlichen durch den Zeitbedarf zum Auffinden der Werte in den<br />

Variablenlisten V,X und Y, und zum Eintragen von Variablen in die<br />

Variablenliste X bestimmt, weswegen als Komplexität wieder O(m) angesetzt<br />

werden darf. Die Komplexität im schlechtesten Fall für die zweite äußere<br />

solange-Schleife ist damit O(nNm).<br />

Die Gesamtkomplexität für die Prozedur ergibt sich damit zu O(nm).<br />

Induktionsvoraussetzung:<br />

Sei d∈©. Für D(H) ≤ d sei die Komplexität der Prozedur MatchWHILE gleich<br />

O(nm).<br />

Induktionsbehauptung:<br />

Für D(H) = d+1 sei die Komplexität der Prozedur MatchWHILE gleich O(nm).<br />

Induktionsschluß:<br />

Wiederum sagt uns der Beweis von Lemma 5.4.5, daß die zweite äußere<br />

solange-Schleife |N| mal durchlaufen wird. Wir haben bereits in der<br />

Induktionsverankerung gesehen, daß wir die Rechenzeit für einen<br />

Schleifendurchlauf im Fall, daß die von M eingelesene Anweisung ein<br />

Sonderzeichen, eine Wort oder eine Zeichenkette ist, als konstant ansehen<br />

dürfen, und im Fall, daß die von M eingelesene Anweisung eine Variable,<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

eine Inkrement oder ein Dekrement ist, mit O(m) abschätzen dürfen. Nach<br />

Lemma 5.4.5 kann aber die eingelesene Anweisung ansonsten nur noch ein<br />

while-Konstrukt sein. Der Zeitbedarf in diesem Fall resultiert aber<br />

wesentlich nur vom rekursiven Aufruf der Prozedur MatchWHILE.<br />

Sei B der Ausdruck des gelesenen while-Konstruktes und C die<br />

Anweisungssequenz. Da für den rekursiven Aufruf die<br />

Induktionsvoraussetzung gültig ist, können wird die Rechenzeit für den<br />

Schleifendurchlauf im schlechten Fall abschätzen durch O(n'm). Dabei sei n'<br />

die Summe der Zahl der Zeichen in B und C.<br />

Die Komplexität der zweiten solange-Schleife ergibt sich jetzt durch<br />

Summation der Rechenzeiten für die einzelnen Schleifendurchläufen und wir<br />

erhalten:<br />

|N|<br />

∑<br />

R = R =<br />

i=1<br />

i<br />

|N|<br />

∑<br />

i=1<br />

⎧O(1)<br />

⎪<br />

⎪<br />

⎨O(m)<br />

⎪<br />

⎪<br />

⎩⎪<br />

O(n im)<br />

falls i - te Anweisung ist Sonderzeichen,<br />

Wort oder Zeichenkette<br />

falls i - te Anweisung ist Variable,<br />

Inkrement oder Dekrement<br />

sonst<br />

Dabei sei Ri die Rechenzeit im i-ten Schleifendurchlauf und ni die Zahl der<br />

Zeichen in der i-ten Anweisung von M. R kann nun abgeschätzt werden zu<br />

O(nNm). Die Gesamtrechenzeit für die Prozedur ergibt sich damit zu O(nm).<br />

Als nächstes wollen wir die Komplexität der Prozedur SampleWExpression untersuchen.<br />

/HPPD<br />

'LH3UR]HGXU6DPSOH:([SUHVVLRQZHUGHPLWGHQ3DUDPHWHUQ&&9;*<br />

DXIJHUXIHQ'DEHLVHLHQ&XQG&%HLVSLHODXVZHUWXQJVIUDJPHQWH9XQG;<br />

9DULDEOHQOLVWHQXQG*HLQ$XVGUXFN'DQQZLUGGLH5HFKHQ]HLWGHU3UR]HGXU<br />

LPVFKOHFKWHVWHQ)DOOGXUFK2_&_PòEHVFKULHEHQZREHLP<br />

PD[_9__;_<br />

Beweis:<br />

Im Beweis des Lemma 5.4.6 haben wir gesehen, daß |C| = |C'| gilt. Demnach<br />

wird die solange-Schleife |C|-mal durchlaufen. Jedes von C gelesene Element<br />

kann entweder eine Zahl, eine Zeichenkette, eine Sonderzeichen oder ein Wort<br />

sein. Falls das gelesene Element ein Sonderzeichen, ein Wort oder ein Zahl ist,<br />

so wird der Schleifendurchlauf in konstanter Zeit beendet. Falls das gelesene<br />

Element eine Zahl ist, so hängt der Aufwand für den Schleifendurchlauf vom<br />

Aufwand des Suchen in den Variablenlisten V und X ab. Diesen Aufwand<br />

können wir für den schlechtesten Fall mit O(|V||X|) ≤ O(m²) abschätzen. Also<br />

kann der Gesamtaufwand für die Prozedur durch O(|C|m²) abgeschätzt<br />

werden.<br />

Wenden wir uns jetzt der Prozedur SampleWSequence zu.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

/HPPD<br />

'LH3UR]HGXU6DPSOH:6HTXHQFHZHUGHPLWGHQ3DUDPHWHUQ''9;+<br />

DXIJHUXIHQ'DEHLVHLHQ'XQG'%HLVSLHODXVZHUWXQJVIUDJPHQWHHLQHU<br />

$QZHLVXQJVVHTXHQ]9XQG;9DULDEOHQOLVWHQXQG+HLQH<br />

$QZHLVXQJVVHTXHQ]:HGHU'QRFK'HQWKDOWHQWHVW.RQVWUXNWH'DQQZLUG<br />

GLH5HFKHQ]HLWGHU3UR]HGXULPVFKOHFKWHVWHQ)DOOGXUFK2_'_Pò<br />

EHVFKULHEHQZREHLP PD[_9__;_<br />

Beweis:<br />

Der Aufwand für die Prozedur ist wesentlich nur von der solange-Schleife<br />

abhängig. Im Beweis des Lemma 5.4.8 wurde gezeigt, daß |D| = |D'| = |H|<br />

und die äußere solange-Schleife |D|-mal durchlaufen wird. Jedes Element von<br />

D und D' kann nur eine Zeichenkette, ein Wort, ein Sonderzeichen oder eine<br />

Zahl sein. Im Falle einer Zeichenkette, eines Wortes oder eines Sonderzeichens,<br />

wird der Schleifendurchlauf in konstanter Zeit beendet. Im Falle einer Zahl<br />

hängt die Komplexität des Schleifendurchlaufs vom Suchen von Werten und<br />

Speicherplätzen in den Variablenlisten V und X ab. Wir können diesen Aufwand<br />

im schlechtesten Fall durch O(|V||X|) ≤ O(m²) abschätzen. Der<br />

Gesamtaufwand für die Prozedur ergibt sich dann zu O(|D|m²).<br />

/HPPD<br />

'LH3UR]HGXU6DPSOH:6HTXHQFHZHUGHPLWGHQ3DUDPHWHUQ''9;+<br />

DXIJHUXIHQ'DEHLVHLHQ'XQG'%HLVSLHODXVZHUWXQJVIUDJPHQWHHLQHU<br />

$QZHLVXQJVVHTXHQ]GHU6FKDFKWHOXQJVWLHIHG9XQG;9DULDEOHQOLVWHQXQG<br />

+HLQH$QZHLVXQJVVHTXHQ]<br />

) UGLH3UR]HGXU6DPSOH:+,/(JHOWHGLHIROJHQGH9RUDXVVHW]XQJ<br />

%HLP$XIUXIGHU3UR]HGXU6DPSOH:+,/(PLWGHQ3DUDPHWHUQ<br />

$$%%9*+ZREHL$XQG$%HLVSLHODXVZHUWXQJHQHLQHV$XVGUXFNV%<br />

XQG%%HLVSLHODXVZHUWXQJHQHLQHU$QZHLVXQJVVHTXHQ]HLQHU<br />

6FKDFKWHOXQJVWLHIHNOHLQHUG9HLQH9DULDEOHQOLVWH*HLQH$XVGUXFNXQG+<br />

HLQH$QZHLVXQJVVHTXHQ]KDWGLH3UR]HGXUHLQH.RPSOH[LWlWLP<br />

VFKOHFKWHVWHQ)DOOYRQ2QPò'DEHLVHLQGLH6XPPHGHU=DKOGHU=HLFKHQ<br />

LQ$$%XQG%XQGP _9_<br />

'DQQZLUGGLH5HFKHQ]HLWGHU3UR]HGXULPVFKOHFKWHVWHQ)DOOGXUFK2QPò<br />

EHVFKULHEHQZREHLQJOHLFKGHU6XPPHGHU=DKOGHU=HLFKHQLQ'XQG'<br />

XQGP PD[_9__;_<br />

Beweis:<br />

Auch hier hängt der Aufwand ausschlaggebend von der solange-Schleife ab.<br />

Nach dem Beweis des Lemma 5.4.11 wird die äußere solange-Schleife |H|-mal<br />

durchlaufen. Ihr Zeitaufwand läßt sich als Summe der Rechenzeiten der<br />

einzelnen Schleifendurchläufen berechnen. Bezeichne Ri die Rechenzeit für den<br />

i-ten Schleifendurchlauf (i∈{1,...,|H|}). Jedes Element von D und D' kann<br />

entweder eine Zeichenkette, ein Wort, ein Sonderzeichen, eine Zahl oder ein<br />

test-Konstrukt sein.<br />

Falls das im i-ten Schleifendurchlauf eingelesene Element eine Zeichenkette, ein<br />

Wort oder ein Sonderzeichen ist, so wird der Schleifendurchlauf in konstanter<br />

Zeit abgeschlossen. Falls das eingelesene Element eine Zahl ist, so wird die<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Komplexität des Schleifendurchlaufs durch die Zugriffe auf die Variablenlisten<br />

V und X bestimmt. Im schlechtesten Fall kann Ri angegeben werden durch<br />

O(|V||X|) ≤ O(m²).<br />

Falls das im i-ten Schleifendurchlauf von D eingelesene Element t ein test-<br />

Konstrukt sein, so muß es das erste einer Folge von test-Konstrukten sein,<br />

nämlich entweder<br />

test A 1 do B 1 end test<br />

test A 2 do B 2 end test<br />

...<br />

test A r do B r end test<br />

oder eine Folge<br />

test A 1 do B 1 end test<br />

test A 2 do B 2 end test<br />

...<br />

test A r do B r end test<br />

test A r+1 skip<br />

Entsprechend muß das von D' eingelesene Element u ein test-Konstrukt sein<br />

und es muß das erste einer Folge<br />

test A’ 1 do B’ 1 end test<br />

test A’ 2 do B’ 2 end test<br />

...<br />

test A’ s do B’ s end test<br />

oder einer Folge<br />

test A’ 1 do B’ 1 end test<br />

test A’ 2 do B’ 2 end test<br />

...<br />

test A’ s do B’ s end test<br />

test A’ s+1 skip<br />

sein. Dabei sind s,r > 1, A1,...,Ar+1,A'1,...,A's+1 Beispielauswertungen eines<br />

Ausdrucks und B1,...,Br,A'1,...,A's Beispielauswertungen einer<br />

Anweisungssequenz, deren Schachtelungstiefe kleiner d sein muß.<br />

Also können wir die Voraussetzungen unseres Lemma für die Prozedur<br />

SampleWHILE verwenden. Für den ersten Aufruf der Prozedur SampleWHILE<br />

im i-ten Schleifendurchlauf werden die Parameter (A1,B1,A2,B2,V,M,N)<br />

übergeben, wobei M ein Ausdruck und N eine Anweisungssequenz. Nach<br />

Voraussetzung ist der Aufwand hierfür im schlechtesten Fall O(n1/2 |V|²), wobei<br />

n1/2 die Summe der Zeichen in den Fragmenten A1,B1, A2 und B2 bedeutet.<br />

Entsprechend liegt der Aufwand für den zweiten Aufruf der Prozedur<br />

SampleWHILE mit den Parametern (A'1,B'1,A'2,B'2,Y,M',N') bei O(n'1/2 |Y|²).<br />

Dabei sei M' eine Ausdruck und N' eine Anweisungssequenz. n'1/2 bedeutet die<br />

Summe der Zeichenzahlen der Fragmente A'1, B'1, A'2 und B'2. Wichtig ist an<br />

dieser Stelle noch, daß es für jede in Y enthaltene Variable eine in X enthaltene<br />

Variable gibt, es gilt also |V| ≥ |X|.<br />

Der Aufwand für den anschließenden Aufruf der Prozedur MatchWHILE mit<br />

den Parametern (M,M',N,N',V,Y,X) liegt nach Lemma 5.5.5 im schlechtesten<br />

Fall bei O(n*,m*), wobei n* die Summe der Zeichenzahlen von M und N und m*<br />

= max (|V|,|X|,|Y|) ist.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Die anschließende solange-Schleife wird gemäß dem Beweis von Lemma 5.4.11<br />

(r-2)-mal durchlaufen, wobei in jedem Schleifendurchlauf ein weiteres test-<br />

Konstrukt von D gelesen wird. In jedem Schleifendurchlauf wird die Prozedur<br />

TestWHILE aufgerufen. Nach Lemma 5.5.4 gilt für diesen Aufruf die<br />

Aufwandsabschätzung O(nj |V|). Dabei bedeutet nj die Summe der Zahl der<br />

Zeichen in Aj und Bj, falls das j-te test-Konstrukt behandelt wird. Der Aufwand<br />

für die erste solange-Schleife berechnet sich demnach durch<br />

r<br />

∑<br />

j=3<br />

O(n |V|)<br />

j<br />

Da wir den schlechtesten Fall betrachten, müssen wir davon ausgehen, daß die<br />

Prozedur TestWExpression im Anschluß an die erste innere solange-Schleife<br />

aufgerufen wird. Nach Lemma 5.5.1 liegt der Aufwand hierfür bei O(|Ar+1|<br />

|V|).<br />

Der Aufwand für die zweite innere solange-Schleife berechnet sich vollkommen<br />

analog zum Aufwand der ersten inneren solange-Schleife zu<br />

s<br />

∑<br />

j=3<br />

O(n’ |X|)<br />

j<br />

n'j bedeute die Summe der Zahl der Zeichen in A'j und B'j, falls das j-te test-<br />

Konstrukt im Schleifendurchlauf gelesen wird.<br />

Wiederum müssen wir davon ausgehen, daß die Prozedur TestWExpression ein<br />

zweites Mal aufgerufen wird. Der Aufwand hierfür berechnet sich nach Lemma<br />

5.5.1 zu O(|Bs+1| |X|).<br />

Dann erhalten wir folgenden Ausdruck für die Rechenzeit:<br />

O(n1/2 |V|²) + O(n'1/2 |Y|²) + O(n*m*) +<br />

s<br />

∑<br />

j=3<br />

O(n’ |X|)<br />

j<br />

+ O(|Bs+1| |X|).<br />

r<br />

∑ O(n j |V|) + O(|Ar+1| |V|) +<br />

j=3<br />

Benutzen wir jetzt die Beziehung m = max (|V|,|X|) ≥ |V| ≥ |Y|, so erhalten<br />

wir einen vereinfachten Ausdruck:<br />

r<br />

O(n1/2 m²) + O(n'1/2 m²) + O(n*m) + ∑ O(n<br />

jm)<br />

+ O(|Ar+1| m) + ∑ O(n’<br />

j<br />

m) +<br />

j=3<br />

O(|Bs+1| m).<br />

Wir führen jetzt die Bezeichnungen n1, n2, n'1, n'2 für die Summe der Zahl der<br />

Zeichen in A1 und B1, A'1 und B'1, A2 und B2, sowie A'2 und B'2 ein. Die<br />

Bezeichnungen nr+1 und n's+1 stehen für die Zahl der Zeichen in Ar+1 und A's+1.<br />

Außerdem sehen wir, daß der Term O(n*m) nicht ins Gewicht fällt, weswegen<br />

wir ihn weglassen können. Unser Ausdruck für die Komplexität vereinfacht sich<br />

jetzt nach Abschätzung nach oben zu:<br />

r+1<br />

2<br />

2<br />

∑ O(n j m ) + ∑ O(n’<br />

j<br />

m )<br />

j=1<br />

s+1<br />

j=1<br />

s<br />

j=3<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Dies können wir wieder großzügig abschätzen und wir erhalten:<br />

Ri = O(Nm²)<br />

Dabei sei Ni die Summe der im i-ten Schleifendurchlauf von D und D' gelesenen<br />

Zeichen. Dann können wir die Gesamtrechenzeit für die Prozedur<br />

SampleSequence angeben durch<br />

|H|<br />

∑<br />

Rges = O(N m ) = O(nm²).<br />

i=1<br />

i<br />

2<br />

Berechnen wir jetzt die Komplexität der Prozedur SampleWHILE.<br />

/HPPD<br />

%HLP$XIUXIGHU3UR]HGXU6DPSOH:+,/(PLWGHQ3DUDPHWHUQ<br />

$$%%9*+ZREHL$XQG$%HLVSLHODXVZHUWXQJHQHLQHV$XVGUXFNV%<br />

XQG%%HLVSLHODXVZHUWXQJHQHLQHU$QZHLVXQJVVHTXHQ]9HLQH<br />

9DULDEOHQOLVWH*HLQH$XVGUXFNXQG+HLQH$QZHLVXQJVVHTXHQ]KDWGLH<br />

3UR]HGXUHLQH.RPSOH[LWlWLPVFKOHFKWHVWHQ)DOOYRQ2QPò'DEHLVHLQGLH<br />

6XPPHGHU=DKOGHU=HLFKHQLQ$$%XQG%XQGP _9_<br />

Beweis:<br />

Die Rechenzeit der Prozedur SampleWHILE berechnet sich folgendermaßen:<br />

Rges = Rexp + Rseq + Rtest + Rew<br />

Dabei bedeuten:<br />

Rges : Rechenzeit für die Prozedur<br />

Rexp : Rechenzeit für den Aufruf der Prozedur SampleWExpression<br />

Rseq : Rechenzeit für den Aufruf der Prozedur SampleWSequence<br />

Rtest : Rechenzeit für die erste für-Schleife (Vergleich der Anfangswerte der<br />

Variablen in X mit den Endwerten der Variablen in X.<br />

Rew : Rechenzeit für das Eintragen der Endwerte der Variablen in X in die<br />

Variablenliste V.<br />

(vollständige Induktion)<br />

Induktionsverankerung:<br />

B und B' enthalten jetzt keine test-Konstrukte.<br />

Nach Lemma 5.5.6 ist der Aufwand für den Aufruf der Prozedur<br />

SampleWExpression abzuschätzen durch<br />

Rexp = O(|A| (max(|V|,|X)²)|.<br />

Für den Aufruf der Prozedur SampleWStatementSequence kann das Lemma<br />

5.5.7 verwendet werden, und es gilt<br />

Rseq = O(|B| (max(|V|,|X|)²)<br />

Die erste für-Schleife wird |X|-mal durchlaufen. Der Aufwand für einen<br />

Schleifendurchlauf resultiert vor allem aus dem Suchen in der Variablenliste<br />

V. Deswegen kann der Aufwand abgeschätzt werden durch O(|V|). Dann gilt<br />

für Rtest:<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Rtest = O(|V| |X|)<br />

Vollkommen analog gilt für die zweite für-Schleife:<br />

Rew = O(|V| |X|)<br />

Wir benötigen die Feststellung, daß es für jede Variablen in X eine Variable<br />

in V gibt. Dann gilt |V| ≥ |X|. Damit vereinfacht sich der Ausdruck für Rges:<br />

Rges = O(|A| m²) + O(|B| m²) + O(m²) + O(m²) = O((|A|+|B|)m²)<br />

Es gilt |A| + |B| ≤ |A| + |B| + |A'| + |B'| = n. Somit ist auch O(nm²) eine<br />

obere Schranke für die Rechenzeit der Prozedur SampleWHILE.<br />

Induktionsvoraussetzung:<br />

B und B' seien Beispielauswertungen einer Anweisungssequenz mit einer<br />

Schachtelungstiefe kleiner gleich d∈©. Dann beträgt der Aufwand für die<br />

Prozedur SampleWHILE O(nm²).<br />

Induktionsbehauptung:<br />

B und B' seien Beispielauswertungen einer Anweisungssequenz der<br />

Schachtelungstiefe d+1. Dann beträgt der Aufwand für die Prozedur<br />

SampleWHILE O(nm²).<br />

Induktionsschritt:<br />

Analog zur Induktionsverankerung erhalten wir:<br />

Rexp = O(|A| (max(|V|,|X)²)|.<br />

Rtest = O(|V| |X|)<br />

Rew = O(|V| |X|)<br />

Für die Berechnung der Rechenzeit der Prozedur<br />

SampleWStatementSequence können wir das Lemma 5.5.8 verwenden, denn<br />

die Voraussetzungen, die in diesem Lemma für die Prozedur SampleWHILE<br />

verlangt werden, werden bereits durch die Induktionsvoraussetzung erfüllt.<br />

Dann erhalten wir die Abschätzung<br />

Rseq = O(nB (max(|V|,|X|)²)),<br />

wobei nB die Summe der Zahl der Zeichen in B und B' ist. Unter Benutzung<br />

der Beziehung |V| ≥ |X| erhalten wir folgenden Ausdruck für Rges:<br />

Rges = O(|A| m²) + O(nB m²) + O(m²) + O(m²) = O((|A|+nB)m²)<br />

Dies können wir wieder durch O(nm²) abschätzen.<br />

Als nächstes schauen wir die Rechenzeit für die Prozedur SampleSequence an.<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

/HPPD<br />

'LH3UR]HGXU6DPSOH6HTXHQFHZHUGHDXIJHUXIHQPLWGHQ3DUDPHWHUQ<br />

79$ZREHL7HLQ%HLVSLHODXVZHUWXQJVIUDJPHQW9HLQH9DULDEOHQOLVWHXQG<br />

GLH$XVJDEHJU|‰H$HLQH$QZHLVXQJVVHTXHQ]LVW<br />

6HLQGLH=DKOGHU=HLFKHQLQ$XQGP _9_VRNDQQGLH.RPSOH[LWlWGHU<br />

3UR]HGXULPVFKOHFKWHVWHQ)DOOEHVFKULHEHQZHUGHQGXUFK2QPò<br />

Beweis:<br />

Die Rechenzeit für die Prozedur SampleSequence hängt maßgeblich von der<br />

Rechenzeit zur Abarbeitung der äußeren solange-Schleife ab. Gemäß des<br />

Beweises von Lemma 5.4.15 wird die äußere solange-Schleife in |A| Schritten<br />

abgearbeitet. Sei Ri für i∈{1,..,|A|} die Rechenzeit im i-ten Schleifendurchlauf.<br />

Dann läßt sich die Komplexität für die Prozedur durch den folgenden Ausdruck<br />

abschätzen:<br />

Rges =<br />

|A|<br />

∑ R i<br />

i=1<br />

Betrachten wir also die Rechenzeit für den i-ten Schleifendurchlauf.<br />

Falls das im i-ten Schleifendurchlauf gelesene Element t eine Zeichenkette, ein<br />

Wort oder ein Sonderzeichen ist, so wird der Schleifendurchlauf sofort beendet.<br />

Falls das im i-ten Schleifendurchlauf gelesene Element t eine Variable, ein<br />

Inkrement oder ein Dekrement ist, so ist der Aufwand für den i-ten<br />

Schleifendurchlauf im wesentlichen durch den Zugriff auf die Variablenliste V<br />

bestimmt. Deswegen kann man als Komplexität O(m) angeben.<br />

Falls t ein test-Konstrukt ist, so ist es das erste einer Folge von test-<br />

Konstrukten der Auswertung eines while-Konstruktes, etwa<br />

test C 1 do D 1 end test<br />

test C 2 do D 2 end test<br />

...<br />

test C r do D r end test<br />

oder der Folge<br />

test C 1 do D 1 end test<br />

test C 2 do D 2 end test<br />

...<br />

test C r do D r end test<br />

test C r+1 skip<br />

Dabei sei r > 2 und C1,..,Cr+1 Beispielauswertungen des Ausdrucks des while-<br />

Konstruktes und D1,..,Dr Beispielauswertungen der Anweisungssequenz des<br />

Ausdrucks. t ist folglich das erste while-Konstrukt und die darauf gelesene<br />

Element u das zweite while-Konstrukt der Folge. Für den Aufruf der Prozedur<br />

SampleWHILE gilt nach Lemma 5.5.9 die Aufwandsabschätzung O(n1/2m²),<br />

wobei n1/2 die Summe der Zahl der Zeichen in C1, C2, D1 und D2 ist.<br />

Nach Lemma 5.4.15 wird die innere solange-Schleife (r-2)-mal durchlaufen,<br />

wobei in jedem Schleifendurchlauf ein weiteres test-Konstrukt von T gelesen<br />

wird und die Prozedur TestWHILE aufgerufen wird. Falls im Schleifendurchlauf<br />

das j-te test-Konstrukt gelesen wird, so gilt nach Lemma 5.5.4 für die<br />

Komplexität des Schleifendurchlaufs im schlechtesten Fall O(njm), falls nj die<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Summe der Zahl der Zeichen in Cj und Dj bedeutet. Dann liegt die Komplexität<br />

der inneren solange-Schleife bei<br />

r<br />

∑<br />

j=3<br />

O(n m)<br />

i<br />

Der Aufwand für den anschließenden Aufruf der Prozedur TestWExpression, von<br />

dem wir bei der Betrachtung des schlechtesten Falles ausgehen müssen, liegt<br />

gemäß Lemma 5.5.1 bei O(|Cr+1| m).<br />

Die Gesamtkomplexität des Schleifendurchlaufs wird dann durch den folgenden<br />

Ausdruck beschrieben:<br />

r<br />

∑<br />

O(n1/2m²) + O(n m) + O(|Cr+1| m).<br />

j=3<br />

i<br />

Schätzen wir diesen Ausdruck nach oben ab und führen wir die Bezeichnungen<br />

n1 für die Summe der Zahl der Zeichen in C1 und D1, sowie n2 für die Summe der<br />

Zahl der Zeichen in C2 und D2 ein, so erhalten wir die gewünschte Beziehung für<br />

Ri<br />

r<br />

∑<br />

2<br />

Ri = O(n m ) = O(n'm²),<br />

j=1<br />

i<br />

wobei n' die Summe der Zahl der Zeichen in der Folge der test-Konstrukte.<br />

Dann können wir für die Gesamtkomplexität der Prozedur den Ausdruck<br />

Rges =<br />

|A|<br />

R i<br />

i=1<br />

∑ = O(nm²)<br />

im schlechtesten Fall angeben.<br />

Nun können wir die Komplexität des Algorithmus SampleProgram bestimmen.<br />

6DW]<br />

'HU$OJRULWKPXV6DPSOH3URJUDPZHUGHDXIJHUXIHQPLWGHQ3DUDPHWHUQ<br />

63ZREHL6HLQH%HLVSLHODXVZHUWXQJXQG3HLQ3URJUDPPLVW6HLQGLH<br />

=DKOGHU=HLFKHQLQ3XQGPGLH=DKODOOHULQ3YRUNRPPHQGHQ9DULDEOHQ<br />

'DQQOLHJWGLH.RPSOH[LWlWI UGHQ$OJRULWKPXVLPVFKOHFKWHVWHQ)DOOEHL<br />

2QPò<br />

Beweis:<br />

Sei Rges die Komplexität des Algorithmus SampleProgram. Dann berechnet sie<br />

sich folgendermaßen:<br />

Rges = REV + Rseq + RGV + RAV<br />

Dabei bedeuten<br />

REV : Zeitbedarf für das Eintragen der Eingabevariablen<br />

Rseq : Zeitbedarf für den Aufruf der Prozedur SampleSequence<br />

RGV : Zeitbedarf für die Generierung der Hauptinitialisationssequenz<br />

RAV : Zeitbedarf für das Suchen der Ausgabevariablen<br />

6HLWH


$XWRPDWLVFKH6\QWKHVHYRQ.ODVVH,3URJUDPPHQ<br />

Wir wissen, daß alle in P vorkommenden Variablen, in der Variablenliste V<br />

enthalten sind. Für REV ist deshalb sicherlich O(m) eine obere Schranke, ebenso<br />

für RAV. Für RGV können wir die Abschätzung O(m²) ansetzen.<br />

Nach Lemma 5.5.10 gilt Rseq = O(n'm²), wobei n' die Zahl der Zeichen in der<br />

Beispielauswertung der Hauptanweisungssequenz von S ist. Dann ist auch<br />

O(nm²) eine obere Schranke für die Laufzeit im schlechtesten Fall. Dies ist dann<br />

auch die Gesamtkomplexität Rges.<br />

6DW]<br />

'HU$OJRULWKPXV6DPSOH3URJUDPHQWVWHKHDXVGHP$OJRULWKPXV<br />

6DPSOH3URJUDPLQGHPMHW]WI UGLH9HUZDOWXQJGHU9DULDEOHQOLVWHQDQVWDWW<br />

OLQHDUHU/LVWHQDXVEDODQFLHUWH6XFKElXPHHLQJHVHW]WZHUGHQ'HU<br />

$OJRULWKPXV6DPSOH3URJUDPZHUGHDXIJHUXIHQPLWGHQ3DUDPHWHUQ63<br />

ZREHL6HLQH%HLVSLHODXVZHUWXQJXQG3HLQ3URJUDPPLVW6HLQGLH=DKOGHU<br />

=HLFKHQLQ3XQGPGLH=DKODOOHULQ3YRUNRPPHQGHQ9DULDEOHQ'DQQOLHJW<br />

GLH.RPSOH[LWlWI UGHQ$OJRULWKPXVLPVFKOHFKWHVWHQ)DOOEHL2QOGPò<br />

Beweis:<br />

Aus dem Beweis von Lemma 5.5.1 ist ersichtlich, daß der Faktor m im Ausdruck<br />

für die Komplexität durch das Suchen in Variablenlisten herrührt. Durch den<br />

Ersatz der linearen Listen durch ausbalancierte Suchbäume verbessert sich der<br />

Aufwand für das Auffinden einer Variablen von O(m) zu O(ld m).<br />

Bemerkung:<br />

Es stellt sich die Frage, ob die Rechenzeit im schlechtesten Fall noch weiter gesenkt werden<br />

kann, zumal unsere Abschätzungen im Beweis von Satz 5.5.1 recht grob waren.<br />

Zum einem haben wir als Länge der Variablenliste V immer dieselbe Zahl angenommen,<br />

nämlich die Gesamtzahl aller Variablen im Programm, obwohl die Variablenliste V während<br />

des Programmlaufs wächst. Für eine worst-case-Betrachtung müssen wir aber davon<br />

ausgehen, daß V maximale Länge hat, d.h. die Länge der Variablenliste ist gleich der Zahl der<br />

Variablen im Programm.<br />

Zum zweiten stellt sich die Frage, warum wir unsere Abschätzungen (fast) immer mit der Zahl<br />

der Zeichen vorgenommen haben, während die Operationen in den Prozeduren, nach denen wir<br />

ja unsere Rechenzeit messen, sich auf die Elemente in den Beispielauswertungsfragmenten,<br />

Ausdrücken und Anweisungssequenzen beziehen. Im schlechtesten Fall fallen beide<br />

Betrachtungsweisen zusammen, da man davon ausgehen kann, daß die Elemente minimale<br />

Länge haben. Außerdem dürfen wir nicht vergessen, daß wir jedes Zeichen der Eingabe<br />

mindestens einmal lesen müssen.<br />

Bemerkung:<br />

Im besten Fall kann die Rechenzeit unseres Algorithmus' mit O(n) abgeschätzt werden (nur<br />

eine Variable im Programm). Eine weitere Reduzierung ist nicht möglich, da jedes Element der<br />

Eingabe gelesen werden muß.<br />

Die durchschnittliche Rechenzeit muß leider wieder mit O(nm²) bzw. O(n(ld m)²) abgeschätzt<br />

werden, für eine genauere Abschätzung wäre eine Statistik über den Aufbau von while-<br />

Programmen notwendig.<br />

Es stellt sich die Frage nach einem Vergleich mit einem laufzeitoptimalem<br />

Synthesealgorithmus. Sicherlich muß ein solcher Algorithmus jedes Element der Eingabe<br />

lesen, wozu O(n) Operationen nötig sind. Sicherlich muß eine Variablenliste geführt werden.<br />

Es ist eine Vermutung, daß hierfür ein Aufwand von O((ld m)²) Operationen im schlechtesten<br />

Fall notwendig ist. Damit läge die Komplexität eines optimalen Algorithmus' bei O(n(ld m)²).<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

6 Weitere Programmklassen<br />

In diesem Kapitel wollen wir diskutieren, inwiefern die Beschränkung der Eingabemenge für<br />

den Synthesealgorithmus auf Klasse-I-Beispielauwertungen eine Einschränkung der Menge<br />

der lernbaren Funktionen darstellt. Ausgehend von dieser Analyse wollen wir Lösungsansätze<br />

angeben, wie der Synthesealgorithmus abgeändert werden kann, so daß die Einschränkungen<br />

aufgehoben werden können und somit die Lernpotenz des Synthesealgorithmus' vergrößert<br />

wird.<br />

6.1 Einschränkungen für Klasse-I-Programme<br />

Fassen wir noch einmal zusammen, welche Bedingungen für Klasse-I-Programme und Klasse-<br />

I-Beispielauswertungen gelten (nach Definition 5.2.1 und Definition 5.2.2):<br />

$(VG UIHQNHLQH]ZHLZKLOH.RQVWUXNWHGLUHNWDXIHLQDQGHUIROJHQ<br />

% (VNRPPHQNHLQHORNDOHQ9DULDEOHQYRU<br />

&'DVHUVWH9RUNRPPHQHLQHU9DULDEOHQLQGHU+DXSWDQZHLVXQJVVHTXHQ]<br />

GHV3URJUDPPHVGDUIQLFKWLQQHUKDOEHLQHV,QNUHPHQWHVRGHU<br />

'HNUHPHQWHVVHLQ<br />

''DVHUVWH9RUNRPPHQHLQHU9DULDEOHQLQHLQHPZKLOH.RQVWUXNWGDUI<br />

QLFKWLQQHUKDOEHLQHV,QNUHPHQWHVRGHU'HNUHPHQWHVVHLQ<br />

( ) UMH]ZHL9DULDEOHQLQHLQHPZKLOH.RQVWUXNWPX‰GLH'LIIHUHQ]<br />

]ZLVFKHQLKUHQ:HUWHLQGHUHUVWHQ(QWIDOWXQJLQGHU]ZHLWHQ(QWIDOWXQJ<br />

YHUVFKLHGHQVHLQ<br />

) 'LH9DULDEOHLQHLQHP'HNUHPHQWGDUILQGHU$QZHLVXQJYRUGHP<br />

'HNUHPHQWQLFKWGHQ:HUWKDEHQ<br />

*,QMHGHU$QZHLVXQJDX‰HUKDOEHLQHVZKLOH.RQVWUXNWHVPX‰GLH'LIIHUHQ]<br />

GHU:HUWH]ZHLHU9DULDEOHQPLQGHVWHQVEHWUDJHQ<br />

A) Es dürfen keine zwei while-Konstrukte direkt aufeinanderfolgen.<br />

Dies ist keine Einschränkung der Lernpotenz, es erinnert an eine ähnliche Regelung in<br />

Sprachen wie Pascal. Der Grund für diese Regel ist, daß wir dann immer wissen, daß zwei<br />

aufeinanderfallende test-Konstrukte zur Auswertung desselben while-Konstruktes gehören. Es<br />

mag jetzt verwundern, warum wir diese Regel eingeführt haben, wo wir doch eine Prozedur<br />

(TestWHILE) haben, deren Zweck es ist, zu erkennen, ob ein test-Konstrukt<br />

Beispielauswertung eines while-Konstruktes ist oder nicht. Betrachten wir dazu die folgende<br />

Beispielauswertung:<br />

input (1)<br />

test 3 < 4 do 5 6 4 end test<br />

test 4 < 6 do 7 8 5 end test<br />

test 5 < 8 do 9 10 6 end test<br />

test 6 < 10 do 11 12 7 end test<br />

output 1<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

So kann kein Synthesealgorithmus unterscheiden, ob diese Zeichenfolge durch Auswertung<br />

des folgenden Programmes<br />

input (x)<br />

set (y := 3)<br />

set (z := 4)<br />

with while y < z do ++z ++z ++y end while<br />

output x<br />

oder dieses Programmes<br />

input (x)<br />

set (y := 3)<br />

set (z := 4)<br />

with while y < z do ++z ++z ++y end while<br />

with while y < z do ++z ++z ++y end while<br />

output x<br />

gebildet wurde.<br />

B) Es kommen keine lokalen Variablen vor<br />

Dies ist eine starke Einschränkung der Ausdrucksfähigkeit unsere Sprache. Wegen dieser<br />

Einschränkung kann das folgende Programm nicht vom Synthesealgorithmus generiert werden:<br />

input (a,b)<br />

set (s := 0)<br />

with<br />

while a > 0 do<br />

with<br />

set (c := b)<br />

while c > 0 do<br />

--c<br />

++s<br />

end while<br />

--a<br />

end while<br />

output s<br />

Eine Methode zur Aufhebung dieser Einschränkung wird in Kapitel 6.2 diskutiert.<br />

C) Das erste Vorkommen einer Variablen in der Hauptanweisungssequenz des Programmes<br />

darf nicht innerhalb eines Inkrementes oder Dekrementes sein.<br />

Dies stellt keine Einschränkung der Menge der lernbaren Funktionen dar. Ohne diese<br />

Forderungen sind die folgenden beiden Programme als Eingabe erlaubt, können aber anhand<br />

ihrer Beispielauswertung nicht unterscheiden werden. Sie sind allerdings ähnlich.<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

input (x)<br />

set (z := 1)<br />

z<br />

output z<br />

und<br />

input(x)<br />

set (z := 0)<br />

++z<br />

output z<br />

D) Das erste Vorkommen einer Variablen in einem while-Konstrukt des Programmes darf<br />

nicht innerhalb eines Inkrementes oder Dekrementes sein.<br />

Auch diese Forderung stellt keine Einschränkung in der Menge der lernbaren Funktionen dar.<br />

Sie kann außerdem leicht umgangen werden. Dazu ist nur eine leichte Modifikation im<br />

Synthesealgorithmus notwendig. Betrachten wir zuerst ein Beispiel:<br />

input (x)<br />

set (z := 10)<br />

with<br />

while z > 0 do<br />

++x<br />

--z<br />

end while<br />

output x<br />

Dieses Programm kann jederzeit durch das folgende Klasse-I-Programm ersetzt werden:<br />

input (x)<br />

set (z := 10)<br />

set (y := 0)<br />

with<br />

while z > y do<br />

x<br />

++x<br />

--z<br />

end while<br />

output x<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

Betrachten wir jetzt eine Beispielauswertung des ersten Programmes:<br />

input (17)<br />

test 10 > 0 do<br />

18<br />

9<br />

end test<br />

test 9 > 0 do<br />

19<br />

8<br />

end test<br />

test 8 > 0 do<br />

20<br />

7<br />

end test<br />

output 20<br />

Die Prozedur SampleWHILE wird aber das folgende while-Konstrukt generieren:<br />

with<br />

while v0 > v1 do<br />

v2<br />

--v0<br />

end while<br />

Der Inhalt der Variablenliste V ist dann:<br />

v0 Anfangswert 10 Endwert 9<br />

v1 Anfangswert 0 Endwert 0<br />

v2 Anfangswert 18 Endwert 18<br />

Der Inhalt der Variablenliste X ist dann:<br />

v0 Anfangswert 9 Endwert 8<br />

v1 Anfangswert 0 Endwert 0<br />

v2 Anfangswert 19 Endwert 19<br />

Die Prozedur SampleWHILE wird dann beim Vergleich der Variablenlisten eine Fehler<br />

melden, da der Anfangswert der Variablen v2 in X nicht mit dem Endwert der Variablen v2 in<br />

V übereinstimmt. An dieser Stelle könnte der Synthesealgorithmus verbessert werden. Eine<br />

Abweichung des Wertes einer Variablen zwischen zwei Entfaltungen eines while-Konstruktes<br />

um den Wert 1 kann nur bedeuten, daß der Wert der Variablen bei ihrem ersten Vorkommen<br />

in um den Wert 1 erhöht worden ist. Also muß an der Position des ersten Vorkommens der<br />

Variablen ein Inkrement stehen (entsprechend muß an der Position des ersten Vorkommens der<br />

Variablen ein Dekrement stehen, wenn der Wert der Variablen zwischen zwei Durchläufen um<br />

den Wert 1 vermindert worden wäre). Der verbesserte Synthesealgorithmus' muß jetzt an der<br />

Position des ersten Vorkommen der Variable v2 im bereits fertig generierten while-Konstrukt<br />

die Anweisung v2 durch die Anweisung ++v2 ersetzen. Damit erhält die Prozedur das richtige<br />

while-Konstrukt<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

with<br />

while v0 > v1 do<br />

++v2<br />

--v0<br />

end while<br />

für die gegebene Beispielauswertung. Entsprechend muß der Anfangswert der Variable v2 in<br />

der Variablenliste V um den Wert 1 erniedrigt werden. Der neue Anfangswert ist also 17, was<br />

auch dem Anfangswert der Variablen x bei der Bildung der Beispielauswertung entspricht.<br />

Es stellt sich die Frage, warum diese Verbesserung nicht in den Synthesealgorithmus<br />

eingebracht wurde. Der eine Grund ist der, daß der Verzicht auf die Erweiterung zur<br />

Einschränkung D) geführt hat, die aber die eigentliche Lernpotenz des Algorithmus' nicht<br />

schmälert. Der zweite Grund ist, daß wir bei dem Beweis des Korrektheitssatzes 5.4.1 immer<br />

indirekt eine Konsistenzbedingung vorausgesetzt haben: Nach dem Lesen der ersten n Zeichen<br />

der Eingabebeispielauswertung ist das Anfangsfragment der ersten n Zeichen ein<br />

Beispielauswertungsfragment des bis hierhin konstruierten Anfangsfragment des Programmes.<br />

Das heißt, der Synthesealgorithmus macht keine Fehler. Wenn ein Teil des Programmes<br />

fertiggestellt ist, so ist es korrekt. Im Falle des verbesserten Synthesealgorithmus müssen wir<br />

die Konsistenzbedingung fallenlassen: Das generierte while-Konstrukt kann richtig sein oder<br />

falsch. Dann läßt sich die Korrektheit des Algorithmus' mit den im vorigen Kapitel<br />

angewandten Methoden nicht zeigen.<br />

E) Für zwei verschiedene Variablen in einem while-Konstrukt muß die Differenz zwischen<br />

ihren Werten in der ersten Entfaltung und in der zweiten Entfaltung verschieden sein.<br />

Diese Einschränkung ist sicher etwas streng, sie vereinfacht jedoch die Wirkungsweise des<br />

Synthesealgorithmus'. Es ist klar, daß diese Bedingung die Lernpotenz einschränkt, denn sie<br />

verbietet Programme wie das folgende:<br />

input (x)<br />

set (z := 10)<br />

with<br />

while z > 0 do<br />

--z<br />

x<br />

--x<br />

end while<br />

output x<br />

Der Grund für diese Bedingung ist es, daß in der Auswertung eines while-Konstruktes zwei<br />

verschiedene Variablen als verschieden erkannt werden. Diese Forderung ist einer der<br />

Hauptgründe warum ein solch positives Resultat wie der Satz 5.4.2 zustande kommen. Aus<br />

der folgenden Beispielauswertung wird der Synthesealgorithmus das ursprüngliche Programm<br />

wieder erzeigen können:<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

input (100)<br />

test 10 > 0 do<br />

9<br />

100<br />

99<br />

end test<br />

test 9 > 0 do<br />

8<br />

99<br />

98<br />

end test<br />

output 98<br />

Jedoch dürften die meisten Synthesealgorithmen bei der folgenden Beispielauswertung<br />

scheitern:<br />

input (10)<br />

test 10 > 0 do<br />

9<br />

10<br />

9<br />

end test<br />

test 9 > 0 do<br />

8<br />

9<br />

8<br />

end test<br />

output 8<br />

Der Grund für diese Schwierigkeit ist, daß die zweite Beispielauswertung auch<br />

Beispielauswertung des folgenden Programmes ist:<br />

input (x)<br />

with<br />

while x > 0 do<br />

--x<br />

++x<br />

--x<br />

end while<br />

Die beiden Programme sind nicht ähnlich, das heißt ein Synthesealgorithmus, der beide<br />

Programme generieren muß, kann nicht korrekt arbeiten, da er aus einer korrekten<br />

Beispielauswertung nicht unterscheiden kann, zu welcher Äquivalenzklasse von Algorithmen<br />

diese Auswertung gehört.<br />

Ein Ausweg wäre sicherlich, eine Bedingung zu finden, die Beispielauswertungen ausschließt,<br />

die zu unlösbaren Problemen führen. Eine solche Bedingung dürfte aber die Lernpotenz des<br />

Synthesealgorithmus nicht mehr einschränken, als sie durch die Bedingung E) eingeschränkt<br />

wird. Eine solche Bedingung für die Menge der zugelassenen Beispielauswertungen zu finden,<br />

ist dem Autor dieser Arbeit bisher nicht gelungen.<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

F) Die Variable in einem Dekrement darf in der Anweisung davor nicht den Wert 0 haben.<br />

Dies ist im Zusammenhang mit der Bedingung E) zu sehen. Die Bedingung stellt keine<br />

Einschränkung in der Lernpotenz dar, denn das Dekrement einer Variable, die bereits den<br />

Wert 0 hat, macht keinen Sinn. Der Algorithmus berücksichtigt die Möglichkeit des<br />

Dekrementes einer Variablen mit dem Wert 0, sofern dies erkannt werden kann. Dies ist im<br />

Fall des folgenden Programmes<br />

input (x)<br />

set (y := 3)<br />

with<br />

while y > 0 do<br />

x<br />

--x<br />

--x<br />

--y<br />

end while<br />

output x<br />

möglich für die Eingabe<br />

input (20)<br />

test 3 > 0 do<br />

20<br />

19<br />

18<br />

2<br />

end test<br />

test 2 > 0 do<br />

18<br />

17<br />

16<br />

1<br />

end test<br />

test 1 > 0 do<br />

16<br />

15<br />

14<br />

0<br />

end test<br />

test 0 > 0 do<br />

14<br />

13<br />

12<br />

0<br />

end test<br />

output 12<br />

Bei diesem Beispiel kann das vierte test-Konstrukt als Teil der Entfaltung des while-<br />

Konstruktes interpretiert werden, da bekannt ist, daß die Variable y am Ende der dritten<br />

Entfaltung den Wert 0 hat. Betrachten wir jetzt zum selbigen Programm eine andere<br />

Beispielauswertung:<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

input (0)<br />

test 3 > 0 do<br />

0<br />

0<br />

0<br />

2<br />

end test<br />

test 2 > 0 do<br />

0<br />

0<br />

0<br />

1<br />

end test<br />

Die Nullen in der Auswertung der Anweisungssequenz des while-Konstruktes sind nicht als<br />

Ergebnisse eines Dekrementes zu erkennen.<br />

G) In jeder Anweisung außerhalb eines while-Konstruktes muß die Differenz der Werte zweier<br />

Variablen mindestens 3 betragen.<br />

Diese Bedingung dient zum Identifizieren von Variablen in einer Beispielauswertung und ist<br />

für die Gültigkeit des Satzes 5.4.2 erforderlich. Wir können außerhalb der Auswertung eines<br />

while-Konstruktes eine Variablen nicht an der Differenz ihrer Werte zwischen zwei<br />

Entfaltungen erkennen. Betrachten wir jetzt einen Wert in einer Beispielauswertung außerhalb<br />

jedes test-Konstruktes. Sei c dieser Wert. Der Wert c kann jetzt der Wert einer Variablen mit<br />

dem Wert c vor der Auswertung der Anweisung sein, der Wert einer Variablen mit dem Wert<br />

c+1 vor der Auswertung eines Dekrementes oder der Wert einer Variablen mit dem Wert c-1<br />

vor der Auswertung eines Inkrementes sein. Um den Wert also eindeutig einer Variablen<br />

zuzuordnen, darf also keine zweite Variable existieren, deren Wert sich um weniger als 3 vom<br />

Wert der ersten Variablen unterscheidet. Betrachten wir dazu das folgende Beispiel: Gegeben<br />

sei das Klasse-I-Programm<br />

input (x)<br />

set (a := 2)<br />

set (b := 5)<br />

a<br />

x<br />

++x<br />

b<br />

output b<br />

Dann ist die folgende Beispielauswertung des Programmes als Eingabe nicht erlaubt:<br />

input (3)<br />

2<br />

3<br />

4<br />

5<br />

output 5<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

Schauen wir uns ein nicht so leicht einsichtiges Beispiel an. Betrachten wir das folgende<br />

Programm:<br />

input (x)<br />

set (a := 1)<br />

with<br />

while a do<br />

++a<br />

end while;<br />

with<br />

while x do<br />

--x<br />

end while<br />

--x<br />

output x<br />

Auch für dieses Programm gibt es eine Beispielauswertung, die zu Problemen führt:<br />

input (7)<br />

test 1 do 2 end test<br />

test 2 do 3 end test;<br />

test 7 do 6 end test<br />

test 6 do 5 end test<br />

4<br />

output 4<br />

Kein Synthesealgorithmus kann unterscheiden, ob die Zahl 4 zur Anweisung --x oder zur<br />

Anweisung ++a gehört.<br />

Die Bedingung G) führt leider zu einer Einschränkung der Lernpotenz.<br />

6.2 Lokale Variablen<br />

Die Zulassung lokaler Variablen in einem while-Konstrukt wäre eine große Verbesserung der<br />

Lernpotenz des Synthesealgorithmus. Prüfen wir zuerst, wie der Verzicht auf die Verwendung<br />

der Bedingung B) für Klasse-I-Programme sich auf die Korrektheit des Synthesealgorithmus'<br />

auswirkt. Wir definieren dazu eine Klasse von Algorithmen, die dieselben Einschränkungen<br />

wie die Klasse-I besitzt, in der jedoch lokale Variablen zugelassen sind.<br />

'HILQLWLRQ<br />

3KHL‰W.ODVVH,,3URJUDPPZHQQIROJHQGH%HGLQJXQJHQHUI OOWVLQG<br />

(VG UIHQNHLQH]ZHLZKLOH.RQVWUXNWHGLUHNWDXIHLQDQGHUIROJHQ<br />

'DVHUVWH9RUNRPPHQHLQHU9DULDEOHQLQGHU+DXSWDQZHLVXQJVVHTXHQ]<br />

YRQ3GDUIQLFKWLQQHUKDOEHLQHV,QNUHPHQWHVRGHU'HNUHPHQWHVVHLQ<br />

'DVHUVWH9RUNRPPHQHLQHU9DULDEOHQLQHLQHPZKLOH.RQVWUXNWGDUI<br />

QLFKWLQQHUKDOEHLQHV,QNUHPHQWHVRGHU'HNUHPHQWHVVHLQ<br />

) UMH]ZHL9DULDEOHQLQHLQHPZKLOH.RQVWUXNWPX‰GLH'LIIHUHQ]<br />

]ZLVFKHQLKUHQ:HUWHLQGHUHUVWHQ(QWIDOWXQJLQGHU]ZHLWHQ(QWIDOWXQJ<br />

YHUVFKLHGHQVHLQ<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

'HILQLWLRQ<br />

(LQH%HLVSLHODXVZHUWXQJHLQHV.ODVVH,,3URJUDPPHVKHL‰W.ODVVH,,<br />

%HLVSLHODXVZHUWXQJZHQQIROJHQGH%HGLQJXQJHQHUI OOWVLQG<br />

'LH9DULDEOHLQHLQHP'HNUHPHQWGDUILQGHU$QZHLVXQJYRUGHP<br />

'HNUHPHQWQLFKWGHQ:HUWKDEHQ<br />

,QMHGHU$QZHLVXQJDX‰HUKDOEHLQHVZKLOH.RQVWUXNWHVPX‰GLH'LIIHUHQ]<br />

GHU:HUWH]ZHLHU9DULDEOHQPLQGHVWHQVEHWUDJHQ<br />

Resultat 1:<br />

Sei P ein Klasse-II-Programm und S eine Klasse-II-Beispielauswertung von P. Jedes while-<br />

Konstrukt in P, das eine lokale Initialisationssequenz enthält, ist lokale Anweisung der<br />

Hauptanweisungssequenz von P. Dann liefert der Algorithmus' SampleProgram ein<br />

Programm Q und es gilt P ≅ Q. (d.h. der Satz 5.4.1 hat Gültigkeit).<br />

Der Grund für dieses Resultat ist klar: Verschiebt man die Deklaration der lokalen Variablen<br />

in P in die Hauptinitialisationssequenz, so erhält man ein zu P ähnliches Programm R. Das<br />

Programm R ist aber dann ein Klasse-I-Programm, und S ist eine Klasse-I-Beispielauswertung<br />

von R. Nach Satz 5.4.1 liefert der Algorithmus SampleProgram dann ein zu R ähnliches<br />

Programm Q, und es gilt nach Lemma 3.5.1 auch P ≅ Q.<br />

Was passiert aber, wenn lokale Variablen in einem while-Konstrukt initialisiert werden, das<br />

nicht Anweisung in der Hauptanweisungssequenz ist. Betrachten wir dazu das Beispiel des<br />

folgenden Klasse-II-Programmes P und das Klasse-I-Programm P':<br />

input (x)<br />

set (y := 10)<br />

with<br />

while y > 0 do<br />

with<br />

set (z := y)<br />

while z > 0 do<br />

x<br />

++x<br />

--z<br />

end while<br />

--y<br />

end while<br />

output x<br />

input (x)<br />

set (y := 10)<br />

with<br />

while y > 0 do<br />

with<br />

while y > 0 do<br />

x<br />

++x<br />

--y<br />

end while<br />

++y<br />

end while<br />

output x<br />

Dann ist jedem einsichtig, daß P und P' nicht ähnlich sind. Betrachten wir jetzt die<br />

Beispielauswertungen A und S' von P und P':<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

input (1)<br />

test 10 > 0 do<br />

test 10 > 0 do<br />

1<br />

2<br />

9<br />

end test<br />

test 9 > 0 do<br />

2<br />

3<br />

8<br />

end test<br />

9<br />

end test<br />

test 9 > 0 do<br />

test 10 > 0 do<br />

3<br />

4<br />

9<br />

end test<br />

test 9 > 0 do<br />

4<br />

5<br />

8<br />

end test<br />

8<br />

end test<br />

output 5<br />

0 do<br />

1<br />

2<br />

9<br />

end test<br />

test 9 > 0 do<br />

2<br />

3<br />

8<br />

end test<br />

9<br />

end test<br />

test 9 > 0 do<br />

test 9 > 0 do<br />

3<br />

4<br />

8<br />

end test<br />

test 8 > 0 do<br />

4<br />

5<br />

7<br />

end test<br />

8<br />

end test<br />

output 5<br />


:HLWHUH3URJUDPPNODVVHQ<br />

Dies ist eine richtige Lösung für eine konstantenbereinigte Form von P'. Die inneren<br />

Entfaltungen der zweiten äußeren Entfaltung unterscheiden sich zwischen S und S'. Hier<br />

könnte der Synthesealgorithmus erkennen, daß die Variable im Ausdruck des inneren while-<br />

Konstruktes nicht die Variable im Ausdruck des äußeren while-Konstruktes ist, da die Werte<br />

nicht übereinstimmen, wenn der Prozedur SampleWSequence, die aus den ersten beiden<br />

inneren Entfaltungen ein while-Konstrukt generieren soll, eine vollständige Variablenliste<br />

übergeben werden könnte, was aber nicht geht, da die Werte der Variablen nicht bekannt sind.<br />

Deshalb liefert die Prozedur die folgende Lösung für beide Eingaben:<br />

with<br />

while y0 < y1 do<br />

y2<br />

++y2<br />

--y0<br />

end while<br />

Die Variablenliste Y hat für die Eingabe S den Inhalt:<br />

y0 Anfangswert 10 Endwert 8<br />

y1 Anfangswert 0 Endwert 0<br />

y2 Anfangswert 3 Endwert 5<br />

Für die Eingabe S' hat die Variablenliste Y den folgenden Inhalt:<br />

y0 Anfangswert 9 Endwert 7<br />

y1 Anfangswert 0 Endwert 0<br />

y2 Anfangswert 3 Endwert 5<br />

Wir sehen, daß unser Synthesealgorithmus wiederum nur für die Eingabe S' eine richtige<br />

Lösung generiert. Beachten wir jetzt noch die Variablenliste X, die die Werte aller Variablen<br />

im Ausdruck der zweiten Entfaltung enthält (für beide Eingaben):<br />

v0 Anfangswert 8 Endwert 9<br />

v1 Anfangswert 0 Endwert 0<br />

Für die Eingabe S' liefert der Synthesealgorithmus als korrekte Lösung ein zu P' ähnliches<br />

Programm. Für die Eingabe S bricht die Prozedur MatchWHILE den Algorithmus mit<br />

Fehlermeldung ab, denn die Variable v0 entspricht der Variablen y0 im Ausdruck der while-<br />

Konstruktes. Der letzte Wert der Variablen v0 vor der Auswertung des inneren while-<br />

Konstruktes in der zweiten äußeren Entfaltung ist aber 9, der erste Wert von y0 in der<br />

Auswertung des inneren while-Konstruktes ist aber 10. Damit erkennt die Prozedur<br />

MatchWHILE zurecht, daß die Eingabe S keine Klasse-I-Beispielauswertung ist.<br />

Es stellt sich jetzt die Frage, ob die Prozedur MatchWHILE das Auftreten einer lokalen<br />

Variablen immer entdecken kann. Wir können uns dabei auf lokale Variablen von while-<br />

Konstrukten beschränken, die selbst in einem Anweisung in einem while-Konstrukt sind, da<br />

lokale while-Konstrukte der Hauptanweisungssequenz gemäß Resultat 1 keine Problem<br />

bereiten. Der Anfangswert einer lokalen Variablen wird vor dem ersten Schleifendurchlauf in<br />

allen Entfaltungen des umgebenen while-Konstruktes immer gleich sein. Also kann eine lokale<br />

Variable von einer zu einem while-Konstrukt globalen Variablen unterschieden werden, wenn<br />

der Wert der Variablen sich ändert, denn dann ist der Wert der nicht-lokalen Variablen<br />

verschieden in den verschiedenen Auswertungen. Ist dies nicht der Fall, so kann aber auch in<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

den Beispielauswertungen nicht zwischen der lokalen und der globalen Variablen<br />

unterschieden werden, und die sich ergebenden Programme sind ähnlich.<br />

In unserem Beispiel erkennen wir, daß die erste Variable im inneren while-Konstrukt eine<br />

lokale Variable dieses while-Konstruktes sein muß. Wir können nun den Synthesealgorithmus<br />

verbessern, indem wir folgende Änderungen einführen:<br />

ì In Prozeduren werden lokalen Variablen der while-Konstrukte erlaubt.<br />

ì Wird in der Prozedur MatchWHILE eine lokale Variable entdeckt, deren Anfangswert mit<br />

dem Wert der Variablen v übereinstimmt, so erzeuge eine neue Variable, etwa w, ersetze<br />

jedes Vorkommen von v im while-Konstrukt durch w, und führe w als globale Variable mit<br />

Anfangswert v ein. Setze danach die Prozedur MatchWHILE fort.<br />

Resultat 2 (Behauptung ohne Beweis):<br />

Sei P eine Klasse-II-Programm, für das die folgende Bedingungen gelten: Wenn die Variable v<br />

ist Anfangswert der lokalen Variablen w, so kommt v nicht im lokalen while-Konstrukt von w<br />

vor. Außerdem kommt die Variable v im while-Konstrukt, in dem das lokale while-Konstrukt<br />

lokal ist, vor Sei S eine Klasse-II-Beispielauswertung von P. Dann liefert der nach obiger<br />

Anleitung verbesserte Algorithmus SampleProgram ein Programm zu P ähnliches Programm<br />

Q.<br />

Die Frage bleibt, warum diese Verbesserung nicht in den Algorithmus eingegangen ist:<br />

1. Der verbesserte Algorithmus arbeitet nicht konsistent, man kann nicht entscheiden, ob die<br />

bisher fertiggestellte Lösung korrekt ist oder noch nachträglich korrigiert werden muß.<br />

Damit ist die in Kapitel 5.4 vorgestellte Beweisidee nicht anwendbar. Die Gültigkeit des<br />

Satzes 5.4.1 ist damit offen.<br />

2. Satz 5.4.2 gilt nicht.<br />

3. Eine lokale Variable darf nicht gleichzeitig mit einer globalen Variablen verwendet werden,<br />

die ihren Anfangswert bestimmt.<br />

4. Jede Variable, die Anfangswert für eine lokale Variable ist, muß vor der Initialisation im<br />

umgebenen while-Konstrukt vorkommen.<br />

5. Die Komplexität verschlechtert sich auf.<br />

Gehen wir auf diese Punkte genauer ein:<br />

1. Der verbesserte Algorithmus arbeitet nicht konsistent.<br />

Man kann nicht entscheiden, ob die bisher fertiggestellte Lösung korrekt ist oder noch<br />

nachträglich korrigiert werden muß. Damit ist die in Kapitel 5.4 vorgestellte Beweisidee nicht<br />

anwendbar. Die Gültigkeit des Satzes 5.4.1 ist damit offen.<br />

2. Satz 5.4.2 gilt nicht.<br />

Gegeben sei die folgende Eingabe:<br />

input (7)<br />

test do 7 end test<br />

test do 7 end test<br />

output 7<br />

So kann der Synthesealgorithmus nicht zwischen zwei möglichen erzeugenden Programmen<br />

unterscheiden:<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

input (x)<br />

with<br />

while do x end while<br />

output x<br />

input (x)<br />

with<br />

set (y := x)<br />

while do y end while<br />

output x<br />

3. Eine lokale Variable darf nicht gleichzeitig mit einer globalen Variablen verwendet werden,<br />

die ihren Anfangswert bestimmt.<br />

In diesem Fall würde auch jedes Vorkommen der lokalen Variablen fälschlicherweise<br />

abgeändert.<br />

4. Jede Variable, die Anfangswert für eine lokale Variable ist, muß vor der Initialisation im<br />

umgebenen while-Konstrukt vorkommen.<br />

Gegeben sei das folgende Klasse-II-Programm:<br />

input (x)<br />

set (y := 1)<br />

with<br />

while do<br />

with<br />

set (z := x)<br />

while x


:HLWHUH3URJUDPPNODVVHQ<br />

Für dieses Programm existiert die folgende Beispielauswertung:<br />

input (7)<br />

test do<br />

test 1


:HLWHUH3URJUDPPNODVVHQ<br />

mit der Variablenliste V:<br />

x0 Anfangswert 1 Endwert 3<br />

x1 Anfangswert 7 Endwert 11<br />

mit der Variablenliste Y:<br />

y0 Anfangswert 3 Endwert 5<br />

y1 Anfangswert 8 Endwert 12.<br />

Beim Aufruf der Prozedur MatchWHILE ist die Variablenliste V leer. Es wird kein Fehler<br />

erkannt. Die Variablenliste V erhält nach dem Aufruf die folgenden Werte:<br />

v0 Anfangswert 3 Endwert 5<br />

v1 Anfangswert 8 Endwert 12<br />

Es wird also keine lokale Variable entdeckt. Die Prozedur SampleWHILE wird feststellen, daß<br />

der Anfangswert der Variablen v1 in X nicht mit dem Endwert der Variablen v1 in V<br />

übereinstimmt und den Algorithmus mit einer Fehlermeldung verlassen.<br />

5. Die Komplexität verschlechtert sich.<br />

Für das ersetzten jedes Vorkommens einer Variablen durch eine andere, muß ein Teil des<br />

bereits erzeugten Programmes nochmals gelesen werden. Hierzu ist im schlechtesten Fall ein<br />

Aufwand O(n) notwendig, wobei n die Länge der Eingabe ist. Dann hängt die Aufwand für die<br />

Synthese aber nicht mehr linear, sondern quadratisch von der Größe der Eingabe ab.<br />

6.3 IF-Konstrukte<br />

Wir wollen jetzt die Syntax der Programme erweitern, indem wir eine if-Konstrukt einführen.<br />

Dazu erweitern wir zuerst den Sprachumfang um die Schlüsselworte if und then und führen<br />

folgende Syntax ein:<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

Tabelle 3 : Erweiterte Syntax der Sprache WHILE<br />

3URJUDPPWH[W<br />

(LQJDEH.RQVWUXNW<br />

,QLWLDOLVDWLRQVVHTXHQ]<br />

,QLWLDOLVDWLRQVNRQVWUXNW<br />

%H]HLFKQHU<br />

=DKO<br />

$XVJDEH.RQVWUXNW<br />

$QZHLVXQJVVHTXHQ]<br />

$QZHLVXQJ<br />

(LQIDFK$QZHLVXQJ<br />

6WULQJ<br />

,QNUHPHQW<br />

'HNUHPHQW<br />

ZKLOH.RQVWUXNW<br />

$XVGUXFN<br />

LI.RQVWUXNW<br />

(LQJDEHNRQVWUXNW,QLWLDOLVDWLRQVVHTXHQ]$QZHLVXQJVVHTXHQ]<br />

$XVJDEHNRQVWUXNW<br />

"input" "("Ã>%H]HLFKQHU^","%H]HLFKQHU`@")"<br />

^,QLWLDOLVDWLRQVNRQVWUXNW`<br />

"set" "(" %H]HLFKQHU":=" %H]HLFKQHU_=DKO")"<br />

%XFKVWDEH^%XFKVWDEH_=LIIHU`<br />

=LIIHU^=LIIHU`<br />

"output"%H]HLFKQHU<br />

^$QZHLVXQJ`<br />

(LQIDFK$QZHLVXQJ_,QNUHPHQW_'HNUHPHQW_ZKLOH.RQVWUXNW_LI.RQVWUXNW<br />

%H]HLFKQHU_=DKO_6WULQJ_6RQGHU]HLFKHQ<br />

^=LIIHU%XFKVWDEH6RQGHU]HLFKHQ7UHQQ]HLFKHQ`<br />

"++"%H]HLFKQHU<br />

"--"%H]HLFKQHU<br />

"with",QLWLDOLVDWLRQVVHTXHQ]"while"$XVGUXFN"do"<br />

$QZHLVXQJVVHTXHQ]"end while"<br />

^(LQIDFK$QZHLVXQJ`<br />

if$XVGUXFN"then"$QZHLVXQJVVHTXHQ]"end if"<br />

Die Definitionen im Kapitel 2 gelten sinngemäß nach obiger Definition. Wir müssen nun die<br />

Beispielauswertung eines if-Konstruktes definieren. Dazu erweitern wir Definition 3.1.1:<br />

Die Entfaltung eines if-Konstruktes der Form<br />

if A then B end if<br />

wobei A ein Ausdruck und B eine Anweiungssequenz ist, ist entweder von der Form<br />

test A do B end test (positive Form)<br />

oder von der Form<br />

test A skip (negative Form)<br />

Die Definitionen über Werte von Programmen und Beispielauswertungen sind dann einfach<br />

um die Entfaltung eines if-Konstruktes zu ergänzen. Solche Beispielauswertungen können<br />

selbstverständlich auch automatisch erzeugt werden.<br />

Wie wollen uns lieber mit der Frage beschäftigen, wie Programme mit if-Anweisungen<br />

automatisch aus Beispielauswertungen synthetisiert werden können. Definieren wir dafür<br />

einfach eine neue Programmklasse:<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

'HILQLWLRQ<br />

(LQ:+,/(3URJUDPPGHUHUZHLWHUWHQ6\QWD[3KHL‰W.ODVVH,,,3URJUDPP<br />

ZHQQIROJHQGH%HGLQJXQJHQHUI OOWVLQG<br />

(VG UIHQNHLQH]ZHLZKLOH.RQVWUXNWHGLUHNWDXIHLQDQGHUIROJHQ<br />

(VNRPPHQNHLQHORNDOHQ9DULDEOHQYRU<br />

'DVHUVWH9RUNRPPHQHLQHU9DULDEOHQLQGHU+DXSWDQZHLVXQJVVHTXHQ]<br />

YRQ3GDUIQLFKWLQQHUKDOEHLQHV,QNUHPHQWHVRGHU'HNUHPHQWHVVHLQ<br />

'DVHUVWH9RUNRPPHQHLQHU9DULDEOHQLQHLQHPZKLOH.RQVWUXNWGDUI<br />

QLFKWLQQHUKDOEHLQHV,QNUHPHQWHVRGHU'HNUHPHQWHVVHLQ<br />

) UMH]ZHL9DULDEOHQLQHLQHPZKLOH.RQVWUXNWPX‰GLH'LIIHUHQ]<br />

]ZLVFKHQLKUHQ:HUWHLQGHUHUVWHQ(QWIDOWXQJLQGHU]ZHLWHQ(QWIDOWXQJ<br />

YHUVFKLHGHQVHLQ<br />

(VG UIHQNHLQH]ZHLLI.RQVWUXNWHDXIHLQDQGHUIROJHQ<br />

(VGDUINHLQZKLOH.RQVWUXNWDXIHLQLI.RQVWUXNWIROJHQ<br />

(VGDUINHLQLI.RQVWUXNWDXIHLQZKLOH.RQVWUXNWIROJHQ<br />

'HILQLWLRQ<br />

(LQH%HLVSLHODXVZHUWXQJHLQHV.ODVVH,,,3URJUDPPHVKHL‰W.ODVVH,,,<br />

%HLVSLHODXVZHUWXQJZHQQIROJHQGH%HGLQJXQJHQHUI OOWVLQG<br />

'LH9DULDEOHLQHLQHP'HNUHPHQWGDUILQGHU$QZHLVXQJYRUGHP<br />

'HNUHPHQWQLFKWGHQ:HUWKDEHQ<br />

,QMHGHU$QZHLVXQJDX‰HUKDOEHLQHVZKLOH.RQVWUXNWHVPX‰GLH'LIIHUHQ]<br />

GHU:HUWH]ZHLHU9DULDEOHQPLQGHVWHQVEHWUDJHQ<br />

(LQLI.RQVWUXNWZHOFKHVQLFKWLQHLQHPZKLOH.RQVWUXNWHQWKDOWHQLVW<br />

GDUIQXULQGHUSRVLWLYHQ)RUPHQWIDOWHWZHUGHQ<br />

(LQLI.RQVWUXNWZHOFKHVORNDOH$QZHLVXQJHLQHVZKLOH.RQVWUXNWHVLVW<br />

PX‰LQGHQHUVWHQEHLGHQ(QWIDOWXQJHQGHVZKLOH.RQVWUXNWHVSRVLWLY<br />

HQWIDOWHWVHLQ<br />

Die Entfaltung eines while-Konstruktes besteht aus mindestens zwei aufeinanderfolgenden<br />

test-Konstrukten, während die Entfaltung eines if-Konstruktes nur aus einem isoliertem test-<br />

Konstrukt bestehen darf (nach Punkten 6 -8 der Definition 6.3.1). Wir können damit die<br />

Beispielauswertung eines test-Konstruktes exakt von der Beispielauswertung eines while-<br />

Konstruktes unterscheiden. Betrachten wir zuerst den Fall, daß das if-Konstrukt lokale<br />

Anweisung der Hauptanweisungssequenz des Programmes ist. Dann muß das if-Konstrukt<br />

positiv entfaltet sein, etwa<br />

test A do B end test<br />

dabei ist A eine Beispielauswertung eines Ausdrucks und B eine Beispielauswertung einer<br />

Anweisung. Man beachte, daß if-Konstrukte keine lokale Initialisationssequenz besitzen. Also<br />

kann die Prozedur SampleSequence zur Analyse herangezogen werden.<br />

Falls das if-Konstrukt lokale Anweisung eines while-Konstruktes ist, so wissen wir, daß es in<br />

den ersten zwei Entfaltungen des while-Konstruktes positiv entfaltet ist. Es werden also in der<br />

Prozedur SampleWSequence diese Entfaltungen des if-Konstruktes gelesen (man beachte, daß<br />

sie als Entfaltungen eines if-Konstruktes identifiziert werden können):<br />

test A 1 do B 1 end test<br />

und<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

test A 2 do B 2 end test<br />

Dabei sind A 1 und A 2 Beispielauswertungen des Ausdrucks des if-Konstruktes und B 1 und B 2<br />

Beispielauswertungen der Anweisungssequenz des if-Konstruktes. Die Prozeduren<br />

SampleWExpression und SampleWSequence können nun einfach zur Synthese des Ausdrucks<br />

und der Anweisungssequenz des if-Konstruktes benutzt werden. Es muß dabei keine neue<br />

Variablenliste angelegt werden. Auf diese Weise kann ein if-Konstrukt gewonnen werden, so<br />

daß obige Fragmente Beispielauswertungen sind. Weitere Beispielauswertungsfragmente des<br />

if-Konstruktes in anderen Entfaltungen des while-Konstruktes können nun von der Prozedur<br />

TestWHILE erkannt werden. Wenn eine solche Beispielauswertung aus einer negativen<br />

Entfaltung besteht, wird einfach nur die Auswertung des Ausdrucks beachtet.<br />

Wie wollen nun hinterfragen, ob die zusätzlichen Bedingungen für Klasse-III-Programme und<br />

Klasse-III-Beispielauswertungen sinnvoll sind, oder die Klasse der möglichen Programme (mit<br />

if-Konstrukten) zu sehr einschränken. Die Bedingungen 6-8 der Definition 6.3.1 sind<br />

sicherlich nicht beschränkend, sie entsprechen Regeln wie in Sprachen wie Pascal.<br />

Leider beschränken die Regeln 3 und 4 der Definition 6.3.2 die Menge der Eingaben stark. Die<br />

Bedingung, ein if-Konstrukt immer positiv oder in den ersten zwei Vorkommen positiv<br />

auszuwerten gleicht der Bedingung, daß der Ausdruck einer if-Anweisung immer wahr ist.<br />

Dies führt aber den Sinn einer if-Anweisung ad absurdum. Die Klasse III ist damit nicht<br />

geeignet als vernünftige Sprachklasse zur Synthese von Programmen.<br />

Versuchen wir jetzt, alternative Ansätze zur Programmsynthese zu finden Wir müssen jedes<br />

if-Konstrukt mindestens einmal positiv auswerten, denn sonst haben wir keine Chance, die<br />

Anweiungssequenz synthetisieren zu können. Deswegen können wir auf die Bedingung 3 nicht<br />

verzichten. Es stellt sich jetzt die Frage, ob eine positive Auswertung des if-Konstruktes in den<br />

Entfaltungen des while-Konstruktes nicht genügt, um eine if-Konstrukt zu generieren. Es sind<br />

aber mindestens zwei Entfaltungen notwendig, um die Zuordnung von Zahlen in einer<br />

Beispielauswertung auf die beteiligten Variablen zu treffen. Wenn wir also nur eine positive<br />

Entfaltung des if-Konstruktes fordern, so müssen wir das Vorkommen von Variablen im if-<br />

Konstrukt ausschließen, was sicherlich unbefriedigend ist.<br />

Wir benötigen also mindestens zwei positive Entfaltungen des if-Konstruktes. Wenn das if-<br />

Konstrukt aber nicht in den ersten beiden Entfaltungen des while-Konstruktes positiv<br />

ausgewertet worden ist, kann im allgemeinen von der Prozedur SampleWHILE nach dem<br />

Lesen der ersten beiden Entfaltungen das while-Konstrukt nicht generiert werden. Nicht nur,<br />

daß das if-Konstrukt in der Anweisungssequenz des while-Konstruktes fehlt (dies könnte ja<br />

später von der Prozedur TestWHILE ergänzt werden), dadurch das wir nicht wissen, welche<br />

Variablen im if-Konstrukt verwendet wurden und welche Werte verändert wurden, konnte<br />

auch der Rest der Anweisungssequenz nicht fehlerfrei synthetisiert werden. Damit kann aber<br />

unser Synthesealgorithmus if-Konstrukte nur auf der Basis der Klasse-III-Programme<br />

bearbeiten.<br />

Aufgrund der oben ausgeführten Problem erübrigt sich die Frage, warum wir das if-Konstrukt<br />

nicht um einen else-Zweig ergänzt haben.<br />

6.4 weitergehende Erweiterungen<br />

In Kapitel 1 haben wir gesehen, daß wir durch Einführung weiterer Konstrukte die<br />

Ausdrucksfähigkeit unserer Sprache erhöhen konnten. Leider ist es nicht möglich, z.B. einen<br />

switch-Konstrukt einzuführen. Denn wie sollten wir jeden Zweig des switch-Konstruktes<br />

zweimal auswerten, und das noch in den ersten beiden Entfaltungen eines while-Konstruktes?<br />

Versuchen wir lieber eine grundlegender Erweiterung in unsere Sprache einzuführen, nämlich<br />

Makros. Dazu gibt es zwei Möglichkeiten: Wir lassen die Makroaufrufe bei der Bildung der<br />

6HLWH


:HLWHUH3URJUDPPNODVVHQ<br />

Beispielauswertungen bestehen oder wir lassen sie bei der Bildung der Auswertung unter den<br />

Tisch fallen.<br />

Betrachten wir zuerst die erste Möglichkeit. Ein solches Programm wäre etwa:<br />

input (x)<br />

double (x)<br />

output x<br />

mit der Beispielauswertung:<br />

input (8)<br />

double (8)<br />

output 16<br />

Wenn dem Synthesealgorithmus jetzt bekannt ist, das das Makro double den Wert der<br />

Variablen in seinem Argument verdoppelt, so weiß er, daß die Variable, die vor dem Aufruf<br />

den Wert 8 innehatte, danach den Wert 16 besitzt. Also kann das obige Programm<br />

synthetisiert werden. Es bleibt aber die Frage, wie dieses "Wissen" an den<br />

Synthesealgorithmus überreicht werden kann.<br />

Falls die Bedeutung des Makros double nicht bekannt ist, so dürfte es schwerfallen, die<br />

Semantik des Makros zu erkennen. Unlösbar wird die Aufgabe, wenn die Beispielauswertung<br />

den Makroaufruf nicht mehr enthält. Die Beispielauswertung des obigen Programms sähe<br />

dann so aus:<br />

input (8)<br />

output 16<br />

Geben wir zum Abschluß noch ein krasseres Beispiel an. Gegeben sei die folgende Eingabe:<br />

input (1)<br />

4<br />

19<br />

11<br />

22<br />

14<br />

output 16<br />

Obige Eingabe dürfte die meisten Synthesealgorithmen überfordern. Die Lösung ist<br />

selbstverständlich das folgende Programm:<br />

input (x)<br />

add3 (x)<br />

add15 (x)<br />

sub8 (x)<br />

double (x)<br />

sub8 (x)<br />

output x<br />

6HLWH


(QWZXUIVHQWVFKHLGXQJHQ<br />

7 Entwurfsentscheidungen<br />

Der Entwurf richtet sich nach folgenden Grundlagen:<br />

1. Das Werkzeug wird den Namen ’[VDPSOH’ tragen. Seine Versionsnummer soll 2.0 lauten.<br />

2. Es wird objektorientierte Programmierung verwendet. Als Programmiersprache wird C++<br />

verwendet. Es wird der Gnu-C++-Compiler verwendet.<br />

3. Das Werkzeug soll unter einer UNIX-Umgebung laufen.<br />

4. Das Programm wird in Komponenten und Unterkomponenten aufgeteilt, die einzeln<br />

spezifiziert, kodiert und getestet werden können.<br />

5. Es werden die GNU-C++-Libraries verwendet.<br />

6. Es werden X11 und OSF/Motif verwendet.<br />

7. Die Steuerung des Programmes geschieht wahlweise über eine interaktive graphische<br />

Benutzeroberfläche oder über Kommandozeilenargumente im Batch-Betrieb.<br />

8. Das Werkzeug enthält einen Texteditor zur Erzeugen der Eingaben. Weiterhin soll<br />

Datenverkehr zu einem Speichermedium unterstützt werden.<br />

9. Die Bedienung des neuen Programmes soll der Bedienung der Version 1.0 des Werkzeugs<br />

ähneln. Des weiteren sollen die Datenformate der neuen Version nach Möglichkeit mit den<br />

alten Datenformaten übereinstimmen.<br />

10. Im Sinne der Wiederverwertung soll vor jeder neuen Spezifikation geprüft werden, ob nicht<br />

eine Komponente der Version 1.0 des Werkzeugs ganz oder teilweise verwendet werden<br />

kann.<br />

11. Das Werkzeug soll auf mehreren Plattformen laufen.<br />

12. Das Werkzeug soll für eine Erweiterung um weitere Programmklassen vorbereitet sein.<br />

13. Natürliche Zahlen werden generell durch den Datentyp unsigned int dargestellt. Ihre obere<br />

Schranke richtet sich nach der internen Darstellung dieses Datentyps und dürfte im<br />

Regelfall 32 Bit betragen.<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8 Der Aufbau von [VDPSOH Version 2.0<br />

Zur besseren Darstellung der Komponenten des Programmes und ihrer Beziehungen<br />

zueinander wurde eine graphische Darstellung gewählt (siehe Abb. 1) Die Pfeile starten dabei<br />

an der exportierenden Komponente und enden an der importierenden Komponente. Es werden<br />

fünf Arten der Beziehungen zwischen Komponenten unterschieden:<br />

ì<br />

ì<br />

ì<br />

ì<br />

ì<br />

ì<br />

Bei der Vererbung benutzt die importierende Komponente eine Klasse der exportierenden<br />

Komponente als Basisdatentyp einer eigenen Klasse. Die importierende Klasse kann dabei<br />

auf private Komponenten und Methoden der übertragenen Klasse nicht zugreifen.<br />

Bei der Bereitstellung eines Datentyps für die importierende Komponente durch die<br />

exportierende Komponente wird der übertragene Datentyp als Typ von Variablen und<br />

Komponenten benötigt. Bei einer Klasse kann dabei nur auf öffentliche Komponenten und<br />

Methoden zurückgegriffen werden.<br />

Die Fehlerbehandlung beinhaltet die Bereitstellung eines Datentyps mit den Namen der<br />

Kodierung der Fehlermeldung und die Bereitstellung einer Funktion zum Aufruf des<br />

Fehlers.<br />

Die Bereitstellung von Funktionen ermöglicht der importierenden Komponente den Aufruf<br />

von Funktionen der exportierenden Komponente.<br />

Bei der Bereitstellung von Callbackroutinen durch die exportierende Komponente werden<br />

diese Routinen von der importierenden Komponente an Aktionen von X-Applikationen<br />

gebunden. Die Callbackroutinen werden nicht von der importierenden Komponente<br />

aufgerufen, sondern von Ereignissen der X-Applikation.<br />

Bei der Bereitstellung von Event-Handlern werden Event-Handler zur Bearbeitung von<br />

Events von der exportierenden Komponente an die importierende Komponente übergeben,<br />

um sie an vom Benutzer des System auflösbare Events zu Binden. Event-Handler werden<br />

von Ereignissen der X-Applikation aufgerufen.<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

Ein Überblick über die Komponenten des Programmes und ihrer Beziehungen zueinander<br />

bietet Abb. 5.<br />

Abbildung 8 : Struktur von [VDPSOH 2.0<br />

Zeichenerklärung:<br />

Bereitstellung von Datentypen<br />

Bereitstellung von Funktionen<br />

Vererbung<br />

Fehlerbehandlung<br />

Interface<br />

Text<br />

SampleText<br />

ProgramText<br />

Computer<br />

Synthesizer<br />

Parser<br />

Der Benutzer erhält dabei nur Kontakt zur Komponente Interface. Diese Komponente enthält<br />

die Funktion main, die als erste Funktion beim Start des Werkzeugs vom Betriebssystem<br />

aufgerufen wird. Nach Auswertung der Kommandozeilenoptionen wird, sofern dies gewünscht<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

wird, die interaktive Benutzerschnittstelle aufgebaut (siehe Kapitel 9). Die Komponente stellt<br />

Funktionen zum Aufbau des Hauptfensters und aller untergeordneten Fenster bereit, sowie die<br />

Callbackroutinen zur Reaktion auf die Events, die vom Benutzer ausgelöst werden. Inbegriffen<br />

ist damit auch das Hilfe- und das Fehlermeldesystem.<br />

Die Komponente Text stellt den Datentyp Text bereit. Dieser beinhaltet Methoden und Daten<br />

zur Verwaltung eines beliebig langen ASCII-Textes, einschließlich Datenverkehrsoperationen.<br />

Die Komponenten SampleText und ProgramText erweitern diese Klasse um Methoden zur<br />

Bildung der Beispielauswertung aus einem WHILE-Programm oder zur Generierung eines<br />

Programmes aus einer Beispielauswertung. Die von diesen Komponenten zur Verfügung<br />

gestellten Klassen SampleText und ComputableText werden von der Komponente Interface<br />

verwendet.<br />

Die Komponente Parser beinhaltet die interne Darstellung von Programmen und<br />

Beispielauswertungen. Zu diesem Zweck stellt sie die Klassen Program und<br />

SampleComputation. Die Komponenten Computer und Synthesizer erweitern diese Klassen<br />

um Methoden zur automatischen Programmsynthese und Auswertungsgenerierung.<br />

8.1 Namenskonventionen<br />

Bei der Kodierung des Werkzeuges wurde bei allen vom Autor frei gewählten Bezeichnern<br />

folgende Namenskoventionen eingehalten:<br />

Tabelle 4 : Namenskoventionen<br />

Art des Bezeichners Namenskonvention Beispiele<br />

Datentypen<br />

Klein- und Großbuchstaben,<br />

Wörter zusammengeschrieben,<br />

jedes Wort beginnt mit einem<br />

Großbuchstaben<br />

Funktionen und Methoden<br />

Variablen<br />

Konstanten<br />

Klein- und Großbuchstaben,<br />

Wörter zusammengeschrieben,<br />

jedes Wort mit Ausnahme des ersten<br />

beginnt mit einem Großbuchstaben<br />

Kleinbuchstaben,<br />

Wörter durch "_" getrennt<br />

Großbuchstaben,<br />

Wörter durch "_" getrennt.<br />

CommandType<br />

Program<br />

LeftSideType<br />

checkCommandLine<br />

compute<br />

getText<br />

number_of_elements<br />

counter<br />

E_NUMBER,<br />

MODE_BATCH<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.2 Die Komponente Interface<br />

Abbildung 9 : Struktur der Komponente Interface<br />

Zeichenerklärung:<br />

Bereitstellung von Datentypen<br />

Bereitstellung von Funktionen<br />

Bereitstellung von Callbackroutinen<br />

Bereitstellung von Event-Handlern<br />

Fehlerbehandlung<br />

Vererbung<br />

Betriebssystem<br />

Main<br />

CommandLine<br />

Graphical<br />

UserInterface<br />

Extended<br />

Operations<br />

EventHandler<br />

Callback<br />

Operations<br />

Help<br />

Messages<br />

HelpErrorText<br />

Error<br />

HelpError<br />

Connection<br />

Text Parser<br />

Synthezizer<br />

ProgramText<br />

SampleText<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.2.1 Die Unterkomponente Main<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

xsample.h<br />

xsample.cxx<br />

AlgorithmType, LogType, ModeType,<br />

CommandType von Unterkomponente<br />

CommandLine<br />

FormData von Unterkomponente Operations<br />

checkCommandLine von Unterkomponente<br />

CommandLine<br />

startInterface von Unterkomponente<br />

GraphicalUserInterface<br />

errorInit und logInit von Unterkomponente Error<br />

keine<br />

main<br />

Die Unterkomponente Main stellt die Funktion main zur Verfügung, die beim Start des<br />

Werkzeugs aufgerufen wird. Der Funktion main werden auch die Kommandozeilenargumente<br />

des Aufrufs übergeben. In der Funktion main wird die Kommandozeile ausgewertet und eine<br />

Instanz des zentralen Datentyps FormData konstruiert. Falls die interaktive Benutzerführung<br />

angewählt wurde, wird die graphische Benutzeroberfläche gestartet, falls der Batch-Modus<br />

angewählt wurde, wird der Programmablauf von der Funktion main selbst durchgeführt.<br />

8.2.2 Die Unterkomponente CommandLine<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

commandline.h<br />

commandline.cxx<br />

AlgorithmType von Unterkomponente Connection<br />

standardAlgorithm, setAlgorithm und<br />

listAlgorithm von Unterkomponente Connection<br />

ModeType, AlgorithmType, LogType,<br />

CommandType<br />

checkCommandLine<br />

Zweck der Unterkomponente CommandLine ist die Auswertung der Kommandozeile mittels<br />

der bereitgestellten Funktion checkCommandLine. Eine nähere Beschreibung der<br />

Kommandozeilenargumente erfolgt in Kapitel 9. Rückgabewert der Funktion ist eine Struktur<br />

des Typs CommandType, in der die das Ergebnis der Komandozeilenanalyse festgehalten<br />

wird.<br />

8.2.3 Die Unterkomponente GraphicalUserInterface<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

gui.h<br />

gui.cxx<br />

FormData, WidgetName, Triple und ButtonName<br />

von Unterkomponente Operations<br />

AlgorithmType von Unterkomponente Connection<br />

errorInit von Unterkomponente Error<br />

helpInit von Unterkomponente Help<br />

Callbackroutinen von Unterkomponente Callback<br />

Eventhandler von Unterkomponente EventHandler<br />

keine<br />

startInterface<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

Die von der Unterkomponente zur Verfügung gestellte Funktion startInterface konstruiert das<br />

Hauptfenster des Formulars, verbindet von den Widgets des Hauptformulars ausgelöste<br />

Events mit den Callbackroutinen und den Eventhandlern und fügt das Programm als X-<br />

Anwendung in die Haupteventschleife des X-Servers ein.<br />

8.2.4 Die Unterkomponente Messages<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

messages.h<br />

messages.cxx<br />

ExtendedFormData von Unterkomponente<br />

ExtendedOperations<br />

Callbackroutinen von Unterkomponente Callback<br />

WarningType<br />

createWarning, createQuestion, fileSelect und<br />

createInfoBox<br />

Die Unterkomponente stellt Funktionen zur Erzeugung von<br />

Warnungsboxen vor versehentlichem Löschen nicht gesicherter Änderungen im Text der<br />

Beispielauswertung oder im Text des Programmes,<br />

Dialogboxen für Sicherheitsabfragen,<br />

Dateiauswahlboxen,<br />

sowie für die Informationsbox, die einen Text über den Autor des Programmes ausgibt.<br />

Callbackroutinen zur Behandlung der von den Dialogfenstern erzeugten Events werden von<br />

der Unterkomponente Callback zur Verfügung gestellt.<br />

8.2.5 Die Unterkomponente Callback<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

callback.h<br />

callback.cxx<br />

ExtendedFormData und OperationType von<br />

Unterkomponente ExtendedOperations<br />

WarningType von Unterkomponente Messages<br />

HelpType von Unterkomponente Help<br />

createWarning, createQuestion, fileSelect und<br />

createInfoBox von Unterkomponente Messages<br />

createHelpDialog von Unterkomponente Help<br />

WarningType<br />

Callbackroutinen<br />

In dieser Unterkomponente werden Callbackroutinen für die Behandlung der Events des<br />

Hauptformulars und der Dialogfenster zur Verfügung gestellt. Die Unterkomponente steuert<br />

ebenfalls den Aufbau der Dialogfenster.<br />

8.2.6 Die Unterkomponente EventHandler<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

eventhandler.h<br />

eventhandler.cxx<br />

keine<br />

keine<br />

keine<br />

Eventhandler<br />

Die Unterkomponente stellt Eventhandler für die Unterkomponente GraphicalUserInterface<br />

bereit.<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.2.7 Die Unterkomponente Help<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

help.h<br />

help.cxx<br />

HelpErrorText von Unterkomponente<br />

HelpErrorText<br />

displayMessage von Unterkomponente HelpError<br />

HelpType<br />

helpInit, createHelpDialog<br />

Die Unterkomponente stellt die Hilfefunktion von [VDPSOH 2.0 zur Verfügung. Zur<br />

Kodierung der Hilfstexte stellt die Unterkomponente den Datentyp HelpType zur Verfügung.<br />

Zum Lesen der Hilfstexte wird die Klasse HelpErrorText von der Unterkomponente<br />

HelpErrorText importiert, zur Darstellung der Hilfstexte in der Hilfebox wird die Funktion<br />

displayMessage der Unterkomponente HelpError verwendet. Die Hilfetexte werden<br />

standardmäßig in der Datei "sample.help" gesucht, über die Umgebungsvariable<br />

"XSAMPLEHELPFILE" kann eine andere Datei angewählt werden.<br />

8.2.8 Die Unterkomponente Error<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

error.h<br />

error.cxx<br />

HelpErrorText von Unterkomponente<br />

HelpErrorTex<br />

LogType von Unterkomponente CommandLine<br />

displayMessage und displayLog von<br />

Unterkomponente HelpError<br />

ErrorType<br />

errorInit, logInit und error<br />

In dieser Unterkomponente werden die Fehlermeldungen des Werkzeugs erzeugt. Der<br />

Datentyp ErrorType beinhaltet eine Kodierung der Fehlermeldungen. Die Texte der<br />

Fehlermlungen werden über die Klasse HelpErrorType der Unterkomponente<br />

HelpErrorType. Die Ausgabe der Fehlermeldungen erfolgt im interaktiven Modus über eine<br />

Hilfebox mittels der Funktion displayMessage, die von der Unterkomponente HelpError<br />

geliefert wird. Im Batch-Modus erfolgt die Ausgabe der Fehlermeldungen über die<br />

Standardfehlerausgabe. Standardmäßig stehen die Fehlermeldungen in der Datei<br />

"sample.error", jedoch kann über die Umgebungsvariable "XSAMLEERRORFILE" eine<br />

andere Datei für die Fehlermeldungen bestimmt werden. Optional kann beim Aufruf der<br />

Funktion error auch einen Fehlerprotokoll angegeben werden. Das Fehlerprotokoll wird in die<br />

Datei "error.log" (oder über eine andere bei der Initialisation angegebene Datei) gespeichert,<br />

sofern diese Funktionalität nicht abgeschaltet wird. Im interaktiven Modus wird das<br />

Fehlerprotokoll mittels der Funktion displayLog in einem Fenster angezeigt.<br />

8.2.9 Die Unterkomponente HelpErrorText<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

helperrortext.h<br />

helperrortext.cxx<br />

keine<br />

keine<br />

ErrorTypeText<br />

keine<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

Die Komponente stellt den Datentyp HelpErrorText zur Verfügung. Über ihn können sowohl<br />

Hilfetexte als auch Fehlermeldungen von Datei gelesen werden.<br />

8.2.10 Die Unterkomponente HelpError<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

helperror.h<br />

helperror.cxx<br />

keine<br />

Callbackroutinen von Unterkomponente Callback.<br />

keine<br />

displayMessage, displayLog<br />

Die Unterkomponente HelpError kreiert eine Mitteilungsbox zur Darstellung der Hilfetexte<br />

und der Fehlermeldungen mit der exportierten Funktion displayMessage. Die Funktion<br />

displayLog dient zur Ausgabe des Fehlerprotokolls in einem Fenster.<br />

8.2.11 Die Unterkomponente Operations<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

operations.h<br />

operations.cxx<br />

AlgorithmType, SampleText, ProgramText von<br />

Unterkomponente Connection<br />

keine<br />

FormData, ButtonName, ButtonType,<br />

WidgetName, Triple<br />

keine<br />

Die Unterkomponente stellt den zentralen Datentype FormData zur Verfügung. In diesem<br />

Datentyp werden alle Informationen, die zur Steurung des Werkzeugs notwendig sind<br />

gespeichert. Außerdem werden weitere Datentypen exportiert, die zur Zugriff und zur<br />

effizienten Speicherung der verschiedenen Widgets in der Klasse FormData notwendig sind.<br />

8.2.12 Die Unterkomponente ExtendedOperations<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

xoperations.h<br />

xoperations.cxx<br />

FormData von Unterkomponente Operations<br />

AlgorithmType von Unterkomponente Connection<br />

standardAlgorithm von Unterkomponente<br />

Connection<br />

OperationType<br />

ExtendedFormData<br />

keine<br />

Die Unterkomponente erweitert den von Operations zur Verfügung gestellten Datentyp<br />

FormData und stellt die Methoden für die Manipulation der Datenstruktur zur Verfügung.<br />

Der Datentyp OperationType dient zur Kodierung der Art der Operation, wenn diese in<br />

ExtendedFormData gespeichert werden soll.<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.2.13 Die Unterkomponente Connection<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

connetion.h<br />

connetion.cxx<br />

SampleText von Komponente SampleText<br />

ProgramText von Komponente ProgramText<br />

keine<br />

AlgorithmType, SampleText und ProgramText<br />

standardAlgorithm, setAlgorithm und<br />

listAlgorithm<br />

Diese Unterkomponenten stellt das Bindeglied dar zwischen der Komponente Interface und<br />

den funktionalen Komponenten. Demnach muß bei Änderungen in den funktionalen<br />

Komponenten (z.B. der Hinzunahme weiterer Programmklassen) in der Komponente Interface<br />

nur die Unterkomponente Connection angepaßt werden. Sollen weitere Algorithmen über die<br />

graphische Benutzeroberfläche angewählt werden können, so sind auch Änderungen in den<br />

Unterkomponenten GraphicalUserInterface und Callback notwendig.<br />

8.3 Die Komponente Text<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

text.h<br />

text.cxx<br />

keine<br />

keine<br />

Text<br />

keine<br />

In der Komponente Text wird der Datentyp Text bereitgestellt, der die Verwaltung einer<br />

beliebig langen Zeichenkette beinhaltet, einschließlich Operationen des Datenverkehrs mit<br />

einem Speichermedium.<br />

8.4 Die Komponente SampleText<br />

Quellcodedateien:<br />

sampletext.h<br />

sampletext.cxx<br />

Import von Datentypen:<br />

AlgorithmType von Komponente Interface<br />

Unterkomponente Connection<br />

Text von Komponente Text<br />

SynthesizableSample von Komponente<br />

Synthesizer<br />

Import von Funktionen:<br />

keine<br />

Export von Datentypen<br />

SampleText<br />

Export von Funktionen<br />

keine<br />

Die Komponente erweitert den Datentyp Text zum Datentyp SampleText durch Hinzunahme<br />

von Operationen zur Programmsynthese. Der Datentyp SampleText wird dann als Klasse der<br />

ASCII-Texte der Beispielauswertungen verwendet. Die ASCII-Darstellung wird für die<br />

Ausgabe auf dem Bildschirm und für die Speicherung auf einem Speichermedium verwendet,<br />

da sie für den Menschen lesbar ist und von jedem Texteditor verarbeitet werden kann. Diese<br />

Darstellung der Beispielauswertungen wurde auch in dieser Arbeit verwendet.<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.5 Die Komponente ProgramText<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

programtext.h<br />

programtext.cxx<br />

AlgorithmType von Komponente Interface<br />

Unterkomponente Connection<br />

Text von Komponente Text<br />

ComputableProgram von Komponente Computer<br />

keine<br />

ProgramText<br />

keine<br />

Die Komponente erweitert den Datentyp Text zum Datentyp ProgramText durch<br />

Hinzunahme von Operationen zur Auswertung von Programmen. Der Datentyp ProgramText<br />

wird dann als Klasse der ASCII-Texte der WHILE-Programme verwendet. Die ASCII-<br />

Darstellung wird für die Ausgabe auf dem Bildschirm und für die Speicherung auf einem<br />

Speichermedium verwendet, da sie für den Menschen lesbar ist und von jedem Texteditor<br />

verarbeitet werden kann. Diese Darstellung der WHILE-Programme wurde auch in dieser<br />

Arbeit verwendet.<br />

8.6 Die Komponente Computer<br />

Quellcodedateien:<br />

computer.h<br />

computer.cxx<br />

Import von Datentypen:<br />

Program, Construct, WhileConstruct,<br />

Sequence, ProgramSequence, Statement,<br />

StatementType und InitialType von Komponente<br />

Parser Unterkomponente Program<br />

SampleComputation, SampleSequence und<br />

TestConstruct von Komponente Parser<br />

Unterkomponente SampleComputation<br />

Import von Funktionen:<br />

keine<br />

Export von Datentypen<br />

ComputableProgram<br />

Export von Funktionen<br />

keine<br />

Die Komponente erweitert den von der Komponente Parser übernommene Klasse Program<br />

zur Klasse ComputableProgram. Wichtigste Erweiterung ist die Methode<br />

ComputableProgram::compute, die eine Auswertung des Programmes berechnet und als<br />

ASCII-Text zurückliefert.<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.7 Die Komponente Synthesizer<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

computer.h<br />

computer.cxx<br />

Program, Construct, WhileConstruct,<br />

Sequence, ProgramSequence, Statement,<br />

StatementType und InitialType von Komponente<br />

Parser Unterkomponente Program<br />

SampleComputation, SampleSequence und<br />

TestConstruct von Komponente Parser<br />

Unterkomponente SampleComputation<br />

ErrorType von Komponente Interface<br />

Unterkomponente Error<br />

error von Komponente Interface<br />

Unterkomponente Error<br />

SynthesizableSample<br />

keine<br />

Die Komponente erweitert den von der Komponente Parser übernommene Klasse<br />

SampleComputation zur Klasse SynthesizableSample. Wichtigste Erweiterung ist die<br />

Methode SynthesizableSample::synthesize, die eine Auswertung des Programmes berechnet<br />

und als ASCII-Text zurückliefert.<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.8 Die Komponente Parser<br />

Abbildung 10 : Struktur der Komponente Parser<br />

Zeichenerklärung:<br />

Bereitstellung von Datentypen<br />

Bereitstellung von Funktionen<br />

Vererbung<br />

Fehlerbehandlung<br />

Variable<br />

Basic<br />

Interface<br />

ProgramText<br />

Program<br />

Sample<br />

Computation<br />

Interface<br />

SampleText<br />

Interface<br />

Scanner<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.8.1 Die Unterkomponente Scanner<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

scanner.h<br />

scanner.cxx<br />

ErrorType von Komponente Interface<br />

Unterkomponente Error<br />

error von Komponente Interface<br />

Unterkomponente Error<br />

WhiteSpacesMode, ScanText<br />

keine<br />

Die Unterkomponente Scanner stellt die wichtigsten Methoden zur syntaktische Analyse eines<br />

Textes zur Verfügung. Mit dem von der Unterkomponente exportierten Datentyp ScanText<br />

können Worte, Zahlen, Zeichenketten und Sonderzeichen aus dem Text gelesen werden. Dabei<br />

können Trennzeichen und Kommentare überlesen werden.<br />

8.8.2 Die Unterkomponente Variable<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

variable.h<br />

variable.cxx<br />

keine<br />

keine<br />

Variable, VariableList<br />

keine<br />

In der Unterkomponente Variable werden die Datentypen Variable und VariableList<br />

bereitgestellt zusammen mit Methoden zur Verwaltung von Variablen und Variablenlisten.<br />

8.8.3 Die Unterkomponente Basic<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

basic.h<br />

basic.cxx<br />

Variable und VariableList von Unterkomponente<br />

Variable<br />

ScanText von Unterkomponente Scanner<br />

keine<br />

OutputState, SkipState, InitialType, Statement,<br />

StatementType, Sequence, Construct und<br />

BasicProgram<br />

keine<br />

Die Unterkomponente Basic stellt Basisdatentypen für die interne Darstellung von<br />

Programmen und Beispielauswertungen zur Verfügung.<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.8.4 Die Unterkomponente Program<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

program.h<br />

program.cxx<br />

Variable und VariableList von Unterkomponente<br />

Variable<br />

ScanText und WhiteSpacesMode von<br />

Unterkomponente Scanner<br />

ErrorType von Komponente Interface<br />

Unterkomponente Error<br />

OutputState, SkipState, InitialType, Statement,<br />

StatementType, Sequence, Construct und<br />

BasicProgram von Unterkomponente Basic<br />

error von Komponente Interface<br />

Unterkomponente Error<br />

WhileConstruct, ProgramSequence, Program<br />

keine<br />

Die Datentypen WhileConstruct, ProgramSequence und Program, die von der<br />

Unterkomponente Program exportiert werden, implementieren die interne Darstellung von<br />

while-Konstrukten, Anweisungssequenzen (und Ausdrücken) und Programmen. Die<br />

Unterkomponente stellt Methoden dar zum Parsen eines ASCII-Textes eines Programmes in<br />

die interne Darstellung mittels des importierten Datentyps ScanText, sowie zur<br />

Rückumwandlung der internen Darstellung eines Programmes in einen ASCII-Text.<br />

8.8.5 Die Unterkomponente SampleComputation<br />

Quellcodedateien:<br />

Import von Datentypen:<br />

Import von Funktionen:<br />

Export von Datentypen<br />

Export von Funktionen<br />

samplecomputation.h<br />

samplecomputation.cxx<br />

Variable und VariableList von Unterkomponente<br />

Variable<br />

ScanText und WhiteSpacesMode von<br />

Unterkomponente Scanner<br />

ErrorType von Komponente Interface<br />

Unterkomponente Error<br />

OutputState, SkipState, InitialType, Statement,<br />

StatementType, Sequence, Construct und<br />

BasicProgram von Unterkomponente Basic<br />

error von Komponente Interface<br />

Unterkomponente Error<br />

TestConstruct, SampleSequence,<br />

SampleComputation<br />

keine<br />

Die Datentypen TestConstruct, SampleSequence und SampleComputation, die von der<br />

Unterkomponente SampleComputation exportiert werden, implementieren die interne<br />

Darstellung von test-Konstrukten, Auswertungsfragmenten und Beispielauswertungen. Die<br />

Unterkomponente stellt Methoden dar zum Parsen eines ASCII-Textes einer<br />

Besipielauswertung in die interne Darstellung mittels des importierten Datentyps ScanText,<br />

sowie zur Rückumwandlung der internen Darstellung einer Beispielauswertung in einen<br />

ASCII-Text.<br />

6HLWH


'HU$XIEDXYRQ[VDPSOH9HUVLRQ<br />

8.9 Erweiterungen<br />

8.9.1 Hinzunahme weiterer Algorithmen<br />

Soll ein weiterer Algorithmus in die Funktionalität des Werkzeugs hinzu genommen werden,<br />

so ist dieser Algorithmus in den Datentyp AlgorithmType in der Unterkomponente<br />

Connection aufzunehmen. Damit dieser Algorithmus über die Kommandozeilenoption -a<br />

angewählt werden kann, sind Änderungen in den Funktionen, die von der Unterkomponente<br />

Connection bereitgestellt werden, notwendig. Zur Aufnahme des Algorithmus' in das<br />

Algorithmenmenü des Hauptformulars der graphischen Benutzeroberfläche muß dieser neue<br />

Menüpunkt in der Unterkomponente GraphicalUserInterface hinzugefügt werden. Die<br />

Beschriftung des Menüpunktes ist in das Resourcenfile aufzunehmen. Des weiteren ist eine<br />

neue Callbackroutine einzuführen und in der Unterkomponente Callback zu definieren.<br />

Auf jedem Fall müssen die Methoden ProgramText::compute und SampleText::synthesize<br />

in den Komponenten Programtext und SampleText angepaßt werden. Dazu muß die neue<br />

Synthesefunktion und/oder die neue Auswertefunktion importiert werden. Falls der neue<br />

Algorithmus angewählt worden ist, sind dann statt der Standardalgorithmen die neuen<br />

Algorithmen aufzurufen.<br />

8.9.2 Hinzunahme weiterer Fehlermeldungen<br />

Zuerst muß eine Kodierung der neuen Fehlermeldung in den Datentyp ErrorType der<br />

Unterkomponente Error aufgenommen werden (und zwar als letztes Element des Datentyps).<br />

Diese Kodierung muß beim Aufruf der Funktion error benutzt werden, wenn die neu<br />

aufzunehmende Fehlermeldung aufgerufen werden soll. Die neue Fehlermeldung muß dann in<br />

die Fehlermeldungsdatei aufgenommen werden, ebenfalls als letztes Element.<br />

8.9.3 Hinzunahme weiterer Hilfstexte<br />

Hierzu muß die Kodierung des neuen Hilfstextes als letztes Element in den Datentyp<br />

HelpType aufgenommen werden. Diese Kodierung ist beim Aufruf der Hilfefunktion mit<br />

createHelpDialog zu verwenden. Der Hilfetext muß als letztes Element in die Hilfetextdatei<br />

angefügt werden.<br />

8.9.4 Hinzunahme weiterer Operationen im Hauptformular<br />

Hierzu sind Änderungen in der Komponente GraphicalUserInterface und in der<br />

Resourcendatei notwendig. Operationen über den Texteditor sollten als Menüeinträge in das<br />

Edit-Menü eingefügt werden. Andere Operationen können in einer gesonderten Menüleiste<br />

eingeführt werden. Benötigte Eventhandler sind in der Unterkomponente EventHandler<br />

aufzunehmen, benötigte Callbacks sind in die Unterkomponente Callback einzufügen.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

9 Benutzerschnittstelle<br />

9.1 Dateien<br />

Das Werkzeug [VDPSOH in der Version 2.0 besteht bei der Installation aus den folgenden<br />

Dateien:<br />

xsample<br />

Sample<br />

sample.help<br />

sample.error<br />

xsample.bm<br />

xsample.icon.bm<br />

xsample.1<br />

Das Programm ist in einer Binärdatei namens<br />

xsample<br />

enthalten.<br />

Zum Start der graphischen Benutzeroberfläche ist ein Resourcenfile namens<br />

Sample<br />

notwendig. Diese Datei muß sich in dem mit der Umgebungsvariable APPLRESDIR<br />

spezifiziertem Verzeichnis oder im Homeverzeichnis des Benutzers befinden, falls die Variable<br />

nicht definiert ist (oder im 'app-default'- Verzeichnis des Systems). Selbstverständlich können<br />

die Resourcen auch auf andere Weise (z.B. .Xdefaults, xrdb) zur Verfügung gestellt werden<br />

Des weiteren muß eine Datei vorhanden sein, in der die Hilfetexte gespeichert sind. Dies ist<br />

standardmäßig die Datei<br />

sample.help<br />

und steht im selben Verzeichnis wie xsample. Mit der Umgebungsvariablen<br />

XSAMPLEHELPFILE kann eine andere Datei und ein anderer Pfad gewählt werden.<br />

Analog muß eine Datei vorhanden sein, in der die Fehlermeldungen gespeichert sind. Diese<br />

Datei heißt<br />

sample.error,<br />

und steht in demselben Verzeichnis wie xsample, sofern nicht mit der Umgebungsvariablen<br />

XSAMPLEERRORFILE eine andere Datei und ein anderer Pfad festgelegt worden ist.<br />

Die Datei<br />

xsample.bm<br />

enthält das Bitmap der Applikation, wie für die Infobox benötigt wird. Die Datei<br />

xsample.icon.bm<br />

enthält die Bitmap für das Icon des Programmes.<br />

Die 'man-page' zum Programm ist in der Datei<br />

xsample.1<br />

enthalten.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Folgende Konvention sollte bei der Wahl der Dateinamen für die Beispielauswertung und die<br />

Programmtexte eingehalten werden:<br />

Die Dateinamen für Programme enden auf .pr, Dateinamen für Beispielauswertungen enden<br />

auf .sc.<br />

9.2 Kommandozeilenoptionen<br />

Kommandozeilenoptionen werden dem Werkzeug beim Start des Programmes übergeben.<br />

Normalerweise gibt man sie beim Aufruf des Programmes aus der Kommandozeile hinter dem<br />

Namen xsample an. Es können mehrere Kommanozeilenoptionen gleichzeitig angegeben<br />

werden, jedoch sind bestimmte Kombinationen ausgeschlossen.<br />

Ein gültiger Aufruf des Werkzeugs ist der folgende:<br />

xsample -sf test.sc -fn fixed -logfilename test.log<br />

Es ist aber nicht möglich, sowohl ein Programm als auch eine Beispielauswertung gleichzeitig<br />

aus der Standardeingabe zu lesen, weswegen der folgende Aufruf abgewiesen wird:<br />

xsample -s -c<br />

Die nachfolgende Tabelle liefert einen Überblick über die möglichen<br />

Kommandozeilenoptionen, die von der Unterkomponente CommandLine oder von der<br />

Application-Shell erkannt werden:<br />

Tabelle 5 : Kommandozeilenoptionen<br />

Option Beispiel Bedeutung<br />

-a Algorithmus -a class-I Auswahl eines Algorithmus' für<br />

Programmauswertung und -synthese. Fehlt diese<br />

Option, so wird beim Start des Programmes der<br />

Standardalgorithmus class-I verwendet. Diese<br />

Option macht nur bei einer Erweiterung des<br />

Werkzeugs um mehrere Algorithmen Sinn.<br />

-b -b Verhindert den Start der graphischen<br />

Benutzeroberfläche (Batch-Mode). Diese Option<br />

kann nur zusammen mit genau einer der Optionen<br />

-s, -sf, -c oder -cf verwendet werden. Die<br />

Wirkung einer vorangegangenen Option -i wird<br />

aufgehoben.<br />

-background Color -background orange Setzt die Hintergrundfarbe.<br />

-bg Color<br />

-bg seashell<br />

-bordercolor Color -bordercolor Setzt die Farbe des Fensterrahmens.<br />

-bd Color<br />

lightskyblue<br />

-borderwidth Zahl -borderwidth 4 Setzt die Breite des Fensterrahmens in Pixel.<br />

-bw Zahl<br />

-bw 10<br />

-c -c Einlesen eines Programs von der<br />

Standardeingabe. Diese Option darf nicht<br />

zusammen mit der Option -s oder der Option -cf<br />

verwendet werden.<br />

-cf Dateiname -cf test.pr Einlesen eines Programs von der Datei mit dem<br />

angegebenen Dateinamen. Diese Option darf nicht<br />

zusammen mit der Option -c verwendet werden.<br />

-display Display -display Bestimmt den für die Ausgabe der graphischen<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

x8.rhrk.uni-kl.de:0.0 Benutzeroberfläche zu verwendenden X-Server.<br />

-foreground Color -foreground #3232cc Setzt die Vordergrundfarbe.<br />

-fg Color<br />

-fg orchid<br />

-font Font<br />

-font 9x15bold Setzt den zu verwendenden Zeichensatz.<br />

-fn Font<br />

-fn 6x10<br />

-geometry Geometry -geometry<br />

200x200+0+0<br />

Legt die Größe des Hauptformulars und seine<br />

Lage auf dem Bildschirm fest.<br />

-help -help Ausgabe eines Hilfetextes über die<br />

Kommandozeilenoptionen auf der<br />

Standardausgabe.<br />

-i -i Bewirkt den Start der graphischen<br />

Benutzeroberfläche (Standardvorgabe). Die<br />

Wirkung einer vorangegangen Option -b wird<br />

aufgehoben.<br />

-iconic -iconic nur Icon anzeigen<br />

-lista -lista Gibt eine Liste der zur Verfügung stehenden<br />

Algorithmen auf der Standardausgabe aus.<br />

-log -log Bewirkt das Anlegen einer Fehlerprotokolldatei<br />

(Standardvorgabe). Die Wirkung einer<br />

vorangegangenen Option -nolog wird aufgehoben.<br />

-logfilename<br />

Dateiname<br />

-logfilename<br />

protokoll.dat<br />

Auswahl des Namens der Fehlerprotokolldatei.<br />

Die Standardvorgabe für die Protokolldatei ist<br />

"error.log". Die Option beeinflußt nicht die<br />

Entscheidung, ob eine Fehlerprotokolldatei<br />

angelegt wird oder nicht.<br />

-name Dateiname -name My_Sample Festlegen der Resourcendatei<br />

-nolog -nolog Verhindert das Anlegen einer<br />

Fehlerprotokolldatei. Setzt die Wirkung einer<br />

vorangegangen Option -log außer Kraft.<br />

-pcolumns Zahl -pcolumns 80 Setzt die Zahl der gleichzeitig angezeigten Spalten<br />

des Programs.<br />

-preadonly -preadonly Verhindert den schreibenden Zugriff auf das<br />

angezeigte Program.<br />

-prows Zahl -prows 30 Setzt die Zahl der gleichzeitig angezeigten Zeilen<br />

des Programs.<br />

-reverse<br />

-rv<br />

Vertauscht Vorder- und Hintergrundfarbe.<br />

-rv<br />

+rv +rv Hebt die Wirkung eines vorangegangenen -rv oder<br />

-reverse wieder auf.<br />

-s -s Einlesen einer Beispielauswertung von der<br />

Standardeingabe. Diese Option darf nicht<br />

zusammen mit der Option -c oder der Option -sf<br />

verwendet werden.<br />

-scolumns Zahl -scolumns 80 Setzt die Zahl der gleichzeitig angezeigten Spalten<br />

der Sample Computation.<br />

-selectionTimeout<br />

Zahl<br />

-selectionTimeout<br />

100<br />

Setzt die Zeitspanne im Millisekunden, in der<br />

zwei miteinander kommunizierende X-<br />

Anwendungen reagieren müssen.<br />

-sf Dateiname -sf test.sc Einlesen einer Beispielauswertung von der Datei<br />

mit dem angegebenen Dateinamen. Diese Option<br />

darf nicht zusammen mit der Option -s verwendet<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

werden.<br />

-sreadonly -sreadonly Verhindert den schreibenden Zugriff auf die<br />

angezeigte Sample Computation.<br />

-srows Zahl -srows 30 Setzt die Zahl der gleichzeitig angezeigten Zeilen<br />

der Sample Computation.<br />

-synchronous -synchronous Schaltet die Pufferung der Weitergabe der<br />

Requests an den X-Server aus. Diese Option<br />

sollte vom Benutzer nicht verwendet werden.<br />

+synchronous +synchronous Hebt die Wirkung von -synchronous auf.<br />

-title Name -title ysample Legt den Titel des Hauptfensters fest.<br />

-xnllanguage Locale -xnllanguage german Setzt die landessprachlichen Optionen für das<br />

Werkzeug. Die Standardeinstellung ist auf den<br />

meisten Systemen US-american.<br />

-xrm<br />

Resourcenstring<br />

-xrm "*foreground:<br />

black"<br />

Setzen von Resourcen.<br />

Eine Option kann mehrmals in derselben Kommandozeile auftauchen. Beinhaltet die Option<br />

ein Argument, so ist das Argument beim letzten Vorkommen der Option in der<br />

Kommandozeile maßgeblich.<br />

9.3 Batch-Mode<br />

Im Batch-Mode wird keine graphische Benutzeroberfläche aufgebaut. Nach Starten des<br />

Werkzeugs hat der Benutzer keine Möglichkeit mehr zur Kommunikation. Deswegen müssen<br />

alle Benutzerkommandos über die Kommandozeile übergeben werden. Zum Start von<br />

[VDPSOH im Batch-Mode muß die Kommandozeilenoption -b angegeben werden. Dem<br />

Benutzer stehen zwei Betriebsarten zur Verfügung: Die Synthese eines Programmes aus einer<br />

Beispielauswertung und die Generierung einer Beispielauswertung aus einem Programm. In<br />

jeder Betriebsart wird die Eingabe entweder von der Standardeingabe oder von Datei gelesen.<br />

Die Ausgabe erfolgt immer auf der Standardausgabe. Im Fehlerfall erfolgt eine Fehlermeldung<br />

auf der Standardfehlerausgabe. Standardmäßig wird zusätzlich eine Fehlerprotokolldatei<br />

angelegt. Man beachte bei den folgenden Beispielen, daß selbstverständlich auch weitere<br />

Kommandozeilenoptionen angegeben werden dürfen.<br />

1. Synthese eines Programmes:<br />

In dieser Betriebsart muß zusätzlich zur Option -b eine der Optionen -s oder -sf angegeben<br />

werden. Der Aufruf<br />

xsample -b -s<br />

liest eine Beispielauswertung von der Standardeingabe, synthetisiert ein Programm und gibt<br />

dieses (sofern die Synthese erfolgreich war) auf der Standardausgabe aus. Der Aufruf<br />

xsample -b -sf eingabe.sc<br />

liest eine Beispielauswertung von der Datei mit dem Dateinamen "eingabe.sc" ein, synthetisiert<br />

ein Programm und gibt dieses bei Erfolg auf der Standardausgabe aus. Man beachte, daß der<br />

angegebene Dateiname ein Pfad zu einer ASCII-Datei sein muß, die eine gültige<br />

Beispielauswertung enthält.<br />

2. Generierung einer Beispielauswertung:<br />

Hier muß neben der Option -b eine der Optionen -c oder -cf angegeben werden. Der Aufruf<br />

xsample -b -c<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

liest ein Programm von der Standardeingabe ein, wertet dieses Programm aus und gibt die<br />

erzeugte Beispielauswertung auf der Standardausgabe aus, sofern kein Fehler bei der<br />

Auswertung auftritt. Der Aufruf<br />

xsample -b -cf eingabe.pr<br />

liest ein Programm von der Datei mit dem Dateinamen "eingabe.pr" ein, wertet es aus und gibt<br />

die Beispielauswertung bei Erfolg auf der Standardausgabe aus. Man beachte, daß der<br />

angegebene Dateiname ein Pfad zu einer ASCII-Datei sein muß, die ein gültiges WHILE-<br />

Programm enthält.<br />

Es gibt drei Hauptanwendungen für die Benutzung des Batch-Mode anstelle der interaktiven<br />

Benutzerführung:<br />

(1) Zur Zeitersparnis<br />

Wenn der Benutzer eine vorgegebene Datei synthetisieren oder auswerten will, so ist die<br />

Benutzung des Werkzeugs im Batch-Mode schneller zu bewerkstelligen. Die Eingabe eines<br />

Komamndozeilenbefehls wie etwa der folgende<br />

xsample -b -sf ~/examples/beispiel1.sc > ausgabe.pr<br />

ist für den geübten Benutzer einfacher als den Start der Benutzeroberfläche, die Selektion<br />

des Dateinamens der zu ladenden Beispielauswertung, die Auswahl des Synthesebuttons<br />

und die Auswahl des Dateinamens, unter dem das Ergebnis gespeichert werden soll.<br />

(2) Bei der Verwendung in Shell-Scripten.<br />

(3) Im Zusammenspiel mit anderen Programmen.<br />

In einer UNIX-Umgebung wird die folgende Kommandozeile Sinn machen:<br />

cut -f 2 listing | xsample -c -b -nolog | tee ausgabe.dat | lpr -Plaser<br />

9.4 Das Hauptformular<br />

Das Hauptformular von [VDPSOH 2.0 ist dasjenige Fenster, daß beim Start des Programmes<br />

im interaktiven Modus aufgebaut wird. Im Rahmen der Möglichkeiten des gewählten<br />

Windowmanagers kann das Fenster auf dem Bildschirm bewegt und in seinen Abmessungen<br />

verändert werden, es kann von anderen Fenstern überlagert werden oder selbst andere Fenster<br />

überlagern, auf volle Bildschirmgröße gebracht werden oder zu einem Icon verkleinert werden.<br />

Neben dem Hauptformular beinhaltet das Werkzeug noch weitere dem Hauptformular<br />

untergeordnete Fenster, die Dialogfenster. Diese sind jedoch meistens nicht sichtbar.<br />

Das Hauptformular besteht aus drei Bereichen, die durch eine Separatorline getrennt sind:<br />

ì<br />

ì<br />

ì<br />

Menüzeile<br />

Aktionsfenster<br />

Pushbuttonzeile<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Abbildung 11 : Das Hauptformular von [VDPSOH 2.0<br />

Menüzeile<br />

Beispielauswertung ist<br />

gesichert und keine Auswertung<br />

des angezeigten Programmes<br />

Anzeige eines nicht<br />

geicherten Inhaltes des<br />

Programmtextes<br />

Dateiname der<br />

Beispielauswertung<br />

Aktionsfenster<br />

Textfenster der<br />

Beispielauswertung<br />

Dateiname des<br />

Programmes<br />

(kein<br />

Dateiname<br />

angegeben)<br />

Angezeigtes<br />

Programm ist durch<br />

Synthese der<br />

Beispielauswertung<br />

entstanden<br />

Textfenster<br />

des<br />

Programmes<br />

horizontale<br />

Scrollbar<br />

vertikale<br />

Scrollbar<br />

Pushbuttonzeile<br />

9.4.1 Die Menüzeile<br />

Die Menüzeile befindet sich direkt unterhalb des Fenstertitels und ist (auf Farbbildschirmen)<br />

farblich hervorgehoben. Sie enthält die folgenden Menüs:<br />

ì<br />

ì<br />

ì<br />

ì<br />

ì<br />

File<br />

Edit<br />

Generate<br />

Algorithm<br />

Help<br />

Bei der Bedienung mit der Maus bewegt man den Mauscursor auf den Eintrag des<br />

gewünschten Menüs in der Menüzeile, drückt die linke Maustaste nieder und fährt bei<br />

gehaltener Maustaste am nun aufgeklappten Pulldownmenü herab bis zum gewünschten<br />

Menüeintrag. Beinhaltet dieser Menüeintrag am Ende das Zeichen ➮, wird klappt bei Anwahl<br />

dieses Menüpunktes ein Untermenü auf. Um einen Menüpunkt aus diesem Untermenü<br />

anzuwählen, bewegt man den Mauscursor (bei weiterhin gehaltener linken Maustaste) zum<br />

dem gewünschten Menüeintrag des Untermenüs. Bewegt man den Mauscursor im Hauptmenü<br />

weiter, so verschwindet das Untermenü.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Ein Menüeintrag wird aktiviert, sobald die linke Maustaste auf diesem Menüeintrag<br />

losgelassen wird. Um keinen Menüpunkt anzuwählen, muß sich der Mauscursor sich beim<br />

Loslassen der linken Maustaste außerhalb jedes Menüeintrags befinden.<br />

Die Menüeinträge können auch mit den Pfeiltasten der Tastatur aufgerufen werden. Dazu<br />

betätigt man die Funktionstaste [F3], während der Tastaturfocus auf dem Hauptformular liegt.<br />

Der Eintrag File in der Menüzeile wird jetzt hervorgehoben gezeichnet. Mit den Tasten [Ç]<br />

und [È] kann jetzt ein Menü angewählt werden. Bei jeder Betätigung der Pfeiltasten wird ein<br />

anderes Menü hervorgehoben. Drückt man die Taste [Ê], während ein Menü hervorgehoben<br />

wird, so klappt an angewählte Menü auf. Mit den Tasten [Ê] und [É] wird ein Menüpunkt<br />

angewählt. Bei Wahl eines durch ➮ gekennzeichneten Menüpunktes klappt ein Untermenü auf.<br />

Um einen Eintrag aus diesem Untermenü zu wählen, bewegt man die Markierung mit der<br />

Taste [È] in das Untermenü hinein und wählt mit den Tasten [Ç] und [È] einen Menüpunkt<br />

aus. Durch Betätigen der Taste [RETURN] wird der in diesem Moment markierte Menüpunkt<br />

aktiviert. Mit der Taste [ESC] kann die Menüauswahl abgebrochen werden.<br />

Des weiteren kann jeder Menüpunkt mit der [ALT]-Taste auf der Tastatur aufgerufen werden.<br />

Das Betätigen der Taste [ALT] zusammen mit dem in einem in der Menüzeile unterstrichenem<br />

Buchstaben öffnet ein Menü. Es gilt (standardmäßig):<br />

[ALT]-F öffnet das File-Menü<br />

[ALT]-E öffnet das Edit-Menü<br />

[ALT]-G öffnet das Generate-Menü<br />

[ALT]-A öffnet das Algorithm-Menü<br />

[ALT]-H öffnet das Hilfemenü<br />

Um einen Menüpunkt in dem geöffneten Menü anzuwählen, drückt man die Taste des<br />

unterstrichenen Buchstabens in dem gewünschten Menüpunkt. Falls ein Untermenü aufklappt,<br />

muß zur Anwahl eines Menüpunktes des Untermenüs die Taste des unterstrichenen<br />

Buchstabens eingegeben werden. Die Menüauswahl kann wieder mit [ESC] abgebrochen<br />

werden.<br />

Einige der wählbaren Operationen sind durch eine weitere Tastenkombination anwählbar, die<br />

dann aber im entsprechenden Menüeintrag angegeben ist.<br />

9.4.2 Das Aktionsfenster<br />

Das Aktionsfenster nimmt den größten Teil des Hauptformulars in Anspruch. Es besteht aus<br />

zwei Fenstern, die durch einen vertikalen Separator getrennt sind. Das linke Fenster ist das<br />

Samplefenster, da in ihm die Beispielauswertung (Sample Computation) angezeigt wird, das<br />

rechte Fenster ist das Programfenster, da in ihm das Programm (Program) angezeigt wird.<br />

Der Schwerpunkt jedes der Teilfensters bildet das Textfenster für die Beispielauswertung oder<br />

das Programm. In ihm wird die momentan bearbeitetet Beispielauswertung bzw. das<br />

momentan bearbeitete Programm angezeigt und kann auch erstellt oder bearbeitet werden. Bei<br />

Auswertung eines Programmes wird die gewonnene Beispielauswertung im Textfenster des<br />

Samplefensters angezeigt, bei der Synthese aus einer Bespielauswertung wird das<br />

synthetisierte Programm im Textfenster des Programfensters angezeigt. Beide Textfenster sind<br />

mit horizontalen und vertikalen Scrollbars versehen.<br />

Über dem Textfenster befindet sich je ein Label, der "Sample Computation" (im<br />

Samplefenster) oder mit "Program" (im Programfenster) beschriftet ist. In der Zeile unterhalb<br />

dieses Labels wird der zuletzt gewählte Dateiname für die Beispielauswertung bzw. für das<br />

Programm angezeigt.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Des weiteren können neben dem Titellabel die folgenden Hinweise eingeblendet werden (beim<br />

Start des Programmes werden sie nicht angezeigt):<br />

[unsaved] : Der angezeigte Text im entsprechenden Fenster enthält<br />

nicht gesicherte Änderungen.<br />

[computed] : die angezeigte Beispielauswertung ist eine Auswertung des<br />

angezeigten Programmes.<br />

[synthesized] : das angezeigte Programm wurde aus der angezeigten<br />

Beispielauswertung synthetisiert.<br />

Sowohl im Samplefenster als auch im Programfenster kann durch Niederdrücken und Halten<br />

der rechten Maustaste ein Popupmenü aufgeklappt werden. Zum Auswahl eines Menüeintrags<br />

bewegt man den Mauscursor bei gehaltener rechten Maustaste auf den gewünschten<br />

Menüeintrag. Läßt man die Maustaste auf dem gewünschten Menüeintrag los, so wird die<br />

gewählte Operation aktiviert. Zum Abbruch der Menüauswahl läßt man die linke Maustaste<br />

los, während kein Menüpunkt angewählt wird.<br />

Das Popupmenü kann auch durch Betätigen der Taste [F4] im Samplefenster oder durch<br />

Betätigen der Taste [F5] im Programfenster angezeigt werden. Dazu muß der Tastaturfocus<br />

sich auf dem Hauptformular befinden, was standardmäßig der Fall ist, wenn sich der<br />

Mauscursor innerhalb des Fensters des Hauptformulars befindet. Ein Menüpunkt kann dann<br />

mit durch Anklicken mit der linken Maustaste aktiviert werden. Ebenfalls wird mit der Taste<br />

[RETURN] der momentan hervorgehobene Menüpunkt aktiviert. Mit den Pfeiltasten kann ein<br />

anderer Menüpunkt angewählt werden. Man beachte, daß während ein Popupmenü<br />

aufgeklappt ist, eine Aktivierung eines Menüeintrags oder ein Abbruch erfolgen muß. Zum<br />

Abbruch der Menüauswahl kann die Taste [ESC] benutzt werden.<br />

9.4.3 Die Pushbuttonzeile<br />

Als weitere Alternative zum Wahl einer Operation sind in der Pushbuttonzeile vier<br />

Pushbuttons angebracht:<br />

Tabelle 6 : Die Pushbuttonezeile<br />

Pushbutton<br />

Synthesize<br />

Compute<br />

Quit<br />

Help<br />

Operation<br />

Die angezeigte Beispielauswertung wird zu einem Programm<br />

synthetisiert. Das synthetisierte Programm wird im Programfenster<br />

angezeigt.<br />

Das angezeigte Programm wird zu einer Beispielauswertung<br />

ausgewertet, und die gewonnene Beispielauswertung wird im<br />

Samplefenster angezeigt.<br />

[VDPSOH wird beendet.<br />

Ein Hilfefenster wird geöffnet und ein Hilfetext wird angezeigt.<br />

Zum Aktivieren eines Pushbuttons klickt man den betreffenden Button mit der linken<br />

Maustaste an.<br />

9.4.4 Verfügbarkeit der Menüeinträge und Pushbuttons<br />

Nicht immer sind alle Menüeinträge und Pushbuttons verfügbar. Zum Beispiel hat es wenig<br />

Sinn, die angezeigte Beispielauswertung in eine Datei zu sichern, wenn gar keine<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Beispielauswertung angezeigt ist, da das entsprechende Fenster leer ist. Inaktive Menüeinträge<br />

und Pushbuttons sind nicht anwählbar (auch nicht über Tastatur). Wenn ein Buttons nicht<br />

anwählbar ist, wird es schwächer gezeichnet dargestellt, die Aufschrift erscheint in Grau statt<br />

in Schwarz.<br />

9.5 Die Menüs<br />

In diesem Abschnitt wollen wir auf die einzelnen anwählbaren Menüeinträge eingehen.<br />

9.5.1 Pulldownmenüs<br />

Die Menüzeile enthält insgesamt fünf Pulldownmenüs, über die alle wesentlichen<br />

Benutzerkommandos aktiviert werden können.<br />

Im File-Menü sind die Operationen, die den Datenverkehr zur Festplatte betreffen, enthalten.<br />

Es enthält die folgenden Menüeinträge:<br />

Tabelle 7 : Das File-Menü<br />

Menüeintrag<br />

im<br />

Hauptmenü<br />

New<br />

Menüeintrag<br />

im<br />

Untermenü<br />

Operation<br />

Beide Textfenster werden gelöscht.<br />

Load Sample Beispielauswertung von Datei laden, Dateiname<br />

auswählen. Eine eventuell angezeigte<br />

Beispielauswertung wird überschrieben.<br />

Load Program Programm von Datei laden, Dateiname auswählen.<br />

Ein eventuell angezeigtes Programm wird<br />

überschrieben.<br />

Reload Sample Beispielauswertung von Datei laden, zuletzt<br />

benutzten Dateiname einer Beispielauswertung<br />

verwenden. Eine eventuell angezeigte<br />

Beispielauswertung wird überschrieben.<br />

Reload Program Programm von Datei laden, zuletzt benutzten<br />

Dateinamen eines Programmes verwenden. Ein<br />

eventuell angezeigtes Programm wird<br />

überschrieben.<br />

Save As Sample Angezeigte Beispielauswertung in Datei sichern,<br />

Dateiname auswählen. Wenn die gewählte Datei<br />

bereits existiert, wird ihr Inhalt überschrieben.<br />

Save As Program Angezeigtes Programm in Datei sichern, Dateiname<br />

auswählen. Wenn die gewählte Datei bereits<br />

existiert, wird ihr Inhalt überschrieben.<br />

Save Sample Angezeigte Beispielauswertung in Datei sichern,<br />

zuletzt verwendeten Dateinamen einer<br />

Beispielauswertung verwenden. Der vorherige Inhalt<br />

dieser Datei wird überschrieben.<br />

Save Program Angezeigtes Programm in Datei sichern, zuletzt<br />

verwendeten Dateinamen eines Programmes<br />

verwenden. Der vorherige Inhalt dieser Datei wird<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Quit<br />

überschrieben.<br />

[VDPSOH wird beendet.<br />

Das Edit-Menü enthält Operationen für die Textfenster. In der derzeitigen Version von<br />

[VDPSOH sind hier nur vier Operationen pro Textfenster enthalten:<br />

Tabelle 8 : Das Edit-Menü<br />

Menüeintrag<br />

im<br />

Hauptmenü<br />

Menüeintrag<br />

im<br />

Untermenü<br />

Operation<br />

Cut Sample Selektierter Text im Textfenster der<br />

Beispielauswertung in das Clipboard kopieren und<br />

aus dem Text der Beispielauswertung ausschneiden.<br />

Cut Program Selektierter Text im Textfenster des Programms in<br />

das Clipboard kopieren und aus dem Text des<br />

Programms ausschneiden.<br />

Copy Sample Selektierter Text im Textfenster der<br />

Beispielauswertung in das Clipboard kopieren.<br />

Copy Program Selektierter Text im Textfenster des Programms in<br />

das Clipboard kopieren.<br />

Paste Sample Inhalt des Clipboards in den Text der<br />

Beispielauswertung an der Position des Textcursors<br />

einfügen.<br />

Paste Program Inhalt des Clipboards in den Text des Programmes<br />

an der Position des Textcursors einfügen.<br />

Clear Sample Selektion im Textfenster der Beispielauswertung<br />

aufheben.<br />

Clear Program Selektion im Textfenster des Programmes aufheben.<br />

Das Generate-Menü enthält nur die beiden Einträge Synthesize und Compute. Mit der<br />

Aktivierung von Synthesize wird aus der angezeigten Beispielauswertung ein Programm<br />

synthetisiert und dieses angezeigt. Der vorherige Inhalt des Programmfensters wird<br />

überschrieben. Mit Aktivierung von Compute wird aus dem angezeigten Programm eine<br />

Beispielauswertung generiert und diese wird angezeigt. Der vorherige Inhalt des<br />

Samplefensters wird überschrieben.<br />

Im Algorithm-Menü kann ein Algorithmus ausgewählt werden, der für Synthese und<br />

Auswertung verwendet werden kann. Es kann immer nur genau ein Algorithmus ausgewählt<br />

sein. Der ausgewählte Algorithmus wird durch eine Markierung vor dem Menüpunkt<br />

gekennzeichnet. Da im momentanen Entwicklungszustand des Werkzeugs nur ein Algorithmus<br />

zur Verfügung steht, macht die Benutzung des Algorithm-Menüs (noch) keinen Sinn.<br />

Das Help-Menü dient zum Aufruf der Hilfsfunktion und zur Anzeige eines<br />

Informationsfensters.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Tabelle 9 : Das Help-Menü<br />

Menüeintrag<br />

im Hauptmenü<br />

Help General<br />

Help On Windows<br />

Help On Menues<br />

Help On Buttons<br />

Help On Keys<br />

Info<br />

Operation<br />

allgemeine Hilfe anzeigen<br />

Hilfe über Aufbau des Hauptformulars anzeigen<br />

Hilfe über die Menüeinträge anzeigen<br />

Hilfe über die Pushbuttonzeile anzeigen<br />

Hilfe über Tastaturbindungen anzeigen<br />

Informationen über den Autor des Programmes anzeigen<br />

9.5.2 Popupmenüs<br />

Das Popupmenü des Samplefenster enthält die folgenden Einträge:<br />

Tabelle 10 : Das Popupmenü des Samplefensters<br />

Menüeintrag<br />

Load<br />

Reload<br />

Save As<br />

Save<br />

Synthesize<br />

Operation<br />

Beispielauswertung von Datei laden, Dateiname auswählen.<br />

Eine eventuell angezeigte Beispielauswertung wird<br />

überschrieben.<br />

Beispielauswertung von Datei laden, zuletzt benutzten<br />

Dateiname einer Beispielauswertung verwenden. Eine eventuell<br />

angezeigte Beispielauswertung wird überschrieben.<br />

Angezeigte Beispielauswertung in Datei sichern, Dateiname<br />

auswählen. Wenn die gewählte Datei bereits existiert, wird ihr<br />

Inhalt überschrieben.<br />

Angezeigte Beispielauswertung in Datei sichern, zuletzt<br />

verwendeten Dateinamen einer Beispielauswertung verwenden.<br />

Der vorherige Inhalt dieser Datei wird überschrieben.<br />

Aus angezeigter Beispielauswertung Programm generieren.<br />

Gewonnenes Programm anzeigen. Der bisherige Inhalt des<br />

Programfensters wird überschrieben.<br />

Der Aufbau des Popupmenüs des Programfensters ist ähnlich:<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Tabelle 11 : Das Popupmenü des Programmfensters<br />

Menüeintrag<br />

Load<br />

Reload<br />

Save As<br />

Save<br />

Compute<br />

Operation<br />

Programm von Datei laden, Dateiname auswählen. Ein eventuell<br />

angezeigtes Programm wird überschrieben.<br />

Programm von Datei laden, zuletzt benutzten Dateinamen eines<br />

Programmes verwenden. Ein eventuell angezeigtes Programm<br />

wird überschrieben.<br />

Angezeigtes Programm in Datei sichern, Dateiname auswählen.<br />

Wenn die gewählte Datei bereits existiert, wird ihr Inhalt<br />

überschrieben.<br />

Angezeigtes Programm in Datei sichern, zuletzt verwendeten<br />

Dateinamen eines Programmes verwenden. Der vorherige Inhalt<br />

dieser Datei wird überschrieben.<br />

Aus angezeigtem Programm Beispielauswertung generieren.<br />

Die gewonnene Beispielauswertung wird angezeigt. Der<br />

bisherige Inhalt des Samplefensters wird dabei überschrieben.<br />

9.5.3 Tear-Off-Menüs<br />

Für häufig verwendete Befehle mag es lästig sein, immer ein Menü zuerst aufklappen zu<br />

müssen, bevor man einen Menüeintrag aktivieren kann. Auch das Lernen der entsprechenden<br />

Tastenkombinationen mag nicht jedem Benutzer gefallen. Deswegen gibt es die Möglichkeit,<br />

jedes Menü in einem eigenem Fenster darzustellen. Dazu wählt man mit der Maus oder mit<br />

den Pfeiltasten die gestrichelte Linie über jedem Menü aus und aktiviert diese Linie durch<br />

Loslassen der entsprechenden Maustaste oder durch Betätigen von [RETURN]. In diesem Fall<br />

wird ein neues Fenster geöffnet, daß nur das angewählte Menü enthält, ein sogenanntes Tear-<br />

Off-Menü. Dieses kann beliebig auf dem Bildschirm plaziert werden. Die Anwesenheit eines<br />

Tear-Off-Menüs beeinträchtigt nicht die Funktionsweise der anderen Menüs.<br />

Zum Anwählen eines Menüeintrags aus einem Tear-Off-Menü genügt es den Eintrag mit der<br />

linken Maustaste anzuwählen. Wird hierdurch ein Untermenü aufgeklappt, so kann ein<br />

Menüeintrag angewählt werden durch Ziehen der Maus bei gehaltener linken Maustaste auf<br />

den gewünschten Menüeintrag des Untermenüs und Loslassen der Maustaste auf dem Eintrag.<br />

Zum Schließen des Tear-Off-Menüs betätigt man die Taste [ESC], während der Mauscursor<br />

sich innerhalb des Fensters des Tear-Off-Menüs befindet.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Abbildung 12 : Tear-Off-Menüs<br />

9.5.4 Zusammenstellung der Menübefehle<br />

Alle Operationen, die durch die Menüs ausgelöst werden können, sind in der folgenden Tabelle<br />

zusammengefaßt. Dabei bedeutet eine Anweisung für einen Menüeintrag wie File-Load-<br />

Sample, daß im File-Menü der Menüpunkt Load und dann in dem nun aufgeklappten<br />

Untermenü der Menüpunkt Sample anzuwählen ist. Die Tastatureingabe [CTRL]-L bedeutet,<br />

daß die Taste L bei gehaltener [CTRL]-Taste zu betätigen ist. Dabei spielt es keine Rolle, ob<br />

die [SHIFT]-Taste gedrückt wurde (großes L) oder nicht (kleines l).<br />

Tabelle 12 : Zusammenstellung der Menübefehle<br />

Operation<br />

Sample Computation<br />

von Datei laden<br />

Program von Datei<br />

laden<br />

zuletzt geladene oder<br />

gesicherte Sample<br />

Computation laden<br />

zuletzt geladenes oder<br />

gesichertes Program<br />

Bedienung in<br />

Menüzeile<br />

File - Load -<br />

Sample wählen<br />

File - Load -<br />

Program wählen<br />

File - Reload -<br />

Sample wählen<br />

File - Reload -<br />

Program wählen<br />

Bedienung in<br />

Popupmenü<br />

Load wählen<br />

(im Samplefenster)<br />

Load wählen<br />

(im Programfenster)<br />

Reload wählen<br />

(im Samplefenster)<br />

Reload wählen<br />

(im Programfenster)<br />

Bedienung mit<br />

Tastatur<br />

[CTRL]-L<br />

oder [ALT]-F L S<br />

[CTRL]-O<br />

oder [ALT]-F L P<br />

[ALT]-F R S<br />

[ALT]-F R P<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

laden<br />

Sample Computation in<br />

Datei speichern, zuletzt<br />

gewählter Dateiname<br />

verwenden<br />

Program in Datei<br />

speichern, zuletzt<br />

gewählter Dateiname<br />

verwenden<br />

Sample Computation in<br />

Datei speichern, neuer<br />

Dateiname wählen<br />

Program in Datei<br />

speichern, neuer<br />

Dateiname wählen<br />

gewählte Selektion im<br />

Samplefenster in<br />

Clipboard kopieren<br />

gewählte Selektion im<br />

Programfenster in<br />

Clipboard kopieren<br />

gewählte Selection im<br />

Samplefenster<br />

ausschneiden und in<br />

Clipboard kopieren<br />

gewählte Selection im<br />

Programfenster<br />

ausschneiden und in<br />

Clipboard kopieren<br />

Inhalt des Clipboard an<br />

Position des<br />

Textcursores im<br />

Samplefenster<br />

einfügen<br />

Inhalt des Clipboard an<br />

Position des<br />

Textcursores im<br />

Programfenster<br />

einfügen<br />

Selektion im<br />

Samplefenster<br />

aufheben<br />

Selektion im<br />

Programfenster<br />

aufheben<br />

Sample Computation<br />

synthetisieren<br />

(auch über Pushbutton<br />

möglich)<br />

Program auswerten<br />

(auch über Pushbutton<br />

möglich)<br />

File - Save -<br />

Sample wählen<br />

File - Save -<br />

Program wählen<br />

File - SaveAs -<br />

Sample wählen<br />

File - SaveAs -<br />

Program wählen<br />

Edit - Copy -<br />

Sample wählen<br />

Edit - Copy -<br />

Program wählen<br />

Edit - Cut - Sample<br />

wählen<br />

Edit - Cut - Program<br />

wählen<br />

Edit - Paste -<br />

Sample wählen<br />

Edit - Paste -<br />

Program wählen<br />

Edit - Clear -<br />

Sampe wählen<br />

Edit - Clear -<br />

Program wählen<br />

Generate -<br />

Synthesize wählen<br />

Generate -<br />

Compute wählen<br />

Save wählen<br />

(im Samplefenster)<br />

Save wählen<br />

(im Programfenster)<br />

SaveAs wählen<br />

(im Samplefenster)<br />

SaveAs wählen<br />

(im Programfenster)<br />

Copy wählen<br />

(im Samplefenster)<br />

Copy wählen<br />

(im Programfenster)<br />

Cut wählen<br />

(im Samplefenster)<br />

Cut wählen<br />

(im Programfenster)<br />

Paste wählen<br />

(im Samplefester)<br />

Paste wählen<br />

(im Programfester)<br />

Clear wählen<br />

(im Samplefenster)<br />

Clear wählen<br />

(im Programfenster)<br />

Synthesize wählen<br />

(im Samplefenster)<br />

Compute wählen<br />

(im Programfenster)<br />

[CTRL]-S<br />

oder [ALT]-F S S<br />

[CTRL]-A<br />

oder [ALT]-F S P<br />

[ALT]-F A S<br />

[ALT]-F A P<br />

[F7]<br />

oder [ALT]-E C S<br />

[F9]<br />

oder [ALT]-E C P<br />

[SHIFT]-[F7]<br />

oder [ALT]-E T S<br />

[SHIFT]-[F9]<br />

oder [ALT]-E T P<br />

[F8]<br />

oder [ALT]-E P S<br />

[F10]<br />

oder [ALT]-E P P<br />

[SELECT]<br />

(im<br />

Samplefenster)<br />

[SELECT]<br />

(im<br />

Programfenster)<br />

[CTRL]-Y<br />

oder [ALT]-G S<br />

[CTRL]-C<br />

oder [ALT]-G C<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Sample Computation<br />

und Program löschen<br />

[VDPSOH beenden<br />

(auch über Pushbotton<br />

möglich)<br />

Standardalgorithmus<br />

wählen<br />

Allgemeine Hilfe<br />

anzeigen<br />

(auch über Pushbutton<br />

möglich)<br />

Hilfe zum<br />

Hauptformular<br />

anzeigen<br />

Hilfe zu Menues<br />

anzeigen<br />

Hilfe zur<br />

Tastaturbelegung<br />

anzeigen<br />

Hilfe zu Pushbuttons<br />

anzeigen<br />

File - New wählen nicht möglich [CTRL]-N<br />

oder [ALT]-F N<br />

File - Quit wählen nicht möglich [CTRL]-Q<br />

oder [ALT]-F Q<br />

Algorithm-Standard<br />

wählen<br />

Help-General<br />

wählen<br />

Help-Windows<br />

wählen<br />

nicht möglich<br />

nicht möglich<br />

nicht möglich<br />

[ALT]-A S<br />

[F1]<br />

oder [ALT]-H G<br />

[ALT]-H W<br />

Help-Menu wählen nicht möglich [ALT]-H M<br />

Help-Keys wählen nicht möglich [ALT]-H K<br />

Help-Buttons<br />

wählen<br />

nicht möglich<br />

[ALT]-H B<br />

9.6 Textbearbeitung<br />

Mit der graphischen Benutzeroberfläche von [VDPSOH 2.0 können eine Beispielauswertung<br />

und ein WHILE-Programm nicht nur gleichzeitig angezeigt, sondern auch erstellt oder<br />

bearbeitet werden. Hierzu muß der Tastaturfocus auf den entsprechenden Fenster sein. Das<br />

heißt, wenn die Beispielauswertung bearbeitet werden soll, muß der Tastaturfocus auf dem<br />

linken Textfenster stehen, soll das Programm bearbeitet werden, muß der Tastaturfocus auf<br />

dem rechten Textfenster stehen. Standardmäßig erhält das Fenster den Tastaturfocus, in dem<br />

sich der Mauscursor befindet.<br />

Überschreitet die Zahl der Zeilen des Textes die Zahl der angezeigten Zeilen, so wird das<br />

Textfenster nicht vergrößert, statt dessen wird immer nur ein Teilstück des Textes angezeigt.<br />

Der Balken innerhalb der vertikale Scrollbar an der Seite des Textfensters zeigt die<br />

angezeigten Zeilen im Bezug zu dem gesamten Text. Bewegt man den Balken mit der Maus<br />

bei gehaltener mittleren Maustaste nach oben oder nach unten, so verschiebt man damit<br />

gleichzeitig auch den angezeigten Ausschnitt des Textes gegen den Anfang oder dem Ende des<br />

Gesamttextes zu. Klickt man mit der mittleren Maustaste auf eine beliebige Position der<br />

Scrollbar, so wir der angezeigte Text so gewählt, daß der Balken sich an der Position der<br />

Maus befindet. Klickt man mit der linken Maustaste auf die Scrollbar oberhalb des Balkens,<br />

so scrollt der angezeigte Text um eine Bildschirmseite (das heißt um so viele Zeilen, wie<br />

gleichzeitig angezeigt werden) nach oben oder an den Anfang des Textes, falls dies nicht<br />

möglich ist. Klickt man mit der linken Maustaste auf der Scrollbar unterhalb des Balkens, so<br />

scrollt der angezeigte Text eine Seite nach unten (oder zum Ende des Textes). Dasselbe gilt<br />

analog bei Überschreitung der Zahl der angezeigten Spalten und der horizontalen Scrollbar.<br />

Die Textfenster von [VDPSOH 2.0 eignen sich keineswegs zur Textverarbeitung, da es keine<br />

einfache Möglichkeit zur Eingabe und Darstellung von Textformaten gibt, insbesondere<br />

unterstützt das Werkzeug kein WYSIWYG. Auch fehlen den Textfenstern (noch) viele<br />

Funktionen der gebräuchlichen Texteditoren.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Die Einfügeposition in einem Textfenster ist immer die Position des Textcursors. Der<br />

Textcursor ist als 'I' dargestellt und wird auch angezeigt, wenn das Textfenster keinen<br />

Tastaturfocus besitzt. Erhält das Fenster aber den Focus, so wird der Textcursor stärker<br />

gezeichnet und blinkt (sofern dies nicht mit der Resource "xsample*blinkRate"<br />

verhindert wird).<br />

Zum Einfügen eines Zeichens an der Position des Textcursors drückt man einfach die<br />

entsprechende Taste auf der Tastatur. Es erfolgt kein automatischer Zeilenumbruch. Zum<br />

Einfügen eines Zeilenumbruchs ist am Ende der Zeile, hinter der der Umbruch eingefügt<br />

werden soll, die Taste [RETURN] (Eingabetaste) zu betätigen. Mit der Taste [TAB]<br />

(Tabulatortaste) wird ein Tabulatorzeichen in den Text eingefügt. Das Tabulatorzeichen wird<br />

als eine Folge von Leerzeichen dargestellt.<br />

Zum Löschen des Textes existieren die folgenden Tastenkombinationen:<br />

Tabelle 13 : Tastenkombination zum Löschen von Text<br />

Zeichen links der Position des Textcursors löschen<br />

Zeichen rechts der Position des Textcursors<br />

löschen<br />

[BACKSPACE]<br />

[DELETE]<br />

Zum Positionieren des Textcursors mit der Maus innerhalb des angezeigten Textabschnittes<br />

klickt man mit der linken Maustaste auf die gewünschte neue Position des Textcursors. Soll<br />

eine etwaige Selektion nicht verändert werden, so muß beim Drücken der linken Maustaste<br />

gleichzeitig die [CTRL]-Taste betätigt werden. Zum Positionieren des Textcursors mittels der<br />

Tastatur existieren die folgenden Möglichkeiten:<br />

Tabelle 14 : Tastenkombinationen zum Bewegen des Textcursors<br />

Textcursor ein Zeichen nach links bewegen<br />

Textcursor ein Wort nach links bewegen<br />

Textcursor eine Bildschirmseite nach links<br />

bewegen<br />

Textcursor an den Anfangs der Zeile bewegen<br />

Textcursor ein Zeichen nach rechts bewegen<br />

Textcursor ein Wort nach rechts bewegen<br />

Textcursor eine Bildschirmseite nach rechts<br />

bewegen<br />

Textcursor an das Ende der Zeile bewegen<br />

Textcursor eine Zeile nach oben bewegen<br />

Textcursor an den Anfang des Absatzes bewegen<br />

Textcursor eine Bildschirmseite nach oben<br />

bewegen<br />

Textcursor an den Anfang des Textes bewegen<br />

Textcursor eine Zeile nach unten bewegen<br />

Textcursor an das Ende des Absatzes bewegen<br />

Textcursor ein Bildschirmseite nach unten<br />

bewegen<br />

Textcursor an das Ende des Textes bewegen<br />

[←]<br />

[CTRL]-[←]<br />

[CTRL]-[PAGE UP]<br />

[ALT]-[←]<br />

[→]<br />

[CTRL]-[→]<br />

[CTRL]-[PAGE DOWN]<br />

[ALT]-[→]<br />

[↑]<br />

[CTRL]-[↑]<br />

[PAGE UP]<br />

[CTRL]-[ALT]-[←]<br />

[↓]<br />

[CTRL]- [↓]<br />

[PAGE DOWN]<br />

[CTRL]-[ALT]-[→]<br />

Dabei müssen Absätze durch eine Leerzeile getrennt sein.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Um mehr als ein Zeichen auf einmal einfügen, löschen, kopieren oder bewegen zu können,<br />

muß mit Selektionen gearbeitet werden. Zum Erstellen einer Selektion bewegt man den<br />

Mauscursor zum Anfang des zu selektierenden Bereiches und zieht die Maus bei gehaltener<br />

linken Maustaste zum Ende des zu selektierenden Bereiches. Überschreitet der Mauscursor<br />

dabei die Fenstergrenzen, so wir der Text automatisch weitergescrollt in die Richtung, in der<br />

der Mauscursor das Fenster verlassen hat. Beim Loslassen der linken Maustaste wird die<br />

Selektion invers dargestellt. Ist die linke Maustaste losgelassen, so führt ein weiterer Klick mit<br />

der linken Maustaste in das Textfenster, ohne daß eine weitere Taste gleichzeitig betätigt wird,<br />

die Aufhebung der Selektion. Denselben Effekt hat auch die Wahl des Menüeintrages Clear im<br />

Edit-Menü oder im Popupmenü des bearbeiteten Textfensters. Soll die Selektion erweitert<br />

werden, so ist gleichzeitig zur linken Maustaste die [SHIFT]-Taste zu betätigen. Dann wird<br />

die Selektion zur Position des Mauszeigers ausgedehnt.<br />

Es gibt drei abkürzende Operationen zum Anlegen einer Selektion mit der Maus:<br />

ì Ein Doppelklick mit der linken Maustaste selektiert das Wort, in dem sich der Mauszeiger<br />

befindet.<br />

ì<br />

Ein Dreifachklick markiert die Zeile, in der sich der Mauscursor befindet.<br />

ì Ein Vierfachklick markiert den vollständigen Text (nicht nur den angezeigten Ausschnitt).<br />

Mit der Tastatur kann eine Selektion mit denselben Tastenkombinationen wir zum Bewegen<br />

des Textcursors erstellt und erweitert werden, wenn zusätzlich die Taste [SHIFT] gehalten<br />

wird. Zum Aufheben der Selektion dient die Taste [SELECT]. Um den vollständigen Text zu<br />

selektieren, kann man die Tastenkombination [CTRL]-/ verwenden. Um die Selektion des<br />

ganzen Textes wieder aufzuheben, verwendet man [CTRL]-\.<br />

Ein selektierter Text kann mit der Tastenkombination [CTRL]-[DELETE] mit Leerzeichen<br />

überschrieben werden. Um die Selektion zu löschen, gibt man einfach ein beliebiges Zeichen<br />

ein, solange sich der Textcursor noch innerhalb der Selektion befindet. In diesem Fall wird die<br />

Selektion aus dem Text durch das eingegebene Zeichen überschrieben. Diese Einstellung kann<br />

mit der Resource "xsample*sampleText.pendingDelete" bzw.<br />

"xsample*programText.pendingDelete" abgeschaltet werden.<br />

Um den selektierten Text zu einer anderen Stelle zu kopieren, bewegt man die Maus an die<br />

Stelle, an der der neue Text eingefügt werden soll, und klickt mit der mittleren Maustaste.<br />

Dann wird der Text an der neuen Stelle eingefügt. Die Markierung der Selektion verschwindet.<br />

Trotzdem bleibt die Selektion gespeichert und kann weiterhin an anderen Stellen eingefügt<br />

werden, bis die Selektion aufgehoben wird, oder ein neuer Text selektiert wird. Soll der Text<br />

von einer Stelle zur anderen verschoben werden, so ist gleichzeitig mit dem Klicken der<br />

mittleren Maustaste die [SHIFT]-Taste zu halten. In diesem Fall wird der selektierte Text an<br />

der neuen Stelle eingefügt und an der alten Position gelöscht. Es ist nicht möglich, selektierten<br />

Text an eine Position innerhalb des selektierten Textes zu kopieren oder zu verschieben.<br />

Es ist nicht nur möglich selektierten Text innerhalb eines Textfensters zu kopieren oder zu<br />

verschieben, es ist auch möglich, den Text zwischen den beiden Textfenstern von [VDPSOH<br />

2.0 auszutauschen. Es ist sogar möglich, Text zwischen verschiedenen X-Anwendungen<br />

auszutauschen. Damit kann eine Selektion eines Textes innerhalb eines Textfensters von<br />

[VDPSOH in das Fenster einer anderen X-Anwendung eingefügt werden, bzw. eine Selektion,<br />

die in einem Fenster eines anderen Programmes angelegt worden ist, in das Textfenster von<br />

[VDPSOH zu schreiben. Ob ein solcher Datenaustausch tatsächlich so einfach realisierbar ist,<br />

hängt von der betroffenen Anwendung ab.<br />

Wird der Austausch über die Selektion nicht unterstützt, oder soll ein Text über die<br />

Lebensspanne der Selektion hinaus aufgehoben werden, so bietet sich die Speicherung im<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Clipboard an. Das Clipboard ist ein universeller Zwischenspeicher, der von allen X-<br />

Anwendungen gelesen und beschrieben werden kann.<br />

Um eine Selektion in das Clipboard zu kopieren, wählt man im Edit-Menü oder im<br />

Popupmenü des Textfensters den Menüpunkt Copy an. Will man die Selektion ins Clipboard<br />

kopieren, gleichzeitig die Selektion löschen, so wählt man statt dessen den Menüpunkt Cut an.<br />

Alternativ kann man eine Selektion kopieren über die Taste [F7] für das Samplefenster bzw.<br />

der Taste [F9] für das Programfenster. Um die Selektion auszuschneiden und ins Clipboard zu<br />

kopieren kann man die Tastenkombinationen [SHIFT]-[F7] bzw. [SHIFT]-[F9] verwenden.<br />

Der Inhalt des Clipboard (der selbstverständlich auch von einer anderen X-Anwendung<br />

beschrieben worden sein kann) läßt sich mittels des Menüpunktes Paste des Edit-Menüs oder<br />

des Popupmenüs des entsprechenden Fensters einfügen. Über die Tastatur ist das Einfügen mit<br />

[F8] für das Samplefenster bzw. [F10] für das Programfenster möglich.<br />

9.7 Dialogfenster<br />

Sinn und Zweck des Hauptformulars ist die Bereitstellung von Kommandoelementen zur<br />

Steuerung des Programmes und die Anzeige und Bearbeitung der Texte für das Programm und<br />

die Beispielauswertung. Ist darüber hinaus eine Kommunikation mit dem Benutzer notwendig,<br />

so werden weitere Fenster geöffnet, sogenannte Dialogfenster. Diese Fenster sind dem<br />

Hauptformular untergeordnet. Das heißt, daß diese Fenster beim Schließen oder beim<br />

Iconifizieren des Hauptformulars verschwinden. Sie lassen sich in der Regel (abhängig vom<br />

verwendeten Windowmanager) nicht iconifizieren oder in ihrer Größe verändern, jedoch kann<br />

man sie auf dem Bildschirm verschieben. Die Dialogfenster von [VDPSOH sind normalerweise<br />

nicht sichtbar. Sie werden nur angezeigt, wenn sie einen bestimmten Zweck zu erfüllen haben,<br />

eine Mitteilung an den Benutzer oder die Auswahl eines Dateinamens. Haben sie ihren Zweck<br />

erfüllt, verschwinden sie wieder von Bildschirm.<br />

Alle Dialogfenster von [VDPSOH 2.0 sind modeless. Das heißt, es wird keine sofortige<br />

Reaktion des Benutzers auf das Dialogfenster erwartet, weder [VDPSOH noch ein anderes<br />

gleichzeitig ablaufendes Programm werden in ihren Eingaben gesperrt. Inwieweit das<br />

Ignorieren des Dialogfensters zum Beispiel im Falle einer Fehlermeldung sinnvoll ist, bleibt<br />

dem Benutzer überlassen.<br />

9.7.1 Sicherheitsabfragen<br />

Bei bestimmten Operation, wie dem Verlassen des Programmes oder dem Laden einer neuen<br />

Datei wird eine Abfragebox geöffnet mit der Bitte um Bestätigung der gewählten Operation.<br />

Die Abfragebox besteht nur aus einem Label mit der Mitteilung und dreier Pushbutton:<br />

Durch Betätigen des linken Pushbuttons mit der linken Maustaste wird die gewählte Operation<br />

fortgesetzt, durch Betätigen des mittleren Pushbuttons wird die Operation abgebrochen. In<br />

beiden Fällen verschwindet die Abfragebox sofort wieder von der Anzeigefläche. Zur<br />

Bestätigung der gewählten Operation kann auch die Taste [RETURN] verwendet werden, zum<br />

Abbruch die Taste [ESC]. Dies gilt allerdings nur, wenn das Dialogfenster den Tastaturfocus<br />

besitzt. Normalerweise muß dazu der Mauscursor sich innerhalb der Abfragebox befinden.<br />

Die Sicherheitsabfrage erscheint immer über der Position des Mauscursors.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Abbildung 13 : Das Dialogfenster der Sicherheitsabfrage<br />

Text der<br />

Sicherheitsabfrage<br />

Button zum Bestätigen der Operation<br />

Hilfebutton<br />

Button zum Abbruch der<br />

Operation<br />

9.7.2 Warnungen<br />

Abbildung 14 : Die Warnungsbox<br />

Text der Warnung<br />

Button zum Bestätigen<br />

der Operation<br />

Button zum Abbruch der<br />

Operation<br />

Hilfebutton<br />

Warnungen werden ausgegeben, wenn eine Operation angewählt wurde, durch die nicht<br />

gespeicherte Änderungen im Inhalt eines der Textfenster oder in beiden Textfenstern gelöscht<br />

werden. Man kann eine Warnung als zweite Sicherheitsabfrage auffassen. Die Warnungsbox<br />

gleicht der Abfragebox. Wiederum sind unter dem Label mit dem Text der Warnung drei<br />

Buttons angebracht. Zum Bestätigen der Operation und damit Überschreiben der nicht<br />

gespeicherten Änderungen klickt man mit der linken Maustaste auf den linken Pushbutton.<br />

Zum Abbruch der gewählten Operation klickt man auf den mittleren Pushbutton. Durch einen<br />

Klick mit der linken Maustaste auf den Pushbutton wird ein weiteres Fenster mit einem<br />

Hilfetext geöffnet. Befindet sich der Tastaturfocus auf dem Dialogfenster, so genügt auch das<br />

Betätigen der Taste [RETURN] zur Bestätigung der gewählten Operation und das Betätigen<br />

der Taste [ESC] zum Abbruch.<br />

Die Warnungsbox verschwindet vom Bildschirm, sobald die gewählte Operation bestätigt oder<br />

abgebrochen wird. Dialogbox erscheint über der Position des Mauscursors.<br />

9.7.3 Die Dateiauswahlbox<br />

Zur Auswahl eines Dateinamens dient die Dateiauswahlbox. Das Fenster der<br />

Dateiauswahlbox besteht aus vier Teilen:<br />

ì<br />

ì<br />

ì<br />

dem Fenster des Dateifilters<br />

der Verzeichnis- und der Dateiliste<br />

dem Fenster des Dateinamens<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

ì vier Pushbuttons<br />

Standardmäßig wird zuerst versucht, eine Datei in dem Verzeichnis zu suchen, von dem aus<br />

[VDPSOH gestartet wurde. Deswegen zeigt das Verzeichnisfenster alle Unterverzeichnisse<br />

(inklusive . und ..) in diesem Verzeichnis an und das Dateifenster die restlichen Dateien an,<br />

sofern sie dem gewählten Filter entsprechen (auch versteckte Dateien, aber die entsprechen<br />

selten dem Filter.<br />

Abbildung 15 : Die Dateiauswahlbox<br />

Fenster des Dateifilters<br />

Verzeichnisliste<br />

Dateiliste<br />

Vertikale Scrollbar<br />

Horizontale Scrollbar<br />

Fenster des Dateinamens<br />

Auswahl akzeptieren<br />

Dateiliste und Verzeichnisliste<br />

neu einlesen<br />

gewählte Operation<br />

abbrechen<br />

Hilfebox<br />

Der gewählte Filter wird im Fenster des Dateifilters angezeigt. Der Eintrag besteht<br />

normalerweise aus dem aktuellem Verzeichnis und dem Filter *.sc, wenn eine<br />

Beispielauswertung angewählt werden soll und *.pr, wenn ein Programm angewählt werden<br />

soll. Diese Vorgaben können über Resourcen geändert werden. Aber auch in einer geöffneten<br />

Dateiauswahlbox kann der Dateifilter verändert werden. Zum Beispiel sollte man den Eintrage<br />

nach dem Verzeichnispfad auf * verkürzen, um alle Dateien angezeigt zu bekommen. Um die<br />

Änderung auszuführen, muß die Taste [RETURN] gedrückt werden, während sich der<br />

Tastaturfocus im Fenster des Dateifilters befindet, oder der zweite Pushbutton (apply) mit der<br />

linken Maustaste angeklickt werden.<br />

Im Fenster des Dateinamens steht der gewählte Dateiname (oder nur ein Verzeichnis, falls<br />

noch kein Dateiname ausgewählt worden ist). Es ist möglich, in dieses Fenster direkt den<br />

Dateinamen hineinzuschreiben. Dies muß immer getan werden, wenn der Name einer bisher<br />

nicht vorhandenen Datei ausgewählt werden soll. Dazu bewegt man den Mauscursor in das<br />

Fenster des Dateinamens hinein, so daß das Fenster den Tastaturfocus erhält.<br />

Als Alternative im Fall, daß der Name einer bereits existierenden Datei angewählt werden soll,<br />

kann der Dateiname in der Dateiliste mit der linken Maustaste angeklickt werden.<br />

Überschreitet die Zahl der Dateien die Zahl der Zeilen in der Dateiliste, so kann die seitliche<br />

Scrollbar wie die Scrollbar in einem Textfenster verwendet werden, um die Anzeige zu<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

verschieben. Die Dateien in der Auswahlliste können auch mit der [RETURN]-Taste<br />

angewählt werden, sofern die betreffende Datei invers dargestellt wird. Über die Pfeiltasten<br />

besteht eine weitere Möglichkeit der Auswahl einer Datei.<br />

Der gewählte Dateiname kann jederzeit geändert werden, bis die Dateiauswahl abgeschlossen<br />

wird. Die Dateiauswahl wird abgeschlossen wenn:<br />

ì<br />

ì<br />

ì<br />

ì<br />

Die Taste [RETURN] gedrückt wird, während der Tastaturfocus im Fenster des<br />

Dateinamens steht und in diesem Fenster ein Dateiname steht.<br />

Die Taste [RETURN] gedrückt wird, während der Tastaturfocus im Dateifenster steht und<br />

ein Dateiname markiert ist. Dann wird der markierte Dateiname angewählt.<br />

Ein Dateiname im Dateifenster mit der linken Maustaste doppeltgeklickt wird. In diesem<br />

Fall wird auch dieser Dateiname gewählt.<br />

Der linke Pushbutton (ok) mit der linken Maustaste gedrückt wird, und im Fenster des<br />

Dateinamens ein Dateiname steht.<br />

Nach erfolgter Auswahl, wird die gewählte Operation (sichern oder laden) fortgesetzt und die<br />

Dateiauswahlbox geschlossen.<br />

Zum Wechsel eines Verzeichnisses kann der Pfad des Verzeichnisses im Fenster des<br />

Dateinamens angegeben werden oder ein Verzeichnisfenster ein Verzeichnis angewählt<br />

werden. Dies geschieht analog wie bei der Auswahl eines Dateinamens, jedoch wird die<br />

gewählte Operation nicht fortgesetzt und die Dateiauswahlbox nicht geschlossen sondern das<br />

Verzeichnis im Fenster des Dateinamens und im Fenster des Dateifilters auf das gewählte<br />

Verzeichnis geändert. Das Verzeichnisfenster und das Dateifenster zeigen jetzt den Inhalt des<br />

neuen Verzeichnissen an.<br />

Mit einem Klick mit der linken Maustaste auf den zweiten Pushbutton (apply) wird das<br />

Verzeichnis nochmals gelesen (z.B. wenn sich der Inhalt geändert hat, während das<br />

Dateiauswahlfenster geöffnet ist).<br />

Ein Klick auf den dritten Pushbutton (cancel) bricht die gewählte Operation ab und schließt<br />

die Dateiauswahlbox. Denselben Effekt hat auch die Taste [ESC], während sich der<br />

Tastaturfocus innerhalb der Dateiauswahlbox befindet. Über den rechten Pushbutton kann ein<br />

Fenster mit einem Hilfetext aufgerufen werden.<br />

Eine Dateiauswahlbox erscheint immer an der Position des Mauszeigers.<br />

9.7.4 Hilfetexte<br />

Eine Hilfebox erscheint aus einem der folgenden Gründe:<br />

ì<br />

ì<br />

ì<br />

ì<br />

Die Taste [F1] wurde betätigt.<br />

Eine der Menüpunkte im Hilfemenü wurde angewählt.<br />

Der Hilfebutton in der Kommandozeile wurde angeklickt.<br />

In einem Dialogfenster wurde der rechte Pushbutton (help) angeklickt.<br />

Das Hilfefenster erscheint immer in der Mitte des Hauptformulars (um kein anderes<br />

Dialogfenster zu überdecken). Neben dem Label mit dem (hoffentlich erhellenden) Hilfetext<br />

enthält die Hilfebox zwei Pushbuttons. Ein Mausklick (mit der linken Maustaste) auf den<br />

linken Pushbutton (ok) schließt das Fenster, während ein Klick auf den rechten Pushbutton ein<br />

weiteres Hilfefenster erscheinen läßt. Wenn der Tastaturfocus auf dem Dialogfenster liegt,<br />

kann das Fenster auch mit der [RETURN]-Taste geschlossen werden.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Abbildung 16 : Die Hilfebox<br />

Hilfetext<br />

Hilfefenster<br />

schließen<br />

Hilfetext<br />

anzeigen<br />

9.7.5 Fehlermeldungen<br />

Bei der interaktiven Benutzerführung werden Fehlermeldungen ebenfalls in einem<br />

Dialogfenster ausgegeben. Die Dialogbox erscheint in der Mitte des Hauptformulars. Neben<br />

dem Text der Fehlermeldung enthält das Fenster zwei Pushbuttons. Ein Klick mit der linken<br />

Maustaste auf den linken Pushbutton (ok) schließt das Fenster, ebenso das Betätigen der Taste<br />

[RETURN]. Durch einen Klick auf den rechten Pushbutton (help) öffnet sich eine Hilfebox.<br />

9.7.6 Die Fehlerprotokollbox<br />

Bei einigen Fehlermeldungen wird zusätzlich ein Fehlerprotokoll angezeigt. Das<br />

Fehlerprotokoll wird in einem eigenen Fenster angezeigt, welches unterhalb des Fenster mit<br />

der Fehlermeldung aufgebaut wird.<br />

Neben der Anzeige des Fehlerprotokolls enthält die Dialogbox zwei Pushbuttons. Ein Klick<br />

mit der linken Maustaste auf den linken der Buttons (oder das Betätigen der Taste [RETURN]<br />

schließt das Dialogfenster. Ein Klick auf den rechten Pushbutton öffnet ein Fenster mit einem<br />

Hilfetext.<br />

Überschreitet das Fehlerprotokoll die Größe des Fensters, so wird nur ein Teil des<br />

Fehlerprotokolls angezeigt. Gleichzeitig erscheinen Scrollbars an den Seiten des angezeigten<br />

Textes, mit denen (analog wie beim Textfenster) der Ausschnitt des angezeigten Protokolls<br />

verschoben werden kann.<br />

6HLWH


%HQXW]HUVFKQLWWVWHOOH<br />

Abbildung 17 : Das Fehlermeldedialogfenster und das Fehlerprotokollfenster<br />

Fehlerprotokoll<br />

vertikale<br />

Scrollbar<br />

Fehlermeldung<br />

Hilfebutton<br />

Fenster<br />

schließen<br />

9.7.7 Die Infobox<br />

Die Infobox dient nur zur Anzeige einer Information über das Werkzeug und seinen Autor. Sie<br />

wird über dem Mauscursor sichtbar. Die Infobox besitzt nur einen einzigen Pushbutton. Klickt<br />

man diesen Button mit der linken Maustaste an, so wird die Infobox geschlossen.<br />

9.8 Die Syntax der Hilfetexte und Fehlermeldungen<br />

Den Dateien der Hilfetexten und Fehlermeldungen liegt dasselbe Format zugrunde. Sie werden<br />

in einer gewöhnlichen ASCII-Datei gespeichert, wobei alle Hilfetexte in einer Datei stehen<br />

müssen, und alle Fehlermeldungen in einer Datei stehen müssen. Die Einträge stehen dabei<br />

hintereinander, wobei die Reihenfolge der Einträge wichtig ist.<br />

Jeder Eintrag eines Hilfetextes bzw. einer Fehlermeldung beginnt mit einer Kopfzeile, deren<br />

erstes Zeichen ein "@" sein muß. Alle Zeilen zwischen zwei Kopfzeilen (außer<br />

Kommentarzeilen) bzw. zwischen der letzten Kopfzeile und dem Dateiende werden zu einem<br />

Eintrag gezählt. Kommentarzeilen werden immer überlesen. Erstes Zeichen einer<br />

Kommentarzeile muß das Zeichen "!" sein. Ebenso werden alle Zeilen vor der ersten<br />

Kopfzeile überlesen. Es versteht sich, daß keine Zeile eines Hilfetextes oder einer<br />

Fehlermeldung mit "@" oder mit "!" beginnen darf.<br />

6HLWH


3RUWLHUXQJHQ<br />

10 Portierungen<br />

Das Werkzeug wurde erfolgreich auf folgenden Systemen implementiert und getestet:<br />

u SUN-SPARC-Cluster der AG Wiehagen unter<br />

w SunOs 5.5<br />

w Gnu C++ 2.7.2<br />

w X11R6<br />

w Motif 1.2<br />

u AIX-Cluster des RHRK (IBM RS6000) unter<br />

w Aix 3.2.5<br />

w Gnu C++ 2.7.2<br />

w X11R6<br />

w Motif 1.2<br />

u Ausbildungscluster des IRZ Kaiserslautern (SUN) unter<br />

w SunOs 4.1.2<br />

w Gnu C++ 2.7.2<br />

w X11R5<br />

w Motif 1.2<br />

u Intel DX2/66 - PC unter<br />

w Linux 2.0.10<br />

w Gnu C++ 2.7.2<br />

w X11R6<br />

w Motif 2.0<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

11 Beispiele von Programmläufen<br />

12 Programmläufe im Batch-Modus<br />

Bei der Benutzung des Werkzeuges zur Auswertung eines WHILE-Programmes im Batch-<br />

Modus kann das Programm entweder in einer ASCII-Text vorliegen oder von der<br />

Standardeingabe eingelesen werden. Wenn es von der Standardeingabe eingelesen wird, so<br />

wird die Eingabe für [VDPSOH von einem anderen UNIX-Programm geliefert. Es ist<br />

selbstverständlich möglich, den Text des WHILE-Programmes direkt über die Tastatur<br />

einzugeben. Der folgende Programmlauf wurde aus einem mit 'script' erstellten Shell-Protokoll<br />

ausgeschnitten:<br />

Script started on Fri Apr 25 13:51:56 1997<br />

christof@nafteta[~/sample] % xsample -b -c<br />

input (a,b,c)<br />

set (d := 50)<br />

with while a > 0 do<br />

with set (e := 40) while b > 0 do<br />

e ++e ++e --b<br />

end while<br />

--a --a ++c<br />

end while<br />

output c<br />

input (10, 20, 30)<br />

test<br />

10 > 0<br />

do<br />

test<br />

20 > 0<br />

do<br />

40 41 42 19<br />

end test<br />

test<br />

19 > 0<br />

do<br />

42 43 44 18<br />

end test<br />

9 8 31<br />

end test<br />

test<br />

8 > 0<br />

do<br />

test<br />

18 > 0<br />

do<br />

40 41 42 17<br />

end test<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

test<br />

17 > 0<br />

do<br />

42 43 44 16<br />

end test<br />

7 6 32<br />

end test<br />

output 32<br />

christof@nafteta[~/sample] % exit<br />

script done on Fri Apr 25 13:55:43 1997<br />

Bei der Benutzung des Werkzeugs zur Generierung einer Beispielauswertung ist es<br />

schwieriger, den Text der Beispielauswertung direkt einzugeben, aber dennoch möglich. Auch<br />

hier wird üblicherweise die Eingabe von Datei oder über eine Pipe gelesen.<br />

Script started on Fri Apr 25 16:12:26 1997<br />

christof@nafteta[~/sample] % xsample -b -s<br />

input (10,20,30)<br />

test 10 < 20 do<br />

11 12 13 19<br />

test 30 > 0 do<br />

writeln (29);<br />

next_value = 29<br />

end test<br />

test 29 > 0 do<br />

writeln (28);<br />

next_value = 28<br />

end test<br />

test 28 > 0 do<br />

writeln (27);<br />

next_value = 27<br />

end test<br />

test 27 > 0 skip<br />

end test<br />

test 13 < 19 do<br />

14 15 16 18<br />

test 27 > 0 do<br />

writeln (26);<br />

next_value = 26<br />

end test<br />

test 26 > 0 do<br />

writeln (25);<br />

next_value = 25<br />

end test<br />

end test<br />

output 25<br />

input (x0, x1, x2)<br />

set (x3 := 0)<br />

with<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

while<br />

x0 x3<br />

do<br />

writeln ( --x2 );next_value =x2<br />

end while<br />

end while<br />

output x2<br />

christof@nafteta[~/sample] % exit<br />

script done on Fri Apr 25 16:17:47 1997<br />

13 Programmläufe mit der graphischen Benutzeroberfläche<br />

Es ist für die meisten Anwender einfacher, das Werkzeug über die graphische<br />

Benutzeroberfläche zu bedienen. Um die Funktionalität des Werkzeugs einschätzen zu können,<br />

haben wir bei den hier eingefügten Testläufen immer nur ein WHILE-Programm vorgegeben,<br />

dieses ausgewertet und aus der generierten Beispielauswertung wieder eine WHILE-<br />

Programm zu synthetisieren. Auf diese Weise können wir die Güte des Programmes<br />

einschätzen, das ursprüngliche Programm zurückzugewinnen.<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

14 Beispiel 1<br />

Abbildung 18 : Beispiel 1 - Programmauswertung<br />

Abbildung 18 zeigt einen einfachen Programmlauf über die graphische Benutzeroberfläche.<br />

Jedes while-Konstrukte wird genau zweimal entfaltet. Dies ist die zur Synthese notwendige<br />

Mindestzahl. Als Werte für die Eingabevariable werden Vielfache der Zahl 10 verwendet<br />

(diese Festlegung ist willkürlich). Man beachte, daß der Kommentar und die Variable w in der<br />

Auswertung nicht auftauchen.<br />

Betrachten wir nun das aus der Auswertung zurücksynthetisierte Programm in der Abbildung<br />

19:<br />

Die nicht verwendete Variable w taucht hier nicht auf, ebensowenig wie der Kommentar.<br />

Ansonsten stimmen aber das eingegebene und das synthetisierte Programm überein.<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

Abbildung 19 : Beispiel 1 - Programmsynthese<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

15 Beispiel 2<br />

Abbildung 20 : Beispiel 2 - Programmauswertung<br />

Auch im zweiten Beispiel (Abbildung 20) taucht der Kommentar in der Auswertung nicht<br />

mehr auf. Bei der Betrachtung der Synthese (Abbildung 22) fällt auf, daß sowohl die lokale<br />

Variable d als auch die Zahlkonstante 100 im synthetisierten Programm durch globale<br />

Variablen ersetzt wurden.<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

Abbildung 21 : Beispiel 2 - Programmsynthese<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

16 Beispiel 3<br />

Abbildung 22 : Beispiel 3 - Programmauswertung<br />

Abbildung 22 zeigt ein weiteres Beispiel für die automatische Auswertung eines Programmes.<br />

Bei der Synthese (Abbildung 23) fällt wieder auf, daß die Konstante 200 durch eine weitere<br />

globale Variable ersetzt wurde.<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

Abbildung 23 : Beispiel 3 - Programmsynthese<br />

6HLWH


%HLVSLHOHYRQ3URJUDPPOlXIHQ<br />

17 Beispiel 4<br />

Das nächste Beispiel soll die Grenzen des Synthesealgorithmus' aufzeigen:<br />

Abbildung 24 : Beispiel 4<br />

A<br />

B<br />

C<br />

Auch in diesem Beispiel (Abbildung 24) wird die Auswertung des eingegebenen Programmes<br />

automatisch berechnet. Die Synthese jedoch scheitert. An der Stelle A kann der<br />

Synthesealgorithmus' nicht entscheiden, ob die Zahl 9 der Wert der bereits bekannten globalen<br />

Variablen, hier c, oder einer neuen lokalen Variablen (d) mit dem Anfangswert c ist (kein<br />

konsistent arbeitender Algorithmus ist dazu in der Lage). Der Synthesealgorithmus entscheidet<br />

sich immer für die globale Variable. Deswegen muß er annehmen, daß die globale Variable c<br />

an der Stelle B den Wert 7 besitzt. Der Wert 9 an der Stelle C in der zweiten Entfaltung des<br />

äußeren while-Konstruktes muß unbedingt ein Wert der globalen Variablen c sein. Da die<br />

Variable aber nicht am Ende der ersten Entfaltung eines while-Konstruktes den Wert 9, und zu<br />

Beginn der zweiten Entfaltung den Wert 7 besitzen kann, wird der Synthesealgorithmus eine<br />

fehlerhafte Eingabe melden.<br />

6HLWH


=XVDPPHQIDVVXQJXQG6FKOX‰EHPHUNXQJHQ<br />

18 Zusammenfassung und Schlußbemerkungen<br />

Ziel dieser Arbeit war es, eine Methode anzugeben, mit der Algorithmen durch einen Rechner<br />

automatisch generiert werden durch Eingabe von Beispielauswertungen. Dies ist ein<br />

Spezialfall einer sehr verbreiteten Lernsituation, nämlich dem Lernen durch gute Beispiele.<br />

Die Lernsituation ist dabei sehr extrem. Der Rechner (der Lernende) erhält nur ein einziges<br />

Beispiel für das zu lösende Problem als Eingabe und muß sofort eine Lösung des Problem<br />

ausgeben.<br />

Die Sprache zur Formulierung des Problems und seiner Lösungen wurde bewußt sehr einfach<br />

gehalten. Trotzdem zeigt Kapitel 1, daß die Mächtigkeit der Sprache WHILE an die<br />

Mächtigkeit der Turingmaschine heranreicht und daß ihre Ausdrucksfähigkeit auch für<br />

Probleme des (technischen) Alltags ausreicht.<br />

Die in den Kapiteln 4 und 5 vorgestellten Algorithmen zur automatischen Generierung der<br />

Beispielauswertungen und der Synthese der WHILE-Programme erfüllen die gestellte<br />

Forderungen. Die gefundenen Abschätzungen für die Rechenzeit sind als gut zu bezeichnen,<br />

da der Aufwand sowohl für die Auswertung als auch für die Synthese nur linear von der<br />

Länge der Eingabe abhängt. Kapitel 6 zeigt die Grenzen unserer Methode. Die Menge der<br />

lernbaren Algorithmen ist eingeschränkt, und diese Einschränkung läßt sich nicht mit<br />

einfachen Mitteln beheben.<br />

In den abschließenden Kapiteln wurde das Werkzeug [VDPSOH2.0 vorgestellt, mit dem die<br />

Algorithmen auch auf mehreren heutigen Rechnersystemen getestet werden können. Das<br />

Werkzeug [VDPSOH stellt auch eine Basis für künftige Entwicklungen auf dem Gebiet dar.<br />

Die Forschung auf dem Gebiet der automatisierten Programmsynthese ist nicht abgeschlossen<br />

und wird es wohl nie sein. Auch diese Arbeit hat einig Fragen offen gelassen:<br />

w Kann die automatisierte Programmsynthese auf Sprachen mit einer höheren<br />

Ausdrucksfähigkeit erfolgen? Es wäre wünschenswert, Sprachen wie Pascal oder C als<br />

Ausgangssprachen verwenden zu können.<br />

w Welche anderen Formen der Eingabe für die Synthese können neben Beispielauswertungen<br />

verwendet werden?<br />

w Wie können die Algorithmen verbessert werden, hinsichtlich der Effizienz und hinsichtlich<br />

der Menge der lernbaren Klassen von Programmen? Gibt es eine Klasse von Programmen,<br />

die von den Algorithmen gelernt werden kann, und eine Obermenge zur Klasse-I darstellt?<br />

Gibt es alternative Ansätze zur Programmsynthese, durch die Menge der lernbaren<br />

Algorithmen erhöht werden kann.<br />

w Welche anderen Synthesealgorithmen können gefunden werden? Das Werkzeug [VDPSOH<br />

ist für die Verwendung verschiedener Algorithmen für Auswertung und Synthese<br />

vorgesehen. Auch wenn keine Obermenge zur Klasse-I gefunden werden kann, so kann<br />

durch die Verwendung mehrerer Algorithmen die Lernpotenz dennoch erhöht werden. Auch<br />

eine Spezialisierung der Algorithmen auf bestimmte Algorithmenklassen kann sinnvoll sein.<br />

6HLWH


$QKDQJ$'LH:LGJHWVWUXNWXUYRQ[VDPSOH<br />

Anhang A Die Widgetstruktur von [VDPSOH 2.0<br />

Abbildung 25 : Die Widgetstruktur des Hauptformulars von [VDPSOH 2.0<br />

ApplicationShell<br />

xsample<br />

Form ???<br />

MenuBar<br />

CascadeButton<br />

menu<br />

fileMenu<br />

PulldownMenu<br />

filePane<br />

PushButton<br />

new<br />

Separator<br />

blank<br />

CascadeButton<br />

load<br />

PulldownMenu<br />

loadPane<br />

PushButton<br />

loadSample<br />

PushButton<br />

loadProgram<br />

CascadeButton<br />

reload<br />

PulldownMenu<br />

reloadPane<br />

PushButton<br />

reloadSample<br />

PushButton<br />

reloadProgram<br />

6HLWH


$QKDQJ$'LH:LGJHWVWUXNWXUYRQ[VDPSOH<br />

Abbildung 26 : Die Widgetstruktur des Hauptformulars von [VDPSOH2.0 (Fortsetzung)<br />

CascadeButton<br />

saveAs<br />

PulldownMenu<br />

saveAsPane<br />

PushButton<br />

PushButton<br />

saveAsSample<br />

saveAsProgram<br />

CascadeButton<br />

save<br />

PulldownMenu<br />

PushButton<br />

PushButton<br />

Separator<br />

savePane<br />

saveSample<br />

saveProgram<br />

blank<br />

PushButton<br />

quit<br />

CascadeButton<br />

edit<br />

PulldownMenu<br />

editPane<br />

CascadeButton<br />

cut<br />

PulldownMenu<br />

cutPane<br />

PushButton<br />

cutSample<br />

PushButton<br />

cutProgram<br />

6HLWH


$QKDQJ$'LH:LGJHWVWUXNWXUYRQ[VDPSOH<br />

Abbildung 27 : Die Widetstruktur des Hauptformulars von [VDPSOH2.0 (Fortsetzung)<br />

CascadeButton<br />

copy<br />

PulldownMenu<br />

copyPane<br />

PushButton<br />

copySample<br />

PushButton<br />

copyProgram<br />

CascadeButton<br />

paste<br />

PulldownMenu<br />

pastePane<br />

PushButton<br />

pasteSample<br />

PushButton<br />

pasteProgram<br />

CascadeButton<br />

clear<br />

PulldownMenu<br />

clearPane<br />

PushButton<br />

clearSample<br />

PushButton<br />

clearProgram<br />

CascadeButton<br />

generateMenu<br />

PulldownMenu<br />

generatePane<br />

PushButton<br />

synthesize<br />

PushButton<br />

compute<br />

6HLWH


$QKDQJ$'LH:LGJHWVWUXNWXUYRQ[VDPSOH<br />

Abbildung 28 : Die Widgetstruktur des Hauptformulars von [VDPSOH 2.0 (Fortsetzung)<br />

CascadeButton<br />

algorithmMenu<br />

PulldownMenu<br />

algorithmPane<br />

ToggleButton<br />

standardAlgorithm<br />

CascadeButton<br />

help<br />

PulldownMenu<br />

helpPane<br />

PushButton<br />

helpGeneral<br />

PushButton<br />

helpOnWindows<br />

PushButton<br />

helpOnMenues<br />

Pushbutton<br />

helpOnButtons<br />

PushButton<br />

helpOnKeys<br />

Separator<br />

blank<br />

Pushbutton<br />

Form<br />

info<br />

actionForm<br />

Form<br />

sampleForm<br />

Label<br />

sampleTitle<br />

6HLWH


$QKDQJ$'LH:LGJHWVWUXNWXUYRQ[VDPSOH<br />

Abbildung 29 : Die Widgetstruktur des Hauptformulars von [VDPSOH2.0 (Fortsetzung)<br />

Label<br />

sampleUnsavedLabel<br />

Label<br />

sampleComputedLabel<br />

Label<br />

sampleFilename<br />

Text<br />

sampleText<br />

popupMenu<br />

samplePopup<br />

Label<br />

label<br />

Separator<br />

blank<br />

PushButton<br />

loadSample<br />

Pushbutton<br />

reloadSample<br />

PushButton<br />

saveAsSample<br />

PushButton<br />

saveSample<br />

PushButton<br />

Separator<br />

synthesize<br />

textsep<br />

Form<br />

programForm<br />

Label<br />

programTitle<br />

6HLWH


$QKDQJ$'LH:LGJHWVWUXNWXUYRQ[VDPSOH<br />

Abbildung 30 : Die Widgetstruktur des Hauptformulars von [VDPSOH 2.0 (Fortsetzung)<br />

Label<br />

Label<br />

programUnsavedLab<br />

el<br />

programSynthesizedLabel<br />

Label<br />

programFilename<br />

Text<br />

programText<br />

popupMenu<br />

programPopup<br />

Label<br />

label<br />

Separator<br />

blank<br />

PushButton<br />

loadProgram<br />

Pushbutton<br />

reloadProgram<br />

PushButton<br />

saveAsProgram<br />

PushButton<br />

saveProgram<br />

PushButton<br />

compute<br />

RowColumn<br />

commandLine<br />

PushButton<br />

synthesizeButton<br />

PushButton<br />

computeButton<br />

PushButton<br />

quitButton<br />

PushButton<br />

helpButton<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

Anhang B Resourcen<br />

Resourcen ermöglichen die Anpassung des Werkzeuges an die persönlichen Bedürfnisse des<br />

Benutzers, ohne dazu bei jedem Aufruf mehrere Kommandozeilenoptionen setzen zu müssen.<br />

Die Resourcen können sowohl in einer ASCII-Datei angegeben werden, aber auch durch die<br />

Komandozeilenoptionen gesetzt werden. Oftmals wird der Wert einer Resource aber vom<br />

Programm unveränderlich festgelegt.<br />

Auf der Suche nach den Resourcen für das Werkzeug wird beim Aufruf von [VDPSOH<br />

folgendermaßen vorgegangen:<br />

ì Es wird die Datei "Sample" im Standard-Application-Default-Verzeichnis des System<br />

gelesen, sofern die Datei in diesem Verzeichnis enthalten ist.<br />

ì<br />

ì<br />

ì<br />

Es wird die Datei "Sample" in dem durch die Umgebungsvariable APPLRESDIR<br />

angegeben Verzeichnis gelesen. Falls diese Datei nicht existiert, wird die Datei "Sample"<br />

im Homeverzeichnis des Benutzers gesucht, und, falls sie gefunden wird, gelesen.<br />

Es werden die Resourcen des X-Servers gelesen. Resourcen können mit der Anweisung<br />

xrdb in den Server geladen werden.<br />

Es wird die Kommandozeilenoption -xrm in der Kommandozeile ausgewertet.<br />

ì Es werden die übrigen Kommandozeilenoptionen ausgewertet, sofern diese den Wert der<br />

Resourcen verändern.<br />

Auf die genauerer Vorgehensweise beim Aufruf des Programmes soll hier nicht eingegangen<br />

sein. Für den Benutzer wichtig ist die Datei Sample, die die für den Benutzer am relevantesten<br />

Resourcen enthält. Zu ihrer Benutzung empfiehlt sich das Setzen der Umgebungsvariablen<br />

APPLRESDIR oder das Setzen eines gleichnamigen Links vom Homeverzeichnis aus auf die<br />

Datei Sample.<br />

Das Programm [VDPSOHbesitzt sehr viele Resourcen, die anhand einschlägiger Fachliteratur<br />

aus der in Anhang A angegebenen Widgetstruktur ermittelt werden kann. Die meisten der<br />

Resourcen sind jedoch vom Programm aus mit festen Werten belegt, oder ihre Festlegung ist<br />

nicht sinnvoll. Die wenigsten Benutzer haben z.B. ein Interesse daran, die genauen<br />

Koordinaten der Position eines Pushbuttons auf dem Bildschirm anzugeben. Deswegen wollen<br />

wir hier nicht alle Resourcen erläutern, sondern nur diejenigen Resourcen, die auch in der<br />

Standard-Resourcendatei Sample enthalten sind.<br />

Mit der Resource<br />

xsample*title<br />

wird der Titel des Fensters des Hauptformulars gesetzt. Wert dieser Resource kann eine<br />

beliebige Zeichenfolge sein. Die Standardvorgabe in dieser Resource ist "xsample 2.0". Der<br />

Titel des Icons kann mit der Resource<br />

xsample*iconName<br />

gesetzt werden. Auch hier ist standardmäßig der Wert "xsample 2.0" eingetragen.<br />

Die Resource<br />

xsample*keyboardFocusPolicy<br />

enthält normalerweise den Wert "POINTER". Dann enthält dasjenige Fenster den<br />

Tastaturfocus, in dem sich der Mauscursor befindet. Wird hier der Wert EXPLICIT<br />

eingetragen, muß jede Applikation, die den Tastaturfocus haben soll, mit der Maus angeklickt<br />

werden. Das Fenster behält dann aber den Focus, auch wenn der Mauscursor sich nicht<br />

innerhalb der Fenstergrenezen befindet.<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

Über die Resource<br />

xsample*blinkRate<br />

regelt man die Frequenz, in der der Textcursor blinkt. Dabei bedeutet der Standardwert 300,<br />

daß der Textcursor alle 300 Millisekunden aufblinkt. Um das Blinken des Cursor<br />

abzuschalten, trägt man in die Resource den Wert 0 ein.<br />

Die Abstände zwischen den einzelnen Widgets innerhalb des Formulars werden mit den<br />

Resourcen<br />

xsample*horizontalSpacing und<br />

xsample*verticalSpacing<br />

festgesetzt. Die angegebenen Werte bezeichnet die horizontalen und vertikalen Abstände in<br />

Pixeln.<br />

Um die Tear-Off-Menüs abzuschalten, kann man als Wert der Resourcen<br />

xsample*tearOffModel<br />

die Konstante TEAR_OFF_DISABLED eintragen.<br />

Mit der Resource<br />

xsample*defaultVirtualBindings<br />

können einige logische Keys existierenden Tasten auf der Tastatur zugeordnet werden. Der<br />

Standardwert dieser Resource ist<br />

osfAddMode:<br />

Insert \n\<br />

osfBackSpace: BackSpace \n\<br />

osfBeginLine: Mod1Left \n\<br />

osfClear:<br />

CtrlDelete \n\<br />

osfDelete:<br />

Delete \n\<br />

osfDown:<br />

Down \n\<br />

osfEndLine:<br />

Mod1Right \n\<br />

osfLeft:<br />

Left \n\<br />

osfPageDown:<br />

Next \n\<br />

osfPageUp:<br />

Prior \n\<br />

osfPrimaryPaste: F6 \n\<br />

osfSelect:<br />

Select \n\<br />

osfRight:<br />

Right \n\<br />

osfUp:<br />

Up<br />

Der Benutzer mag diese Belegung an seine eigenen Wünsche und den Gegebenheiten seiner<br />

Tastatur anpassen wollen. Um zum Beispiel die Taste [HOME] für den logischen Key<br />

osfBeginLine zu verwenden, ändert man die entsprechende Zeile um in:<br />

osfBeginLine: Home \n\<br />

Die Form der verwendeten Separatoren zum Abtrennen des Aktionsfensters von der<br />

Pushbuttoonzeile und von der Menüzeile und zum Abtrennen des Samplefensters vom<br />

Programfenster werden in den Resourecen<br />

xsample*uppersep.separatorType,<br />

xsample*lowersep.separatorType und<br />

xsample*textsep.separatorType<br />

festgelegt. Die Resourcen können die folgenden Werte annehmen:<br />

NO_LINE, SINGLE_LINE, DOUBLE_LINE, SINGLE_DASHED_LINE,<br />

DOUBLE_DASHED_LINE, SHADOW_ETCHED_IN, sowie<br />

SHADOW_ETCHED_OUT.<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

Mit der Resource<br />

xsample*menu*menuAccelerator<br />

kann diejenige Taste festgelegt werden, mit der auf die Menüzeile mit den Cursortasten<br />

zugegriffen werden kann. Der Standardwert dieser Resource ist F3.<br />

Die Beschriftungen der einzelnen Menüs in der Menüzeile werden über die Resourcen<br />

xsample*menu*fileMenu.labelString,<br />

xsample*menu*editMenu.labelString,<br />

xsample*menu*generateMenu.labelString,<br />

xsample*menu*algorithmMenu.labelString und<br />

xsample*menu*helpMenu.labelString<br />

festgelegt. Mit den Resourcen<br />

xsample*menu*fileMenu.mnemonic,<br />

xsample*menu*editMenu.mnemonic,<br />

xsample*menu*generateMenu.mnemonic,<br />

xsample*menu*algorithmMenu.mnemonic und<br />

xsample*menu*helpMenu.mnemonic<br />

wird derjenige Buchstabe festgelegt, über dessen Taste zusammen mit der [ALT]-Taste das<br />

Menü aufgeklappt wird. Diese Buchstabe wird in der Beschriftung des Menüs unterstrichen.<br />

Die Beschriftung der einzelnen Menüeinträge (auch die Einträge der Untermenüs) werden über<br />

die folgenden Resourcen festgelegt:<br />

xsample*menu*new.labelString<br />

xsample*menu*load.labelString<br />

xsample*menu*loadSample.labelString<br />

xsample*menu*loadProgram.labelString<br />

xsample*menu*reload.labelString<br />

xsample*menu*reloadSample.labelString<br />

xsample*menu*reloadProgram.labelString<br />

xsample*menu*saveAs.labelString<br />

xsample*menu*saveAsSample.labelString<br />

xsample*menu*saveAsProgram.labelString<br />

xsample*menu*save.labelString<br />

xsample*menu*saveSample.labelString<br />

xsample*menu*saveProgram.labelString<br />

xsample*menu*quit.labelString<br />

xsample*menu*cut.labelString<br />

xsample*menu*cutSample.labelString<br />

xsample*menu*cutProgram.labelString<br />

xsample*menu*copy.labelString<br />

xsample*menu*copySample.labelString<br />

xsample*menu*copyProgram.labelString<br />

xsample*menu*paste.labelString:<br />

xsample*menu*pasteSample.labelString<br />

xsample*menu*pasteProgram.labelString<br />

xsample*menu*clear.labelString<br />

xsample*menu*clearSample.labelString<br />

xsample*menu*clearProgram.labelString<br />

xsample*menu*synthesize.labelString<br />

xsample*menu*compute.labelString<br />

xsample*menu*algorithmMenu.labelString<br />

xsample*menu*standardAlgorithm.labelString<br />

xsample*menu*helpGeneral.labelString<br />

xsample*menu*helpOnWindows.labelString<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

xsample*menu*helpOnMenues.labelString<br />

xsample*menu*helpOnButtons.labelString<br />

xsample*menu*helpOnKeys.labelString<br />

xsample*menu*info.labelString<br />

Die entsprechenden Resourcen zur Wahl der Buchstabens zur Menüauswahl über die Tastatur<br />

unterscheiden sich von den Resourcen zur Wahl des Eintrags nur dadurch, daß die<br />

Zeichenfolge "labelString" durch "mnemonic" ersetzt wird.<br />

Es können nun noch weitere Tastenkombinationen gewählt werden, mit denen ein Menüeintrag<br />

aufgerufen werden kann. Um die dafür notwendige Resource zu erhalten ersetzt man die<br />

Zeichenkette "labelString" durch die Zeichenkette "accelerator". In der Datei Sample sind die<br />

folgenden "Accelerators" definiert:<br />

xsample*menu*new.accelerator:<br />

CtrlN<br />

xsample*menu*loadSample.accelerator: CtrlL<br />

xsample*menu*loadProgram.accelerator: CtrlO<br />

xsample*menu*saveSample.accelerator: CtrlS<br />

xsample*menu*saveProgram.accelerator: CtrlA<br />

xsample*menu*quit.accelerator:<br />

CtrlQ<br />

xsample*menu*synthesize.accelerator: CtrlY<br />

xsample*menu*compute.accelerator: CtrlC<br />

xsample*menu*cutSample.accelerator: ShiftF7<br />

xsample*menu*cutProgram.accelerator: ShiftF9<br />

xsample*menu*copySample.accelerator: F7<br />

xsample*menu*copyProgram.accelerator: F9<br />

xsample*menu*pasteSample.accelerator: F8<br />

xsample*menu*pasteProgram.accelerator: F10<br />

xsample*menu*helpGeneral.accelerator: F1<br />

Es steht dem Benutzer frei, diese Tastenkombinationen umzubelegen oder zu ergänzen.<br />

Diese Shortcuts sollten auch im Menü angezeigt werden. Über weitere Resourcen kann ein<br />

beliebiger Text hinter den "labelString" in einen Menüeintrag eingetragen werden. Für die<br />

oben definierten Shortcuts gelten normalerweise die folgenden Einträge:<br />

xsample*menu*new.acceleratorText:<br />

Ctrl-N<br />

xsample*menu*loadSample.acceleratorText: Ctrl-L<br />

xsample*menu*loadProgram.acceleratorText: Ctrl-O<br />

xsample*menu*saveSample.acceleratorText: Ctrl-S<br />

xsample*menu*saveProgram.acceleratorText: Ctrl-A<br />

xsample*menu*quit.acceleratorText: Ctrl-Q<br />

xsample*menu*synthesize.acceleratorText: Ctrl-Y<br />

xsample*menu*compute.acceleratorText: Ctrl-C<br />

xsample*menu*cutSample.acceleratorText: Shift-F7<br />

xsample*menu*cutProgram.acceleratorText: Shift-F9<br />

xsample*menu*copySample.acceleratorText: F7<br />

xsample*menu*copyProgram.acceleratorText: F9<br />

xsample*menu*pasteSample.acceleratorText: F8<br />

xsample*menu*pasteProgram.acceleratorText:F10<br />

xsample*menu*helpGeneral.acceleratorText: F1<br />

Kommen wir nun zur Pushbuttonleiste. Die Aufschriften auf den vier Pushbuttons werden in<br />

den Resourcen<br />

xsample*synthesizeButton.labelString,<br />

xsample*computeButton.labelString,<br />

xsample*quitButton.labelString und<br />

xsample*helpButton.labelString<br />

eingegeben.<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

Über die Resourcen<br />

xsample*sampleTitle.labelString und<br />

xsample*programTitle.labelString<br />

stellt man die Beschriftung der Überschriftlabel des Samplefensters und des Programfensters<br />

ein. Standardmäßig sind beide Fenster mit einem Rahmen versehen. Zur Angabe der Breite der<br />

Rahmens dienen die Resourcen<br />

xsample*sampleTitle.highlightThickness und<br />

xsample*programTitle.highlightThickness<br />

Die Standardbreite beträgt 2 Pixel. Die Breite der Randline wird mit den Resourcen<br />

xsample*sampleTitle.borderWidth und<br />

xsample*programTitle.borderWidth<br />

eingegeben. Ihr Wert wird in der Datei Sample mit 1 Pixel angegeben.<br />

Im Samplefenster können zwei Flags angezeigt werden. Das este Flag zeigt an, daß der Inhalt<br />

des Textfensters nicht gesichert ist, das zweite Flag zeigt an, daß die angezeigte<br />

Beispielauswertung aus der Auswertung des angezeigten Programmes hervorgegangen ist.<br />

Diese Flags werden über die folgenden Resourcen festgelegt:<br />

xsample*sampleUnsavedLabel.labelString und<br />

xsample*sampleComputedLabel.labelString.<br />

Entsprechend können im Programfenster ebenfalls zwei Flags eingeblendet werden. Das erste<br />

Flag zeigt an, daß der Inhalt des Textfensters nicht gesichert ist, das zweite Flag zeigt an, daß<br />

das angezeigte Programm aus der Synthese der angezeigten Beispielauswertung<br />

hervorgegangen ist. Die beiden Flags werden mit den Resourcen<br />

xsample*programUnsavedLabel.labelString und<br />

xsample*programSynthesizedLabel.labelString<br />

beschriftet.<br />

Der angezeigte Dateiname kann nur während der Laufzeit von [VDPSOH festgelegt werden. Es<br />

ist aber möglich, anzugeben, welcher Text an der Stelle des Dateinamens stehen soll, wenn<br />

kein Dateiname angegeben ist. Die Datei Sample enthält die folgenden Festlegungen:<br />

xsample*sampleFilename.labelString: -<br />

xsample*programFilename.labelString: -<br />

Standardmäßig kann in den Textfenstern eine angezeigte Beispielauswertung oder ein<br />

angezeigtes Programm verändert werden. Soll eine Beispielauswertung oder ein Programm vor<br />

versehentlichem Überschreiben geschützt werden, bietet [VDPSOH die beiden<br />

Kommandozeilenoprionen -sreadonly und -preadonly an. Es ist aber trotzdem möglich, den<br />

Schreibschutz für alle Aufrufe von zu [VDPSOH aktivieren. Dazu kann man die Resourcen<br />

xsample*sampleText.editable und<br />

xsample*programText.editable<br />

benutzen. Falls für die Resourcen der Wert 'False' eingetragen wird, so wird jeder Versuch, ein<br />

Zeichen in das entsprechende Textfenster einzufügen oder ein Zeichen vom entsprechenden<br />

Textfenster zu löschen, abgewehrt. Es wird nur ein Piepston ausgegeben, aber der angezeigte<br />

Text nicht verändert.<br />

Die Zahl der Zeilen und Spalten in jedem Textfenster kann über die Resourcen<br />

xsample*sampleText.rows,<br />

xsample*sampleText.columns,<br />

xsample*programText.rows und<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

xsample*programText.columns<br />

bestimmt werden. Standardmäßig enthalten beide Fenster 30 Zeilen und 50 Spalten. Die<br />

Größe der Textfenster kann aber auch über die Kommandozeile oder auch zur Laufzeit des<br />

Programmes durch Verändern der Größe des Fensters des Hauptformulars angepaßt werden.<br />

Über die Resourcen<br />

xsample*sampleText.pendingDelete und<br />

xsample*programText.pendingDelete<br />

kann entschieden werden, ob eine Selektion durch Eingabe eines Zeichens überschrieben wird.<br />

Der Standardwert für beide Resourcen ist 'True', womit diese Funktionalität aktiviert wird.<br />

Der Benutzer mag den Wert auf 'False' abändern, wenn er nicht wünscht, daß seine<br />

Selektionen überschrieben werden können.<br />

Mit den beiden Resourcen<br />

xsample*sampleForm*menuPost und<br />

xsample*programForm*menuPost<br />

wird angegeben, mit welcher Maustaste die Popupmenüs erschenen soll. Die Standardvorgabe<br />

hierfür ist . Dann wird das entsprechende Popupmenü aufgeklappt, solange<br />

innerhalb des Samplefenster oder innerhalb des Programfensters die rechte Maustaste<br />

gedrückt ist. Da die beiden anderen Maustasten für das Arbeiten mit Selektionen benötigt<br />

werden, bietet es sich nicht an, diese Maustasten für das Popupmenü zu verwenden. Aber ein<br />

Wert wie Shift wäre denkbar. in diesem Fall klappt das Popupmenü auf, wenn<br />

gleichzeitig die rechte Maustaste und die [SHIFT]-Taste gedrückt sind.<br />

Zusätzlich können zwei Tastenkombinationen festgelegt werden, mit denen die Popupmenüs<br />

angezeigt werden können, ohne die Maus zu benutzen. Hierfür stehen die folgenden Reosurcen<br />

bereit:<br />

xsample*sampleForm*menuAccelerator und<br />

xsample*programForm*menuAccelerator.<br />

Zur Festlegung der Überschrift über die Popupmenüs werden die Resourcen<br />

xsample*samplePopup*label.labelString und<br />

xsample*programPopup*label.labelSring<br />

verwendet. Die Standardvorgaben für diese Resourcen sind "Sample" und "Program".<br />

Für die Beschriftung der Menüpunkte im Popupmenü des Samplefensters enthält die Datei<br />

Sample die folgenden Vereinbarungen:<br />

xsample*samplePopup*loadSample.labelString: Load<br />

xsample*samplePopup*reloadSample.labelString: Reload<br />

xsample*samplePopup*saveAsSample.labelString: SaveAs<br />

xsample*samplePopup*saveSample.labelString: Save<br />

xsample*samplePopup*synthesize.labelString: Synthesize<br />

Entsprechend gilt für die Beschriftung der Einträge im Popupmenp des Programfensters:<br />

xsample*programPopup*loadProgram.labelString: Load<br />

xsample*programPopup*reloadProgram.labelString: Reload<br />

xsample*programPopup*saveAsProgram.labelString: SaveAs<br />

xsample*programPopup*saveProgram.labelString: Save<br />

xsample*programPopup*compute.labelString: Compute<br />

Wenden wir uns nun den Dialogfenstern zu. Der Text der Infobox wird im Quellcode von<br />

[VDPSOH festgelegt und kann vom Benutzer nicht verändert werden. Wohl aber kann das<br />

angezeigte Icon ausgetauscht werden über den Wert der Resource<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

xsample*infoBox.symbolPixmap.<br />

Der Wert dieser Resource muß eine Datei sein, die ein Bitmap enthält. Die Standardvorgabe<br />

für diese Datei ist xsample.bm.<br />

Der Fenstertitel für die Infobox wird in der Resource<br />

xsample*infoBox.dialogTitle<br />

angegeben.<br />

Die Infobox besitzt nur einen einzigen Pushbutton. Seine Aufschrift steht in der Resource<br />

xsample*infoBox.okLabelString.<br />

Es gibt insgesamt drei verschiedene Warnungsboxen, die den Benutzer daran erinnern, daß er<br />

im Begriff ist, den nicht gespeicherten Inhalt seiner Textfenster zu überschreiben. Die drei<br />

Warnungsboxen unterscheiden sich dahin, daß die Warnung sich auf das Samplefenster, das<br />

Programfenster oder auf beide Fenster beziehen kann. Zur Festlegung des Textes der drei<br />

Warnungsboxen stehen die folgenden Resourcen zur Verfügung:<br />

xsample*warningSample.messageString,<br />

xsample*warningProgram.messageString, sowie<br />

xsample*warningBoth.messageString.<br />

Zur Festlegung der Überschriften der drei Fenster werden die Resourcen<br />

xsample*warningSample.dialogTitle,<br />

xsample*warningProgram.dialogTitle und<br />

xsample*warningBoth.dialogTitle<br />

verwendet.<br />

Die Warnungsbox besitzt drei Pushbuttons. Über den linken Pushbutton wird die gewählte<br />

Operation fortgesetzt. Ihre Aufschrift steht in den Resourcen<br />

xsample*warningSample.okLabelString,<br />

xsample*warningProgram.okLabelString und<br />

xsample*warningBoth.okLabelString.<br />

Der mittlere Pushbutton bewirkt den Abruch der gewählten Operation. Zur Festlegung seiner<br />

Aufschrift werden die Resourcen<br />

xsample*warningSample.cancelLabelString,<br />

xsample*warningProgram.cancelLabelString und<br />

xsample*warningBoth.cancelLabelString<br />

zur Verfügung gestellt.<br />

Der rechte Pushbutton dient zum Aufruf der Hilfefunktion mit der Anforderung für Hilfe für<br />

die Warnungsbox. Die Aufschrift über diesen Pushbutton wird in den Resourcen<br />

xsample*warningSample.helpLabelString,<br />

xsample*warningProgram.helpLabelString und<br />

xsample*warningBoth.helpLabelString<br />

festgelegt.<br />

Für die Sicherheitsabfrage werden insgesamt sechs Dialogboxen verwendet, da es sechs<br />

Operationen gibt, die bestätigt werden müssen. Es sind dies New, Load Sample, Load<br />

Program, Reload Sample, Reload Program und Quit. Zur Bestimmung des Textes der<br />

Sicherheitsabfragen werden die folgenden Resourcen zur Verfügung gestellt:<br />

xsample*questionNew.messageString,<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

xsample*questionLoadSample.messageString,<br />

xsample*questionLoadProgram.messageString,<br />

xsample*questionReloadSample.messageString,<br />

xsample*questionReloadProgram.messageString und<br />

xsample*questionExit.messageString.<br />

Vollkommen analog zu den Warnungsboxen kann auch der Fenstertitel, sowie die Aufschrift<br />

auf den drei Pushbuttons festgelegt werden. Um die dazu notwendigen Resourcen zu erhalten,<br />

ersetzt man die Zeichenkette "messageString" durch "dialogTitle", "okLabelString",<br />

"cancelLabelString" oder "helpLabelString".<br />

Betrachten wir nun die Dateiauswahlbox. Es gibt zwei verschiedene Dateiauswahlboxen, je<br />

eine zu Auswahl eines Programmes und eine zur Auswahl einer Beispielauswertung. Die<br />

Fensterüberschriften werden durch die Resourcen<br />

xsample*sampleFileSelectionBox.dialogTitle und<br />

xsample*programFileSelectionBox.dialogTitle<br />

gesetzt. Für die Festlegung der Überschrift über dem Fenster des Dateifilters stehen die<br />

Resourcen<br />

xsample*sampleFileSelectionBox.filterLabelString und<br />

xsample*programFileSelectionBox.filterLabelString<br />

zur Verfügung.<br />

Der verwendete Dateifilter wird durch die folgenden Resourcen gesetzt:<br />

xsample*sampleFileSelectionBox.dirMask und<br />

xsample*programFileSelectionBox.dirMask.<br />

Die Standardwerte für die Resourcen sind '*.sc' für die Dateiauswahlbox der<br />

Beispielauswertungen und '*.pr' für die Dateiauswahlbox der Programme.<br />

Mit den Resourcen<br />

xsample*sampleFileSelectionBox.dirListLabelString und<br />

xsample*programFileSelectionBox.dirListLabelString<br />

bestimmt man die Überschrift über das Verzeichnisfenster. Analog kann man mit den<br />

Resourcen<br />

xsample*sampleFileSelectionBox.fileListLabelString und<br />

xsample*programFileSelectionBox.fileListLabelString<br />

die Überschrift über das Dateifenster und mit den Resourcen<br />

xsample*sampleFileSelectionBox.selectionLabelString und<br />

xsample*programFileSelectionBox.selectionLabelString<br />

die Überschrift über das Fenster des Dateinamens festlegen.<br />

Die Dateiauswahlboxen verfügen über vier Pushbuttons. Mit dem linken Button wird die<br />

Dateiauswahl abgeschlossen. Für die Festlegung der Aufschrift auf diesen Pushbutton dienen<br />

die Resourcen<br />

xsample*sampleFileSelectionBox.okLabelString und<br />

xsample*programFileSelectionBox.okLabelString.<br />

Die Aufschrift auf den zweiten Pushbutton, mit dem das aktuelle Verzeichnis erneut<br />

eingelesen werden kann, wird mit den Resourcen<br />

xsample*sampleFileSelectionBox.applyLabelString und<br />

xsample*programFileSelectionBox.applyLabelString<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

festgelegt. Mit dem dritten Pushbutton kann die gewählte Operation abgebrochen werden. Die<br />

Aufschrift auf diesen Button steht in den Resourcen<br />

xsample*sampleFileSelectionBox.cancelLabelString, sowie<br />

xsample*programFileSelectionBox.cancelLabelString.<br />

Der rechte Pushbutton dient zum Aufruf eines Hilfefensters mit einem Hilfetext über die<br />

Dateiauswahlbox. Ihre Aufschrift ist in den Resourcen<br />

xsample*sampleFileSelectionBox.helpLabelString und<br />

xsample*programFileSelectionBox.helpLabelString<br />

enthalten.<br />

Kommen wir nun zur Hilfebox. Neben der Darstellung der Hilfetexte werden in der Hilfebox<br />

auch Fehlermeldungen wiedergegeben. Es können beliebig viele Hilfeboxen gleichzeitig am<br />

Bildschirm angezeigt werden. In beiden Fällen wird die dargebotene Meldung nicht aus den<br />

Resourcen, sondern aus getrennten Datei bestimmt. Für die Festlegung des Fenstertitels steht<br />

die Resource<br />

xsample*helpBox.dialogTitle<br />

zur Verfügung.<br />

Die Hilfebox verfügt nur über zwei Pushbuttons. Mit dem linken Button wird die Box<br />

geschlossen, während mit dem rechten Button eine weitere Hilfebox mit einer weiteren<br />

Fehlermeldung geöffnet wird. Für die Festlegung der Aufschriften auf die beiden Button,<br />

können die Resourcen<br />

xsample*helpBox.okLabelString und<br />

xsample*helpBox.helpLabelString<br />

verwendet werden.<br />

Auch der Inhalt der Fehlerprotokollbox wird von [VDPSOH zur Laufzeit festgelegt. Es können<br />

beliebig viele Fehlerprotokollboxen gleichzeitig angezeigt werden. Der Fenstertitel kann über<br />

die Resource<br />

xsample*logBox.dialogTitle<br />

bestimmt werden.<br />

Wie die Hilfebox, so hat auch die Fehlerprotokollbox zwei Buttons, mit denen die Box<br />

geschlossen werden kann oder eine Hilfetext angefordert werden kann. Für die Aufschriften<br />

auf diesen Pushbuttons stehen die Resourcen<br />

xsample*logBox.okLabelString und<br />

xsample*logBox.helpLabelString<br />

bereit.<br />

Da die Größe der Fehlerprotokolldatei unbeschränkt ist und damit auch die Größe des<br />

Bildschirms überschreiten kann, ist es notwendig, die Größe der Fehlerprotokollbox<br />

festzusetzen. Höhe und Breite der Anzeigefläche werden durch die Resourcen<br />

xsample*logBox*scrolledLog.width und<br />

xsample*logBox*scrolledLog.height<br />

vorgegeben. Die Standardwerte dieser Resourcen sind 400 Pixel und 250 Pixel.<br />

Über die Resource<br />

xsample*logBox*scrolledLog.scrollBarDisplayPolicy<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

kann bestimmt werden, ob die Scrollbars innerhalb der Fehlerprotokollbox immer angezeigt<br />

werden sollen, oder nur dann, wenn das Fehlerprotokoll die festgelegten Dimensionen der<br />

Anzeigefläche überschreitet. Der Standardwert für diese Resource ist AS_NEEDED. Dann<br />

wird die Scrollbar nur bei Bedarf angezeigt. Soll die Scrollbar dagegen immer angezeigt<br />

werden, so ist für diese Resource der Wert STATIC einzusetzen.<br />

Die Farben für den Vordergrund und den Hintergrund des Hauptformulars werden durch die<br />

Resourcen<br />

xsample*background und<br />

xsample*foreground<br />

bestimmt.<br />

Die Farbe der Menüleiste wird mit der Resource<br />

xsample*menu*background<br />

geregelt. Da keine Vordergrundfarbe gesetzt wird, wird die Vordergrundfarbe des<br />

Hauptformulars verwendet.<br />

Die Vorder- und Hintergrundfarbe des Überschriftslabel des Samplefenster, sowie die Farbe<br />

des Randes kann mit den Resourcen<br />

xsample*sampleTitle*background,<br />

xsample*sampleTitle*foreground und<br />

xsample*sampleTitle*borderColor<br />

festgelegt werden. Analog gibt es für das Überschriftslabel des Programfensters die Resourcen<br />

xsample*programTitle*background,<br />

xsample*programTitle*foreground und<br />

xsample*programTitle*borderColor.<br />

Die Hintergrundfarbe der Textfenster wird mit den Resourcen<br />

xsample*sampleText*background und<br />

xsample*programText*background<br />

bestimmt. Entsprechend werden die Vordergrundfarben der beiden Textfenster durch die<br />

folgenden Resourcen gegeben:<br />

xsample*sampleText*foreground und<br />

xsample*programText*foreground.<br />

Zur Bestimmung der Farbe des Randes der Textfenster benutzt man die Resourcen<br />

xsample*sampleText*borderColor und<br />

xsample*programText*borderColor.<br />

Über die Resourcen<br />

xsample*sampleText*borderWidth und<br />

xsample*programText*borderWidth<br />

kann die Breite des Randes des Randes der Textfenster gesetzt werden.<br />

Zum Setzen der Vorder- und Hintergrundfarbe der Pushbuttons in der Pushbuttonzeile können<br />

dir folgenden Resourcen verwendet werden:<br />

xsample*synthesizeButton*background,<br />

xsample*computeButton*background,<br />

xsample*quitButton*background,<br />

xsample*helpButton*background,<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

xsample*synthesizeButton*foreground,<br />

xsample*computeButton*foreground,<br />

xsample*quitButton*foreground und<br />

xsample*helpButton*foreground.<br />

Mit den Resourcen<br />

xsample*warningSample*background,<br />

xsample*warningSample*foreground,<br />

xsample*warningSample*bordercolor,<br />

xsample*warningProgram*background,<br />

xsample*warningProgram*foreground,<br />

xsample*warningProgram*bordercolor,<br />

xsample*warningBoth*background,<br />

xsample*warningBoth*foreground und<br />

xsample*warningBoth*bordercolor<br />

legt man Vordergrund-, Hintergrund- und Randfarbe für die Warnungsbox fest.<br />

Analog exitieren für die Abfragebox die Resourcen:<br />

xsample*questionNew*background,<br />

xsample*questionNew*foreground,<br />

xsample*questionNew*bordercolor,<br />

xsample*questionLoadSample*background,<br />

xsample*questionLoadSample*foreground,<br />

xsample*questionLoadSample*bordercolor,<br />

xsample*questionLoadProgram*background,<br />

xsample*questionLoadProgram*foreground,<br />

xsample*questionLoadProgram*bordercolor,<br />

xsample*questionReloadSample*background,<br />

xsample*questionReloadSample*foreground,<br />

xsample*questionReloadSample*bordercolor,<br />

xsample*questionReloadProgram*background,<br />

xsample*questionReloadProgram*foreground,<br />

xsample*questionReloadProgram*bordercolor,<br />

xsample*questionExit*background,<br />

xsample*questionExit*foreground und<br />

xsample*questionExit*bordercolor.<br />

Der Hintergrund der Dateiauswahlbox wird durch die Resourcen<br />

xsample*sampleFileSelectionBox.background und<br />

xsample*programFileSelectionBox.background<br />

bestimmt.<br />

Die Farben der Hilfebox sind in den Resourcen<br />

xsample*helpBox*background,<br />

xsample*helpBox*foreground und<br />

xsample*helpBox*bordercolor<br />

abgelegt. Entsprechend sind für die Farben der Fehlerprotokollbox die Resourcen<br />

xsample*logBox*background,<br />

xsample*logBox*foreground,<br />

xsample*logBox*bordercolor und<br />

6HLWH


$QKDQJ%5HVRXUFHQ<br />

xsample*logBox*logLabel.background<br />

bestimmt.<br />

6HLWH


$QKDQJ&4XHOOWH[W<br />

Anhang C Quelltext<br />

Das Werkzeug ist in der Programmiersprache C++ geschrieben. Der Quelltext des<br />

Programmes einschließlich der Spezifikationen der einzelnen Klassen und Funktionen liegt auf<br />

dem SUN-SPARC-Cluster der AG Wiehagen und kann auf Wunsch eingesehen werden. Eine<br />

Verwendung des Quelltextes gleich welcher Art ist jedoch nur mit Einwilligung des Autors<br />

gestattet. Der Quelltext für das Werkzeug besteht aus den folgenden Dateien:<br />

Tabelle 15 : Die Dateien des Quellcodes<br />

Komponente/Unterkomponente Datei Lines of Code<br />

Interface/Main<br />

xsample.h<br />

xsample.cxx<br />

89<br />

146<br />

Interface/CommandLine commandline.h<br />

commandline.cxx<br />

156<br />

331<br />

Interface/<br />

GraphicalUserInterface<br />

gui.h<br />

gui.cxx<br />

134<br />

1263<br />

Interface/Callback<br />

callback.h<br />

callback.cxx<br />

517<br />

1854<br />

Interface/Messages<br />

messages.h<br />

messages.cxx<br />

143<br />

442<br />

Interface/EventHandler eventhandler.h<br />

eventhandler.cxx<br />

77<br />

59<br />

Interface/Error<br />

error.h<br />

error.cxx<br />

378<br />

227<br />

Interface/Help<br />

help.h<br />

help.cxx<br />

106<br />

111<br />

Interface/HelpError<br />

helperror.h<br />

helperror.cxx<br />

95<br />

146<br />

Interface/HelpErrorText helperrortext.h<br />

helperrortext.cxx<br />

118<br />

168<br />

Înterface/Operations operations.h<br />

operations.cxx<br />

368<br />

556<br />

Interface/ExtendedOperations xoperations.h<br />

xoperations.cxx<br />

506<br />

868<br />

Interface/Connection connection.h<br />

connection.cxx<br />

116<br />

74<br />

Text<br />

text.h<br />

text.cxx<br />

280<br />

222<br />

SampleText<br />

sampletext.h<br />

sampletext.cxx<br />

245<br />

154<br />

ProgramText<br />

programtext.h<br />

programtext.cxx<br />

234<br />

153<br />

Synthesizer<br />

synthesizer.h<br />

synthesizer.cxx<br />

131<br />

1852<br />

Computer<br />

computer.h<br />

computer.cxx<br />

133<br />

254<br />

Parser/SampleComputation samplecomputation.h<br />

samplecomputation.cxx<br />

386<br />

1170<br />

Parser/Program program.h 545<br />

6HLWH


$QKDQJ&4XHOOWH[W<br />

Parser/Basic<br />

Parser/Scanner<br />

Parser/Variable<br />

program.cxx 1865<br />

basic.h<br />

398<br />

basic.cxx<br />

88<br />

scanner.h<br />

293<br />

scanner.cxx<br />

535<br />

variable.h<br />

354<br />

variable.cxx<br />

526<br />

18866<br />

6HLWH


$QKDQJ'9HU]HLFKQLVGHUYHUZHQGHWHQ/LWHUDWXU<br />

Anhang D Verzeichnis der verwendeten Literatur<br />

[1] Stroustrup Bjarne: Die C++-Programmiersprache, 2. Auflage: Bonn, München,<br />

Paris: Addison-Wesley 1992<br />

[2] Gottheil K. et. al.: X und Motif: Einführung in die Programmierung des Motif-<br />

Toolkits und des X-Windows-Systems: Berlin et. al.: Springer 1992<br />

[3] Nye Adrian: Xlib Programming Manual, 3. Auflage: Sebastopol: O'Reilly &<br />

Associates 1992<br />

[4] Nye Adrian: Xlib Reference Manual, 3. Auflage: Sebastopol: O'Reilly & Associates<br />

1992<br />

[5] Nye Adrian, O'Reilly Tim: X Toolkit Intrinsics Programming Manual, Motif<br />

Edition, 3. Auflage: Sebastopol: O'Reilly & Associates 1993<br />

[6] Flanagan David: X Toolkit Intrinsics Reference Manual, 3. Auflage: Sebastopol:<br />

O'Reilly & Associates 1992<br />

[7] Heller Dan, Fergusan Paula: Motif Programming Manual, 2. Auflage: Sebastopol:<br />

O'Reilly & Associates 1994<br />

[8] Ferguson, Paula M., Motif Reference Manual: Sebastopol : O'Reilly & Associates<br />

1993<br />

[9] Aho, Alfred et al.: Compilerbau: Bonn et. al.: Addison-Wesley 1988<br />

[10] Kopp Herbert, Compilerbau, Grundlagen, Methoden, Werkzeuge: München, Wien:<br />

Hanser 1988<br />

[11] Louden Keneth C., Programming Languages: principles and practice: Boston: PWS-<br />

Kent 1993<br />

[12] Kowalk Wolfgang P., Korrekte Software: Semanik, Spezifikation, Verifikation und<br />

Testen von Programmen: Mannheim et. al.: BI-Wissenschaftsverlag 1993<br />

[13] Hopcroft John E., Ullman Jeffrey D.: Einführung in die Automatentheorie, formale<br />

Sprachen und Komplexitätstheorie, 2. Auflage: Reading et. al.: Addison-Wesley<br />

1990<br />

[14] Kinber E. B.: „Inductive Synthesis of Programs for Recursive Functions from<br />

Sample Computations“. Inform. Process. Cybern. EIK 25 (1989) 8/9, S. 435-456<br />

6HLWH


,QGH[<br />

Index<br />

A<br />

Aktionsfenster 225<br />

Algorithmus 7<br />

Alphabet 39<br />

Anweisung 17, 39<br />

Anweisungssequenz 39<br />

Äquivalenz 59<br />

Äquivalenzrelation 60<br />

Ausdruck 39<br />

Ausgabevariable 17<br />

Auswertung 18<br />

B<br />

Batch-Mode 222<br />

Beispielauswertung 58, 67, 85<br />

Beispielauswertungsfragment 59<br />

Benutzeroberfläche 222, 233<br />

Benutzerschnittstelle 205<br />

Bezeichner 39<br />

Clipboard 236<br />

Dateiauswahl 237<br />

Datenverkehr 227<br />

Dekrement 18, 39<br />

Dialogfenster 236<br />

C<br />

D<br />

E<br />

Eingabekonstrukt 39<br />

Eingabemenge 53<br />

Eingabevariable 17, 40<br />

Entfaltung 45<br />

Fehlermeldungen 240<br />

Fehlerprotokoll 240<br />

F<br />

if-Konstrukt 196<br />

Initialisation 18<br />

Initialisationskonstante 43<br />

Initialisationskonstrukt 39, 41<br />

Initialisationssequenz 39<br />

Inkrement 18, 39<br />

I<br />

K<br />

Klasse-I-Beispielauswertung 86, 181<br />

Klasse-II-Beispielauswertung 190<br />

Klasse-III-Beispielauswertung 198<br />

Klasse-III-Programm 198<br />

Klasse-II-Programm 189<br />

Klasse-I-Programm 86, 181<br />

Kodierungsfunktion 26<br />

Kommandozeile 207<br />

Kommandozeilenoptionen 220<br />

Konstante 43<br />

konstantenbereinigte Form 63<br />

Makro 199<br />

Menü 224, 227<br />

Menüzeile 224, 227<br />

M<br />

P<br />

partiell rekursive Funktion 25<br />

Popupmenü 226, 229<br />

primitiv rekursive Funktion 22<br />

Programm 43<br />

Programmfragment 43<br />

Programmkonstante 43<br />

Programmtext 39<br />

Programmvariable 41<br />

Pushbuttonzeile 226<br />

Registermaschine 32<br />

Resourcen 263<br />

R<br />

H<br />

Hauptanweisungssequenz 40<br />

Hauptformular 223<br />

Hauptvariable 42<br />

Hilfe 239<br />

6HLWH


,QGH[<br />

S<br />

Schachtelungstiefe 44<br />

Schleife 18<br />

Schlüsselworte 39<br />

Selektion 235<br />

Sicherheitsabfrage 236<br />

String 39<br />

Strukturäquivalenz 47<br />

Synthese 85<br />

T<br />

Tear-Off-Menü 230<br />

Textfenster 225, 233<br />

Trennzeichen 39<br />

Turingmaschine 17, 29<br />

V<br />

Variable 17, 41, 42, 189<br />

Variablenliste 67<br />

Variablensubstitution 60<br />

Vererbung 203<br />

Vorkommen 46<br />

W<br />

Warnungen 237<br />

WHILE 7, 39<br />

WHILE-berechenbar 22<br />

while-Konstrukt 39, 181<br />

WHILE-Programm 17, 18, 85<br />

WHILE-Programme 39<br />

Wort 42<br />

Z<br />

Zeichenvorrat 39<br />

6HLWH

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

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!