Ich habe hier also Kürzel benutzt, die formale Schreibweise allerdings würde sehr komplex aussehen, stell wir uns vor, wir haben 100 unterschiedliche mögliche Ereignisse, jedes davon mit 5 Attributen.
Ein Beispiel: Das Ereigniss CodeChange habe folgende Attribute: Dateiname, Zeilenbeginn (der Änderung), Zeilenende der Änderung, Uhrzeit, gelöschter/überschriebener Code, neuer/geschriebener Code. Folgende Notation wäre nunb also z.B. erforderlich: (CCxyzt"""") würde heißen: CodeChange mit belegtem Dateinamen-Wert (Variable) → x, Zeilenbeginn → y, …, gelöschter Code = "", neuer Code = "" (Ich will damit andeuten das man auch das setzen von konkreten konstanten Werten erlauben sollte.Ein solcher Sprachkonstrukt erfordert eine Abbildung auf die hinter den Kürzeln stehenden deutlich längeren Ereignisscodes. (Scheint mir Recht umständlich, vielleicht aber mit assoziativen Arrays) Auf jedenfall müsste jeder der ein Ereigniss definiert, damit ja auch der zu generierende Episodenerkenner neue Ereignisse in dieser Strucktur anmelden!
Der Entwurf einer solchen Sprache übersteigt den zeitlichen Rahmen meiner Arbeit, es bleibt fraglich ob existierende Sprachen z.B. RegExp dafür verwendet werden können.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Es ist denkbar das reguläre Ausdrücke hilfreich sind. Sie ermöglichen einen einfachen Vergleich. Die bereits oben beschriebene Abbildung wäre allerdings auch hierbei wünschenswert und ausserordentlich komplex. "Ich habe so ein bisschen das Gefühl, dass man sich hierbei tierisch verrennen kann!" Da ein Codegenerierer wohl eher nicht zu den verfolgten Ansätzen zählt bliebe ghier die Frage: "Wie aönnen Klassenstruckturen aufgebaut sein, so dass die Semantik der Objektoperationen auch bei Nebenläufigkeit erhalten bleibt?" Insbeondere die Aufrufhierachie ist hierbei ein Problem, da ich zum Zeitpunkt eines Zustandwechsels ini einigen Fällen einen neuen Thread starten muss in anderen aber nicht. Bsp:: Aufgabe: Erkenne Episode A * A (* ist hier nichtleerer wildcard) auf Stream DADFSAB Ablauf: lese D → kein Zustandswechsel (Zustand 0) lese A → Zustandswechsel (spalte Prozess ab; neuer Prozess(X) Zustand 1 alter Prozess(Y) Zustand 0) lese D → Zustandswechsel in Prozess(X) (Prozess(X) in Zustand 2; keine Abspaltung sinnvoll) lese F → keine Zustandswechsel lese S → keine Zustandswechsel lese A → Zustandswechsel (spalte neuen Prozess(Z) mit Zustand 1 aus Prozess(Y) ab; Prozess(X) terminiewrt und wirf Ereigniss!) lese B → Zustandswechsel in Prozess(Z) auf Zustand 2; keine Abspaltung …...- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Zuerst schreibt oder verändert der beobachtete Entwickler eine Zeile (im weiteren mit dem Wert x versehen) in einer Datei (im weiteren mit y bezeichnet). Nun führt er maximal 4 für die Episode unbedeutende Aktionen aus (Achtung: hierbei darf kein erfolgreiches debugging der Datei y stattfinden, da dieses den Automaten verwerfen würde). Nach missglücktem Debugging der Datei y dürfen weitere unbedeutende Aktionen auftreten (maximal 4). Nun erfolgt eine Änderung im unmittelbaren Umfeld von Zeile x in Datei y (z.B.: x+-2), wiederum gefolgt von maximal 4 unbedeutenden Operationen (Events). u.s.w. Nach dreimaligem negativem Debugging und einer erneuten Veränderung im Umfeld von x in Datei y wird ein erfolgreiches Debugging der Datei y durchgeführt. Damit soll die Episode erkannt sein und ein neues Ereigniss "geworfen" werden mit den folgenden Parametern Datei und ursp. Zeile.
Wir betrachten nun diese Episode in unterschiedlichen Notationen:
Als erweiterter Zustandsautomat:siehe Anhang (episode1automat)!
in eigener Notation: (zur Schreibweise: - zeitliche Abfolge von oben nach unten! - 'int a, int b' meint: Auftreten mindestens a-mal und maximal b-mal (Das Zeichen # steht hierbei für den wildcard, also "beliebig") - (...) → Klammern umschließen Ereignissmengen - <...> → spitze Klammern umschließen einzelne Ereignisse - [...] → eckige Klammern umschließen Bedingungen - eine EReignissmenge besteht aus einem einzelenen Eereigniss oder eine wildcard (hier: *) mit ausschluß einer Ereignissmenge oder ist leer, und aus Bedingungen - das Zeichen \ entspricht der Mengenoperation "ohne" bzw. "exklusive" - das Zeichen / stellt den Beginn der Aktionsangaben dar, die bei auftreten eines gültigen ereignisses durchgeführt werden sollen repektive müssen - eine Zeile repräsentiert ein Vergleichsmuster und besteht aus Häufigkeitsangabe des Auftretens, Ereignissmenge (zum Vergleich) und möglichen Aktionen (letzteren beiden dürfen leer sein ersteres ist als '0,#' darzustellen falls beliebig.)'1,1' (< write >[true]) / x:= this.line; y:= this.file;
'0,4' (*\(< run-debug >[this.result=="successfull"&&this.file==y])[true]) /
'1,1' (< run-debug >[this.result=="failed"&&this.file==y]) /
'0,4' (*\(< run-debug >[this.result=="successfull"&&this.file==y])[true]) /
'1,1' (< write >[x-2<=this.line<=x+2&&this.file==y]) /
'0,4' (*\(< run-debug >[this.result=="successfull"&&this.file==y])[true]) /
'1,1' (< run-debug >[this.result=="failed"&&this.file==y]) /
'0,4' (*\(< run-debug >[this.result=="successfull"&&this.file==y])[true]) /
'1,1' (< write >[x-2<=this.line<=x+2&&this.file==y]) /
'0,4' (*\(< run-debug >[this.result=="successfull"&&this.file==y])[true]) /
'1,1' (< run-debug >[this.result=="failed"&&this.file==y]) /
'0,4' (*\(< run-debug >[this.result=="successfull"&&this.file==y])[true]) /
'1,1' (< write >[x-2<=this.line<=x+2&&this.file==y]) /
'0,4' (*\(< run-debug >[this.result=="failed"&&this.file==y])[true]) /
'1,1' (< run-debug >[this.result=="successfull"&&this.file==y]) / throw '< trial-error >, file=y, line=x, time=§TIMESTAMP§';
hierbei tritt folgendes Problem auf: Nehmen wir an dass, anders als hier, die Anzahl der negativen Debugging-Schritte >= 3 sein soll (hier bisher: ==3)! Was folgt daraus? Wie kann man das umsetzen? Muss man für jede Mögliche Anzahl jeweils eine eigene Struktur schreiben? Läßt sich das Problem vielleicht durch Anwendung des Kompositum-Musters beheben? Oder reicht vielleicht die Tatsache das eine Epsiode mit mehr als 3 Debugg-schrittenferner auch eine mit genau drei Debug-schritten enthält?(Achtung: Hierbei ist auf die Auswirkungen auf die Variable x zu achten!) als regulärer Ausdruck:Die Darstellung der erläuterten Epsiode gestalltet sich, wie bereits im ersten Abschnitt beschrieben schwierig, sobald ich fortschrritte damit erreiche werde ich sie hier hinzufügen. Derzeit ist es mir noch nicht gelungen einen korrekt geformten regulären Ausdruck für die genannte Episode zu formulieren.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
In diesem Abschnitt geht es darum den in Abschnitt 2 vorgestellten, selbstentworfenen Beschreibungsmechanismus für die Darstellung von Episoden konkret zu Formulieren und genauer zu erläutern.
Die unten abrufbare Datei haeufigkeitsnotation.png (bzw.: ~.dia) erläutert dabei die Notation der Häufigkeiten eines "Ereignisstyps" (-menge) durch Abbildung auf das erweiterte Zustandsübergangsautomatenmodell. Ich habe soeben (26.Juni) die dateien häufigkeitsnotation.png und ~.dia überarbeitet. Insbesondere ist das ganze jetzt modular dargestellt und der Abbruchzustand ist eingearbeitet. (Nebenbei kam mir die erste Idee für einen Namen. Da es sich im Endeffekt um eine Skriptsprache zur Beschreibung von turing-mächtigen Automaten handelt könnte man sie vielleicht TUMAS(TuringMächtigeAutomatenSprache) nennen, hier also Java-TUMAS, na wie klingt das?! ;o)Ich habe heute (20.Juni 06) an der Formalisierung des Beschreibungsmechanismus gearbeitet.Die Ergebnisse stehen unten zum Download bereit (beschreibungsmechanismus-formalisierung.*). Es kann sein, das sich daran noch einmal was ändert. Kommentare und Beispiele werden folgen. Leider ist das ganze auf Grund der Klammersetzung doch nicht mehr ganz so übersichtlich geworden. Anmerkungen und Kritik kann gerne an mich gesendet werden!
aktuelle Probleme:
1. Betrachten wir folgende zwei Beipiele zur multierror-erkennung:
'1,*' {< error >} /
'1,1' {< error >} / throw '< multierror >';
bzw.:
'1,1' {< error >} / int count=1;
'0,*' {< error >} / count++;
'1,1' {< error >} / throw '< multierror >, int count = count+1';
Da innerhalb des Zustandsübergangsautomatenmodells so-oder-so gezählt wird, stellt sich die Frage, ob man nicht irgendwie auf den eh vorhandenen Zähler zugreifen können sollte, in solch einem Fall könnte man dann ersteres Beipiel nutzen anstelle des zweiteren komplizierteren.
Außerdem wird deutlich wie unzureichend die throw-Anweisung definiert ist. Die Trennung der Attribute durch Kommata ist Problematisch. Und auch die Tatsache das man nicht auf Klassenebene arbeitet ist nicht optimal. Wäre vielleicht folgende rein-java-syntaktisch geschrieben Zeile besser? (outStream sei dabei der fest deffinierte Attributname des Datenstroms innerhalb des Controllers (siehe Objektmodell); throwOut müsste natürlich noch in eine zum Datenstrom passende Form gebracht werden.).
'1,1' {< error >} / MultierrorEvent throwOut = new MultierrorEvent(count+1); outStream.add(throwOut);