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.
 
  |