ConditionTriggeredInstructions
(Wenn => Dann)
- CTI besteht aus Konditionen
(auch Bedingungen
genannt), Instruktionen und Deklarationen.
- Programme werden als geschlossene Systeme betrachtet, die nur über
entsprechend deklarierte Datenobjekte kommunizieren, die gemeinsam verwendet
werden. Interne, nicht für die gemeinsame Verwendung deklarierte Daten dürfen zwischen Systemen nicht
ausgetauscht werden oder zugreifbar sein. Die bedingten Anweisungen, aus
denen ein System besteht, werden CI genannt.
Dadurch ist es "hardwarenah" ; CIs können leicht in Schaltungen umgesetzt
werden (quasi "instruktionsweise"). Die Bedingungen werden durch Gatter, die Instruktionen durch
verschiedene Speicher realisiert. Funktionen sind Module oder Chips
(mit eigenem Takt).
- Jegliche Sequentialität ist
implizit über die Bedingungen. Instruktionen
können einzeln oder geblockt sein. Instruktionen innerhalb von Blöcken
müssen streng "parallel" sein ; es darf keinerlei Bedingungen für ihre
Ausführung (z.B. Sequentialität) oder
Abhängigkeiten geben außer der, dass alle Instruktionen immer zusammen
(im gleichen "Takt") ausgeführt werden, also nicht nur ein Teil davon.
Auch die "blockfreien"
(unbedingten) CIs eines Systems sind als "parallel" zu betrachten, werden also
quasi in der Theorie alle zugleich
ausgeführt, und dürfen untereinander keinerlei Abhängigkeiten besitzen, die
sich nicht implizit aus den Bedingungen und ihren Instruktionen ergeben.
- Prinzipiell müssen alle Bedingungen, die theoretisch
(also nicht praktisch) eintreten können,
auch durch Instruktionen bearbeitet werden, also Bedingung in einer CI sein
(Vollständigkeit). Bedingungen, die nicht
eintreten dürfen, erhalten als Instruktion eine ERROR-Fehlerfunktion. Durch
die Funktion EXIT können (solche)
Funktionen das Programmende
bewirken. Andernfalls steuert die ERROR-Funktion die weitere
Programmausführung über die zur Kommunikation benutzten Datenobjekte.
- CIs mit den selben Bedingungsteilen innerhalb
des gleichen Blocks (also gleichen
Prio-Bedingungen) werden automatisch zu
einer CI mit
einem Block der Vereinigung all ihrer Instruktionen zusammengefasst
(ergibt sich aus 3).
- Die Instruktionen von CIs werden insofern auf Widerspruchsfreiheit
geprüft, als sie nicht zu verschiedenen Ergebnissen führen dürfen, wenn ihre
zugehörigen Bedingungen zugleich erfüllt sein können
(Unverträglichkeit). Die Bedingungen
von CIs müssen
sich bei möglichen Widersprüchen durch die Instruktionen also definitiv ausschließen.
Beispiel:
Z ≠ 2 => I=
1 und
Z > 1 => I= 3
sind
unverträglich.
- Funktionen können direkt implementiert oder CI-Subsysteme sein. Der
Datenaustausch erfolgt in jedem Fall durch als Parameter übergebene Datenobjekte
ohne
Nebenwirkungen oder direkte
(Return-)Wertübergabe.
Wert- Funktionen liefern nur
einen einzelnen Wert zurück, z.B. einen Wahrheitswert, und sind nur für die
Verwendung in Bedingungen bestimmt. Sie dürfen als Parameter übergebene
Datenobjekte nicht ändern. Bei CI-Implementierung nutzen Wert-Funktionen die
Instruktion RETURN(Wert) zum Verlassen der Funktion und zur Wertübergabe.
CI-Subsysteme sind der Direktimplementierung vorzuziehen
(Fehlersicherheit).
Funktionsnamen, die mit einem "?" enden,
bezeichnen stets Funktionen mit Wahrheits-Returnwert TRUE oder FALSE.
- Das CTI-EntwicklungsSystem
soll selbst in CTI implementiert sein. Hierzu muss eine erste
Übersetzung
der
CIs des Entwicklungssystems in eine vorhandene Programmiersprache
(C++) manuell erfolgen, die schließlich ein
ausführbares Programm liefert. CTI-ES soll später voll interaktiv arbeiten
und CTI selbstständig compilieren.
Eine CI müsste in
(erweitertem) C++ stets so darstellbar sein:
if ( Bedingung ) { Instruktionsfolge } [ else { Instruktionsfolge }. Der Bereich "else"
kann fehlen, falls dort keine Instruktionen anzugeben sind.
Elementardaten- und Datenstruktur-Deklarationen
(struct oder class) wie in C++
(mit dynamischer Allokation wie bei Java).
Es gibt weder Sprünge, Schleifen noch verdeckte Abhängigkeiten.
-
Sequenzen:
Strenge
(inhaltliche)
Sequenzen werden so realisiert, dass ihre CI indiziert werden
(durchnummeriert) und der Index der CI innerhalb ihrer Instruktionsfolge einer
Indexvariablen zugewiesen wird. Diese kann in der Bedingung der Nachfolger-CI
auf den Wert des Index der zuletzt ausgeführten geprüft werden.
"Taktsynchrone" Sequenzierung
(Indexfortschaltung bei Schleifen) kann durch das
Kopierprinzip für RW-Objekte (13) implizit
ohne Flags und Bedingungsabfragen erfolgen
(außer bei transparenten
Funktionen ?). Technische Sequenzierung innerhalb eines Taktes,
ja formale Sequenzierung überhaupt, ist überflüssig und mit dem CTI-Konzept
der reinen Bedingungssteurung unvereinbar (zu
beweisen).
Infolge der Kopie-Rückkopie-Funktion und der nur
einmaligen Änderungsmöglichkeit pro Takt ändern reguläre Anweisungen
innerhalb eines Taktes keine Daten, so dass nachfolgende Anweisungen kein
geändertes Environment vorfinden. Es können durch technische Sequenzen nur
Flags, sowie deren Abfrage, und Takte eingespart werden, also
Ausführungszeit.
Vorsicht bei Iteration oder Rekursion einer
Sequenz !
Indexvariable
sind, außer bei transparenten Sequenzfunktionen, lokal, temporär und zu 0 initialisiert.
Die Indexvariable bestimmt die Instanz einer Sequenz. Die Sequenz läuft,
solange die Indexvariable != 0 ist.
Die erste CI setzt die Indexvariable auf 2 und "Index == 1" wird
als nächstes abfragt. Die folgenden CI der Sequenz fragen den Index des Vorgängers ab und
die letzte CI setzt die Indexvariable wieder 0. Die Sequenz wird also mit
Index=1 gestartet. Mehrfachausführung der CI einer Sequenz innerhalb einer Instanz
(vgl. ZYKLUS) sind so ausgeschlossen. Um eine Sequenz nur einmal zu konstruieren und iterativ oder
rekursiv mehrfach auszuführen, muss sie in eine Funktion eingebettet werden,
deren Parameter eine Indexvariable beinhalten kann. Diese "Sequenz-Funktion"
wird normalerweise erst beendet, wenn die letzte Instruktion der Sequenz
ausgeführt ist. In diesem Fall (keine
"Transparenz") ist keine Indexvariable als Parameter
erforderlich (nur lokal). Ist sie aber vorhanden und durch die Funktion änderbar
(Referenz-Übergabe), so kann die Sequenz auch vor
ihrem Ende mit dem Funktions-RETURN verlassen und
bei Wiederaufruf fortgeführt werden
("Transparenz").
Das Sequenzende muss dann extern abgefragt werden.
Technische Indexvariablen
Technische Indexvariable sind
RW und immediate
(inhaltliche nicht), d.h. es wird
innerhalb eines Ausführungstaktes auch beim Lesen immer auf den Write-Anteil
der Variable selbst zugegriffen, nicht auf den taktinvarianten Read-Anteil
(bzw. eine Kopie davon). Das Update der
technischen Indexvariablen nach Bearbeitung einer CI-Instruktion ist
unabhängig von deren Ausführungsbedingung.
Nur bei
inhaltlicher Sequenz ist zu
unterscheiden, ob die Inkrementierung der Indexvariablen von der Erfüllung der CI-Bedingung
abhängig sein soll oder nicht
(Inkrementierung dann zusätzlich auch im else-Bereich ). Sie müssen
per Instruktion am Ende der Sequenz 0
gesetzt werden, da sich die Sequenz über mehrere "Takte" erstrecken kann. Technische
Indexvariable werden vom System geführt und enthalten ein Ausführungsflag
für jede lokale Instruktion, das abgefragt werden kann. Kurze technische, nicht transparente Sequenzen könnten auch durch eine
Sequenz-Anweisung der Form seq { Instruktionsfolge } realisiert
werden, die vom System besonders geprüft und konventionell der Reihe nach
abgearbeitet wird. Es ist nur eine seq-Anweisung pro Block
(Menge der Anweisungen im selben "Takt")
erlaubt. Alle Variablen und Daten sind innerhalb
immediate, werden also von ihrer Write-Komponente gelesen statt von
ihrer Read-Komponente. Die Ergebnisse einer seq-Anweisung müssen von der
Ausführungsreihenfolge im Rahmen der regulären
CI-Instruktionen unabhängig sein.
Mit der auch für "transparente Sequenzfunktionen" gültigen
Festlegung, dass ein Verlassen der Funktion stets nach Taktende erfolgt,
gilt auch für diese, dass technische Indexvariable beim
Funktionseintritt initalisiert werden müssen. Durch diesen
Mechanismus lassen sich "Takte" einsparen (sonst
nichts).
- Prio-Bedingungen, Blockung
CI-Anweisungen können auch geblockt sein. Ein CI-Block hat die Form
Prio-Bedingung => CI-Instruktionsfolge, darstellbar als if ( Prio-Bedingung
) { if ( Bedingung1 ) { Instruktionfolge1 } ; if ( Bedingung2 ) {
Instruktionfolge2 } .... }. Dies ist äquivalent zu { if ( Prio-Bedingung &&
Bedingung1 ) { Instruktionfolge1 } ; if ( Prio-Bedingung && Bedingung2
) { Instruktionfolge2 } .... }.
Mit der Erzeugung einer AO-Instanz
(siehe
Folgepunkt) in einem Block wird dieser durch deren CI-Anweisungen
erweitert. Diese CI-Anweisungen sind auf den Block beschränkt und damit
dessen Prio-Bedingungen unterworfen. Dies gilt
insbesondere für Funktionen, wobei der Funktionsaufruf selbst quasi die
Prio-Bedingung darstellt.
-
Algorithmische Objekte ("Programme",
z.B. ZYKLUS, Funktionen, "Macros" usw. ; um Instruktionen erweiterte "class"-Definition)
AOs bestehen aus Parametern, Datenobjekten, Instruktionsfolgen, Funktionen
und Eigenschaften. Letztere sollen sicherstellen, dass das AO genau das
tut, was es soll, und keine Fehlfunktionen möglich sind. AOs können wie
Bausteine über das CTI-ES an jeder Stelle eingesetzt werden, an der eine
Instruktion stehen kann. Das CTI-ES fragt interaktiv Parameter ab und prüft, ob
bereits zur Entwicklungszeit prüfbare Randbedingungen verletzt werden. AOs können statisch
(fester
Programmbestandteil, wie Macros) und dynamisch
(werden bei Bedarf generiert und wieder
gelöscht) sein, werden durch CLOSE geschlossen
(beim Verlassen beendet ; alle inneren Daten werden
ungültig) oder sind transparent
(Default ; alle inneren Daten bleiben bis zum expliziten
Abschluss gültig). Dies gehört alles zu den
"Eigenschaften". Eingebettete AOs
("inline", "Macro") können die
Variablen ihrer Umgebung benutzen, wenn sie unverwechselbar und namensgleich
sind. Solche "externen" Variablen sind uneingeschränkt manipulierbar.
Die Unveränderlichkeit RO externer Variablen kann erreicht werden, indem sie
explizit innerhalb des AOs auf lokale Variable kopiert werden oder sie kann in den AO-Eigenschaften verankert sein und wird geprüft
(Default: Veränderlichkeit RW). Interne und
externe Variablen von AOs können
(bei
Namensungleichheit) durch Kopplungsanweisungen der Form "interne
Variable"="externe Variable"
(dem AO-Namen in
Klammern nachgestellt) verbunden werden. Dies gilt auch für
Funktionsaufrufe ; die Parameter werden also auch hier nicht
positionsgebunden, sondern durch explizite Zuweisung zugeordnet. Bei der
Funktionsimplementierung müssen keine Übergabeparameter angegeben werden.
Interne Variablen von AOs müssen vor ihrer Nutzung als Wert initialisiert
oder mit einer externen Variablen verknüpft werden. Im letzteren Fall wird
deren Initialisierung geprüft.
AOs werden über die reservierte RETURN-Instruktion verlassen.
Hierdurch wird
die wiederholte Ausführung der CIs beendet. Ein automatisches
Verlassen nach Abarbeitung aller Instruktionen findet nicht statt.
Alle Variablen behalten auch nach dem Verlassen durch RETURN ihren Wert
(sind also "statisch"),
wenn sie nicht durch die Funktionen RELEASE() oder CLOSE in den
Grundzustand zurückversetzt werden. Nur durch CLOSE wird ein
dynamisches AO entladen. RELEASE allein setzt
alle internen
Variablen eines AOs in den Grundzustand zurück, ohne das AO zu
schließen. Sie ist Teil des "Creators" für die Einstellung des Grundzustands.
- ZYKLUS
Ein ZYKLUS ist ein AO, das in definierten Zyklen
arbeitet. Es ist eine Zyklus-Variable und eine ?ZYKLUS_NEXT-Funktion
erforderlich. Diese Funktion bestimmt, ob ein Durchlauf abgearbeitet ist
oder alle Durchläufe abgearbeitet sind und schaltet gegebenenfalls die
Zyklus-Variable fort. Die Zyklus-Variable "zählt" die durchlaufenen Zyklen und kann zur
Adressierung z.B. von Array-Komponenten verwendet werden. Ein ZYKLUS-AO hat
als Basis-Eigenschaften (Flags): INITIALISIERT,
AKTUELLER_DURCHLAUF_ABGEARBEITET, NÄCHSTER_DURCHLAUF und
ALLE_DURCHLÄUFE_ABGEARBEITET (DISABLE). Die Eigenschaften werden durch
RELEASE und CLOSE in den Grundzustand versetzt. Eine Zyklus-Variable ist
nicht immediate. Alle CTI-Instruktionen müssen "per Hand" in
eine compilierbare Programmiersprache übersetzbar sein.
- Die Ausführung eines CTI-Programms muss "getaktet"
erfolgen. Hierbei werden alle (auf Grund erfüllter
Bedingungen) erreichbaren
CI-Anweisungen und -Instruktionen innerhalb eines "Taktes" genau einmal
ausgeführt ; d.h. die Instruktionen von CIs ohne erfüllte Bedingung und CIs,
die auf Grund nicht erfüllter Prio-Bedingungen nicht angesprochen werden,
bleiben unausgeführt. Innerhalb eines Taktzyklus
dürfen keine Variablen oder sonstigen Daten geändert werden, die im
Taktzyklus auch gelesen werden, es sei denn sie sind ausdrücklich
"immediate"
(jeder Lese-Zugriff muss auf originale Daten
erfolgen). Hieraus ergibt sich, dass alle RW-Variablen
(und anderen Datenobjekte) einen Read- und
einen Write-Anteil besitzen müssen (, sind also
keine Skalare mehr, sondern "Vektoren"). Konstanten und WO-Objekte
können weiterhin skalar bleiben. Der Write-Anteil wird am "Taktende"
(, wenn alle zum Takt gehörenden CI-Instruktionen
ausgeführt wurden) systemimmanent auf den Read-Anteil zurückkopiert.
"Außerhalb" aller Takteinheiten müssen Read- und
Write-Anteil identisch sein.
Funktionen bilden ein eigenes "Taktobjekt". Hierzu werden die Read-Anteile
aller externen RW-Objekte, auf die die Funktion zugreift, kopiert und alle
Rückabbildungen von Write- auf Read-Anteile durch funktionsinterne Takte wie
gehabt an den Kopien durchgeführt. Die
Write-Anteile von
(externen)
Referenzobjekten werden direkt geschrieben
(sind
immer "immediate").
RETURN und CLOSE werden erst ausgeführt, wenn alle erreichbaren CI-Anweisungen des letzten
Taktes, während dessen die RETURN-oder CLOSE-Instruktion angesprochen wird, ausgeführt
wurden. Eine Rückabbildung der Write- auf die Read-Anteile erfolgt
für externe RW-Referenzobjekte durch die Funktion nicht.
Bei internen statischen Variablen transparenter Funktionen erfolgt die
Rückabbildung regulär bei jedem Taktende und durch RETURN bzw. CLOSE.
Transparente Funktionen beginnen also stets mit
einem neuen
Takt.
RW- und WO-Objekte dürfen innerhalb eines
Taktzyklus nur einmal beschrieben werden (auch Spiegelungen).
- Daten-Validierung
Das CTI-ES sieht vor, dass alle Datenobjekte mit Bedingungen für den Zugriff
auf sie versehen werden können. Die Prüfung geschieht zur Entwicklungszeit.
Ein Zugriff ist nur gültig (valid), wenn die Bedingungen, unter denen die
CTI-Instruktion ausgeführt wird, während derer der Datenzugriff erfolgt, mit
den Validitätsbedingungen des Datenobjekts übereinstimmt.
Validitätsbedingungen können notwendig, hinreichend und optional sein.
Optionale Bedingungen dürfen den Ausführungsbedingungen lediglich nicht
widersprechen, können aber auch ohne Bezug dazu sein. Eine erfüllte
hinreichende Bedingung setzt alle anderen Bedingungen außer Kraft
(impliziert also notwendig&hinreichend).
Ist keine hinreichende Bedingung erfüllt, so müssen alle notwendigen erfüllt
sein und keiner optionalen darf widersprochen werden.
Die Validierung umfasst auch ein Flag für die Initialisierung von Variablen,
welches vor jedem Lesen der Variablen gesetzt werden muss. Die Überprüfung
zur Entwicklungszeit setzt einen vollständigen "Verfolgungsalgorithmus" des
CTI-ES voraus, der den Nachweis erlaubt, dass unter allen möglichen
Bedingungen vor dem Lese-Zugriff auf eine Variable eine Initialisierung
erfolgt ist.
- Modularisierung, Modulselektion
- Das CTI-ES soll so arbeiten, dass neue Anweisungen immer dann
eingegeben werden können, wenn sie mir einfallen (oder aus einer Datei gelesen
werden können).
- Das CTI-ES soll für die Einordnung einer neuen CI alle vorhandenen
Funktionen und Datenobjekte zur Auswahl stellen, die neue Anweisung im Kontext
sofort prüfen und nötigenfalls anpassen (z.B. bezüglich der Namen von
Datenobjekten).
- Für alle Funktionen, Datenobjekte und Anweisungen müssen ausführliche
Erklärungstexte abrufbar sein.
- Die Bedingungen einer CI oder eines CI-Blocks müssen zusammengefasst
darstellbar und in der Darstellung nach konjunktiven und disjunktiven Verknüpfungen gegliedert
sein.
- Aufzeigen der Zusammenhänge von Datenobjekten.
CTI-Programmierung
Zuerst werden alle Anweisungen, Bedingungen und
Vorgänge, die einem einfallen, sprachlich formuliert. Hierbei ergibt sich i.d.R.
eine Daten- und Arbeitsvariablenstruktur. Auf diese Struktur aufbauend werden
alle sprachlich formulierten Anweisungen in CTI-Instruktionen umgesetzt. Deren
Modularisierung kann später erfolgen, bzw. es ergeben sich dabei auch
Funktionsdefinitionen, die später ausgearbeitet werden. Das CTI-ES sorgt später
für die Einhaltung der systemspezifischen Randbedingungen und Vollständigkeit.
Die Programmierung kann dann durch Eingabe einzelner Anweisungen
(unter Aufruf von Modulumgebungen und
Einordnungshilfen) inkremental fortgesetzt werden. Durch direkte
Umsetzung inkrementaler CTI-Instruktionen in Maschinencode kann dies sogar zur
Programm-Laufzeit erfolgen und sofort wirksam werden. Dies sprachliche Umsetzung
in CTI-Instruktionen kann mit entsprechendem Aufwand halb- oder vollautomatisch
erfolgen. Hierzu muss das CTI-ES lernfähig gemacht werden, sowohl für die
Umsetzung Sprache-CTI, als auch für die Compilierung von CTI in C++ oder
Maschinencode.
Tabellarische Entwicklung
Zur besseren Darstellung, insbesondere für die
Heraushebung und Gültigkeitsbereichs-Erkennung von Prio-Bedingungen, eignet sich
die tabellarische Darstellung. Prio-Bedingungen belegen dabei eine eigene Spalte S und sind zu tieferen Zeilen
Z hin gültig, bis in der selben oder in einer weiter links gelegenen Spalte in
einer tiefer gelegenen Zeile Z' wieder eine Prio-Bedingung steht
(Felder in Spalte S zwischen Z und Z' leer).
Die parallelen Anweisungen stehen untereinander in der äußerst rechten
noch belegten Spalte
der jeweiligen Zeile und werden unter den
UND-verknüpften Bedingungen in den Spalten weiter links ausgeführt:
|
Prio1 |
Bed0 |
Bed_0A |
Anw_0A1
Anw_0A2 |
|
|
|
Bed_0B |
Anw_0B |
Prio2 |
PBed2 |
Bed1 |
Bed_1A |
Anw_1A1
Anw_1A2
Anw_1A3 |
Bed3 |
Anw_3 |
|
|
|
entspricht:
Prio1 && Bed0 && Bed_0A: Anw0A1 ; Anw_0A2.
Prio1 && Bed0 && Bed_0B: Anw0B.
Prio2 && PBed2 && Bed1: Anw1A1 ; Anw_1A2 ; Anw_1A3.
Bed3: Anw_3.
Die Bedingungen in einer Spalte müssen eine vollständige disjunkte
widerspruchsfreie (automatisch zu prüfende)
Zerlegung bilden:
~(B1 | B2 ...| Bn) == FALSE und
für alle i != j gilt (Bi && Bj) == FALSE und (Bi
⇒
~Bj) == FALSE
Übungen:
CTI für Suchalgorithmus mit inverser Vergleichsrichtung
Suchcode-Pointer
scp Suchcode-Anfangs- und Endpointer
(Folgeadresse) sca, sce
Vergleichsstring-Pointer vsp
Vergleichsstring-Länge
vl < 254
attribut-tabelle[c]
atb Attributtabellen-Länge 256
Vergleichszeichen
c
match-Pointer-Tabelle[m] mpt
mpt-Index m
memset(atb,0xFF,0x100) ;
// for ( i= 0 ; i < 256 ; i++) atb[i]= 255
; // atb initialisieren zu unbelegt
// Vergleichszeichen als atb-Index ; letzte Position im Vergleichsstring
for ( i= vl-1 ; i >= 0 ; i--) atb[vsp[i]]= atb[vsp[i]] == 255 ? i :
atb[vsp[i]] ;
for ( m= 0 , scp= sca ; scp < sce ; scp++)
{ for ( i= vl-1 ; i >= 0 ; i-- )
{ p= atb[scp[i]]
;
if ( p == 255 ) { scp+= i ; break ; } ; // Suchcode-Pointer
auf Zeichen (kein Vorkommen)
if ( p == i )
continue ; //
(letztes) Vorkommen an der gleichen Position
if ( i >
p ) { scp+= i-p-1 ; break ; } ;
// synchronisieren (Zeichen beim Folgevergleich richtig stehend)
if ( scp[i] !=
vsp[i] ) break ;
} ;
if ( i < 0 ) mpt[m++]= scp ;
} ;