Sign in to follow this  
cypherx

Help with C/C++ interface for my language

Recommended Posts

Hi, I've been writing a lisp-derivative scripting language. I'm quite happy with the features (first-class closures, partial function evaluation, a class-based object system, other goofy stuff I wanted to try implementing). The C/C++ interface however is really unfriendly. Every lisp function accepts an argument list (an s-expression) and returns another s-expression. So right now the only functions I can bind in C++ must have the signature Expr* (*func) (Expr*). This is a hassle since I have to write wrapper functions around any existing function I want to bind. Any ideas on how to make a better interface? (it currently works like this)
Expr* plus_one(Expr* args)
{
   double val = first(args)->getValue();
   val += 1.0;
   return new Number(val);
}

int main()
{
   LispMachine lisp;
   lisp.BindFunction("++", &plus_one);
   Expr* result = lisp.run("(++ 2)");
   cout << result;
}

Thanks, Alex

Share this post


Link to post
Share on other sites
For your returns, you could provide automatic conversions from C++ Datatypes to your expressions. Your example would become


double plus_one(Expr* args)
{
double val = first(args)->getValue();
return val += 1.0;
}


You will need several versions of the "bind" method, one for every return type plus one for the "Expr*". Then you can put the user function in a wrapper.

Share this post


Link to post
Share on other sites
It might be way more than you want, but you should take some time and write a swig module for your language and create wrappers through it.

www.swig.org

It's not particulary difficult(there are already like 10 other modules to look at). I believe it will be time well spent.

Share this post


Link to post
Share on other sites
Gorg,
Thanks for directing me to SWIG. For now I want to spend most of my time adding language features. Once those are conrete I will probably make a swig module.

Steadtler,
I like the idea of automatic type conversions, since I already implement them internally within the language (expr->getValue(), expr->toString()). Thanks for the idea.

-Alex

Share this post


Link to post
Share on other sites
I'm posting this for the benefit of anyone else struggling to make a good C++ interface to a scripting language. I finally made something that allows most C++ functions to be hooked in to my lispish language with minimal effort.

Example:

int f1(int x, int y) { return x + y; }
string f2 (float num) { num += 0.9; return lexical_cast<string>(num); }

int main()
{
LispMachine lisp;
lisp.BindFunction("adder", f1);
lisp.BindFunction("other-func", f2);

Expr result = lisp.RunString("(other-func (adder 2 3))");
print(result); //prints "5.9"
return 0;
}



The trick to binding different C++ data types to wrap the function pointer in an ExternalFunction class, which does type conversion from standard C++ types to my language's types. To cover all the possible types and different numbers of arguments requires really ugly gobs of partial template specialization...but it works, and the end-user never has to see the ugly insides.

-Alex

Share this post


Link to post
Share on other sites

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

Sign in to follow this