Bestes Design für die API einer eingebetteten Scriptsprache?



  • Hallo,

    ich habe mich nun Informiert, wie das im großen und ganzen mit Scanner, Interpreter und Parser funktioniert.

    Jetzt stellt sich mir aber die Frage, wie man denn am besten die API für so eine eingebettete Scriptsprache designt.

    Die LUA-API benutzt beispielsweise einen Stack, d.h. die API bietet Funktionen, mit denen man Werte auf einen lib-internen Stack legen kann. Danach ruft man eine Funktion auf, und das Ergebnis wird wiederrum auf den Stack gelegt, von dort kann man sich die Werte per extra Funktion abholen.

    Ich halte das zwar für die Lösung, die am einfachsten umzusetzten ist, aber irgendwie dann doch unnötig umständlich (oder?).

    Wie machen das denn andere APIs von eingebetteten Script- und Programmiersprachen? Python usw.?

    oder anders gefragt: Wie würdet ihr das designen? Mit Stack oder doch anders?



  • Schon mal ueberlegt, wie normalerweise Parameter in C oder C++ an Funktionen uebergeben werden, bzw. wie das auf dem Prozessor in Binaercode realisiert wird?

    Die LUA-API benutzt beispielsweise einen Stack

    Ich wuerde es eher als Array bezeichnen, aber das ist kein grosser Unterschied.

    Mit Stack oder doch anders?

    Mit Stack ...



  • Du schlägst also Design ala LUA vor?



  • Die Lua Entwickler sind hochgelobte Ingenieure und Professoren, die Sprache wird seit 20 Jahren fast pausenlos entwickelt, in den besten Spielen unserer Zeit eingesetzt und gehört zu den schnellsten.
    Zudem ist die API der Hardware nachempfunden und stand stets im Fokus über der Sprache selbst.

    Du machst also nichts falsch, dir daran ein Beispiel zu nehmen.



  • Ein Grund für so ein Design ist der Garbage Collector. Man kann Lua-Werte nicht direkt kopieren, weil der GC diese dann aus den Augen verlieren würde. Der Stack ist eine Wurzel des GC. Echte Zeiger auf Stack-Elemente gibt Lua einem nicht, weil der Stack bei einer Reallokation verschoben werden kann. Stattdessen spricht man Stack-Elemente mit Indizes an.
    In C fehlen Sprachmittel, um dieses Problem zu umgehen. Komplexe APIs sind in C nicht ungewöhnlich. Die Lua-APIs sind "gut genug".
    Wie man so etwas in C++ machen würde, zeigt Luabind, ein Wrapper für Lua. Da sind Lua-Werte als echte Werttypen verfügbar. Lua-Funktionen können direkt mit C++-Werten aufgerufen werden. C++-Funktionen können unkompliziert in Lua verfügbar gemacht werden.



  • es kommt auch drauf an was du mit der scriptsprache vor hast. lua ist ja eher ein theoretisches ding. es war weder dafuer gemacht schnell zu sein, noch um irgendwas mehr zu machen als den leuten die theorie zu zeigen. die ersten versionen haben entsprechend komplett auf stack interpreter gesetzt und waren sehr ineffizient (mittlerweile, ich glaube seit Lua5 laeuft es mittels registern statt nur stack). die API ist geblieben.
    wenn du also einfach nur einen interpreter basteln willst, kannst du lua nachcoden und machst nichts falsch. es ist auch recht ok fuer simple dinge.

    es gibt aber auch komplexe alternativen die z.B. vieles vom c++ code in die scriptsprache reflektieren, manchmal mit freakigen templates+macros, manchmal mit seperaten tools die ueber den c++ und script code gehen und stubs generieren fuers gegenseitige (transparente) aufrufen. damit kannst du sehr flexibel coden und merkst nichts davon dass es nur interpretiert ist, wenn du fertig bist, kannst du c++ code draus basteln und nochmal bauen, alles laeuft wie bisher nur schneller. (das ziel ist dann also die "API" komplett zu verstecken).
    funktionen aufrufen ist ja nur der einfache teil, aber gerade wenn du mehr mit scripten machst, wirst du schnell dazu kommen ganze klassen layouts, mit hierarchy etc. spiegeln zu muessen. ich hab das letztes jahr mit JNI fuer java gemacht, das ist echt unmengen an arbeit. nicht nur die implementierung, aber auch die wartung.

    fuer automatismus kannst dir z.B. http://www.swig.org/ anschauen.

    in letzter zeit hab ich auch einige entwickler gesehen die in richtung scripting mittels c++ gehen. in dem zusammenhang http://www.softintegration.com/

    falls du was wirklich gutes schaffen willst, werden die tools und die integration mehr zeit fressen als parser, compilre + interpret zusammen, also frag dich erstmal wirklich was du erreichen willst. stack ist gut genug fuer die meisten.



  • rapso schrieb:

    mittlerweile, ich glaube seit Lua5 laeuft es mittels registern statt nur stack

    Wo ist da denn der Unterschied in Software?



  • cooky451 schrieb:

    rapso schrieb:

    mittlerweile, ich glaube seit Lua5 laeuft es mittels registern statt nur stack

    Wo ist da denn der Unterschied in Software?

    Für Register-VMs oder Register+Stack VMs gibt es verschiedene Ansätze. Gemeinsam ist: sie haben Operationen die Regsiter nutzen.
    Im Compiler musst du register-allocation implementieren (verkompliziert die code erzeugung stark im vergleich zur einfachen Stackcode generierung)

    @API ...
    Ein AST-Interpreter währe auch eine Möglichkeit.
    Am besten du guckst dir noch einige andere APIS an.





  • gary1195 schrieb:

    cooky451 schrieb:

    rapso schrieb:

    mittlerweile, ich glaube seit Lua5 laeuft es mittels registern statt nur stack

    Wo ist da denn der Unterschied in Software?

    Für Register-VMs oder Register+Stack VMs gibt es verschiedene Ansätze. Gemeinsam ist: sie haben Operationen die Regsiter nutzen.
    Im Compiler musst du register-allocation implementieren (verkompliziert die code erzeugung stark im vergleich zur einfachen Stackcode generierung)

    und gleichzeitig kann es viele unnuetze verschiebeoperationen sparen. ein stack ist vermutlich ausreichend um formeln abzuarbeiten (deswegen ist die x86-fpu bzw x87 stack bassierend), aber program-flow, loops, verschachtelungen, funktionsaufrufe koennen recht ineffizient werden. aus der sich sind wohl 4 register ein ziemlicher sweat-spot was effiziens angeht.

    beim implementieren einer API nutzen manche scriptsprachen die internen register um darueber parameter zu bekommen (ich glaube pawn script macht das, aber nagel mich nicht drauf fest :P), manche (wie z.b. in der doom3 engine) nutzen auch die register der cpu um parameter an die scriptsprache zu uebergeben. (ich hab es vor einiger zeit auf x64 portiert und aufgrund ganz anderer calling convention, gerade zwischen float und int registern, war das sehr umstaendlich).


Log in to reply