commit 412a71a7c0d604919046c788820f1d264cf31af7 Author: Max Rottenkolber Date: Sun Jul 26 20:44:19 2015 +0200 Add MicroLisp documentation. diff --git a/software/microlisp/microlisp-architektur.mk2 b/software/microlisp/microlisp-architektur.mk2 new file mode 100644 index 0000000..3cd828f --- /dev/null +++ b/software/microlisp/microlisp-architektur.mk2 @@ -0,0 +1,617 @@ +< Ausgangssituation + + < Projektziele und Kundenwünsche + + Im Rahmen des *MicroLisp-Projekts* soll eine Umgebung für die + Entwicklung von Programmen für die _MicroTouch_-Plattform produziert + werden. Die Entwicklungsumgebung soll sowohl einen Kompilierer als auch + einen Emulator bereit stellen, die jeweils den entworfenen Lisp-Dialekt + _MicroLisp_ implementieren. + + Der Kunde will die Entwicklung von Anwendungen für die + _MicroTouch_-Plattform erleichtern und beschleunigen, indem er den + direkten Kontakt mit gerätenahen Sprachen wie _C_ und + _Assemblersprache_ vermeidet. Die _MicroLisp_-Sprache soll durch ihre + Dynamik und Ausdrucksstärke einen wesentlich unaufwendigeren + Entwicklungsprozess ermöglichen. Sie soll über eine *automatisierte + Speicherbereinigung* verfügen, den _Lambda-Calculus_ implementieren und + *plattformspeziefische Operationen* wie Ein- und Ausgabe unterstützen. + Außerdem soll die Sprache durch ein _Makrosystem_ erweiterbar sein. + + Mit Beendigung des Projekts soll das Verhältnis zwischen Kosten und + Nutzen abgewogen werden. Hierbei soll insbesondere überprüft werden, ob + die erwartete *Produktivitätssteigerung* erreicht wurde. + + > + + < Teilaufgaben des Projekts + + Der Entwicklung der benötigten Softwarekomponenten geht eine + umfangreiche Planung voraus. Die Planung beinhaltet alle Komponenten + und ihre internen Schnittstellen im System. Zusätzlich muss die + Interaktion mit Schnittstellen außerhalb des Systems geplant werden. + + Die Entwicklungsumgebung besteht aus mehreren Software-Komponenten die + in Zusammenarbeit Programme für die zwei Endpunkte, Kompilation und + Emulation, generieren. Zusätzlich gibt es eine _Standardbibliothek_ + die die Sprache mit grundlegenden Prozeduren und _Makros_ anreichert. + + Die *Analysatorkomponente* liest eine _MicroLisp_-Quelldatei und + erzeugt einen _abstrakten Syntaxbaum_. Die *Makrokomponente* + transformiert den _abstrakten Syntaxbaum_ mit Hilfe von + _Makroprozeduren_, die unter anderem in einer _Standardbibliothek_ + definiert sind. Danach kann das Programm entweder durch die + *Emulationskomponente* in der Entwicklungsumgebung interaktiv + ausgeführt oder durch die *Kompilationskomponente* in _C_-Quelltext + umgewandelt werden. Das resultierende _C_-Programm greift auf die + *Laufzeitkomponente* zurück, um erweiterte Funktionalitäten von + _MicroLisp_ zu ermöglichen. Die Entwicklung jeder Komponente stellt + eine Teilaufgabe dar. Die Komponenten müssen außerdem auf + Funktionalität und Korrektheit getestet werden. + + #media 1.1 Die Komponenten im Überblick.# + komponenten.png + + Abschließend soll angesichts einer Kosten-Nutzen-Analyse getestet + werden ob die _MicroLisp_-Entwicklungsumgebung die Projektziele erfüllt. + Dazu wird eine Testanwendung mit _MicroLisp_ und in _ANSI C_ entwickelt + und die Ergebnisse werden verglichen. + + > + + < Projektumfeld und Schnittstellen + + Die _MicroLisp_-Sprache ist ein _Lisp-Dialekt_. Eine detaillierte + Definition der Sprache kann in der _MicroLisp_-Bedienungsanleitung + gefunden werden. + + _MicroLisp_-Programme sollen in _ANSI C_-Quelltext und von dort aus + wiederum in Maschinenanweisungen für _Atmel AVR_ \[Atmel AVR\] + Prozessoren kompiliert werden. Da die _MicroTouch_-Plattform sehr stark + begrenzte Hardware-Ressourcen bietet, sollen die resultierenden + Programme die Ressourcen des Geräts möglichst schonen. + + Der größte Teil der Komponenten soll in _Common Lisp_ geschrieben + werden, daher wird eine Schnittstelle die _SBCL Common + Lisp_-Implementation sein. Sie wird die Plattform sein, auf der die + Entwicklungsumgebung ausgeführt wird. Eine weitere Schnittstelle des + Systems wird die _GNU Compiler Collection_, die die generierten + _C_-Programme in Maschinenanweisungen übersetzen soll. + + #media 1.2 Systemlandschaft im Überblick.# + systemlandschaft.png + + > + +> + +< Ressourcen- und Ablaufplanung + + < Ressourcenplanung + + Die für das _MicroLisp_-Projekt benötigten materiellen Ressourcen + bleiben aufgrund der Software-Lastigkeit des Projekts sehr + überschaubar. Für die Planung, Entwicklung und Dokumentation der + Komponenten wird mindestens ein Software-Entwickler für die + festgesetzte Dauer von 70 Stunden benötigt. + + An Sachmitteln fällt ein Arbeitsplatz mit einem Desktop-Computer an. + Dieser muss in der Lage sein, ein _UNIX_-artiges Betriebssystem + auszuführen, welches wiederum die _GNU Compiler Collection_ und die + _SBCL Common Lisp_-Implementation unterstützen muss. + + Bis auf die Personalkosten, den Desktop-Computer und den Arbeitsplatz + fallen keine Kosten an. Die benötigte Software ist _Open Source_ + und frei verfügbar. Als Betriebssystem kann eine frei erhältliche + _UNIX_-Variante wie _BSD_ oder _Linux_ verwendet werden. + + > + + < Ablaufplanung + + Zuerst muss das System und seine Architektur geplant werden. Die als + erstes zu programmierende Komponente ist der Analysator. Danach können + die Makro- und Emulatorkomponenten parallel programmiert werden. Wenn + die oben genannten Komponenten einsatzbereit sind, ist bereits eine + repräsentative Ausführungsumgebung für die _MicroLisp_-Sprache + implementiert. Somit kann die Programmierung der _Standardbibliothek_ + beginnen und eine _Test-Suite_ für die Sprache geschrieben werden. + + Mit der _Test-Suite_ müssen dann die primitiven Operatoren der + Sprache, sowie die Prozeduren und _Makros_ der _Standardbibliothek_ + auf Korrektheit und Integrität getestet werden. Somit soll schon + frühzeitig die Funktionalität der Sprache sichergestellt werden können. + Außerdem ist es bereits möglich zu prüfen, ob die Sprache die + Anforderungen an die Produktivitätssteigerung beim Programmieren + erfüllt. + + Wenn die Tests zeigen, dass ein zufriedenstellender Stand erreicht ist, + kann mit der Programmierung der _Laufzeitumgebung_ und der + Kompilationskomponente begonnen werden. Wenn beide Komponenten + funktionstüchtig sind, kann _MicroLisp_-Quelltext in lauffähigen + _C_-Quellcode übersetzt werden. + + Um die Integrität der Kompilationskomponente und die Korrektheit der + _Laufzeitumgebung_ zu gewährleisten, wird mithilfe der _Test-Suite_ die + Funktionalität beider Komponenten getestet. Dabei wird besonderer Wert + auf die Korrektheit interner Vorgänge der Laufzeitkomponente gelegt. + + Wenn die Tests ein überzeugendes Ergebnis liefern, kann die + Kosten-Nutzen-Analyse durchgeführt werden. Dazu wird eine ausreichend + komplexe Testanwendung sowohl in _MicroLisp_ als auch in _C_ + programmiert. Die resultierenden Anwendungen werden unter den + Gesichtspunkten Quelltext-Komplexität, Performanz, Wartbarkeit und + Erweiterbarkeit verglichen. Anhand dieses Vergleichs soll die + Rentabilität des _MicroLisp_-Projekts beurteilt werden. + + In Anhang 1 ([#section-5-1]) wird der oben beschriebene Ablaufplan + durch ein Flussdiagramm visuell dargestellt. + + Aus der Ablaufplanung lassen sich mehrere zentrale Termine entnehmen. + Dazu gehören wichtige *Meilensteine* in der Programmierung der + Komponenten sowie die drei *Testphasen*. In Abbildung 2.2 werden die + Termine tabellarisch zusammengefasst. Die Terminplanung berücksichtigt + einen Zeitraum von zehn Stunden für das Verfassen der + Projektdokumentation. + + #table 2.2 Termine aus der Ablaufplanung.# + | Tag | Teilaufgabe + | Tag 2 | Meilenstein 1: Erste repräsentative Ausführungsumgebung + | Tag 4 | Testphase 1: Analysator-, Makro-, Emulationskomponente und Standardbibliothek + | Tag 6 | Meilenstein 2: Lauffähige C-Programme können erzeugt werden + | Tag 7 | Testphase 2: Laufzeitumgebung und Kompilationskomponente + | Tag 8 | Testphase 3: Kosten-Nutzen-Analyse durch Testanwendung + + > + +> + +< Durchführung und Auftragsbearbeitung + + < Vorgehensweise & architektonische Entscheidungen + + Die Projektdurchführung beginnt, wie in Abbildung 2.1 veranschaulicht + wird, mit der Planung der Systemarchitektur. Ich entscheide mich, wie + in Abbildung 1.1 dargestellt wird, für eine modulare Architektur. Diese + trennt Softwarekomponenten mit unabhängigen Funktionalitäten sauber von + einander ab. Quelltext 3.1 veranschaulicht wie das System + Subkomponenten, ohne geteilten Status oder verknüpfter Semantik, + in einer Oberprozedur kombiniert. + + #code 3.1 Definition der Emulationsfunktion {evaluate}.# + + (defun evaluate (expression environment) + "Evaluate MicroLisp EXPRESSION in ENVIRONMENT." + (evaluate-expanded-expression + (expand-expression expression *macros*) + environment)) + # + + Diese Art der Programmierung hat den Vorteil, dass ausgehend vom + Quelltextbeispiel 3.1 die Prozedur {evaluate-expanded-expression} + unabhängig von der Prozedur {expand-expression} definiert werden kann. + Gleichermaßen benötigt die Oberprozedur {evaluate} keine Informationen + über Implementationsdetails der anderen beiden Prozeduren, um sie + anzuwenden. Diese Eigenschaften erleichtern nachträgliche Änderungen + und Erweiterungen an Systemkomponenten und beschränken die Komplexität + des gesamten Systems. + + Die Analysatorkomponente kann mit geringem Aufwand entwickelt werden, + da die _MicroLisp_-Sprache und _Common Lisp_ untereinander Syntaxregeln + teilen. Die benötigten Prozeduren zum Einlesen von + _MicroLisp_-Quelldateien werden von _Common Lisp_ zur Verfügung + gestellt. Diese generieren einen _abstrakten Syntaxbaum_ der als + verschachtelte _Listenstruktur_ repräsentiert wird. Die in Abbildung + 3.2 veranschaulichte Repräsentationsform, ermöglicht es + _MicroLisp_-Quelltext mit geringem Aufwand zu verarbeiten. + + #media 3.2 Interne Repräsentation des _abstrakten Syntaxbaums_. + Dargestellt durch die so genannte "Box and Pointer"-Notation.# + ast.png + + Nun können Makrokomponente und Emulationskomponente parallel entwickelt + werden. Weil ich alleine am _MicroLisp_-Projekt arbeite, entscheide ich + mich dafür die Makrokomponente als erstes zu implementieren. Diese + Komponente sucht in einem _Abstrakten Syntaxbaum_, ausgegeben von der + Analysatorkomponente, nach Ausdrücken, für die in einer _Makrotabelle_ + ein _Makro_ definiert ist und dehnt die Ausdrücke mithilfe des _Makros_ + aus. + + #code 3.3 Signatur der Prozedur zum Suchen und Ausdehnen von + _Makroausdrücken_.# + + (defun expand-expression (expression macros) + "Expand MACROS in EXPRESSION and return expanded expression." + [...]) + # + + Ein _Makro_ ist als eine Prozedur implementiert, die als Parameter die + Argumente eines _Makroausdrucks_ annimmt und einen neuen Ausdruck als + Rückgabewert hat. Quelltext 3.4 zeigt eine einfache _Makroprozedur_. + + #code 3.4 _Makroprozedur_ die einen klassischen {if}-Ausdruck zu einem + {cond}-Ausdruck ausdehnt.# + + (lambda (condition then else) + `(cond (,condition ,then) + (t ,else))) + # + + Angenommen die Prozedur {expand-expression} aus Quelltext 3.3 findet + einen Ausdruck in der Form {(if BEDINGUNG WAHR-AUSDRUCK + FALSCH-AUSDRUCK)}, übergibt diesen Ausdruck an die _Makroprozedur_ + aus Quelltext 3.4 und ersetzt ihn mit dem Rückgabewert, dann lautet der + ausgedehnte Ausdruck {(cond (BEDINGUNG WAHR-AUSDRUCK) (t + FALSCH-AUSDRUCK))}. So wurde der _MicroLisp_-Sprache mithilfe des + _Axioms_ {cond} ein neues Kontrollkonstrukt {if} hinzugefügt. + + Die Entwicklung der Emulationskomponente birgt zwei Hauptprobleme: Die + Umsetzung von _Axiomen_ und die Implementation von Prozeduren. Die + _MicroLisp-Axiome_ und -Datentypen lassen sich mithilfe von _Common + Lisp_ mit wenig Aufwand umsetzten, weil beide Sprachen auf den gleichen + Kernfunktionen aufbauen. Es müssen lediglich die _MicroLisp-Axiome_ und + -Datentypen den entsprechenden Operatoren aus _Common Lisp_ zugeordnet + werden. + + #code 3.5 Ausschnitt aus der Emulationskomponente: Umsetzung des + {add}-Axioms.# + + (add (+ (evaluate (first call-arguments) environment) + (evaluate (second call-arguments) environment))) + # + + Quelltext 3.5 zeigt eine Klausel aus einem {case}-Ausdruck. Jedes + _Axiom_ wird in einer Klausel wie dieser implementiert. Das + {add}-_Axiom_ zum Addieren von Zahlen wird umgesetzt, indem die + Argumente (_MicroLisp-Ausdrücke_) mit der Emulationskomponente rekursiv + ausgewertet werden und mit dem _Common Lisp_ Additionsoperator {+} + summiert werden. + + _MicroLisp_-Prozeduren müssen einer essentiellen Anforderung gerecht + werden. Sie müssen den _lexikalischen Sichtbarkeitsbereich_ von + _Bezeichnern_ innerhalb ihres Körpers, genannt _Funktionsabschluss_, + implementieren. Dafür muss die Zuordnung von _Bezeichnern_ und Werten, + auch _Environment_ genannt, zur Zeit der Prozedurdefinition konserviert + werden. + + #code 3.6 _Konstruktor_ für eine Prozedur.# + + (defun make-procedure (lambda-expression environment) + "Return new procedure consisting of LAMBDA-EXPRESSION and + ENVIRONMENT." + (unless (lambda-p lambda-expression) + (error "~a is not a valid lambda expression." + lambda-expression)) + (list 'procedure + lambda-expression + environment)) + # + + Quelltext 3.6 zeigt wie der _Konstruktor_ {make-procedure} ein + Prozedurobjekt _instanziiert_. Er übernimmt einen _Lambda-Ausdruck_ und + ein _Environment_ als Parameter und gibt ein Objekt zurück, das den + _Lambda-Ausdruck_ mit dem _Environment_ verknüpft. Wenn eine Prozedur + aufgerufen wird, werden die _Bezeichner_ im Körper der Prozedur + mithilfe des konservierten _Environments_ Werten zugeordnet. + + Die initiale _Standardbibliothek_ beinhaltet Prozeduren und _Makros_, + die der Entwicklung der _Test-Suite_ erleichtern. Die Implementation + dieser ist nicht zwangsweise trivial, jedoch spielt sie im Rahmen des + _MicroLisp_-Projekts eine geringfügige Rolle und wird deswegen nicht + genauer erläutert. + + Als nächstes wird die wichtigste und komplexeste Komponente, die + _Laufzeitumgebung_ entwickelt. Die Repräsentation von Werten stellt die + erste Herausforderung dar. Aufgrund der dynamischen Eigenschaften von + _MicroLisp_ muss die statische Typisierung von _C_ umgangen werden. + + #code 3.7 Definition des {value}-Typs durch geschickte Ausnutzung von + _C_ {struct}- und {union}-_Ausdrücken_.# + + enum type { PROCEDURE, CELL, SYMBOL, NUMBER, CHARACTER }; + + [...] + + typedef struct { + enum type type; + struct symbol *symbol; + } symbol; + + [...] + + union value { + enum type type; + procedure procedure; + cell cell; + symbol symbol; + number number; + character character; + }; + + typedef union value value; + # + + Quelltext 3.7 zeigt, wie die Typen der _MicroLisp_-Sprache zu einem Typ + {value} zusammengefasst werden. Alle Typen sowie die {value} {union} + haben ein Feld {type}. Dieses ermöglicht den speziellen Typ eines + {value}-Objekts zu ermitteln. So können _MicroLisp_-Objekte innerhalb + der _Laufzeitumgebung_ einheitlich als {value}-Objekt herumgereicht + werden. Diese Technik impliziert, dass die primtiven Operatoren die + Typen von Objekten zur _Laufzeit_ überprüfen müssen, um + _Speicherzugriffsfehler_ zu vermeiden. + + Anders als bei der Emulationskomponente müssen die _Axiome_ und + Datentypen der Sprache von Hand implementiert werden. Beispielsweise + müssen in _Symbole_ mit _C_ Strukuren implementiert werden. + + #code 3.8 Struktur und Schnittstelle des {symbol}-Typs.# + + /* symbol-structure: Symbol structure. */ + + struct symbol { + unsigned long identifier; + char *name; + }; + + + /* symbol: Constants and prototypes for symbol functions. */ + + #define T new_symbol("T") + #define NIL NULL + + symbol *new_symbol (char *); + symbol *symbolic_equality (symbol *, symbol *); + symbol *symbol_p (value *); + # + + Quelltext 3.8 zeigt Details der internen Repräsentation von + _Symbolen_. Die Prozedur {new_symbol} wird verwendet um _Symbole_ aus + _Literalen_ zu erzeugen. Sie nimmt einen Namen in Form einer + Zeichenkette als Parameter und gibt das entsprechende _Symbol_ zurück. + Weil _Symbole_ einzigartig sind und es aber mehrere _Instanzen_ von + einem _Symbol_ geben kann werden sie nicht im {symbol}-Objekt + gespeichert. Stattdessen sucht {new_symbol} in einer Tabelle nach einer + {symbol}-Struktur mit gleichem Namen. Wenn keine passende Struktur + gefunden wird, fügt {new_symbol} einen neuen Eintrag für ein _Symbol_ + mit dem Namen und einem eindeutigen Schlüssel in die Tabelle ein. + Anschließend wird ein {symbol}-Objekt mit einem _Zeiger_ auf die + entsprechende Struktur zurückgegeben. + + Es sind zwei spezielle _Symbole_ {T} und {NIL} vordefiniert, + konventionell indizieren sie die _Wahrheitswerte_. Die Prozedur + {symbolic_equality} entspricht dem {symbolic=}-_Axiom_. Sie gibt {NIL} + zurück, wenn die Schlüssel der übergebenen _Symbole_ nicht gleich + sind. Die Prozedur {symbol_p} entspricht dem {symbol?}-_Axiom_ und gibt + {NIL} zurück wenn das übergebene Objekt nicht vom Typ {symbol} ist, wie + sich durch das uniforme {type}-Feld des {value}-Typs feststellen lässt. + + Die Implementation des {symbol}-Typs ermöglicht den effizienten + Vergleich von _Symbolen_ anhand eines numerischen Schlüssels, anstatt + zum Beispiel einer Zeichenkette. Weil _Symbole_ primär als Schlüssel + verwendet werden, sind die Eigenschaften dieser Implementation + essenziell für die Performanz der Sprache. + + Die _MicroLisp_-Sprache soll automatisierte _Speicherbereinigung_ + implementieren. Standardmäßig unterstützt _C_ jedoch nur manuelle + Speicherverwaltung. Um diese Diskrepanz zu überwinden, wird ein + schlanker _Referenzzählender Garbage Collector_ mit folgender + Schnittstelle implementiert. + + #code 3.9 Schnittstelle des _Garbage Collectors_.# + + void use (value *); + void disuse (value *); + void collect_garbage (void); + # + + Die {use}-Prozedur inkrementiert den _Referenzzähler_ eines Objekts. + Dieser _Referenzzähler_ wird in einer _Hashtabelle_ gespeichert, die + die _Speicheradressen_ der Objekte als Schlüssel verwendet. Wenn ein + Objekt noch keinen Eintrag in der Referenztabelle hat wird dieser von + {use} eingefügt. Die {disuse}-Prozedur dekrementiert den + _Referenzzähler_ eines Objekts. Die {collect_garbage}-Prozedur + befreit den Speicherplatz, der von _Speicheradressen_ in der + Referenztabelle referenziert wird, wenn der entsprechende + _Referenzzähler_ null ist. + + Die {use}- und {disuse}-Prozeduren werden von Prozeduren der + _Laufzeitumgebung_ aufgerufen, die Objekte binden. So bindet zum + Beispiel die {new_procedure}-Prozedur, die eine _MicroLisp_-Prozedur + instanziiert, die Objekte in ihrem _Environment_. Die Verwendung der + {use}- und {disuse}-Prozeduren garantiert in diesem Fall das die + Objekte aus dem _Environment_ solange verfügbar sind wie sie benötigt + werden. Die {collect_garbage}-Prozedur wird periodisch von der + _Laufzeitumgebung_ aufgerufen, um den Speicher zu bereinigen. + + Es wurde die _Referenzzählende_ Variante des _Garbage Collectiors_ + gewählt, weil sie vergleichsweise implementationsunaufwendig ist. Der + implementierte _Garbage Collector_ kann die standard + Speicherverwaltungsprozeduren {malloc} und {free} verwenden und es muss + kein spezieller _Heap_ implementiert werden, wie zum Beispiel bei der + _Mark and Sweep_ Variante. + + Als Letztes muss die Kompilationskomponente entwickelt werden und dank + der umfangreichen _Laufzeitumgebung_ muss diese nur noch ein Problem + lösen. Die _MicroLisp_-Sprache behandelt Prozeduren als _Objekte erster + Klasse_. Dementsprechend können Prozeduren an jedem Ort im Quelltext + definiert werden. _C_ unterstützt allerdings nur Prozedurdefinitonen + auf oberster Ebene des Quelltextes. + + #code 3.10 Prozedursignatur aus der Kompilationskomponente zum + Extrahieren von Prozedurdefinitionen.# + + (defun nextract-procedures (expanded-expressions) + "Extract procedures from EXPANDED-EXPRESSIONS, return procedures + and expressions in which procedures are replaced with pointers + (desctructively)." + [...]) + # + + Quelltext 3.10 zeigt die Signatur der Prozedur zum Extrahieren von + Prozedurdefinitionen. Die extrahierten Prozedurdefinitionen werden dann + gesammelt am Anfang des resultierenden _C_-Programms als Prozeduren + {proc1} bis {procN} definiert und können aufgrund der vorhersehbaren + Namenskonvention von Aufrufen der {new_procedure}-Prozedur referenziert + werden. + + > + + < Qualitätssicherung + + Um die Qualität der Softwarekomponenten während der Entwicklung zu + sichern, wird eine _Test-Suite_ geschrieben die die _Axiome_ der + Sprache sowie die Prozeduren und _Makros_ der _Standardbibliothek_ + abdeckt. + + #code 3.11 Ausschnitt aus der _Test-Suite_.# + + (test (assert "T does not evaluate to itself." + (symbolic= t (quote t))) + [...]) + # + + Quelltext 3.11 zeigt einen Ausschnitt aus der _Test-Suite_. Die + _Test-Suite_ wird wie in der Ablaufplanung beschrieben Ausgewertet um + die Funktionalität der Systemkomponenten zu verifizieren, wenn die + Meilensteine erreicht sind. Um die Laufzeitkomponente zusätzlich zu + verifizieren wird ein _C-Profiler_ verwendet. Die Internen Vorgänge der + _Laufzeitumgebung_ werden Analysiert um subtile Fehler wie + _Speicherlecks_ aufzudecken. + + Abschließend wird eine Testanwendung sowohl in _MicroLisp_ als auch in + _ANSI C_ entwickelt. Die Quelltexte der Testanwendungen {units.ml} und + {units-c.c} sind unter dem Verzeichnis {test/} hinterlegt. Beide + Anwendungen sind vom Funktionsumfang her identisch. Sie interpretieren + eine einfache Sprache zum Umwandeln von Längeneinheiten und berichten + die Ergebnisse. Um beide Entwicklungsumgebungen zu vergleichen, werden + relevante Merkmale von {units} und {units-c} aus Entwickler- und + Benutzersicht gemessen. + + #table 3.12 Messergebnisse von {time}. {real} bezeichnet die Zeit + zwischen Aufruf und Beendigung des Programs, {user} bezeichnet die Zeit + die im _Benutzermodus_ und {sys} die Zeit die im + _Kernelmodus_ verbracht wird.# + | Laufzeit | {units} 1x | {units-c} 1x | {units} 1000x | {units-c} 1000x + | {real} | 0.008s | 0.007s | 7.373s | 6.378s + | {user} | 0.003s | 0.000s | 2.070s | 0.540s + | {sys} | 0.003s | 0.000s | 2.976s | 1.193s + + Weil der Funktionsumfang beider Anwendungen identisch ist kann aus + Sicht des Benutzers nur die Performanz verglichen werden. Mit dem + _UNIX_-Werkzeug {time} wird die Laufzeit beider Anwendungen gemessen. + Die Messergebnisse in Tabelle 3.12 zeigen, dass messbare + Performanzunterschiede erst bei sehr langen Berechnungen auftreten. Der + Benutzer kann den Performanzunterschied bei den Testanwendungen nicht + wahrnehmen. + + Aus Sicht des Entwicklers fällt nicht nur auf, dass die _C_-Anwendung + fast doppelt so lang ist. Die Einheitentabelle kann in der + _MicroLisp_-Anwendung mithilfe der _primitiven_ Datentypen zentral und + Leserlich definiert werden. In der _C_-Anwendung muss eine passende + Datenstruktur erst geschaffen werden. Dabei kommen einige + Implementationsfragen auf, wie zum Beispiel arbiträre Begrenzungen, die + nicht relevant für die Logik der Anwendung sind. Um eine neue + Längeneinheit zu definieren müssen mehrere Stellen im Quelltext + angepasst werden. + + Zusätzlich ermöglicht die _MicroLisp_-Sprache intensive Abstraktion durch + Prozeduren höherer Ordnung wie {find} und {map}. _C_ erschwert durch + das statische Typsystem selbst die Abstraktion von generischen + Operationen. Durch die verringerte Abstraktion muss der Entwickler der + _C_-Anwendung auf eine Vielzahl von unrelevanten Details achten. + + Der direkte Vergleich zeigt, dass die _C_-Anwendung nicht nur in der + initialen Entwicklung wesentlich aufwendiger ist. Auch die Wart- und + Erweiterbarkeit ist erschwert. Es wird sichtbar das die + _MicroLisp_-Entwicklungsumgebung den Aufwand der Anwendungsentwicklung + langfristig stark mindert. + + > + +> + +< Projektergebnisse + + < Abnahme und Projektübergabe + + In das Abnahmeprotokoll fließt eine Analyse von Stand und + Funktionalität der Softwarekomponenten sowie die Kosten-Nutzen-Analyse + ein. Tabelle 4.1 zeigt das Abnahmeprotokoll. + + #table 4.1 Abnahmeprotokoll des _MicroLisp_-Projekts. Fehlergrad: + 1 = hoch, 2 = mittel, 3 = niedrig.# + | Abnahmekriterium | Ergebnis (Fehlergrad) + | Funktionalität durch _Test-Suite_ bestätigt | Ja + | Laufzeitkomponente ist Performanzoptimiert | Nein (3) + | automatisierte Speicherbereinigung ist funktional | Ja + | _Lambda-Calculus_ ist implementiert | Ja + | _Axiome_ für Ein- und Ausgabe vorhanden und funktional | Ja + | Ergebnisse der Kosten-Nutzen-Analyse zufriedenstellend | Ja + | Qualität der Dokumentation zufriedenstellend | Ja + + Da das Abnahmeprotokoll keine wesentlichen Mängel aufweist, kann das + Projekt wie geplant übergeben werden. Die _Laufzeitumgebung_ wird den + Anforderungen an Funktionalität zwar gerecht, ihre Performanz ist + allerdings verbesserungswürdig. Weitere Entwicklung im Umfang der + Systemwartung soll die Performanz der _Laufzeitumgebung_ optimieren und + gegebenenfalls bisher unerkannte Fehler beheben. + + > + + < Fazit + + Im Rahmen des Projekts wurde eine umfangreiche Entwicklungsumgebung für + die _MicroLisp_-Sprache entwickelt. Die geforderten Komponenten sind + funktionstüchtig und werden den Kundenwünschen weitgehend gerecht. Das + resultierende Softwaresystem ist in der Lage, die _MicroLisp_-Sprache + zu emulieren und nach _C_ zu kompilieren und bietet den gewünschten + _Makro_-Mechanismus zur Erweiterung der Sprache. + + Der geplante Ablauf konnte eingehalten werden und die gewählten + Methoden haben sich bewährt. Allerdings muss angemerkt werden, dass die + der _Laufzeitumgebung_ inhärente Komplexität größer ist als angenommen + wurde. Demnach konnte die Qualität der Laufzeitkomponente nur auf einen + zufriedenstellenden aber verbesserungswürdigen Stand gebracht werden. + + Vor Beginn des Projekts hätte der Aufwand für die Entwicklung der + einzelnen Softwarekomponenten intensiver evaluiert werden müssen. Eine + detailliertere Abschätzung des Aufwands hätte zu dem Ergebnis geführt, + dass das System innerhalb der festgesetzten 70 Stunden zwar vollständig + entwickelt werden kann, jedoch reicht die Zeit nicht aus um die + gewünschte Qualität aller Softwarekomponenten zu erreichen. Der + Projektantrag hätte also spezifizieren müssen, dass das Ziel des + Projekts eine Vorabversion der Entwicklungsumgebung ist, die + nachträglich iterativ weiterentwickelt werden soll. + + Als besonders positiv kann die _Test-Suite_ bewertet werden. Sie stellt + einen Qualitätssicherungsmechanismus für mehrere Komponenten des + Systems dar, weil sie sowohl die Emulations- und Kompilations- sowie + Makro- und Laufzeitkomponente testet. Es stellt sich außerdem heraus, + dass der geplante Ablauf, in Form der Emulationskomponente, sehr + schnell eine Implementation der konzipierten Sprache produziert. Die + initiale Implementation ermöglicht schon früh das Testen der Sprache + und stellt eine Referenz für weitere Entwicklungsschritte dar. + + Abschließend kann gesagt werden, dass die Entwicklung der + _MicroLisp_-Entwicklungsumgebung noch nicht endgültig abgeschlossen + ist. Im Rahmen des _MicroLisp_-Projekts wurde allerdings ein robustes + und erweiterbares System entwickelt, welches fast allen Anforderungen + gerecht wird und einen wichtigen Meilenstein darstellt. Somit wurde + eine Produktionstaugliche Umgebung für die Entwicklung komplexer + Software geschaffen. Dementsprechend ist das Projekt in seiner + Gesamtheit als erfolgreich zu bewerten. + + > + +> + +< Anhang + + < Anhang 1: Ablaufplan als Flussdiagramm + + #media 7.1 Geplanter Ablauf im Flussdiagramm.# + ablaufplan.png + + > + +>