Diplomarbeit Fachbereich Informatik
Diplomarbeit Fachbereich Informatik
Diplomarbeit Fachbereich Informatik
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