Einführung in Purga (v.0.33)

Einleitung

Dieses Tutorial ist eine kleine Einführung in die Skriptsprache Purga von Virtual Maxim. Es wird dabei neben den Sprachmerkmalen auch die Verwendung von Purga in C++ gezeigt. Dabei wird Visual C++ 2005 verwendet.

Geschichte von Purga

Purga ist eine relativ junge Skriptsprache, die 2007 von Virtual Maxim entwickelt wurde. Sie befindet sich in einem recht frühen Entwicklungsstadium, läuft aber dennoch sehr solide und wird kontinuierlich erweitert.

Download und Installation

Bevor wir mit unserem ersten Purga-Skript starten können, müssen wir uns erst einmal den aktuellen Purga-Interpreter herunterladen. Dazu gehen wir auf die Virtual Maxim-Seite, wählen in der Navigation „Projekte“, „Aktuelle Projekte“, wählen das entsprechende Projekt aus und finden nun auf der Purga-Projektseite einen Downloadlink der aktuellen Purga-Version. Zur Zeit dieses Tutorials war das Version 0.33. Nach vollzogenem Download entpacken wir das Archiv in einem beliebigen Ordner. Es enthält unter anderem eine Beispielanwendung, eine Dokumentation als Übersicht über die Sprachmerkmale von Purga und natürlich die für die Programmierung mit Purga in C++ essentiellen Dateien, wie die Lib, die DLL und die Header. Lib und DLLs gibt es zudem für verschiedene Compiler (u. a. für Visual C++ 2005 und 2008).

Das erste Skript

Um gleich mal mit einem praktischen Beispiel zu beginnen wird auch in diesem Tutorial zu allererst ein „Hallo Welt“-Skript geschrieben, das in der Konsole eben diese Zeichenfolge ausgeben wird.

Wir erstellen also eine neue, leere Konsolenanwendung mit beliebigem Namen und fügen wir dem Projekt eine neue Datei hinzu, der wir den Namen „main.cpp“ geben und die wir mit einer Main-Funktion bestücken. Um den Purga-Interpreter verwenden zu können kopieren in das Projektverzeichnis die Lib, die DLL sowie den Include-Ornder. Wir includen zum Einen „iostream“, da wir enstprechende Funktionen zum Zeichnen in der Konsole brauchen, zum Anderen die Purga-Headerdatei.

#include <iostream>
#include "include/purga.h"

#pragma comment(lib, "purga.lib")

int main()
{
  return 0;
}

Nun deklarieren wir ein Objekt der Klasse Purga. Mit diesem können wir Purga-Skripte ausführen, Purga-Variablen auslesen und noch vieles mehr anstellen (mehr dazu im nächsten Kapitel „Purga-Klasse“). Am Ende unserer Main-Funktion entfernen das Objekt dann wieder.

int main()
{
  purga::Purga *p = new purga::Purga();

  delete p;

  return 0;
}

Da die Skriptsprache Purga von sich aus keine Möglichkeit hat irgendwelche Werte auszugeben, benötigen wir noch eine entsprechende Print-Funktion in C++:

void __stdcall print(const wchar_t* text)
{
  std::wcout << text << std::endl;
}

Diese Funktion soll in unserem zukünftigen Purgaskript aufgerufen werden. Damit dies geschehen kann müssen wir die Funktion beim Purga-Interpreter bekannt machen. Dies geschieht durch die Methode „RegisterFunction“. Diese benötigt den Funktionsprototypen und einen Zeiger auf die Funktion.

p->RegisterFunction(L"void print(char)", &print);

Nach dieser Bekanntgabe sind wir bereit für das erste Skript.
Dazu erstellen wir im Projektverzeichnis eine neue Textdatei mit dem Namen „hallowelt.purga“.
Anschließend geben wir in ihr unser erstes Purga-Skript ein:

@print("Hallo Welt");

Zur kurzen Erläuterung: Wir rufen hier unsere C++-Funktion auf, die wir zuvor beim Purga-Interpreter registriert haben. Funktionsaufrufe beginnen in Purga mit dem @-Zeichen, Zeilen schließt man, wie in C++, mit einem Semikolon.

Nun führen wir dieses Skript einmal aus. Zu diesem Zweck gibt es die „ExecuteScript“-Methode, der wir den Namen unserer Skriptdatei übergeben:

p->ExecuteScript(L"hallowelt.purga");

Zum Überblick und zur Kontrolle nochmal der gesamte C++-Code:

#include <iostream>
#include <windows.h>
#include "include/purga.h"
#pragma comment(lib, "purga.lib")

void __stdcall print(const wchar_t* text)
{
  std::wcout << text << std::endl;
}

int main()
{
  purga::Purga *p = new purga::Purga();

  p->RegisterFunction(L"void print(char)", &print);
  p->ExecuteScript(L"hallowelt.purga");

  delete p;

  return 0;
}

Purga-Klasse

Nach diesem ersten praktischen Beispiel wenden wir uns nun den weiteren Methoden der Purga-Klasse zu.

Übersicht:

  • bool CacheScript(const wchar_t* file) Skript wird in den Cache gelegt
  • bool ExecuteScript(const wchar_t* file) Führt eine Skriptdatei aus
  • bool ExecuteScriptString(const wchar_t* script) Führt ein Skript aus einem String aus
  • bool RegisterVariable(const wchar_t* var_name, type &var) Registriert die Variable var
  • bool GetVariable(const wchar_t* var_name, type& variable) Gibt eine Variable aus dem Skript zurück
  • bool RegisterFunction(const wchar_t* FullNameOfFunction, void* Function) Registriert eine Funktion unter dem Namen FullNameOfFunction
  • const wchar_t* GetVersion(void) const Liefert die Purga-Version zurück
  • GetLogManager LogManager &GetLogManager(void) const Gibt eine Referenz auf den LogManager zurück

CacheScript

Mit Hilfe der CacheScript-Methode kann man eine Scriptdatei im Cache ablegen, wodurch die Ausführungsgeschwindigkeit erhöht wird.

p->CacheScript(L"MeinSkript.purga");    // Skript in Cache legen
p->ExecuteScript(L"MeinSkript.purga");  // Skript ausführen

ExecuteScript

Führt ein Skript aus einer Datei aus.

p->ExecuteScript(L"MeinSkript.purga");  // Skript ausführen

ExecuteScriptString

Führt ein Skript aus einem String aus.

p->ExecuteScriptString(L"print(\"Hallo 2. Welt\")");

RegisterVariable

Registriert eine Variable, die im Purga-Skript unter dem angegebenen Namen angesprochen werden kann. Wenn diese im Skript geändert wird, wird sie auch in C++ geändert. Mehr zu Variablen in Purga im entsprechenden Kapitel.

int cppNumber = 42;
p->RegisterVariable(L"numma", cppNumber);

p->ExecuteScript(L"foo.purga");

GetVariable

Liefert den Wert, der mit dem angegebenen Namen Purga-Variable, zurück.

p->ExecuteScript(L"foo.purga");

int ret = 0;
p->GetVariable(L"number", ret);

RegisterFunction

Registriert eine C++-Funktion, die im Purga-Skript unter dem angegebenen Namen angesprochen werden kann. Alle Parameter der C++-Funktion müssen Referenzen sein. Als Rückgabetyp ist nur Integer zugelassen.

void __stdcall myFunction(int& arg)
{
  // ...
}

// ...

p->RegisterFunction(L"void meineFunktion(int)", &myFunction);
p->ExecuteScript(L"foo.purga");

GetVersion

Liefert die verwendete Purga-Version zurück.

std::wcout << p->GetVersion();

Die Skriptsprache Purga

Allgemeines

Nach dem vorherigen Kapitel, das die Verwendung von Purga in C++ beschrieben hat, folgt nun ein theoretisches Kapitel über die Sprache Purga an sich.

Kommentare

Auch im Bereich der Kommentare ähnelt Purga C++. So werden einzeilige Kommentare mit // eingeleitet und mehrzeilige von /* und */ umschlossen.

// Dies ist ein einzeiliger Kommentar...

/* Dies ist ein
mehrzeiliger
Kommentar */

Datentypen

Wie schon aus obiger Tabelle ersichtlich kennt Purga auch Datentypen. Um genau zu sein 4 Stück: Integer, Float, Boolean und Char.

Variablen

Variablen werden wie in C++ deklariert. Zuerst der Typ, dann der Variablenname. Zudem kann man schon bei der Deklaration einen Wert zuweisen.

int zahl = 12;
float zahl2 = 3.4;
bool leben = false;
char name = "Hans-Peter";

Operatoren

Purga unterstützt neben den 4 arithmetischen Operatoren (+, -, *, /) sowie dem Zuweisungsoperator (=) auch Inkrement- und Dekrementoperatoren (++, –) und Vergleichsoperatoren (<, <=, >, >=, ==, !=).

int one = 12;
int two = 13;
one++;

int result = one + two; // 26

If-Abfrage

If-Abfragen ähneln denen in C++.

if (a == 12)
{
  // ...
}
elseif (a > 12)
{
  // ...
}
else
{
  // ...
}

Desweiteren sind auch mehrere Bedingungen möglich. Derzeit kennt Purga allerdings nur die beiden logischen Operatoren Und (and) sowie Oder (or). Exklusives Oder (XOR) ist noch nicht vorhanden.

int number = 12;
int age = 56;
if (number == 12 or age == 56)
{
  // ...
}

Schleifen

Purga kennt 2 Schleifentypen: die while- und die for-Schleife. Variablen die im Kopf der Schleife deklariert werden, sind nur in der Schleife verfügbar.

while (i<= 20)
{
  // ...
}

for (int i=0; i<=10; i++)
{
  @print("i = " + i);
}

C++-Funktionen aufrufen

Wie bereits im Hallo-Welt-Skript erwähnt, kann man aus einem Purga-Skript heraus auch zuvor bekannt gegebene C++-Funktionen aufrufen. Solche Funktionsaufrufe beginnen mit einem @.

@meineFunktion(12, "Hallo");

Schreibe einen Kommentar