GameMonkey Script

GameMonkey Script Forums
It is currently Mon Mar 25, 2019 1:39 pm

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Sat Dec 29, 2007 2:10 pm 
Offline

Joined: Thu Dec 20, 2007 8:55 am
Posts: 13
Currently, I'm working on a script system that make binding transparent and effortless to use with PALib ( Nintendo DS homebrew SDK)
After googling, I found:

- Python: Excuse me, is this an embedded script language? :wink: :wink:
- AngelScript http://www.angelcode.com/angelscript/ : has the ability to directly access C++ code since its function calling part is written in assembly. However, it's kinda big for a handheld with 4MB of RAM and the language is like a "scripted C++" . Moreover, ARM(NDS's processor) does not have the "call" instruction like x86, it uses some other crazy asm things that I don't want to look into. So AngelScript won't compile
- Lua: No, thanks I don't like basic-like style. (if then) and luabind , the easiest binding system is not so light. It requires Boost.
-This article : http://www.codeguru.com/cpp/w-p/dll/article.php/c115/ . The second part is the main point of it(calling function dynamically by asm) but the first part is what I'm into. Consider this piece of code:

Code:
int myFunction(short a, short b)
{
 cout<<a<<endl;
 cout<<b<<endl;
 return a+b;
}

struct _stack
{
 unsigned long args[10];
}stack
typedef int (*funcPointer)(_stack);

stack.args[0]=1;
stack.args[1]=2;

cout<<((funcPointer*)myFunction)(stack)<<endl;

--> It'll prints
1
2
3
This is what I'm using.

This solution advantages:
-Works on almost all systems with a C++ compiler because it leaves the function calling part to the compiler
-Easy to understand since everything is in C/C++ no asm
Disavantages:
-Works with cdecl only since the caller will take care of the stack
-Limited stack size
-Can be slow since extra data are pushed/poped every function call

How to use
Include gmFunctionWrapper.h and .cpp+ gmFunctionManager.h and .cpp
Binding function is as easy as this:
Code:
#include "gmFunctionManager.h"

int myFunction(short a, short b)
{
 cout<<a<<endl;
 cout<<b<<endl;
 return a+b;
}

void myFunction2(char* str)
{}

float myFunction3(char* str,float a)
{}

int main(blah blah)
{
  gmMachine machine;
  gmFunctionManager manager(&machine);
  library(testLib)
  {
     def(GM_INT,myFunction,"ii"),
     def(GM_NULL,myFunction2,"s"), //non-returning function is of type NULL
     def(GM_FLOAT,myFunction3,"sf")
  };
/*The syntax is
library(library's name)
{
 def(return type,function pointer,parameters' types),
 def(return type, function pointer 2, parameters' types)
}
paramters' type:
i= int
f= float or int
s= string
t= table
u= user-defined type (no checking)
*/
  manager.registerLibrary(testLib,sizeof(testLib)/sizeof(testLib[0]),"testLib");

//To bind 1 single function:
//manager.registerFunction(return type,function pointer, function name, parameters' types)
 manager.registerFunction(GM_INT,printf,"printf","s");
}


Remarks:
-Define GM_NO_TYPE_CHECK to bypass type checking
-Define GM_HANDLE_EXCEPTION to enable some simple exception handlings
-When a host function crashes. The program will break at gmFunctionProxy. If it is debug mode, check wrapper->name for the name of the script function.
-Refers to the attached project for more info

TODO:
-Param type checking
-Investigate the strange bug when binding printf

Limitation:
-Will not work properly with printf due to the way it handles doubles and floats
-cdecl functions only because caller cleans the stack, we can push in more than what's needed
-Cannot pass a struct as an argument or return value. However, pointer to a struct is supported.

Download:
http://www.zshare.net/download/73106885a2f2cd/


Last edited by bull on Fri Feb 08, 2008 10:13 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 30, 2007 1:00 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 708
Good stuff bull! Thanks for sharing that, and welcome to the forum. As you suggest, even if not used asis, your imlementation could be the basis for other, (not necessarily GM) binding systems.

Here's a few misc thoughs after looking at your implementation:
o You could add optional parameter validation by getting the user to enter a parameter type string eg.
def(GM_INT,myFunction,"ii"),
Where "ii" is scanned rapidly at call time (or in debug build) to check for integer type.
o Consider alternate macros to simplify syntax eg.
beginlib() // Maybe skip name and just reg per whole file? Use singleton to auto-reg?
reg() // Skip trailing comma?
reg()
endlib() // Close quotes etc?
o Add simple example usage to your source code in comment or readme like you have in the forum.
o The stack implementation (all params are Int32) is not portable. Eg. The PowerPC CPU used in Xbox 360 and PS3 will need float params passed differently. There are various work arounds for this.

Anyway, just a few thoughts. Good work :)


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 06, 2008 6:39 pm 
Offline

Joined: Fri Nov 24, 2006 9:50 am
Posts: 165
Interesting - is that really safe? (the whole passing an array by value to a typecast-overriden function call?)
It seems like it could be and is kind of a crazy way to get around that particular C/C++ limitation.

The only concern I have is that it will be copying 10 values every time - is there a way to construct the array inline so as to remove that copy?

something like func( array( val1, val2, val3 ) )

or at least template it to reduce the copy size (you could create a template class to define a calling function for each no. of parameters).

As Greg says, a validator string would be great too - then you could even take const char* params and cast the pointers to int32s for the stack array. Scanning through the validation string to prepare the args is little to no cost at all at runtime.

SomeFunc( const char* name, float x, float y, int flags )

...
def( SomeFunc, STRING FLOAT FLOAT INT );

where STRING is a macro containing "s", FLOAT is "f" etc., to concatenate into "sffi".

Seems like a great system.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 21, 2008 8:41 am 
Offline

Joined: Thu Dec 20, 2007 8:55 am
Posts: 13
Quote:
u could add optional parameter validation by getting the user to enter a parameter type string eg.
def(GM_INT,myFunction,"ii"),
Where "ii" is scanned rapidly at call time (or in debug build) to check for integer type.

I'm working on it
Do u have any idea how to provide a syntax for user-type parameters?

Quote:
Consider alternate macros to simplify syntax eg.
beginlib() // Maybe skip name and just reg per whole file? Use singleton to auto-reg?
reg() // Skip trailing comma?
reg()
endlib() // Close quotes etc?

Sorry, i prefer the current syntax, it's more C-like: {} instead of "begin end"
singleton to auto-reg? wat do you mean?

Quote:
Add simple example usage to your source code in comment or readme like you have in the forum.

Ok

Quote:
The stack implementation (all params are Int32) is not portable. Eg. The PowerPC CPU used in Xbox 360 and PS3 will need float params passed differently. There are various work arounds for this.

I know nothing about those platforms so I can't do anything about it.
The "stack" is also not a real stack but a "reversed stack". You can see how I "push" parameters into the "stack", which is actually passing all params as an array. So I think it will still work on those platforms.

Quote:
is that really safe? (the whole passing an array by value to a typecast-overriden function call?)

As long as the return type is correct, calling convention is cdecl, I think nothing wrong can happen.

Quote:
The only concern I have is that it will be copying 10 values every time - is there a way to construct the array inline so as to remove that copy?

There is a way but it's not very nice. Since C++ template is compile-time, not run-time. I have to do something like this:
switch(stackPointer)
{
case 1:
call<1>();
break;
case 2:
call<2>();
break;
....
}

Quote:
something like func( array( val1, val2, val3 ) )

It means every function has its own "stack" which will eats up a lot of memory.

Quote:
-I'm working on class binding using the same technique.

Seems like it's not possible. According to wikipedia, MSVC++ do thiscall similar to stdcall while gcc do it like cdecl. It means no extra params can be passed for MSVC


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 21, 2008 12:57 pm 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 708
bull wrote:
I'm working on it
Do u have any idea how to provide a syntax for user-type parameters?

I only use a few user types like Vector3 and GameObject so only a couple of letters are required. I find it easier to work with few types and work around those limitations than try to duplicate more types or hierarchies in script. Manual bindings may be used for special rare cases. I also use a 'many' parameter binding which behaves like C '...' but does not map directly to native type parameters.
Quote:
singleton to auto-reg? wat do you mean?

At present you declare a binding then manually register it later. You could use a static variable with constructor to add the declaration to a container, then later in code at one place, register all bindings together.

(Refering to other comments...)Yes it is hard to elliminate copies. Still, a carefully coded Param struct/class with overloaded constructor can help accept variable inputs with a single copy and store.


Top
 Profile  
Reply with quote  
PostPosted: Fri Feb 08, 2008 10:16 am 
Offline

Joined: Thu Dec 20, 2007 8:55 am
Posts: 13
Updated, please refer to first post

Changes:
-Added parameter validation.
-Use an object: "gmFunctionManager" to control binding. Memory is freed when gmFunctionManager is deleted

Quote:
At present you declare a binding then manually register it later. You could use a static variable with constructor to add the declaration to a container, then later in code at one place, register all bindings together.

I'm using a "gmFunctionManager" now. I think a single-ton might not be flexible as in some cases, the user might want to use several gmMachine.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group