Ideen zu einer Implementierung einer Skriptsprache für das COACH-Vehikel
- Nach den ganzen Vorüberlegungen, sollen nun einige ganz konkrete Ansätze zur Umsetzung einer Skriptsprache und des zugehörigen Interpreters dargestellt werden.
|
Konfiguration eines Fuzzy-Systems
- Ein Fuzzy-System wird durch die Lage der Maxima der Zugehörigkeitsfunktionen und eine Liste an Regeln beschrieben.
- Beides ließe sich auch in Array bzw. Matrix-Form über Funk als eine Art Skript auf ein Vehikel übertragen.
- Erinnern Sie sich an Kapitel 10.3 Regelungssysteme, dass die Regeln als eine einfache Matrix von Indices für den Einachser umgesetzt werden konnten:
|
...
int indices[25] = {
0,0,1,2,2,
0,1,2,2,3,
0,1,2,3,4,
1,2,2,3,4,
2,2,3,4,4
};
...
Code 0-1: Ausschnitt aus der Klasse Fuzzysystem für den Einachser.
- Natürlich können die übertragenen Arrays und Matrizen nicht direkt als "Skript" bezeichnet werden.
- Bei entsprechender Anlage mehrerer Fuzzy-Systeme zur Gestaltung des Verhaltens des Vehikels, entspricht der resultierende Effekt jedoch durchaus dem, bei dem das Verhaltensmuster über ein gewöhnliche(re)s Skript beschrieben wird.
|
Interpretation einer Liste von Befehlen
- In unserem Fall kommt es nicht sehr darauf an, dass die Skriptbefehle von einem Menschen direkt gelesen und verstanden werden.
- Der Verzicht hierauf erübrigt jedenfalls die Notwendigkeit eines komplizierteren Befehlsinterpreters, der die Wörter im Skript mit einer Liste mit den erlaubten Befehlen vergleicht.
- Statt dessen wäre eine Nummer für eine aufzurufende Funktion auch ausreichend.
- Angenommen, die verfügbaren Funktionen benötigten keine Übergabeparameter und lieferten auch keine Rückgabewerte, dann könnte ein sehr simpler Interpreter in folgender Weise mit einer switch-Anweisung realisiert werden:
|
for(int i=0;i<ANZAHL_BEFEHLE;i++)
{
switch(befehls_liste[i])
{
case 0:
antriebs_regelung.setzteSollwert(20);
break;
case 1:
servo.links();
break;
case 2:
wert[k++] = sensor.hole_wert();
k%=10;
break;
...
}
}
Code 0-2: Denkbarer Programmabschnitt des Skript-Interpreters mittels switch-Anweisung
- An dem Beispiel wird ersichtlich:
- Auch wenn die Befehlsliste keine Parameter enthält, kann dies realisiert werden, indem unterschiedliche Befehlsnummern, die gleiche Funktion, jedoch mit unterschiedlichen Parametern aufrufen.
- Ebenso können Rückgabewerte von Funktionen gespeichert werden, wenn die entsprechende Zuweisung direkt in einer der auswählbaren Anweisungen steht.
- Ähnlich der Trennung zwischen Regeln und Zugehörigkeitspositionen bei Fuzzy-Systemen, können Parameter auch unabhängig zum Skript auf das Vehikel übertragen werden.
|
Verzicht auf "switch" und vergleichbare Kontrollstrukturen durch Einsatz von Funktionszeigern
- C/C++ bietet die Möglichkeit neben Variablen auch Funktionen in Zeigern zu speichern.
- Indem man die Zeiger aller verfügbaren Methoden in einem Array speichert und das "Skript" aus der Angabe der Indices dieses Arrays, kann auf die switsch-Anweisung verzichtet werden.
- In C++ können Funktionszeiger aber nur folgendermaßen (testweise auf einem PC) umgesetzt werden:
|
#include<iostream>
using namespace std;
class Befehle
{
public:
void tudies()
{
cout<<"dies"<<endl;
}
void tudas()
{
cout<<"das"<<endl;
}
void tujenes()
{
cout<<"jenes"<<endl;
}
};
int main()
{
Befehle befehle;
void (Befehle::*zeiger[3])(void) = {
&Befehle::tudies,
&Befehle::tudas,
&Befehle::tujenes,
};
int skript[4] = {0,1,0,2};
for(int i=0;i<4;i++)
(befehle.*(zeiger[skript[i]]))();
}
Code 0-3: Verwendung von Funktionszeigern, um auf einen Teil der Kontrollstrukturen bei der Skriptinterpretation verzichten zu können
- Erläuterungen:
void (Befehle::*zeiger[3])(void) ist ein Array von 3 Funktionszeigern mit dem Namen "zeiger".
- Es hat als Übergabeparameter und Rückgabewert "void".
&Befehle::tudies wählt den Zeiger auf die Methode "tudies" der Klasse "Befehle" aus.
- Da Funktionen in C++ an Objekte gebunden sind und nur über eine Syntax "OBJEKTNAME.FUNKTION()" aufgerufen werden können, wäre ein Aufruf, um die nullte Funktion in zeiger anzusprechen der Art
*(zeiger[0]))(); in C++ unzulässig.
- Mit
(befehle.*(zeiger[skript[i]]))(); wird die im Zeiger gespeicherte Funktion an ein Objekt gebunden.
|
- Diskussion:
- Die Verwendung von Funktionszeigern führ sicher zu einem performanteren Programm.
- Sie setzt aber voraus, dass alle möglichen Methoden in einer Klasse gesammelt werden.
- Dies zu bewerkstelligen kann wiederum einen recht hohen Programmieraufwand bedeuten.
|