Lua C:我该如何使用Lua源代码创建一个Lua解释器,以便执行给定的Lua代码块?

我想要一个详细的解释。

如何使用 Lua 源代码创建一个 Lua 解释器,可以执行给定的 Lua 代码块?这些 Lua 代码块将以 char 的形式发送。

原文链接 https://stackoverflow.com/questions/4271857

点赞
stackoverflow用户28045
stackoverflow用户28045

调用Lua从C

这篇文档解释了如何在C代码中调用Lua,以及如何将值从Lua传递到C中。

如果您对Lua和C的交互感到困惑或者在忙于写一些需要使用绑定的代码,本文可以为您提供很大的帮助。

这篇文档是关于使用Lua 4.0的,但是随着版本的更新,整体的逻辑并没有变化。

湾区Lua用户组邮件列表中的范例

以下是使用Lua 4.0的范例代码,其中最关键的部分是将信息从Lua堆栈中提取并使用它们。

//Including Lua's sources
  #include "lua/src/lua.h"
  #include "lua/src/lualib.h"
  #include "lua/src/lauxlib.h"

  int main (void) {

    lua_State *L = lua_open();

    //Load the Lua code chunk into the lua_State struct
    luaL_loadstring(L, "function testme(x) return x * 2 end");

    //Call the function testme with the argument 9
    lua_pushnumber(L, 9);
    lua_call(L, 1, 1);
    printf("%d ", (int)lua_tonumber(L,-1));
    lua_pop(L, 1);  /* pop returned value */
    lua_close(L);

    return 0;
}

关于c++的同类型事情

以下是一个简单的例子,显示如何将一个table从Lua中传递到C++。

该例子通过在Lua中调用一个函数并将其返回值存储在C++的变量中来展示。

struct LuaRef
{
  lua_State *ref;
  int stackPos;

  LuaRef(lua_State *L, int index) :
    ref(L), stackPos(lua_gettop(L))
  {
    // Push the element at index onto the stack (adds a lua reference)
    lua_pushvalue(L, index);
  }

  // Copy constructor
  LuaRef(const LuaRef& ref) :
    ref(ref.ref), stackPos(ref.stackPos)
  {
    // Duplicate the stack position to keep this reference alive
    lua_pushvalue(ref.ref, ref.stackPos);
  }

  // Destructor
  ~LuaRef()
  {
    // remove the ref from the stack
    lua_pop(ref, 1);
  }

  // Implicit const char* conversion operator (for getting string references)
  operator const char* () const
  {
    return lua_tostring(ref, stackPos);
  }

  // Explicit bool conversion operator (for checking if the reference is not nil)
  explicit operator bool () const
  {
    return !lua_isnil(ref, stackPos);
  }

  // Return a reference to a specific field of the table
  LuaRef operator [] (const char* key) const
  {
    // Push the key on the stack followed by the table
    lua_pushstring(ref, key);
    lua_gettable(ref, stackPos);
    return LuaRef(ref, -1);
  }

  // Call the Lua function with the provided arguments
  template<typename ...Args>
  LuaRef operator () (Args&&... args) const
  {
    // Push the function onto the stack
    lua_pushvalue(ref, stackPos);

    // Push each argument onto the stack
    int n = sizeof...(Args);
    int result = push_args(ref, std::forward<Args>(args)...);
    if (result != LUA_OK) throw_lua_error(ref, result);

    // Call the function with the given arguments
    result = lua_pcall(ref, sizeof...(Args), LUA_MULTRET, 0);
    if (result != LUA_OK) throw_lua_error(ref, result);

    // Return a reference to the result(s)
    return LuaRef(ref, -1);
  }

  // Push an object onto the Lua stack
  template<typename T>
  void push(T&& value) const
  {
    push_value(ref, std::forward<T>(value));
  }
};

// Custom exception class for Lua errors
class LuaError : public std::runtime_error
{
public:
  LuaError(const std::string& error = "") :
    std::runtime_error(error)
  {}
};

// Helper function for pushing arguments onto the stack
template<typename T>
int push_value(lua_State *L, T&& arg)
{
  stack<T, pusher<T>>::push(L, std::forward<T>(arg));
  return 1;
}

// Specialization for const char* strings
template<>
int push_value<const char*>(lua_State *L, const char* const &arg)
{
  lua_pushstring(L, arg);
  return 1;
}

// Specialization for returning multiple values
template<typename ...Args>
class stack<return_type<Args...>, returner<Args...>>
{
public:
  static return_type<Args...> get(lua_State *L, int index, int& results)
  {
    // Push the function arguments onto the stack (and ignore any extra values)
    int size = push_args(L, std::forward<Args>(Args)..., const char*());
    index -= size;

    // Call the function with the given arguments
    int result = lua_pcall(L, size, LUA_MULTRET, 0);
    if (result != LUA_OK) throw_lua_error(L, result);

    // Retrieve the results from the Lua stack
    results = lua_gettop(L) - index + 1;
    return get_return_values<return_type<Args...>>::get(L, index, results);
  }
};

// Main application loop
int main()
{
  try
  {
    // Start the LuaVM
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    // Load the script
    luaL_dostring(L, R"(
      function createTable()
        return {
          name = "Bob",
          age = 30,
          occupation = "plumber",
        }
      end
    )");

    // Call the Lua function and store the result as a LuaRef
    LuaRef table = LuaRef(L)()["createTable"]();

    // Get the contents of the table (by key) and print them to the console
    std::cout
      << "Name: " << table["name"]
      << ", Age: " << table["age"]
      << ", Occupation: " << table["occupation"]
      << std::endl;
  }
  catch (const std::exception &e)
  {
    // Handle any Lua errors (syntax errors, runtime exceptions, etc.)
    std::cerr << "Error: " << e.what() << std::endl;
  }

  return 0;
}

在这个例子中,我们向Lua注册了一个函数,返回一个名为“ Bob”的对象。

C++代码使用LuaRef结构来获取该对象并输出其内容。

2010-11-24 21:56:20
stackoverflow用户65696
stackoverflow用户65696

你需要调用 lua_load 来编译代码块,然后调用 lua_call 来运行它。如果想要一个很好的实例来学习如何实现,可以查看这里的示例

任何 Lua API 函数的第一个参数始终是解释器状态,即 lua_open() 的返回值。

该示例实际上使用 luaL_loadbuffer 来封装对 lua_load 的调用,使 C 字符串的编译变得更容易。您可以在参考手册中的辅助库章节中了解如何使用它。这会在 lua 堆栈的顶部留下一个 lua _chunk_,然后可以用 lua_call 来调用它,但示例使用 lua_pcall,它提供一些错误处理。由于你刚刚编译的 chunk 不带任何参数(它是一个 chunk 而不是函数)并且没有任何你感兴趣的返回值,而且你想看到完整的错误信息,因此除了第一个参数(始终是 lua 解释器状态)之外的所有参数都可以是零。

2010-11-24 22:02:38