DoubleX
DoubleX

Reputation: 371

Best way for C++ and Lua I/O interaction on stack

I was wondering the best way to interact with lua I/O in C++ code.

lua script:

while true do
    local input = io.read("*line")
    if input == "hello" then
        print("world")
    else
        print("hmmm...")
    end
end

C++ code:

lua_State* L = luaL_newstate();
luaL_openlibs(L);
int r = luaL_dofile(L, "foo.lua");

When I ran the C++ code, the foo.lua script I/O seems replacing the original I/O in C++. The another interesting thing is lua's function print seems to insert the value into the stack.(I can use lua_tostring(L, -1) to fetch the print message).

What I want to know is there any ways to interact with lua script more elegantly instead of covering my std I/O. Like, if I push the "hello" into the stack, it can gives me "world" back?

Upvotes: 0

Views: 637

Answers (1)

Personage
Personage

Reputation: 484

This is how I tend to write a C program that executes a Lua script using Lua's C API:

#include <stdio.h>
#include <stdlib.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#define MIN_ARGC 2

int main(int argc, char** argv) {
    // Check to make sure a Lua file was passed to this program as a command-line
    // argument.
    if (argc < MIN_ARGC) {
        fprintf(stderr, "Lua filename expected from command line\n");
        exit(EXIT_FAILURE);
    }

    lua_State* L = luaL_newstate();
    // NOTE: good idea to make sure the lua_State* initialized.
    if (!L) {
        fprintf(stderr, "Error initializing Lua\n");
        exit(EXIT_FAILURE);
    }

    // Open standard Lua libraries--math, string, etc.
    luaL_openlibs(L);

    // At this point, I register any C functions for use in Lua using the macro
    // lua_register.

    // I usually create an int called fail; if an error occurs during the execution of
    // the Lua script, fail is set to 1.
    int fail = 0;

    // Execute the Lua script passed to this program as argv[1]; and, in the event of
    // an error, print it to stderr.
    if ((fail = luaL_dofile(L, argv[1])))
        fprintf(stderr, "%s\n", lua_tostring(L, -1));

    // Make sure to close your lua_State*.
    lua_close(L);

    return (fail) ? EXIT_FAILURE : EXIT_SUCCESS;
}

Here is a trivial example of a C function that can be called from Lua. It returns an int and has one parameter, a lua_State*:

int lua_foo(lua_State* L) {
    printf("foo\n");
    return 0;
}

This is a lua_CFunction, and its return value refers to the number of values it will push on to the Lua stack. In the case of my trivial function lua_foo, it pushes nothing on to the stack, so it returns 0.

It could be registered with the macro lua_register as follows:

lua_register(L, "foo", lua_foo);

It could then be called from Lua, in a script executed by this program via luaL_dofile, as foo().

As for the example script that you provided in your question, there is no condition to break out of the while-loop. Try this instead:

while (true) do
    local input = io.read("*l")
    if (input == "hello") then
        print("world")
        -- Include a statement here to break out of the loop once the user has
        -- input 'hello'.
        break
    else
        print("hmm...")
    end
end

Upon inputting "hello," the loop will break and the script should successfully exit; and the value of r in your C/C++ code will be set to 0, indicating normal script execution by luaL_dofile.

EDIT:

As far as the part of your question concerning Lua I/O and "elegant" interaction with C, you have to remember that Lua is implemented in ANSI C; which means that, at a lower level, Lua calls C functions. There is nothing wrong with calling Lua I/O functions, so long as you handle them correctly, as they are simply Lua wrappers for C functions.

Upvotes: 1

Related Questions