Fremdkörper: Squirrel-Interpreter und Skripte für C++

Der weiterführende Artikel zeigt, wie sich der Squirrel-Interpreter und Skripte in C++-Anwendungen einbinden lassen.

Um ein Squirrel-Script aus einem Spiel oder einer Anwendung aufzurufen, muss man zunächst den Interpreter einbinden. Die dazu im Squirrel-Archiv mitgelieferte statische Bibliothek ist allerdings nur für C++-Programme ausgelegt. Anbindungen an andere Sprachen existieren derzeit noch nicht. Da aber auch der Quellcode des Interpreters recht schlank ausfällt, sollten Schnittstellen zu Java und Co leicht umzusetzen sein.
Hat man eine C++-Anwendung vorliegen, verlangt der Aufruf einer Squirrel-Funktion nur wenige zusätzliche Zeilen Programmcode. Möchte man beispielsweise die Squirrel-Funktion “quadrat(i)”

function quadrat(x)
{
 return x*x;
}

aus der Datei “quadrat.nut” starten, aktiviert man im C++-Programm zunächst den Interpreter respektive die von ihm angebotene virtuelle Maschine:

HSQUIRRELVM vm;
vm = sq_open(1024);

Die Funktion “sq_open()” erstellt eine virtuelle Maschine mit einer Stackgröße von hier anfänglich “1024” Elementen. Über diesen Stack tauschen Squirrel-Skripte und C-Programm gleich ihre Daten aus. Für alle nachfolgenden Aktionen muss man dort zunächst die Root-Tabelle ablegen:

sq_pushroottable(vm);

Als Nächstes kann man das Script laden. Für diese Standardaufgabe stellt die mitgelieferte Standard I/O Library (“sqstdio.h”) eine kompakte Funktion bereit:

sqstd_dofile(vm, "quadrat.nut",0,1);

Sie kompiliert das Squirrel-Skript “quadrat.nut” und führt es aus. In diesem Beispiel hat das lediglich zur Folge, dass die neue Funktion “quadrat()” in der Root-Tabelle landet. Jetzt muss man alle für den Aufruf der Funktion “quadrat()” nötigen Informationen auf den Stack schieben. Um später die aktuelle, aufgeräumte Situation wiederherstellen zu können, merkt man sich zunächst die Stackgröße:

int top = sq_gettop(vm);

Die “quadrat()”-Funktion liegt in der Root-Tabelle, folglich wandert sie zuerst auf den Stack:

sq_pushroottable(vm);

Es folgt der Name der Funktion:

sq_pushstring(vm,_SC("quadrat"),-1);

Der Parameter “-1” sorgt hier dafür, dass die Funktion die Stringlänge des Namens automatisch bestimmt. Als Nächstes zerrt man die eigentliche Funktion aus der Root-Tabelle:

sq_get(vm,-2);

“sq_get()” holt sich das erste Objekt vom Stack (in diesem Fall der String “quadrat”) und benutzt es als Schlüssel auf das nächste Element (der Root-Tabelle). Das Ergebnis (die Funktion “quadrat()”) landet anschließend auf dem Stack. Jetzt ist der Parameter an der Reihe. Dazu muss zunächst wieder die Root-Tabelle auf den Stack:

sq_pushroottable(vm);

gefolgt von einer Integerzahl:

sq_pushinteger(vm, 3);

Abschließend muss man nur noch die Squirrel-Funktion aufrufen:

sq_call(vm,2,1,0);

Die Zahl “2” zeigt an, dass die Funktion nur zwei Parameter hat (“this” und die Zahl). Der dritte Parameter weist darauf hin, dass die Squirrel-Funktion ein Ergebnis zurückliefert. Genau das landet wieder oben auf dem Stack, wo man es nur noch abholen muss:

int ergebnis;
sq_getinteger(vm,sq_gettop(vm),&ergebnis);
<literal>
"sq_gettop(vm)" zeigt "sq_getinteger()" dabei das oberste Element auf dem Stack. Abschließend gilt es noch aufzuräumen. Als Erstes stellt man die ursprüngliche Stackgröße wieder her: <literal>sq_settop(vm,top);

Für “sqstd_dofile()” liegt jetzt auf dem Stack noch einmal die Root-Tabelle. Auch sie ist jetzt überflüssig:

sq_pop(vm,1);

Zu guter Letzt fährt man noch die virtuelle Maschine herunter:

sq_close(vm);

Listing 5 zeigt noch einmal das komplette Beispiel.

Listing 5: Beispiel für den Aufruf einer Squirrel-Funktion aus C++

#include <stdarg.h> 
#include <stdio.h> 

#include <squirrel.h>
#include <sqstdio.h>

int main(int argc, char* argv[]) 
{
 // VM erstellen:
 HSQUIRRELVM vm; 
 vm = sq_open(1024); 

 // Root-Tabelle auf den Stack:
 sq_pushroottable(vm);

 // Script laden:
 sqstd_dofile(vm, "quadrat.nut",0,1);

 // Funktion holen und auf den Stack legen:
 int top = sq_gettop(vm); //merke die Stackgröße
 sq_pushroottable(vm); //Root-Tabelle auf den Stack
 sq_pushstring(vm,_SC("quadrat"),-1); // Name auf den Stack:
 sq_get(vm,-2); // Funktion holen

 // Parameter auf den Stack und Funktion aufrufen:
 sq_pushroottable(vm); // Root-Tabelle auf den Stack
 sq_pushinteger(vm, 3); // Füttere quadrat() mit 3
 sq_call(vm,2,1,0);  // Funktion aufrufen:

 // Ergebnis holen und ausgeben:
 int ergebnis;
 sq_getinteger(vm,sq_gettop(vm),&ergebnis);
 printf("%d \n", ergebnis);

 // VM stoppen und aufräumen:
 sq_settop(vm,top);
 sq_pop(vm,1);
 sq_close(vm);
 return 0; 
}

Die erforderlichen Headerdateien “squirrel.h” und “sqstdio.h” lagern im Unterverzeichnis “include” des Squirrel-Archivs, die beiden zugehörigen statischen Bibliotheken unter “libs”. Nach dem gleichen Prinzip kann man auch umgekehrt aus Squirrel-Scripten heraus C++-Funktionen aufrufen. Wem die ganzen Funktionen zu umständlich erscheinen, der findet gleich mehrere C++Klassenbibliotheken im Squirrel-Wiki

E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben