Integrating LOLCode with C/C++

440 views
Skip to first unread message

Joseph Toppi

unread,
Feb 19, 2013, 10:50:32 PM2/19/13
to lci-g...@googlegroups.com
Is there documentation that covers extending the language to allow easier calls against C/C++ libraries? I am working on a game project and I want to be able to write LOLCode scripts that manipulate in game objects.

For example Lua has a concept of libraries which can be included either from a script or by C calls while setting up the Lua interpreter. Using the Lua API ( http://www.lua.org/manual/5.2/manual.html#4 ) you can make Lua functions in those libraries which are backed by C functions.

I think this is wrong, but my current line of research indicates it might be possible to inject FuncDefStmtNode instances ( http://lolcode.org/docs/struct_func_def_stmt_node.html ) at some stage of parsing to allow the actual script to call C functions.

Justin Meza

unread,
Feb 20, 2013, 9:36:32 AM2/20/13
to lci-g...@googlegroups.com
Hey Joseph,

I was thinking about this a bit and the cleanest way to do it may be to make some separate source code files for bindings to libraries and then, during interpretation, when a function name is not defined in any scope, check the "bindings" scope and perform the function call.

In fact, there should probably be a standard interface to use when generating new bindings to external libraries.  Library calls can specify a name and parameter structure to export to the user and then implement a function that is called when the interface they exported is called from the interpreter.

I think I may have seen some ideas on this on the old LOLCODE forums which may be worth looking for.

- Justin
--
You received this message because you are subscribed to the Google Groups "lci-general" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lci-general...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Joseph Toppi

unread,
Feb 21, 2013, 5:21:02 PM2/21/13
to lci-g...@googlegroups.com
I have only read bits and pieces of the doxygen, I will read more to get a better idea of how LCI does scope resolution. Superficially, what you say sounds like a sane way to handle it.

I can only think of one problem; the presumption that bound functions are checked last in resolution implies that in the event of a name collision that a name create in the script takes precedence simply because the binding scope/namespace wasn't and won't be checked. Depending on implementation difficulty it might make more sense to have the "bindings" put things in the same namespace as the main block before parsing a script so that duplicate names will be caught early and therefor remove the possibility of collisions. It also sounds like there would be one fewer token search if these were in the same scope, I assume there is some kind of tree structure used while searching for tokens.

I still can't get over how hilarious this syntax is. I am unaware of LOLCode supporting namespaces (other than typical programming scopes main, loop, local and conditional blocks) otherwise it would make sense to actually have some language mechanism to explicitly resolve scope. If scoped resolution did exist and I bound my game's types, the resulting syntax could look something like the following couldn't it?
I HAZ A PointInSpace ITZ A Vector3 FRUM Ogre3D


Ridiculousness aside, what would a set of "bindings" look like?

For example, Lua provides a mechanism to provide a name (for use in scripts), a pointer to a C function, a count of arguments, and passes this into the runtime (also called the Lua State). Then when being called it pushes the arguments from the script onto the Lua stack and the provided function is expected to pop the required arguments from the stack. In practice this leads to programmers who use Lua into creating a series of functions that do nothing but register functions with the Lua runtime and another series of functions to act as intermediaries between Lua and the actual functionality. If you make these for your project by hand, then it could become rather tedious but another project called SWIG can read a C/C++ source file and can emit these two groups of functions.

A set of language bindings that could handle call the C function call from a pointer directly without needing the stack intermediary would certainly be possible and easier to use. Likely there would be a performance cost though.

Justin Meza

unread,
Feb 21, 2013, 6:08:47 PM2/21/13
to lci-g...@googlegroups.com
I spent a bit of time yesterday browsing the old LOLCODE forums, thinking about this, and writing a little bit of pseudo-code.  First, here is what it may look like:

HAI 1.4
    CAN HAS STDIO?
    I HAS A filename ITZ "temp.txt"
    I HAS A mode ITZ "r"
    I HAS A file
    file R STDIO IZ FOPENIN YR filename AN YR mode
    BTW "file" is a BUKKIT with some state that's used by the stdio functions
    ...
    STDIO IZ FCLOSEIN YR file
KTHXBYE

Here is one possible implementation sketch which I tried to have leverage the existing parsing and interpretation structure as much as possible:

Create binding.{c,h}, which provide the binding infrastructure.  For example, in binding.h, there would be something like:

#ifndef __BINDING_H__
#define __BINDING_H__

#include "parser.h"

/**
 * Stores a binding to an external library call to export.
 */
typedef struct {
    IdentifierNode *library;    /**< The library this binding belongs to. */
    FuncDefStmtNode *interface; /**< The interface that exports the binding. */
} Binding;

#endif /* __BINDING_H__ */

Here, "library" is used to determine which top-level BUKKIT to add "interface" to as an element.  "interface" is defined like other FuncDefStmtNodes (i.e., it contains a function name, an argument list, and a function body), *except* that it's function body is actually a call to some C code that can reference the current variable scope (which will contain the arguments).  Here is how that might be accomplished:

In parser.h, add a new type of statement node, ST_BINDING, whose corresponding struct looks like this:

/**
 * Stores a binding to a native function.
 */
typedef struct {
    ReturnObject *(*binding)(ScopeObject *); /**< The function that implements the binding. */
} BindingStmtNode;

This is really ugly because it deals with a pointer to a function, but here is what is going on:  This statement type's member "binding" is a pointer to a C function that takes as an argument a pointer to a ScopeObject (which stores variable state), and returns a pointer to a ReturnObject.  This function could be implemented by the person binding libraries like this:

ReturnObject *FOPENIN(ScopeObject scope)
{
    /* extract arguments from scope */
    ValueObject fname = getScopeValueLocal(scope, ...);
    ValueObject mode = getScopeValueLocal(scope, ...);
    /* do actual binding stuff */
    FILE *file = fopen(getString(fname), getString(mode));
    /* create a BUKKIT and store "file" in it */
    return createArrayValueObject(/* the BUKKIT created above */);
}

This can be stored in the body of the FuncDefStmtNode from the Binding struct defined above, and will more or less "just work" with the existing function call code.

Notice that this will probably require modifying the ValueData union to store a new void * element of binary blob data to store state passed around among library calls.

Also, this implementation source code should probably live in a "libs/" folder in the main source code directory with sub-folders for each of the libraries ("libs/STDIO" and so on).  It would be nice to have pre-compiled BUKKITs for each of the libraries that can be dynamically inserted into the top-level scope as they are imported via "CAN HAS" statements.

Just some thoughts!

- Justin


Justin Meza

unread,
Feb 24, 2013, 2:47:23 AM2/24/13
to lci-g...@googlegroups.com
Just following up on this:  I made some additions to the future branch of lci that provides some basic support for binding to external libraries.  For example, the following code (libtest.lol) runs OK (it opens itself, reads its first 7 bytes, "HAI 1.3", and closes itself):

HAI 1.3

    CAN HAS STDIO?
    I HAS A file
    file R I IZ STDIO'Z FOPENIN YR "libtest.lol" AN YR "r" MKAY
    I HAS A str ITZ I IZ STDIO'Z FREADIN YR file AN YR 7 MKAY
    VISIBLE str
    I IZ STDIO'Z FCLOSIN YR file MKAY
KTHXBYE

The code needs to be cleaned up heavily.  There are lots of helper functions to be made, the organization of the library-specific code needs to be figured out, and importing syntax and calling syntax need to be handled / streamlined.  But it's a start.

- Justin

Joseph Toppi

unread,
Feb 26, 2013, 9:13:44 PM2/26/13
to lci-g...@googlegroups.com
I am sure that you know, but when I built the future branch and ran
the tests a few of them failed. Here is the summary 'make test' gave
me.

The following tests FAILED:
1 - 1-BFInterpreter (Failed)
19 - 1-Breaks (Failed)
20 - 2-Increment (Failed)
21 - 3-Decrement (Failed)
24 - 6-UnaryFunction (Failed)
287 - 1-If (Failed)
288 - 2-Else (Failed)
289 - 3-ElseIf (Failed)
290 - 1-Simple (Failed)
291 - 2-Breaks (Failed)
292 - 3-Default (Failed)
293 - 4-MixedTypes (Failed)
303 - 5-Recursion (Failed)
304 - 6-DoubleRecursion (Failed)

I suspect this is because of the syntax changes you mentioned but I
have not investigated yet. It might take me a few days to do so.


--
- Joe Toppi
(402) 714-7539
Top...@gmail.com

Justin J. Meza

unread,
Feb 26, 2013, 9:40:30 PM2/26/13
to lci-g...@googlegroups.com
Hey Joe,

> I am sure that you know, but when I built the future branch and ran
> the tests a few of them failed. Here is the summary 'make test' gave
> me.
>
> The following tests FAILED:
> 1 - 1-BFInterpreter (Failed)
> 19 - 1-Breaks (Failed)
> 20 - 2-Increment (Failed)
> 21 - 3-Decrement (Failed)
> 24 - 6-UnaryFunction (Failed)
> 287 - 1-If (Failed)
> 288 - 2-Else (Failed)
> 289 - 3-ElseIf (Failed)
> 290 - 1-Simple (Failed)
> 291 - 2-Breaks (Failed)
> 292 - 3-Default (Failed)
> 293 - 4-MixedTypes (Failed)
> 303 - 5-Recursion (Failed)
> 304 - 6-DoubleRecursion (Failed)
>
> I suspect this is because of the syntax changes you mentioned but I
> have not investigated yet. It might take me a few days to do so.

Thanks for pointing this out! (To be honest, I hadn't yet checked what
my changes had broken.) It turns out it was just that a few keywords
that ended in a question mark ("O RLY?" and "WTF?") were not getting
parsed correctly due to the new way I was parsing code for library
imports (question marks are now their own tokens).

Anyway, I pushed a change that now gives me a 100% pass rate on my
machine. Thanks again!

- Justin

Joseph Toppi

unread,
Feb 26, 2013, 9:42:25 PM2/26/13
to lci-g...@googlegroups.com
Now 'make test' says:

100% tests passed, 0 tests failed out of 307

Total Test time (real) = 11.14 sec


I will let you know how integration goes. If I make any helper
functions I will pass them along to you.
Reply all
Reply to author
Forward
0 new messages