Sign in to follow this  
  • entries
    149
  • comments
    510
  • views
    94474

Binding C functions

Sign in to follow this  
noaktree

96 views

Initial thoughts...

To bind a C function to the scripting language we must first define what each C function must look like. We we'll need a way to access parameter data sent by the scripting language - let's just call it an SL from now on. Also we'll need a way to return a value to the SL from the C language.

We will use the SL_Object class to bind functions and return data to the SL.

About the C functions...

C function parameters will be sent using a class named SL_To_C_Parameter_List. This class contains a vector list of Variable_Object_Data_s structs which will contain one of several possible data type's data. This parameter data is accessed through interface functions like int Get_SL_Integer(unsigned int Parameter_Index); All C functions will be of type void. So each function that is to be bound to SL will take the form:

void Function_Name ( SL_To_C_Parameter_List p );

The SL_Object will be used to return a particular value if the C function is not declared as type void. Wait... I hear you thinking, "I thought all bound C function's were of type void" and you're right according to C syntax but the SL brains will see each bound C function as having a return type value which is set at bind-time. A C function returns values to the SL using a function such as SL_Object.C_To_SL_Return_Integer( int Data); or a similar function that may send a string, float, or vector. These functions push the returned value onto a stack which can be accessed by the SL brains after the C function finishes execution.

So a typical C function might look like this:

void Switch_Camera (SL_To_C_Parameter_List Parameters)
{
// We kow that there is only one parameter and it an integer
int Camera_Index = Parameters. Get_SL_Integer(0);

// Set the new camera
// Return 0 to SL on fail then exit
if(FAILED(Set_Camera_By_Index(Camera_Index)))
{
SL_Object.C_To_SL_Return_Integer(0);
return;
}
else
SL_Object.C_To_SL_Return_Integer(1);
}


The binding function...

We will need to bind this C function to the SL using the Bind_C_Function(void (*Function_Pointer) (SL_To_C_Parameter_List), vector Parameter_Type_List, SLC_Parameter_Type Return_Type); member function of SL_Object.

The first parameter of this function is a pointer to any function of type void with a single parameter of type SL_To_C_Parameter_List. The second parameter is a vector list of each parameter expected by the C function. The SLC_Parameter_Type is just an enumerated type defined in the SL header. The third parameter defines the return type of the C function. With this knowledge Bind_C_Function() can add the C function to an internal function map which the SL accesses each time it is looking for a particular function to call. Within each map entry can be found a pointer to a C function that looks like this: void (*Function_Pointer) (SL_To_C_Parameter_List).

Now when the internal workings of SL want to call a C function it needs only to build a SL_To_C_Parameter_List P and call the function Function_Pointer(P); Then if the function is not of type void we pop the return value off of the return stack and use it in whatever expression the C function was called from within the SL script.

This is what I'll be implementing tomorrow. What do ya think?
Sign in to follow this  


6 Comments


Recommended Comments

Quote:
What do ya think?

Interesting [smile]

Although I'm no expert on the finer points of correct software architecture it does seem to have a couple of odd things.

The first one I noticed, which is quite possibly a non-issue, is type-safety (I think thats the correct name).

Your example for Switch_Camera() seems to rely on the presence of a single integer. For general purpose usage (where you personally might not be the author of the script/c-code) it seems like it could be easy to abuse/mis-use.

What happens if they request a non-existant element or element of a different type (element 0 is a float not an int)...?

The second one that looked odd was the return mechanism. Why not have the C-Func return the SL_Object? Having an automagically existing SL_Object that must be configured before a return just looks a little bit prone to programmer-error...

I'm sure it'll work fine though, and it's quite possible I've just misinterpretted what you wrote [smile]

Good luck!
Jack

Share this comment


Link to comment

Hehe, I use a similar system:

//script code
bln=AScriptCall("whee!");
//bln is true


//real code
void AScriptCall(ScriptCall *sc)
{
if(sc->ArgumentValid(0))
{
string str=sc->StringArgument(0);
//str is "whee!"
sc->Return(true);
}
}

Share this comment


Link to comment
Well, I read your script slightly differently that the others seemed to. When you wrote "Get_SL_Integer(0)", I assumed you meant the first integer in the parameter list...not the first parameter. If not...then I certainly concur with what seems to be a type-safety nightmare. You might want to check types...which can be a hassle for typing. I suppose the type checking could exist in "Parameters.Get_SL_Type()" method for your script.

Another possibility is to have some RTTI style stuff, and at the beginning of the methods have something like this:

SL_Object.Check_Parameter_List_Matches(SL_INT, SL_INT, SL_STRING);
(or use a vector)

Then, if the list isn't comprised of an INT, then another INT, then a STRING, you have a broken call.

Just an idea.

Share this comment


Link to comment
The way Lua does it is similair. The c binding function gets passed a stack with the parameters on it.

You can check the type of the parameter on top of the stack before you try to pull it off to avoid the type problems.

Share this comment


Link to comment
Quote:
What happens if they request a non-existant element or element of a different type (element 0 is a float not an int)...?

The second one that looked odd was the return mechanism. Why not have the C-Func return the SL_Object? Having an automagically existing SL_Object that must be configured before a return just looks a little bit prone to programmer-error...
I agree with the first issue completely. There needs to be a way to type check the parameters. The index value passed to the Get_SL_Integer function accessed the first parameter in the list. I had already decided to make these functions return a bool value. The type checking can take place internally. bool Get_SL_Integer(int Index, int &Out_Data);

As for the return type I like where you are going with this but you have a wrong view of the SL_Object. It is actually the interface for the script and is responsible for loading, executing, etc. So it will already exist. However it still seems a little clumsy to require its use in the C function. I will probably define a return type for C functions which allows the same sort of interface. Of course if the wrong type is returned then the SL interpreter would catch it and throw an error. The only thing that I don't like about this solution is that a return value is required even for void types.

Quote:
SL_Object.Check_Parameter_List_Matches(SL_INT, SL_INT, SL_STRING);
This is not a bad idea. Thanks for suggesting it. [smile]

I appreciate all of your comments. Thanks! [smile]

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now